patch

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

patch

补丁生成

Third leg of the static pipeline (
/vuln-scan
/triage
/patch
). Turns a ranked list of verified findings into candidate diffs.
The skill never applies a diff to the target repo. Output is inert text in
./PATCHES/
for a human to review and apply out-of-band — see
docs/patching.md#reviewing-generated-patches
. There is no
--apply
or
--approve
flag by design: the capability isn't present, so it can't be prompt-injected into use.
Invoke with
/patch <findings-path> [--repo PATH] [--top N] [--id fNNN] [--model M] [--fresh]
.
Arguments (parse from
$ARGUMENTS
):
  • findings path (first positional, required):
    TRIAGE.json
    ,
    VULN-FINDINGS.json
    , a pipeline
    results/<target>/<ts>/
    directory, or any JSON the
    /triage
    ingest table recognizes.
  • --repo PATH
    : target codebase, read-only (default cwd). Required for static mode; the skill stops if cited files don't resolve under it.
  • --top N
    : patch only the N highest-severity true positives (static mode).
  • --id fNNN
    : patch only the finding with this id.
  • --model M
    : passed through to
    vuln-pipeline patch
    in execution-verified mode. Ignored in static mode (subagents inherit the orchestrator's model).
  • --fresh
    : ignore
    ./.patch-state/
    checkpoint and start over.
Tools. Prefer Read, Glob, Grep, Write, Task. Some sessions do not provision Glob or Grep;
allowed-tools
is a permission filter, not a loader. When they are unavailable, fall back to the read-only Bash commands whitelisted above:
rg
/
grep
for search,
ls
for enumeration,
head
/
file
/
wc
for sniffing,
jq
for JSON ingest. Bash is otherwise permitted only for
python3 .claude/skills/_lib/checkpoint.py
(state I/O) and
vuln-pipeline patch
(execution-verified delegate).
find
is NOT permitted.
Write scope. The Write tool may target ONLY paths under
./PATCHES/
and
./.patch-state/
. Never write into
--repo
, never
git apply
, never
patch
, never edit target source. If a step seems to require it, the step is wrong.

静态流水线的第三个环节(
/vuln-scan
/triage
/patch
)。 将已排序的已验证漏洞列表转换为候选diff文件。
本技能绝不会将diff应用到目标仓库。输出内容是
./PATCHES/
目录下的惰性文本,供人工审核后离线应用——详见
docs/patching.md#reviewing-generated-patches
。设计上没有
--apply
--approve
参数:该功能不存在,因此无法通过提示注入触发。
调用方式:
/patch <findings-path> [--repo PATH] [--top N] [--id fNNN] [--model M] [--fresh]
参数(从
$ARGUMENTS
解析):
  • 漏洞路径(第一个位置参数,必填):
    TRIAGE.json
    VULN-FINDINGS.json
    、流水线
    results/<target>/<ts>/
    目录,或任何
    /triage
    流程可识别的JSON文件。
  • --repo PATH
    :目标代码库,只读(默认当前目录)。静态模式下必填;若引用文件无法在此路径下解析,技能将终止。
  • --top N
    :仅为前N个最高严重性的真阳性漏洞生成补丁(静态模式)。
  • --id fNNN
    :仅为指定ID的漏洞生成补丁。
  • --model M
    :在执行验证模式下传递给
    vuln-pipeline patch
    。静态模式下忽略(子代理继承编排器的模型)。
  • --fresh
    :忽略
    ./.patch-state/
    检查点,从头开始执行。
工具:优先使用Read、Glob、Grep、Write、Task。部分会话未提供Glob或Grep;
allowed-tools
是权限过滤器,而非加载器。当这些工具不可用时,回退到上述白名单中的只读Bash命令:
rg
/
grep
用于搜索,
ls
用于枚举,
head
/
file
/
wc
用于探查,
jq
用于JSON解析。Bash仅允许用于
python3 .claude/skills/_lib/checkpoint.py
(状态输入输出)和
vuln-pipeline patch
(执行验证委托)。
find
命令不允许使用。
写入范围:Write工具仅能写入
./PATCHES/
./.patch-state/
路径下的文件。绝不能写入
--repo
目录,绝不能执行
git apply
patch
或编辑目标源代码。若某步骤似乎需要这些操作,则该步骤存在错误。

Checkpointing (runs before Phase 0 and after every phase)

检查点机制(在第0阶段前和每个阶段后运行)

State persists to
./.patch-state/
so a fresh
/patch
session resumes without re-spawning patch or reviewer subagents. All checkpoint I/O goes through
python3 .claude/skills/_lib/checkpoint.py
(atomic, JSON-validated). The Write→
--from
pattern keeps repo-derived bytes out of Bash argv; never pass payload via heredoc or stdin.
State files:
progress.json
(single source of truth:
{"status": "running"|"complete", "phase_done": N, "shards_done": [...]}
),
phaseN.json
,
_chunk.tmp
.
Start of run. Bash:
python3 .claude/skills/_lib/checkpoint.py load ./.patch-state
  • status == "absent"
    OR
    "complete"
    , OR
    --fresh
    in
    $ARGUMENTS
    → fresh start. Bash:
    python3 .claude/skills/_lib/checkpoint.py reset ./.patch-state
    , proceed to Phase 0.
  • status == "running"
    with
    phase_done == N
    → resume. Read
    phase0.json
    ..
    phaseN.json
    in order (and any
    shard_*.json
    listed in
    shards_done
    ), merge into working state, print
    Resuming from checkpoint: Phase N complete
    , skip to Phase N+1. Do not re-spawn any subagent whose output is already checkpointed.
End of every phase N. Write tool →
./.patch-state/_chunk.tmp
with the phase's JSON, then Bash:
python3 .claude/skills/_lib/checkpoint.py save ./.patch-state <N> <name> --from ./.patch-state/_chunk.tmp
End of run. After writing
PATCHES.md
and
PATCHES.json
, Bash:
python3 .claude/skills/_lib/checkpoint.py done ./.patch-state 4

状态会持久化到
./.patch-state/
目录,因此新的
/patch
会话可以恢复执行,无需重新启动补丁或审核子代理。所有检查点输入输出均通过
python3 .claude/skills/_lib/checkpoint.py
执行(原子操作,JSON验证)。Write→
--from
模式可避免仓库衍生字节进入Bash参数;绝不要通过 heredoc 或标准输入传递负载。
状态文件:
progress.json
(唯一可信来源:
{"status": "running"|"complete", "phase_done": N, "shards_done": [...]}
)、
phaseN.json
_chunk.tmp
运行开始:执行Bash命令:
python3 .claude/skills/_lib/checkpoint.py load ./.patch-state
  • status == "absent"
    "complete"
    ,或
    $ARGUMENTS
    中包含
    --fresh
    → 从头开始。执行Bash命令:
    python3 .claude/skills/_lib/checkpoint.py reset ./.patch-state
    , 进入第0阶段。
  • status == "running"
    phase_done == N
    → 恢复执行。依次读取
    phase0.json
    ..
    phaseN.json
    (以及
    shards_done
    中列出的所有
    shard_*.json
    ),合并到工作状态,打印
    Resuming from checkpoint: Phase N complete
    ,跳至第N+1阶段。不要重新启动任何输出已被检查点保存的子代理。
每个阶段N结束:使用Write工具将阶段的JSON写入
./.patch-state/_chunk.tmp
,然后执行Bash命令:
python3 .claude/skills/_lib/checkpoint.py save ./.patch-state <N> <name> --from ./.patch-state/_chunk.tmp
运行结束:写入
PATCHES.md
PATCHES.json
后,执行Bash命令:
python3 .claude/skills/_lib/checkpoint.py done ./.patch-state 4

Phase 0: Parse arguments and detect mode

第0阶段:解析参数并检测模式

0a. Parse
$ARGUMENTS

0a. 解析
$ARGUMENTS

Extract findings path (first positional),
--repo
(default
.
),
--top
,
--id
,
--model
,
--fresh
. If no findings path, stop and ask.
提取漏洞路径(第一个位置参数)、
--repo
(默认
.
)、
--top
--id
--model
--fresh
。若未提供漏洞路径,终止并询问用户。

0b. Detect mode

0b. 检测模式

Inspect the findings path:
  • execution-verified mode when the path is a directory containing
    reports/manifest.jsonl
    OR
    found_bugs.jsonl
    OR
    run_*/result.json
    (pipeline output). The findings have PoC bytes + ASAN traces + reproduction commands; the pipeline's verification ladder applies.
  • static mode otherwise:
    TRIAGE.json
    ,
    VULN-FINDINGS.json
    , generic finding JSON, or markdown. No PoC; the oracle is a fresh-context reviewer.
Record
mode
in working state. The two modes share Phase 1 ingest then fork at Phase 2.
Checkpoint: Write tool →
./.patch-state/_chunk.tmp
:
{"phase": 0, "mode": "exec"|"static", "args": {repo, top, id, model, findings_path}}
Then Bash:
python3 .claude/skills/_lib/checkpoint.py save ./.patch-state 0 mode --from ./.patch-state/_chunk.tmp

检查漏洞路径:
  • 执行验证模式:路径为包含
    reports/manifest.jsonl
    found_bugs.jsonl
    run_*/result.json
    的目录(流水线输出)。漏洞包含PoC字节、ASAN跟踪信息和复现命令;流水线的验证流程将生效。
  • 静态模式:其他情况,包括
    TRIAGE.json
    VULN-FINDINGS.json
    、通用漏洞JSON或Markdown文件。无PoC;验证依赖全新上下文的审核员。
在工作状态中记录
mode
。两种模式共享第1阶段的解析流程,在第2阶段分叉。
检查点:使用Write工具将以下内容写入
./.patch-state/_chunk.tmp
{"phase": 0, "mode": "exec"|"static", "args": {repo, top, id, model, findings_path}}
然后执行Bash命令:
python3 .claude/skills/_lib/checkpoint.py save ./.patch-state 0 mode --from ./.patch-state/_chunk.tmp

Phase 1: Ingest and normalize

第1阶段:解析与标准化

Same input contract as
/triage
Phase 1. Normalize every input format to a flat
findings[]
of dicts. Pull what's present; never guess what's absent.
/triage
第1阶段的输入规则一致。将所有输入格式标准化为扁平的
findings[]
字典数组。提取已有字段;绝不猜测缺失字段。

1a. Recognized containers (priority order)

1a. 可识别的输入容器(优先级顺序)

  1. TRIAGE.json
    — read
    .findings[]
    . Filter to
    verdict == "true_positive"
    .
    This is the canonical input: already verified, deduped, ranked, owner-tagged.
  2. VULN-FINDINGS.json
    — read
    .findings[]
    . Unverified; print
    Warning: VULN-FINDINGS.json is unverified scanner output. Consider /triage first.
    and continue.
  3. Pipeline results directory — one finding per
    reports/bug_NN/
    . Map
    report.json
    description
    ,
    crash.crash_type
    category
    , ASAN top-frame →
    file
    /
    line
    . Record
    bug_id = NN
    for the
    --bug N
    delegate flag.
  4. Generic
    *.json
    with a top-level list or a
    findings
    /
    results
    /
    issues
    /
    vulnerabilities
    array.
  1. TRIAGE.json
    — 读取
    .findings[]
    过滤出
    verdict == "true_positive"
    的条目
    。这是标准输入:已验证、去重、排序、标记所有者。
  2. VULN-FINDINGS.json
    — 读取
    .findings[]
    。未验证;打印
    Warning: VULN-FINDINGS.json is unverified scanner output. Consider /triage first.
    并继续执行。
  3. 流水线结果目录 — 每个
    reports/bug_NN/
    对应一个漏洞。 将
    report.json
    映射为
    description
    crash.crash_type
    映射为
    category
    , ASAN顶层栈帧映射为
    file
    /
    line
    。记录
    bug_id = NN
    用于
    --bug N
    委托参数。
  4. 通用
    *.json
    文件,包含顶层列表或
    findings
    /
    results
    /
    issues
    /
    vulnerabilities
    数组。

1b. Field aliases (canonical ← also-accept)

1b. 字段别名(规范字段 ← 兼容字段)

CanonicalAlso accept
file
path
,
location.file
,
filename
line
line_number
,
location.line
,
lineno
category
type
,
cwe
,
rule_id
,
crash_type
severity
severity_rating
,
level
,
priority
title
name
,
summary
,
message
description
details
,
report
,
body
,
evidence
,
rationale
recommendation
fix
,
remediation
,
mitigation
owner_hint
owner
,
component
Attach
id
(
f001
,
f002
, ... in ingest order; preserve existing ids from TRIAGE.json) and
source
(relative path of the file it came from).
规范字段兼容字段
file
path
,
location.file
,
filename
line
line_number
,
location.line
,
lineno
category
type
,
cwe
,
rule_id
,
crash_type
severity
severity_rating
,
level
,
priority
title
name
,
summary
,
message
description
details
,
report
,
body
,
evidence
,
rationale
recommendation
fix
,
remediation
,
mitigation
owner_hint
owner
,
component
添加
id
(按解析顺序为
f001
f002
...;保留TRIAGE.json中的已有ID)和
source
(来源文件的相对路径)。

1c. Filter and order

1c. 过滤与排序

  • If
    --id fNNN
    : keep only that finding.
  • If
    --top N
    (static mode): sort by
    severity
    HIGH > MEDIUM > LOW then
    confidence
    desc, keep the first N.
  • Drop findings with no
    file
    (cannot patch what cannot be located). Record them as
    skipped
    with reason
    "no source location"
    .
  • 若指定
    --id fNNN
    :仅保留该漏洞。
  • 若指定
    --top N
    (静态模式):按
    severity
    HIGH > MEDIUM > LOW排序,再按
    confidence
    降序排序,保留前N个。
  • 丢弃无
    file
    字段的漏洞(无法定位的漏洞无法修补)。将这些漏洞记录为
    skipped
    ,原因是
    "no source location"

1d. Locate the target codebase (static mode)

1d. 定位目标代码库(静态模式)

Resolve
--repo
. For the first 5 findings with a
file
, check the path resolves under repo (try as-given, then with common prefixes stripped). If none resolve, stop: tell the user the cited files aren't reachable and suggest a
--repo
value.
Checkpoint: Write tool →
./.patch-state/_chunk.tmp
:
{"phase": 1, "mode": ..., "findings": [...], "skipped": [...], "repo": ...}
Then Bash:
python3 .claude/skills/_lib/checkpoint.py save ./.patch-state 1 ingest --from ./.patch-state/_chunk.tmp

解析
--repo
路径。对前5个有
file
字段的漏洞,检查路径是否在仓库下可解析(先尝试原路径,再尝试去除常见前缀)。若均无法解析,终止:告知用户引用文件无法访问,并建议指定
--repo
值。
检查点:使用Write工具将以下内容写入
./.patch-state/_chunk.tmp
{"phase": 1, "mode": ..., "findings": [...], "skipped": [...], "repo": ...}
然后执行Bash命令:
python3 .claude/skills/_lib/checkpoint.py save ./.patch-state 1 ingest --from ./.patch-state/_chunk.tmp

Phase 2: Generate patches

第2阶段:生成补丁

Forks on
mode
.
根据
mode
分叉执行。

2A. Execution-verified mode — delegate to the pipeline

2A. 执行验证模式 — 委托给流水线

The pipeline already implements the build → reproduce → regress → re-attack ladder with executable oracles. Do not reimplement it.
For each finding (or once for the whole directory if no
--id
/
--top
filter), Bash:
vuln-pipeline patch <findings_path> --model <--model arg> [--bug <bug_id>]
The pipeline writes
<findings_path>/reports/bug_NN/{patch.diff, patch_result.json}
itself. After it returns, Read each
patch_result.json
and copy
verdict
+
rationale
into working state. Set
verified: "ladder_passed"
when
verdict.passed == true
, else
verified: "ladder_failed"
.
If the CLI exits non-zero (no
build_command
, missing target config), record the stderr as the finding's
error
and continue with remaining findings.
Skip Phase 3 (the ladder is the verifier). Proceed to Phase 4.
Checkpoint per finding: Write tool →
./.patch-state/_chunk.tmp
=
{"id": ..., "verified": ..., "verdict": ..., "diff_path": ...}
, then Bash:
python3 .claude/skills/_lib/checkpoint.py shard ./.patch-state <id> --from ./.patch-state/_chunk.tmp
. After all findings, write the consolidated phase payload to
_chunk.tmp
then:
python3 .claude/skills/_lib/checkpoint.py save ./.patch-state 2 generate --from ./.patch-state/_chunk.tmp
流水线已实现构建→复现→回归→重攻击的验证流程,包含可执行验证器。不要重新实现该流程。
对每个漏洞(若未指定
--id
/
--top
过滤,则对整个目录执行一次),执行Bash命令:
vuln-pipeline patch <findings_path> --model <--model arg> [--bug <bug_id>]
流水线会自行将补丁写入
<findings_path>/reports/bug_NN/{patch.diff, patch_result.json}
。执行完成后,读取每个
patch_result.json
并将
verdict
+
rationale
复制到工作状态。当
verdict.passed == true
时设置
verified: "ladder_passed"
,否则设置
verified: "ladder_failed"
若CLI执行非零退出(无
build_command
、缺少目标配置),将stderr记录为漏洞的
error
并继续处理剩余漏洞。
跳过第3阶段(流水线流程已完成验证)。进入第4阶段。
每个漏洞的检查点:使用Write工具将以下内容写入
./.patch-state/_chunk.tmp
=
{"id": ..., "verified": ..., "verdict": ..., "diff_path": ...}
,然后执行Bash命令:
python3 .claude/skills/_lib/checkpoint.py shard ./.patch-state <id> --from ./.patch-state/_chunk.tmp
。所有漏洞处理完成后,将合并后的阶段负载写入
_chunk.tmp
,然后执行:
python3 .claude/skills/_lib/checkpoint.py save ./.patch-state 2 generate --from ./.patch-state/_chunk.tmp

2B. Static mode — one patch subagent per finding

2B. 静态模式 — 每个漏洞对应一个补丁子代理

One Task per finding, all in a SINGLE assistant message for parallel execution.
subagent_type: "general-purpose"
. Never set
run_in_background
— you need the diff text, not an async handle.
Each subagent has read-only access to
--repo
. It cannot modify the target; it emits the diff as text in its response. The orchestrator writes that text to
PATCHES/bug_NN/patch.diff
.
每个漏洞对应一个Task,所有Task在同一条助手消息中并行执行。
subagent_type: "general-purpose"
。绝不要设置
run_in_background
——需要diff文本,而非异步句柄。
每个子代理对
--repo
拥有只读访问权限。它无法修改目标代码;仅能在响应中输出diff文本。编排器会将该文本写入
PATCHES/bug_NN/patch.diff

Patch subagent prompt (assemble once, reuse per finding)

补丁子代理提示词(组装一次,每个漏洞复用)

You are conducting authorized security research as part of a defensive
assessment. Your task: write a candidate fix for ONE verified vulnerability
finding in a codebase you have read-only access to.

You may use Read, Glob, and Grep ONLY on paths inside {REPO_PATH}. You may
NOT build, run, install, edit files on disk, or reach the network. You will
emit the fix as a unified diff in your final response; you will NOT apply it.

────────────────────────────────────────────────────────────────────────
FINDING:

  id:        {id}
  file:      {file}
  line:      {line}
  category:  {category}
  severity:  {severity}
  title:     {title}

  description:
  {description}

  recommendation:
  {recommendation or "(none provided)"}

────────────────────────────────────────────────────────────────────────
PROCEDURE:

1. READ THE CODE. Open {file} at line {line} and the surrounding function.
   Understand what the code does — do not trust the finding's description as
   the only source.

2. ROOT CAUSE FIRST. Trace backward from the cited sink to where the bad
   value or missing check originates. The fix usually belongs there, not at
   the line the scanner flagged. Name the root-cause location (file:line).

3. VARIANT HUNT. Grep for sibling call sites with the same pattern. Your fix
   should cover all of them, or your rationale should say why not.

4. MINIMAL DIFF. Smallest change that fixes the root cause. No refactoring,
   no drive-by cleanup, no reformatting, no comment-only changes. Match the
   surrounding code's style (brace placement, naming, error handling).

5. ADVERSARIAL SELF-CHECK. Re-read your diff as an attacker. Name one input
   variation that would reach the same bad state without tripping your
   change. If you can name one, your fix is at the wrong layer — go back to
   step 2.

6. REGRESSION TEST. As part of the diff, add ONE test case that fails before
   your change and passes after — placed wherever the project keeps its
   tests (look for test_*/, *_test.*, tests/, spec/). If no test directory
   exists, omit the test and say so in <test_note>.

────────────────────────────────────────────────────────────────────────
OUTPUT — your final response MUST contain exactly these tags. Emit the diff
verbatim between the markers; do NOT wrap it in ``` fences.

<patch_diff>
--- a/path/to/file
+++ b/path/to/file
@@ ... @@
 context line
-removed line
+added line
</patch_diff>
<rationale>what changed and why, mechanically — file:line of root cause,
what the change enforces</rationale>
<variants_checked>file:function pairs you grepped for the same
pattern, and whether each needed the fix</variants_checked>
<bypass_considered>the input variation you tried in step 5 and why it
no longer reaches the bad state</bypass_considered>
<test_note>where the regression test landed, or why none was
added</test_note>

If you determine the finding is NOT fixable as described (wrong file, code
already patched, finding is a false positive), emit:

<patch_diff>NONE</patch_diff>
<rationale>why no patch is appropriate</rationale>
You are conducting authorized security research as part of a defensive
assessment. Your task: write a candidate fix for ONE verified vulnerability
finding in a codebase you have read-only access to.

You may use Read, Glob, and Grep ONLY on paths inside {REPO_PATH}. You may
NOT build, run, install, edit files on disk, or reach the network. You will
emit the fix as a unified diff in your final response; you will NOT apply it.

────────────────────────────────────────────────────────────────────────
FINDING:

  id:        {id}
  file:      {file}
  line:      {line}
  category:  {category}
  severity:  {severity}
  title:     {title}

  description:
  {description}

  recommendation:
  {recommendation or "(none provided)"}

────────────────────────────────────────────────────────────────────────
PROCEDURE:

1. READ THE CODE. Open {file} at line {line} and the surrounding function.
   Understand what the code does — do not trust the finding's description as
   the only source.

2. ROOT CAUSE FIRST. Trace backward from the cited sink to where the bad
   value or missing check originates. The fix usually belongs there, not at
   the line the scanner flagged. Name the root-cause location (file:line).

3. VARIANT HUNT. Grep for sibling call sites with the same pattern. Your fix
   should cover all of them, or your rationale should say why not.

4. MINIMAL DIFF. Smallest change that fixes the root cause. No refactoring,
   no drive-by cleanup, no reformatting, no comment-only changes. Match the
   surrounding code's style (brace placement, naming, error handling).

5. ADVERSARIAL SELF-CHECK. Re-read your diff as an attacker. Name one input
   variation that would reach the same bad state without tripping your
   change. If you can name one, your fix is at the wrong layer — go back to
   step 2.

6. REGRESSION TEST. As part of the diff, add ONE test case that fails before
   your change and passes after — placed wherever the project keeps its
   tests (look for test_*/, *_test.*, tests/, spec/). If no test directory
   exists, omit the test and say so in <test_note>.

────────────────────────────────────────────────────────────────────────
OUTPUT — your final response MUST contain exactly these tags. Emit the diff
verbatim between the markers; do NOT wrap it in ``` fences.

<patch_diff>
--- a/path/to/file
+++ b/path/to/file
@@ ... @@
 context line
-removed line
+added line
</patch_diff>
<rationale>what changed and why, mechanically — file:line of root cause,
what the change enforces</rationale>
<variants_checked>file:function pairs you grepped for the same
pattern, and whether each needed the fix</variants_checked>
<bypass_considered>the input variation you tried in step 5 and why it
no longer reaches the bad state</bypass_considered>
<test_note>where the regression test landed, or why none was
added</test_note>

If you determine the finding is NOT fixable as described (wrong file, code
already patched, finding is a false positive), emit:

<patch_diff>NONE</patch_diff>
<rationale>why no patch is appropriate</rationale>

Spawn

启动子代理

For each finding in
findings[]
, build a Task call with the prompt above (substituting
{REPO_PATH}
,
{id}
,
{file}
,
{line}
,
{category}
,
{severity}
,
{title}
,
{description}
,
{recommendation}
).
description: "patch {id}"
.
If
len(findings) > ~40
, shard into sequential batches of ~40 (each batch one message). Per-finding shard checkpoint after each result is parsed.
If any Task call returns
status: "async_launched"
instead of the subagent's text, the runtime backgrounded it. Pick one recovery and use it for the whole batch:
  • If completion notifications arrive in your conversation: parse each subagent's tagged blocks from its notification
    result
    as it lands. Do not end your turn until every finding is accounted for.
  • If notifications do not arrive: do NOT poll transcript files. Re-spawn the missing patch subagents in a fresh Task batch (smaller shard, e.g. 10) and use the synchronous results. The same recovery applies to reviewer subagents in Phase 3.
findings[]
中的每个漏洞,使用上述提示词构建Task调用(替换
{REPO_PATH}
{id}
{file}
{line}
{category}
{severity}
{title}
{description}
{recommendation}
)。设置
description: "patch {id}"
len(findings) > ~40
,将其拆分为约40个漏洞一组的连续批次(每个批次对应一条消息)。解析每个结果后,为每个漏洞创建分片检查点。
若任何Task调用返回
status: "async_launched"
而非子代理的文本,表示运行时已将其后台执行。选择以下一种恢复方式并对整个批次使用:
  • 若对话中收到完成通知:在通知的
    result
    中解析每个子代理的标签块。直到所有漏洞处理完成后再结束当前轮次。
  • 若未收到通知:不要轮询转录文件。在新的Task批次中重新启动缺失的补丁子代理(更小的分片,例如10个)并使用同步结果。 该恢复方式同样适用于第3阶段的审核子代理。

Parse

解析结果

From each Task result, extract the five tagged blocks. Tolerate leading/ trailing whitespace, stray ``` fences, and HTML-escaped entities (
&lt;
&gt;
&amp;
— some runtimes escape angle brackets in notification payloads; unescape before writing the diff). If
<patch_diff>
is
NONE
or empty, mark
status: "no_patch"
. Otherwise write the diff text to
./PATCHES/bug_NN/patch.diff
(NN = zero-padded index in sorted order) and record
rationale
,
variants_checked
,
bypass_considered
,
test_note
.
Checkpoint per finding: Write tool →
./.patch-state/_chunk.tmp
=
{"id": ..., "bug_nn": "NN", "status": ..., "rationale": ..., ...}
, then Bash:
python3 .claude/skills/_lib/checkpoint.py shard ./.patch-state <id> --from ./.patch-state/_chunk.tmp
. After all findings, write the consolidated phase payload to
_chunk.tmp
then:
python3 .claude/skills/_lib/checkpoint.py save ./.patch-state 2 generate --from ./.patch-state/_chunk.tmp

从每个Task结果中提取五个标签块。允许存在首尾空格、多余的```围栏和HTML转义实体(
&lt;
&gt;
&amp;
— 部分运行时会在通知负载中转义尖括号;写入diff前需反转义)。若
<patch_diff>
NONE
或空, 标记
status: "no_patch"
。否则将diff文本写入
./PATCHES/bug_NN/patch.diff
(NN为排序后的零填充索引)并记录
rationale
variants_checked
bypass_considered
test_note
每个漏洞的检查点:使用Write工具将以下内容写入
./.patch-state/_chunk.tmp
=
{"id": ..., "bug_nn": "NN", "status": ..., "rationale": ..., ...}
,然后执行Bash命令:
python3 .claude/skills/_lib/checkpoint.py shard ./.patch-state <id> --from ./.patch-state/_chunk.tmp
。所有漏洞处理完成后,将合并后的阶段负载写入
_chunk.tmp
,然后执行:
python3 .claude/skills/_lib/checkpoint.py save ./.patch-state 2 generate --from ./.patch-state/_chunk.tmp

Phase 3: Independent review (static mode only)

第3阶段:独立审核(仅静态模式)

One reviewer subagent per generated diff, all in ONE message,
subagent_type: "general-purpose"
.
The reviewer never sees the finding's
description
,
recommendation
, or the patch author's
rationale
.
It gets only
{file, line, category}
plus the raw diff bytes, and re-derives whether the diff is a minimal, in-scope fix by reading the source itself. This keeps any instructions embedded in finding prose from reaching both the author and the gate.
每个生成的diff对应一个审核子代理,所有子代理在同一条消息中启动,
subagent_type: "general-purpose"
审核员绝不会看到漏洞的
description
recommendation
或补丁作者的
rationale
。仅能获取
{file, line, category}
以及原始diff字节,并通过读取源代码自行判断diff是否为最小化、符合范围的修复方案。这样可避免漏洞描述中嵌入的指令同时影响补丁作者和审核环节。

Reviewer prompt (assemble once, reuse per diff)

审核员提示词(组装一次,每个diff复用)

You are reviewing a candidate security patch as a maintainer would. You have
read-only access to the unpatched source at {REPO_PATH}. You may use Read,
Glob, Grep. You may NOT build, run, or apply the diff.

You have NOT seen the scanner's description of the vulnerability or the
patch author's reasoning. Work only from the location, the category, and the
diff.

LOCATION: {file}:{line}
CATEGORY: {category}

DIFF UNDER REVIEW:
<diff>
{diff_text — or, for diffs over ~50 lines, replace this block with:
"Read the diff at ./PATCHES/bug_NN/patch.diff" and let the reviewer Read it}
</diff>

────────────────────────────────────────────────────────────────────────
ANSWER FOUR QUESTIONS:

1. SCOPE. Does the diff touch only files/functions on the path between
   {file}:{line} and its callers? List any hunk that falls outside that
   path.

2. SUPPRESSION. Does the diff fix a root cause, or does it suppress the
   symptom (try/except: pass, early-return on a magic value, deleting the
   check that fired, lowering a log level)?

3. NEW SURFACE. Does the diff add parsing, trust a new input field, weaken
   validation elsewhere, or remove a security-relevant check?

4. STYLE. 0-10: would you merge this as-is?
   0-3 wrong layer / suppression; 4-6 correct but noisy; 7-10 minimal,
   targeted, matches surrounding style.

────────────────────────────────────────────────────────────────────────
End your response with EXACTLY:

  REVIEW: ACCEPT | REJECT
  STYLE_SCORE: <0-10>
  OUT_OF_SCOPE_HUNKS: <comma-separated file:line, or none>
  REASON: <2-4 sentences citing specific diff hunks and source lines>

ACCEPT requires: in-scope, root-cause fix, no new attack surface,
style >= 5. Otherwise REJECT.
You are reviewing a candidate security patch as a maintainer would. You have
read-only access to the unpatched source at {REPO_PATH}. You may use Read,
Glob, Grep. You may NOT build, run, or apply the diff.

You have NOT seen the scanner's description of the vulnerability or the
patch author's reasoning. Work only from the location, the category, and the
diff.

LOCATION: {file}:{line}
CATEGORY: {category}

DIFF UNDER REVIEW:
<diff>
{diff_text — or, for diffs over ~50 lines, replace this block with:
"Read the diff at ./PATCHES/bug_NN/patch.diff" and let the reviewer Read it}
</diff>

────────────────────────────────────────────────────────────────────────
ANSWER FOUR QUESTIONS:

1. SCOPE. Does the diff touch only files/functions on the path between
   {file}:{line} and its callers? List any hunk that falls outside that
   path.

2. SUPPRESSION. Does the diff fix a root cause, or does it suppress the
   symptom (try/except: pass, early-return on a magic value, deleting the
   check that fired, lowering a log level)?

3. NEW SURFACE. Does the diff add parsing, trust a new input field, weaken
   validation elsewhere, or remove a security-relevant check?

4. STYLE. 0-10: would you merge this as-is?
   0-3 wrong layer / suppression; 4-6 correct but noisy; 7-10 minimal,
   targeted, matches surrounding style.

────────────────────────────────────────────────────────────────────────
End your response with EXACTLY:

  REVIEW: ACCEPT | REJECT
  STYLE_SCORE: <0-10>
  OUT_OF_SCOPE_HUNKS: <comma-separated file:line, or none>
  REASON: <2-4 sentences citing specific diff hunks and source lines>

ACCEPT requires: in-scope, root-cause fix, no new attack surface,
style >= 5. Otherwise REJECT.

Spawn and parse

启动与解析

One Task per finding with
status != "no_patch"
. Parse the trailing block. Attach
review
,
style_score
,
out_of_scope_hunks
,
review_reason
to the finding. Set
verified: "static_review_only"
for every static-mode result regardless of ACCEPT/REJECT — the label describes the verification class, not the outcome.
Checkpoint: Write tool →
./.patch-state/_chunk.tmp
:
{"phase": 3, "findings": [...]}
Then Bash:
python3 .claude/skills/_lib/checkpoint.py save ./.patch-state 3 review --from ./.patch-state/_chunk.tmp

对每个
status != "no_patch"
的漏洞启动一个Task。解析末尾的结果块。将
review
style_score
out_of_scope_hunks
review_reason
附加到漏洞记录中。无论审核结果是ACCEPT还是REJECT,为所有静态模式结果设置
verified: "static_review_only"
——该标签描述的是验证类别,而非结果。
检查点:使用Write工具将以下内容写入
./.patch-state/_chunk.tmp
{"phase": 3, "findings": [...]}
然后执行Bash命令:
python3 .claude/skills/_lib/checkpoint.py save ./.patch-state 3 review --from ./.patch-state/_chunk.tmp

Phase 4: Output

第4阶段:输出

4a. Per-finding
patch_result.json

4a. 每个漏洞的
patch_result.json

For each finding (both modes), Write
./PATCHES/bug_NN/patch_result.json
:
json
{
  "id": "f003",
  "source": "TRIAGE.json#2",
  "title": "...",
  "file": "...",
  "line": 0,
  "category": "...",
  "severity": "HIGH",
  "owner_hint": "...",
  "mode": "exec" | "static",
  "verified": "ladder_passed" | "ladder_failed" | "static_review_only",
  "review": "ACCEPT" | "REJECT" | null,
  "style_score": 0,
  "out_of_scope_hunks": [],
  "rationale": "...",
  "variants_checked": "...",
  "bypass_considered": "...",
  "test_note": "...",
  "review_reason": "...",
  "verdict": { "t0_builds": true, "...": "(exec mode only, from pipeline)" }
}
In exec mode, also Read the pipeline's
<findings_path>/reports/bug_NN/patch.diff
and Write its bytes to
./PATCHES/bug_NN/patch.diff
so both modes land in the same place.
对每个漏洞(两种模式),写入
./PATCHES/bug_NN/patch_result.json
json
{
  "id": "f003",
  "source": "TRIAGE.json#2",
  "title": "...",
  "file": "...",
  "line": 0,
  "category": "...",
  "severity": "HIGH",
  "owner_hint": "...",
  "mode": "exec" | "static",
  "verified": "ladder_passed" | "ladder_failed" | "static_review_only",
  "review": "ACCEPT" | "REJECT" | null,
  "style_score": 0,
  "out_of_scope_hunks": [],
  "rationale": "...",
  "variants_checked": "...",
  "bypass_considered": "...",
  "test_note": "...",
  "review_reason": "...",
  "verdict": { "t0_builds": true, "...": "(exec mode only, from pipeline)" }
}
在执行模式下,还需读取流水线的
<findings_path>/reports/bug_NN/patch.diff
并将其内容写入
./PATCHES/bug_NN/patch.diff
,确保两种模式的输出位置一致。

4b.
./PATCHES.json

4b.
./PATCHES.json

json
{
  "patch_completed": true,
  "mode": "exec" | "static",
  "repo": "...",
  "summary": {
    "input_count": 0,
    "patched": 0,
    "no_patch": 0,
    "accepted": 0,
    "rejected": 0,
    "ladder_passed": 0
  },
  "findings": [ { ...patch_result.json shape... } ]
}
json
{
  "patch_completed": true,
  "mode": "exec" | "static",
  "repo": "...",
  "summary": {
    "input_count": 0,
    "patched": 0,
    "no_patch": 0,
    "accepted": 0,
    "rejected": 0,
    "ladder_passed": 0
  },
  "findings": [ { ...patch_result.json shape... } ]
}

4c.
./PATCHES.md
(incremental)

4c.
./PATCHES.md
(增量生成)

Step 1 — header. Write tool →
./PATCHES.md
(clobbers prior):
markdown
undefined
步骤1 — 头部:使用Write工具写入
./PATCHES.md
(覆盖原有内容):
markdown
undefined

Candidate Patches

候选补丁

{if mode == "static":}
Static review only. These diffs were authored and reviewed by independent agents reading source. They were NOT compiled, run, or re-attacked. Read each diff yourself before applying — see
docs/patching.md#reviewing-generated-patches
for what to look for.
{if mode == "exec":}
Execution-verified. Each diff passed (or failed) the pipeline verification ladder: build → reproduce → regress → re-attack. The ladder proves the crash is gone, not that the diff introduces no new problems.
Input: {findings_path} · Repo: {repo} · {N} findings → {M} diffs


**Step 2 — per finding** (sorted: ACCEPT/ladder_passed first, then by
severity). Write `./.patch-state/_chunk.tmp`:

````markdown
{if mode == "static":}
仅静态审核。这些diff由独立代理读取源代码生成并审核。未经过编译、运行或重攻击测试。应用前请自行审核每个diff——详见
docs/patching.md#reviewing-generated-patches
了解审核要点。
{if mode == "exec":}
执行验证通过。每个diff已通过(或未通过)流水线验证流程:构建→复现→回归→重攻击。该流程仅证明崩溃已修复,不保证diff未引入新问题。
输入来源:{findings_path} · 代码库:{repo} · {N}个漏洞 → {M}个diff


**步骤2 — 每个漏洞详情**(排序规则:ACCEPT/ladder_passed优先,然后按严重性排序)。写入`./.patch-state/_chunk.tmp`:

````markdown

bug_{NN}: [{severity}] {title} ({id})

bug_{NN}: [{severity}] {title} ({id})

{file}:{line}
· {category} · owner: {owner_hint or "?"} Status: {verified} · review {review or "n/a"} · style {style_score or "n/a"}/10 Diff:
PATCHES/bug_{NN}/patch.diff
({hunk count} hunks, {line count} lines)
Rationale: {rationale} Variants checked: {variants_checked} Bypass considered: {bypass_considered} {if review == "REJECT":}
Rejected by reviewer: {review_reason} {if out_of_scope_hunks:} Out-of-scope hunks: {out_of_scope_hunks}


Then `checkpoint.py append ./PATCHES.md --from ./.patch-state/_chunk.tmp`.

**Step 3 — footer.** Append a `## Skipped` table for findings with no `file`
or `status == "no_patch"`, one line each with the reason.

**Checkpoint (final):** Bash:
`python3 .claude/skills/_lib/checkpoint.py done ./.patch-state 4`
{file}:{line}
· {category} · 所有者:{owner_hint or "?"} 状态:{verified} · 审核结果 {review or "不适用"} · 风格评分 {style_score or "不适用"}/10 Diff文件
PATCHES/bug_{NN}/patch.diff
({hunk count}个代码块,{line count}行)
修复说明:{rationale} 已检查变体:{variants_checked} 已考虑绕过方式:{bypass_considered} {if review == "REJECT":}
审核拒绝原因:{review_reason} {if out_of_scope_hunks:} 超出范围的代码块:{out_of_scope_hunks}


然后执行`checkpoint.py append ./PATCHES.md --from ./.patch-state/_chunk.tmp`。

**步骤3 — 尾部**:添加`## 已跳过漏洞`表格,列出无`file`字段或`status == "no_patch"`的漏洞,每行包含一个漏洞及原因。

**最终检查点**:执行Bash命令:
`python3 .claude/skills/_lib/checkpoint.py done ./.patch-state 4`

4d. Terminal summary

4d. 终端摘要

Under ~10 lines:
Patches generated ({mode} mode): {N} findings → {M} diffs.

  Accepted:  {n}   {title of top accepted}
  Rejected:  {n}
  No patch:  {n}
  {if exec:} Ladder passed: {n}/{M}

Wrote ./PATCHES/bug_NN/, ./PATCHES.md, ./PATCHES.json
{if static:} These are drafts. Review before applying — see docs/patching.md.

控制在约10行以内:
补丁生成完成({mode}模式):{N}个漏洞 → {M}个diff。

  已接受:  {n}   {top accepted的标题}
  已拒绝:  {n}
  无补丁:  {n}
  {if exec:} 流水线验证通过:{n}/{M}

已写入 ./PATCHES/bug_NN/、./PATCHES.md、./PATCHES.json
{if static:} 这些为草稿版本。应用前请审核——详见docs/patching.md。

Guard rails

防护规则

  • The skill never applies diffs. No
    git apply
    , no
    patch
    , no Edit against
    --repo
    . If you find yourself needing to, the design is wrong.
  • Write only under
    ./PATCHES/
    and
    ./.patch-state/
    .
  • Reviewer isolation. The reviewer prompt receives
    {file, line, category, diff}
    and nothing else from the finding. Do not pass it
    description
    ,
    recommendation
    ,
    exploit_scenario
    , or the patch author's
    rationale
    .
  • Always set
    subagent_type
    .
    Forking would leak every finding's prose into every patch subagent.
  • All Task calls for a phase in ONE message. Serial spawning is correct but N× slower.
  • Checkpoint before starting the next phase, every time.
  • Exec mode delegates, never reimplements. If
    vuln-pipeline patch
    isn't on PATH, stop and tell the user; don't fall back to static mode silently.

  • 技能绝不会应用diff。禁止执行
    git apply
    patch
    或对
    --repo
    执行Edit操作。若发现需要这些操作,说明设计存在错误。
  • 仅能写入
    ./PATCHES/
    ./.patch-state/
    目录
  • 审核员隔离。审核员提示词仅接收
    {file, line, category, diff}
    ,不接收漏洞的其他信息。不要传递
    description
    recommendation
    exploit_scenario
    或补丁作者的
    rationale
  • 必须设置
    subagent_type
    。若不设置,会将每个漏洞的描述泄露给所有补丁子代理。
  • 同一阶段的所有Task调用放在同一条消息中。串行启动虽然正确,但速度慢N倍。
  • 进入下一阶段前必须创建检查点,每次都要执行。
  • 执行模式仅委托,绝不重新实现。若
    vuln-pipeline patch
    不在PATH中,终止并告知用户;不要静默回退到静态模式。

Testing this skill

技能测试

Static mode against the canary fixture:
/vuln-scan targets/canary
/triage VULN-FINDINGS.json --repo targets/canary --auto
/patch TRIAGE.json --repo targets/canary --top 3
Expected: three diffs under
PATCHES/bug_00..02/
, each
verified: "static_review_only"
,
review: ACCEPT
, style ≥ 7 for the planted overflow/UAF/format-string bugs.
Execution-verified mode against pipeline output:
vuln-pipeline run drlibs --runs 3 --parallel --stream --model <m>
/patch results/drlibs/<ts>/ --model <m>
Expected: delegates to
vuln-pipeline patch
, surfaces
verified: "ladder_passed"
per bug, copies diffs into
./PATCHES/
.

针对canary测试用例的静态模式:
/vuln-scan targets/canary
/triage VULN-FINDINGS.json --repo targets/canary --auto
/patch TRIAGE.json --repo targets/canary --top 3
预期结果:
PATCHES/bug_00..02/
目录下生成三个diff,每个diff的
verified: "static_review_only"
review: ACCEPT
、风格评分≥7,对应植入的溢出/UAF/格式化字符串漏洞。
针对流水线输出的执行验证模式:
vuln-pipeline run drlibs --runs 3 --parallel --stream --model <m>
/patch results/drlibs/<ts>/ --model <m>
预期结果:委托给
vuln-pipeline patch
,每个漏洞标记
verified: "ladder_passed"
,将diff复制到
./PATCHES/
目录。

Design notes

设计说明

  • TRIAGE.json is canonical input because patching unverified findings wastes tokens on false positives. VULN-FINDINGS.json is accepted with a warning for convenience.
  • Static mode emits a regression test inside the diff rather than running it. The skill cannot execute target code (constraint of the static pipeline); the test is for the human who applies the diff.
  • Reviewer never sees finding prose. Target source can contain injected instructions that survive into a scanner's
    description
    field. The patch author sees that prose (it has to, to know what to fix); the reviewer doesn't, so injected text cannot pass its own gate.
  • verified
    is the verification class, not pass/fail.
    static_review_only
    means "an agent read it" regardless of ACCEPT/REJECT.
    ladder_passed
    /
    ladder_failed
    means "ASAN decided." Downstream tooling should branch on this field, not on
    review
    .
  • Output shape matches the pipeline (
    PATCHES/bug_NN/{patch.diff, patch_result.json}
    ) so consumers don't care which mode produced it.
  • TRIAGE.json是标准输入,因为为未验证漏洞生成补丁会浪费令牌在假阳性上。为方便使用,VULN-FINDINGS.json会被接受但会给出警告。
  • 静态模式在diff中包含回归测试,而非运行测试。技能无法执行目标代码(静态流水线的约束);测试供应用diff的人员使用。
  • 审核员绝不会看到漏洞描述。目标源代码可能包含注入的指令,这些指令会保留到扫描器的
    description
    字段中。补丁作者需要看到这些描述(才能知道要修复什么);审核员看不到,因此注入的文本无法通过审核环节。
  • verified
    表示验证类别,而非通过/失败
    static_review_only
    表示“已由代理读取”,无论审核结果是ACCEPT还是REJECT。
    ladder_passed
    /
    ladder_failed
    表示“由ASAN判定”。 下游工具应根据该字段分支处理,而非
    review
    字段。
  • 输出格式与流水线一致
    PATCHES/bug_NN/{patch.diff, patch_result.json}
    ),因此消费者无需关心生成模式。