Install any skill in seconds. Free to start, no credit card required.
Get Started Free →Use when the user reports a bug, broken behavior, regression, failing test, or asks to investigate/root-cause/debug. Trigger on: 修个 bug, 这个 bug, 排查一下, 复现, 这个错怎么回事, 为什么 X 不工作, debug, RCA, fix this bug, investigate, reproduce. Guides root-cause debugging: reproduce with a failing test, list hypotheses, trace backward, fix only the confirmed cause, verify red-green-red, and leave a regression test. Does not symptom-patch or write commit messages.
| Test case | Without → With | Effect | Δ tokens | Δ turns |
|---|---|---|---|---|
| case-05 | ✗→✓ | ▲ Improved | 394% | 0% |
| case-06 | ✗→✓ | ▲ Improved | 945% | 0% |
| case-08 | ✗→✓ | ▲ Improved | 399% | 0% |
| case-09 | ✗→✓ | ▲ Improved | 277% | 0% |
| case-10 | ✗→✓ | ▲ Improved | 964% | 0% |
Hypothesis-driven debugging & fix workflow with No fix without root cause. Replaces guess-and-patch with: reproduce → hypothesize → diagnose (backward trace) → fix → defense-in-depth → verify → regress.
This skill only debugs and fixes. It does not gather feature requirements (that's dev-grill-docs; dev-spec is a compatibility alias), does not plan large refactors (that's dev-plan), and does not write commit messages on its own (that's dev-code-review / dev-commit-writer after the fix is in).
Use this skill when the user reports a bug, asks why something is broken, or wants a structured root-cause-driven fix.
Trigger phrases include:
修个 bug这个 bug排查一下复现这个错怎么回事为什么 X 不工作debugRCAfix this buginvestigatereproduceOutput goes to .claude/artifacts/fixes/<bug-slug>.md.
Optional arguments:
--quick: small bugs such as typo, off-by-one, or single-function fixes--deep: hairy bugs such as heisenbugs, race conditions, cross-system bugs, or production incidents; forces 3-5 hypotheses, tagged instrumentation, defense-in-depth, and pattern analysis执行前先加载 references/dev-baseline.md。不假设、最小代码、外科手术式改动、可验证成功标准 全程生效。
baseline 与本 skill 的关联点(本 skill 的核心):
按 $ARGUMENTS 或自动判断。下表是所有 phase 在三档模式下的差异:
| 模式 | 触发场景 | Hypothesis(Step 3) | Instrument(Step 4) | Defense-in-depth(Step 6b) | RCA(Step 8) | |---|---|---|---|---|---| | --quick | typo / off-by-one / 单文件单函数 / 用户已点出疑似行 | 跳过形式化(写一句怀疑即可) | 不做 | 跳过 | 简短摘要 | | 默认 | 多文件 / 中等复杂度 / 用户描述含糊 | 1-2 条(置信度 H/M/L) | 可选(IDE breakpoint 或现有 logger) | 跳过 | 标准 artifact | | --deep | heisenbug / race / 跨系统 / 生产事故 / 间歇性失败 | 强制 3-5 条跨多维(代码逻辑 / 数据 / 并发 / 环境 / 误解需求) | 必做 + tagged log | 可选(blocker 强烈建议) | 完整 RCA + 预防措施 |
Verify 三步循环(red→green→red)和 failing test 入仓 是任何模式都不能跳的硬门槛。
如果用户输入 --quick 但 Capture 阶段出现以下任一信号,主动建议升级到 --deep(让用户确认):
输出形式:「检测到 race / blocker / 跨系统 信号,建议升 --deep 走完整 hypothesis + instrument + RCA。继续 quick / 升级 deep / 你的版本?」
Capture(任何模式都要做):
## Triage
- **Symptom**:用户描述的现象,一句话
- **Expected**:正常应该怎样
- **Repro 起点**:用户给的命令 / 输入 / URL / 触发动作
- **Environment**:OS / runtime version / 相关 service 版本(只列与 bug 可能相关的)
- **First seen**:何时开始出现 / 关联近期改动
- **Severity**:阻塞 / 影响功能 / 视觉小瑕疵如果以上信息缺关键项(尤其 Repro 起点 / Symptom),直接向用户追问补全,不要自己猜。补全前不进 Step 2。
dev-fix 通常会在 Step 2b 写 failing test,之后在 Step 6 写修复。第一次写文件前必须检查:
bashgit status --short git branch --show-current
判定:
git status --short 为空,且本次 bug fix 会写测试 / 代码 / 配置,先询问用户是否创建独立 worktree。main / master / release/* 时,默认推荐 worktree。推荐命令:
bashgit worktree add -b codex/<bug-slug> ../<repo>-<bug-slug>
创建后在新 worktree 内确认 git status --short 为空,再写 failing test。
目标:把 bug 编码成一个自动测试,跑会失败。
剥离无关因素,留下触发 bug 的最小输入 + 最小代码路径。能用单测就别开浏览器,能用 unit test 就别开 e2e。
在仓库适当位置(同模块的 test 文件 / 新建 <module>.bug.test.<ext>)写一个测试,断言期望行为。
bash# 跑测试 <run test cmd> # 必须 FAIL ❌ # 如果 PASS,说明你没真复现 bug,或测试断言写错了 → 回 Step 2a
跑 test 至少 3 次连续都失败,才算 reliably reproduces。如果偶尔通过偶尔失败,这是 race / timing 问题,升级到 --deep 模式。
涉及时序 / race 的 repro,用 condition-based-waiting 替代固定 sleep(借鉴自 obra/superpowers condition-based-waiting):
ts// ❌ 反例:固定 sleep,会 flaky await sleep(500); expect(await getOrderStatus(id)).toBe('confirmed'); // ✅ 正例:condition polling,等条件成立而非等时间 await waitFor(() => getOrderStatus(id).then(s => s === 'confirmed'), { timeout: 5000 });
固定 sleep 要么产生假阴性,要么拖慢测试,且真正的 race 永远抓不稳。condition polling 让 test 等真实状态,不是凭运气等够时间。
> Hard rule:Step 2 不通过(无 reliably failing test)禁止进 Step 3。这条是 baseline「可验证成功标准」的最强落地。
每个 hypothesis 必须能解释 Step 2 的 failing test —— 即「如果 H 成立,test 应当呈现什么观察」。这是「可证伪」的根 —— 没法预测观察的假设跟「我感觉是 X」没区别。
H<n>: <一句话 root cause 假设>
预测观察:<如果 H<n> 成立,test / log / behavior 应当呈现什么>
证据收集方式:<怎么验证 — log / breakpoint / git bisect / 阅读 X 函数>
置信度(confidence):H / M / L ← 你看到 evidence 后,觉得这条多大可能是真
prior probability:<在看到任何 evidence 之前,这条假设有多大可能成立> ←0-100% 估值
优先级:1, 2, 3...(本轮 diagnose 顺序,从 H 优先)confidence vs prior 区分:
confidence 是「已经看了一些 evidence 之后的判断」—— 通常 H1 confidence 较高,因为是你最直觉的假设prior 是「完全没看 evidence 时这条假设的客观可能性」—— 反映场景多样性--deep 必查)--deep 列了 3-5 个 hypothesis 后,自检 prior probability 分布:
--quick 模式不强制完整模板,但在 artifact 里至少写一句「怀疑 root cause: <一句话> + 一句预测观察」。
列 1-2 个,按格式填全 4 个字段。
--deep 模式强制列 3-5 个,跨不同维度(避免单一思路盲点):
≥ 3 个差异化方向。绝不省略 contrarian 视角(devil's advocate:「会不会根本不是这块的问题?」)。
--deep only,默认可选)目的:为 Step 5 Diagnose 收集 evidence。加 tagged debug log 到代码,用唯一字符串 bug-<slug> 作为 grep 锚点,事后一键移除:
python# bug-<slug> DEBUG START print(f"[bug-<slug>] relevant_state at line 42: {state}") # bug-<slug> DEBUG END
约束:
bug-<slug> 必须出现在每条 log + 每个 START/END 注释里(便于 Step 7d grep -rn "bug-<slug>" . 一发命中,不依赖空格数 / region 关键字 / 注释风格)console.log / print 没锚点 —— 那种是「污染」,Step 7d grep 抓不到--deep 必做(通常需要事后回看完整日志);默认 / quick 可选(用 IDE breakpoint 或现有 logger 也行)。按 hypothesis 排好的概率从高到低:
confirmed / eliminated / inconclusiveroot-cause-tracing)当 hypothesis 看起来 confirmed 时,不要在第一个可疑帧就修。从观察到的失败点,沿调用栈反向追溯,问每一帧:
一直追到 bad value / bad state 被首次引入的那一帧,在那里修。
为什么重要 —— 在中间帧打补丁(把异常 swallow 掉、把 NaN 兜底成 0、把 null 当空数组)只是把 bug 推回上游,根因仍在,下次会从另一条路径再爆。defense-in-depth(见 Step 6b)是在 root cause 修完后额外加多层兜底,不是替代 root cause 修复。
反例:
ts// 报错点:line 88,user.email is undefined // ❌ 在 line 88 加 if 守卫(把症状包起来) if (!user?.email) return; // ✅ 反向追溯:user 从哪来?→ getUserById() → DB query 漏字段 // 在 getUserById 修 select 语句,补 email 列。
跨整个 dev-fix 调用周期,维护两个累计计数器:
hypothesis_busted_count:高置信(H)hypothesis 被 evidence 证伪的次数(L/M 不计)fix_attempt_failed_count:Step 6 + Step 7 完整跑过 + Step 7a 仍 RED 或 Step 7b stash 后 GREEN(test 没真抓 bug)的次数两个计数都跨模式累计 —— 默认模式列 2 个 H 假设全 fail,升 deep 再列 1 个 H 假设 fail,累计就到 3,触发升级,而非每次升模式重新计 0。
触发动作:
| 状态 | 建议 | |---|---| | hypothesis_busted_count == 默认模式上限(2) 且仍未 confirm | 提示用户升 --deep 多列假设、做 instrument、反向追溯。95% 的「找不到 root cause」其实是 investigation 不完整(借鉴 superpowers)—— 不放弃,先升级 | | hypothesis_busted_count >= 3(deep 模式列了 3 个 H 假设全 fail) | 这通常不是 implementation bug,是架构 / 设计问题。STOP 假设循环,升级 dev-plan --deliberate | | fix_attempt_failed_count >= 3 | 同上,但更确定 —— 每次都 confirm 假设了仍修不对,期望的不变量在当前架构里站不住。STOP fix 尝试,升级 dev-plan --deliberate |
升级时:
Status: BELOW_CONFIDENCE_THRESHOLD(假设全 fail)或 NEEDS_DESIGN_CHANGE(fix 多次 fail)> 「找不到 root cause」≠ 没有 root cause。但「3 次高置信 fail / 3 次 fix attempt fail」是不同性质的卡点 —— 这时放下 keyboard 找架构问题,比再列第 4 个假设更可能解决。
应用 baseline「外科手术式改动」:
如果根因分析显示 fix 必须改架构 / 类设计 / 模块边界 / 跨服务契约,立刻 STOP dev-fix,不要勉强写小补丁:
Status: NEEDS_DESIGN_CHANGE> 「Root cause 已锁定为 X,但 fix 需要改 Y 模块设计。建议跑 dev-plan 评估改动方案,plan 通过后再回 dev-fix Step 6 做实施。当前 dev-fix 暂停,artifact 已落 .claude/artifacts/fixes/<slug>.md(Status: NEEDS_DESIGN_CHANGE)。」
判断标准:改动会动到 ≥ 2 个文件的公共接口 / DB schema / 跨服务消息格式 / 类继承层级 / 主要数据流向 —— 任一就是结构性。如果只是同一函数内换实现 / 同一类内补字段 / 单文件加守卫,不算结构性,继续 Step 6。
--deep 可选,默认 / quick 跳过)借鉴自 obra/superpowers defense-in-depth。Root cause 已修完后,有针对性地在多层边界加 validation,防止同类问题在其他入口或未来 regression 再现。
Defense-in-depth ≠ 顺手 refactor。两者必须严格区分:
| Defense-in-depth(允许加) | 顺手 refactor(禁止加) | |---|---| | 在调用 root cause 函数的 boundary 加 input validation | 把 root cause 函数本身重写 | | 在 DB 层加 NOT NULL constraint(本次 root cause 是 NULL 误处理) | 把整张表 schema 重设计 | | 在 API 入口加 schema 校验(本次 root cause 是异常输入) | 把整套 validation 框架替换 | | 加一条 unit test 覆盖刚 fix 的 case 的相邻 case | 把整个 test 套件从 jest 迁到 vitest |
判定标准:加的每一行都能直接关联到「防止本次 root cause 类型问题再现」。否则就是 refactor,不许加。
行数硬上限(防 LLM 把 refactor 包装成 defense):
dev-plan 评估架构)理由:LLM 在「想让代码更好」的状态下容易把整个调用链加 schema 校验、把整个相关函数加 logging 等说成 defense。用客观行数门把判断转成可量化阈值,断绝主观开脱空间。
> 例外:仅 DB constraint / type schema 这类「单条声明性配置」(例如 ALTER TABLE ... ADD CONSTRAINT)即使逻辑上重要也只算 1 行 effective。不要为了卡上限砍掉真正必要的 constraint。
--quick / 默认模式 默认跳过,只修 root cause--deep 模式 可选,根据 bug 严重度决定:加完 Step 6b 后,所有新加的 validation / assertion 也要被 test 覆盖(否则就是没真正生效的兜底)。
任何模式都不能跳过这步。这是 dev-fix 与「随手 fix」的根本区别。
bash<run failing test> # 期望:GREEN ✓ (fix 生效)
bashgit stash # 临时移除 fix <run failing test> # 期望:RED ✗ (test 仍能捕获 bug,没误绿) git stash pop # 恢复 fix <run failing test> # 期望:GREEN ✓
> 如果 7b 第一步是 GREEN(stash 后 test 还能过)—— 说明 test 没真测到 bug,回 Step 2 重写 test。这是常见陷阱(test 写得太宽松)。
最低范围:修改文件所在 package / 模块的全部 test(不只跑你刚加的 regression test)。具体识别方式按语言:
bash# Python pytest <module-dir>/ # e.g. pytest src/orders/ # TypeScript / Node pnpm test <pkg> # 或 jest <module-pattern> # Go go test ./<pkg>/... # e.g. go test ./internal/cart/... # Rust cargo test --package <pkg> # Java / Kotlin gradle :<module>:test
整库 test 慢则至少跑修改文件所在 package。期望:全 GREEN ✓。
--deep 必做)用 Step 4 加的唯一锚点 bug-<slug> 一发命中所有 instrumentation:
bashgrep -rn "bug-<slug>" . # 找出所有需要删除的行 # 删除每条命中(START / END 注释 + 中间的 log 调用一起) grep -rn "bug-<slug>" . # 期望:0 条匹配
重要:必须 0 匹配 才算 instrumentation 干净。任何残留(包括 START/END 注释)都属污染。
落到 .claude/artifacts/fixes/<bug-slug>.md(目录不存在则创建)。
模板:
markdown# Bug: <一句话标题> > Status: FIXED | BELOW_CONFIDENCE_THRESHOLD | NEEDS_DESIGN_CHANGE > Mode: --quick | (default) | --deep > Severity: blocker | functional | minor > Author: <user> > Last updated: <YYYY-MM-DD> ## Symptom <用户报的现象> ## Expected <应该怎样> ## Reproduction - 命令 / 步骤:... - 测试位置:`tests/<file>.test.ts:42` - 复现稳定性:3/3 reliably fails(stash fix 后) ## Hypotheses & diagnosis | # | Hypothesis | Verdict | Evidence | |---|---|---|---| | H1 | ... | confirmed (root cause) | log 显示 X / git bisect 指向 commit Y | | H2 | ... | eliminated | 反向测试,X 状态正常 | | H3 | ... | eliminated | 代码路径根本没走 | ## Root cause <2–3 句:为什么会发生,因果链是什么> ## Fix - 改动文件:`path/to/x.ts:88-92` - 一句话改了什么:... - 代码 diff 摘要(关键行,不要贴整个 diff) ## Verification > 用 V- 前缀(verification log)而非 AC-,避免与 spec acceptance criteria 混淆。 - V-1: failing test → GREEN ✓ - V-2: stash fix → test 重新 RED ✓(证明 test 真捕获 bug) - V-3: 修改文件所在 package 全部 test → all GREEN ✓ - (deep) V-4: instrument 已全部移除(`grep -rn "bug-<slug>" .` → 0 匹配) ## Regression test - 路径:`tests/<file>.test.ts:42` - 名称:`should not <bug 描述> when <trigger condition>` ## Defense-in-depth(deep 模式且加了兜底时填) - 加在哪几层:input boundary / DB constraint / assertion / monitoring(选 1–3 项) - 每条对应的「防止 root cause 类型问题再现」的因果说明 - 兜底是否被 test 覆盖 ## Pattern analysis(必填,借鉴 obra/superpowers) 本次 root cause 的**模式形状**(例:错误吞没 / null 路径未守 / 数据竞争 / 边界假设错 / 异常输入未校验)是否在仓库其他位置也存在? | 搜索方式 | 命中数 | 是否本次同类隐患 | |---|---|---| | `git grep -n "<关键 pattern>"` | N | 是 / 否,各 M 处 | **如有同类**,在下方 Follow-ups 列出每处的 file:line + 一句话描述。本次**不修**(违反 surgical),作为单独 issue / 后续 commit 处理。 ## Open questions / Follow-ups <本次没修但发现的相关问题,例如「同一函数另一分支也有类似风险」「需要追溯何时引入(git bisect)」;Pattern analysis 命中的同类隐患也列在这里;无则省略> ## RCA(deep 模式必填) - **何时引入**:commit hash + 日期(git bisect 结果) - **为什么没被发现**:测试覆盖盲区 / staging 与 prod 差异 / etc - **预防措施**:加什么 test / 加什么 lint / 改什么流程
BELOW_CONFIDENCE_THRESHOLD 让用户决策,不要硬猜。--deep 模式 hypothesis 少于 3 个 —— 单一思路有视野盲点。--deep 模式漏 instrumentation 移除步骤 —— 留下 tagged log = 污染代码。dev-plan,artifact 标 Status: NEEDS_DESIGN_CHANGE。计数跨模式累计,见 Step 5 Escalation。--deep 多列假设、加 instrument、反向追溯,比放弃更可能找到。真正放下的标准是 Step 5 escalation 三次失败,不是「我看了一会觉得没有」。dev-fix is the bug-path SDD contract. It replaces a feature spec with a failure contract:
Symptom and Expected define the behavior gap.Reproduction and Regression test define executable proof.Hypotheses & diagnosis prevents guessing.Root cause defines the only path the fix should change.Verification defines what dev-verify must check before completion.Pattern analysis defines follow-ups without expanding this fix.If the confirmed root cause requires a broader redesign, mark the artifact NEEDS_DESIGN_CHANGE and route to dev-plan instead of hiding a refactor inside the bug fix.
Recommended agent_type: worker
Use when:
Do:
../../docs/multi-agent-policy.md for concurrent-work boundaries.Do not:
Output:
Other measured skills in the registry, with their headline benchmark lift.