# 护栏体检:防止静默失效 (/docs/guardrails/health-check) > 护栏会被工具覆盖、被上游合并冲掉,所以要定期检查它们还在、还管用 护栏失效时不会报错,只会悄悄消失。所以要像体检一样定期检查:**会话开始时自动跑一个脚本**,确认关键的 deny 规则还在、备份 hook 真的会备份;**上游会改的共享文件,在 CI 里用行为断言守住**;切换配置、大合并之后,再做一次全面体检。这套做法是我在 2026 年 10 月那次事故之后加上的,还在试,所以整页标 🧪。 ## 为什么会失效:三条路径 [#为什么会失效三条路径] 下面三条,我是在同一次排查里一起发现的: 1. **被工具覆盖。** 用一个模型供应商切换工具从第三方模型切回官方时,它把 `~/.claude/settings.json` 整份重写,权限规则、hook、插件启用状态全部丢失。表面症状只是“所有插件都关了” 2. **被上游合并冲掉。** 在一个 fork 的 Makefile 里加的备份步骤,在一次上游大合并中被覆盖 3. **文件还在,没有挂载。** hook 脚本好好地躺在磁盘上,但 settings 里没有任何事件引用它 三条的共同点:没有报错、没有提示,你只会在真正需要它的那一刻,发现它已经不在了。还有一条连带的:hookify 这类插件生成的规则,靠插件本身的 hook 执行,插件被关掉,规则就一起失效。 ## 原则:查行为,不查文本 [#原则查行为不查文本] grep 到 `pg_dump` 不代表备份会发生:它可能在注释里、在另一个 target 里,或者失败被 `|| true` 吞掉了。settings 里有一条命令名带 `db-backup` 的 hook,也不代表它会匹配、会备份。所以下面的检查都是**真跑一遍,看结果**:喂一段模拟输入,换上假的 `pg_dump` 和 `psql`,看该发生的有没有发生、不该发生的有没有被拦住。 ## 1. 会话开始自动检查 [#1-会话开始自动检查] SessionStart hook 的标准输出会被加进 Claude 的上下文。利用这一点:检查脚本在一切正常时什么都不输出,发现问题就打印出来,Claude 会在开始干活之前提醒你。 保存为 `~/.claude/hooks/guardrail-check.sh`,加上执行权限: ```bash #!/usr/bin/env bash # SessionStart hook:检查关键护栏还在不在、还管不管用。全部正常时什么都不输出。 # SessionStart 的标准输出会进入 Claude 的上下文,所以发现问题就打印出来,让 Claude 提醒你。 settings="$HOME/.claude/settings.json" problems=() # 1. 关键 deny 规则还在 for rule in 'Bash(rm -rf ~)' 'Bash(git push --force origin main *)' 'Bash(git reset --hard origin/main *)'; do jq -e --arg r "$rule" '(.permissions.deny // []) | index($r) != null' "$settings" > /dev/null 2>&1 \ || problems+=("deny 规则不见了:$rule") done # 2. 备份 hook 挂着,而且真的会备份:取出 PreToolUse 上挂的命令,喂一段模拟输入。 # 假的 pg_dump 只记录自己被调用过,然后故意失败,所以不会产生真实备份 hook_cmd="$(jq -r '[.hooks.PreToolUse[]?.hooks[]?.command | strings | select(test("db-backup"))][0] // empty' "$settings" 2>/dev/null)" if [ -z "$hook_cmd" ]; then problems+=("数据库备份 hook 没有挂载到 PreToolUse") else shim="$(mktemp -d)" printf '#!/bin/sh\ntouch "%s/called"\nexit 1\n' "$shim" > "$shim/pg_dump" chmod +x "$shim/pg_dump" printf '%s' '{"cwd":"/tmp/guardrail-check","tool_input":{"command":"psql -c \"DROP TABLE t\""}}' \ | PATH="$shim:$PATH" DATABASE_URL="postgresql://guardrail-check/fake" bash -c "$hook_cmd" > /dev/null 2>&1 rc=$? [ -e "$shim/called" ] || problems+=("备份 hook 收到 DROP TABLE 却没有调用 pg_dump") [ "$rc" -eq 0 ] || problems+=("备份 hook 的退出码是 $rc,可能会拦住正常命令") rm -rf "$shim" fi # 3. hookify 还启用着(不用 hookify 就删掉这一项) jq -e '.enabledPlugins["hookify@claude-plugins-official"] == true' "$settings" > /dev/null 2>&1 \ || problems+=("hookify 插件没有启用,它的规则全部不生效") if [ ${#problems[@]} -gt 0 ]; then echo "【护栏体检】发现问题,开始工作前请先告诉用户:" printf -- '- %s\n' "${problems[@]}" fi exit 0 ``` 第 2 项是行为检查:它把 settings 里真正挂着的那条命令跑一遍,喂给它一条 `DROP TABLE`,看它有没有去调用 `pg_dump`、退出码是不是 0。脚本被删、正则写坏、hook 会误拦正常命令,都会在这里暴露出来。按你自己的情况,改 deny 列表和插件名;不用 hookify 的话,删掉第 3 项。 **关键一步:体检 hook 不要和被检查的东西放在同一个文件里。** 如果它挂在 `~/.claude/settings.json`,切换工具整份重写这个文件时,体检会和规则一起消失。把它挂在托管设置里(工具改不到),或者挂在各项目的 `.claude/settings.json` 里(进了 git,被改动能从 diff 里看出来): ```json { "hooks": { "SessionStart": [ { "hooks": [ { "type": "command", "command": "\"$HOME\"/.claude/hooks/guardrail-check.sh" } ] } ] } } ``` 托管设置的路径和写法见[权限规则](/docs/guardrails/permissions)。 ## 2. 在 CI 里做行为断言 [#2-在-ci-里做行为断言] fork 里你改过、上游也会改的文件(Makefile、部署脚本、CI 配置),在 CI 里加一步行为断言。以[三层护栏](/docs/guardrails)里的 `db-reset` 为例:用假的 `pg_dump` 控制备份成败,用假的 `psql` 记录 reset 有没有真的执行。保存为 `scripts/check-guardrails.sh`: ```bash #!/usr/bin/env bash # CI 行为断言:备份成功时 db-reset 照常执行;备份失败时必须停下,不能继续 reset。 # 用假的 pg_dump 控制备份成败,用假的 psql 记录 reset 有没有真的执行。 set -uo pipefail shim="$(mktemp -d)" log="$shim/psql-calls.log" printf '#!/bin/sh\necho "psql $*" >> "%s"\n' "$log" > "$shim/psql" chmod +x "$shim/psql" run_reset() { # $1:假 pg_dump 的退出码 printf '#!/bin/sh\nexit %s\n' "$1" > "$shim/pg_dump" chmod +x "$shim/pg_dump" : > "$log" PATH="$shim:$PATH" HOME="$shim" DATABASE_URL="postgresql://ci/fake" make db-reset > /dev/null 2>&1 } run_reset 0 && [ -s "$log" ] \ || { echo "::error::对照组失败:备份成功时 db-reset 没有走到 reset,目标可能被删了"; exit 1; } if run_reset 1 || [ -s "$log" ]; then echo "::error::备份失败时 db-reset 没有停下"; exit 1 fi echo "护栏断言通过:备份失败时 db-reset 会停下" ``` 脚本里有两组:对照组确认 `db-reset` 目标还在、能走到 reset,否则“备份失败时没执行”可能只是因为目标被删了;实验组确认备份失败时 reset 一步都没走。你的 reset 实际调用的如果不是 `psql`(比如 supabase、prisma、docker),把假命令换成它。 然后在 GitHub Actions 里加一步,顺带确认 ask 规则还在: ```yaml - name: 护栏断言 run: | bash scripts/check-guardrails.sh jq -e '.permissions.ask | index("Bash(make db-reset *)") != null' .claude/settings.json > /dev/null \ || { echo "::error::.claude/settings.json 里的 ask 规则不见了"; exit 1; } ``` 下一次上游合并冲掉你的改动时,PR 会直接变红,而不是半年后才被发现。复盘里写下的检查命令,都应该这样变成 CI。 ## 3. 全面体检:/ainative:doctor [#3-全面体检ainativedoctor] 本手册的插件带了一个只读的体检命令 `/ainative:doctor`:检查插件和 skill 是否冗余或互相抢触发、权限规则和 hook 是否还在、配置有没有被切换工具覆盖。适合在这些时候跑: - 换电脑或重装之后 - 切换模型供应商之后 - 上游大合并之后 - 每个月一次 安装和其他功能见[本手册的 Claude Code 插件](/docs/reference/plugin)。 ## 不装任何东西,也能看一眼 [#不装任何东西也能看一眼] | 命令 | 看什么 | |---|---| | `/permissions` | 所有权限规则,以及每条来自哪个文件 | | `/hooks` | 按事件列出所有已挂载的 hook | | `/status` | `Setting sources` 一行:托管设置有没有生效 | | `claude doctor` | 安装是否健康、哪些设置因为写错被丢弃 | | `claude plugin list` | 插件是否还处于启用状态 | 这几条只能告诉你“配置还在”,不能告诉你“还管用”。管不管用,要靠上面两种行为检查。 ## 常见坑 [#常见坑] - [防护规则会悄悄失效](/docs/pitfalls/guardrails-decay) - [切换工具会整份覆盖设置](/docs/pitfalls/config-overwrite) - [跟代码绑定的文档跟代码放一起](/docs/pitfalls/code-coupled-docs) ## 相关 [#相关] - [三层护栏](/docs/guardrails) - [用 hook 兜底](/docs/guardrails/hooks) - [让 ops 和项目一起进化](/docs/org/evolve) - [本手册的 Claude Code 插件](/docs/reference/plugin) # 用 hook 兜底 (/docs/guardrails/hooks) > PreToolUse hook 在危险命令执行前尽力备份一份,hookify 用一句话生成规则 权限规则管“能不能做”,hook 管“做之前先做什么”。我用得最多的一个 hook 是一份**尽力而为的兜底备份**:Claude 要跑破坏性的数据库命令时,先把 `DATABASE_URL` 指向的库 `pg_dump` 一份。它不拦任何命令,备份不成也照样放行。真正能拦住破坏的是另外两层:应用层(reset 脚本先备份,备份失败就退出)和 ask 规则(执行前由你确认)。 ## 为什么用 hook [#为什么用-hook] - **规则写不出来的,hook 能写。** 权限规则按命令文本做前缀匹配;hook 是任意脚本,可以用正则、不区分大小写、读环境变量 - **它在权限模式之前执行。** 官方文档写明:PreToolUse hook 在所有权限模式下都会先运行,返回 deny 时,即使开着 bypass 也会拦下([原文](https://code.claude.com/docs/en/hooks-guide#hooks-and-permission-modes)) - **它是确定的。** hook 由 Claude Code 在固定时机执行,不依赖模型“记得”去做 Anthropic 的 [AI-native SDLC playbook](https://claude.com/resources/articles/the-ai-native-sdlc-playbook) 把“用 hook 做审批关卡”列为十二招之一。我的分工稍有不同:卡人用 ask 规则,简单、看得见;hook 只兜底,不拦人。原因很实际:兜底的 hook 一旦会拦人,误报一两次你就想把它关掉,关掉之后就什么都没有了。 ## 自动备份 hook [#自动备份-hook] 先说清楚它管不到什么:它只备份启动 Claude Code 的环境里 `DATABASE_URL` 指向的那个库。命令实际操作的如果是另一个库、另一个连接串,或者一个 Docker 卷,这份备份帮不上忙;没有连接串、`pg_dump` 失败时,它也只提示一句,命令照样执行。所以它是第三道网,替代不了前两道: - **应用层**:reset 脚本先备份,备份失败就退出,reset 根本不会执行(写法见[三层护栏](/docs/guardrails))。[本地数据库也要按生产对待](/docs/pitfalls/local-db-is-prod)里说的“备份失败就不执行”,指的就是这一层 - **ask 规则**:破坏性命令执行前,由你来确认(见[权限规则](/docs/guardrails/permissions)) 需要 `jq` 和 `pg_dump`。本地库没有密码的话,也可以直接把连接串写进脚本。 保存为 `~/.claude/hooks/db-backup.sh`: ```bash #!/usr/bin/env bash # PreToolUse hook:尽力而为的兜底备份,不拦任何命令。 # Claude 要跑破坏性数据库命令时,先把 DATABASE_URL 指向的库 pg_dump 到 ~/db-backups/。 # 没有连接串、备份失败,都只提示、照样 exit 0;真正拦住破坏的是应用层和 ask 规则。 set -uo pipefail input="$(cat)" cmd="$(printf '%s' "$input" | jq -r '.tool_input.command // empty' 2>/dev/null)" [ -z "$cmd" ] && exit 0 # 不区分大小写:DROP / TRUNCATE、dropdb、各种 db reset、删卷、带 -v 的 compose down pattern='drop[[:space:]]+(table|database|schema)|dropdb[[:space:]]|truncate[[:space:]]|db[-:_ ]reset|migrate[[:space:]]+reset|volume[[:space:]]+rm|compose[[:space:]]+down.*[[:space:]](-v|--volumes)' printf '%s' "$cmd" | grep -Eiq "$pattern" || exit 0 say() { jq -nc --arg m "db-backup hook:$1" '{systemMessage: $m}'; } db_url="${DATABASE_URL:-}" if [ -z "$db_url" ]; then say "命中破坏性命令,但环境里没有 DATABASE_URL,没有备份" exit 0 fi # 文件名 = 项目名 + 时间戳 + 进程号;先写临时文件,成功后再改名。目录 700,文件 600 umask 077 dir="$HOME/db-backups" mkdir -p "$dir" && chmod 700 "$dir" cwd="$(printf '%s' "$input" | jq -r '.cwd // empty' 2>/dev/null)" project="$(basename "${cwd:-unknown}" | tr -cd 'A-Za-z0-9._-')" name="${project:-project}-$(date +%Y%m%d-%H%M%S)-$$" tmp="$(mktemp "$dir/.$name.XXXXXX")" || { say "建不了临时文件,没有备份"; exit 0; } if pg_dump -Fc -d "$db_url" -f "$tmp" 2>/dev/null && mv "$tmp" "$dir/$name.dump"; then say "已把 DATABASE_URL 指向的库备份到 $dir/$name.dump" else rm -f "$tmp" say "pg_dump 失败,没有备份成功" fi exit 0 ``` 加上执行权限,喂一条假的输入测一下: ```bash chmod +x ~/.claude/hooks/db-backup.sh echo '{"tool_input":{"command":"psql -c \"drop table users\""}}' | ~/.claude/hooks/db-backup.sh; echo "exit=$?" ``` 应该看到一行带 `systemMessage` 的 JSON,退出码是 0。 在 `~/.claude/settings.json` 里挂到 PreToolUse 上: ```json { "hooks": { "PreToolUse": [ { "matcher": "Bash", "hooks": [ { "type": "command", "command": "\"$HOME\"/.claude/hooks/db-backup.sh", "timeout": 300 } ] } ] } } ``` 然后在 Claude Code 里运行 `/hooks`,确认它出现在 PreToolUse 下面。**脚本在磁盘上不等于生效,挂上了才算。** 我就栽在过这一步。 几个设计上的选择: - **永远 exit 0。** 备份失败、没装 `pg_dump`、没有连接串,都只提示、不拦截。要拦的事,交给应用层和 ask 规则 - **用 `systemMessage` 提示。** PreToolUse 的 hook 正常退出时,它的 stderr 你和 Claude 都看不到;输出一个带 `systemMessage` 字段的 JSON,提示才会显示给你 - **备份之间不会互相覆盖。** 文件名由项目名、时间戳和进程号组成,几个会话同时触发也不会撞名;先写临时文件,`pg_dump` 成功后再改名,失败时只删自己的临时文件 - **备份就是你的数据。** 目录权限 700、文件 600,只有你自己能读。`-Fc` 是压缩的自定义格式,`pg_restore --list <备份文件>` 能快速看一眼里面有什么;但真正证明能恢复的,是定期把它恢复到一个临时库里抽查数据(做法见[本地数据库也要按生产对待](/docs/pitfalls/local-db-is-prod)) - **宁可多备份。** `grep -rn "drop table" src/` 这样的命令也会触发一次备份。误报的代价是一个多余的文件,漏报的代价是数据。`~/db-backups/` 记得定期清理 - **挂在用户级。** 这样对所有项目生效。但用户级文件也最容易被工具覆盖,所以一定要配合[体检](/docs/guardrails/health-check);最关键的 hook 也可以放进托管设置 ## hookify:一句话生成规则 [#hookify一句话生成规则] 不想自己写脚本时,可以用官方插件 hookify: ```bash claude plugin install hookify@claude-plugins-official ``` 然后用 `/hookify`(完整写法是 `/hookify:hookify`)加一句话描述规则: ```text /hookify 执行 vercel --prod 之前提醒我先确认 ``` 它会在项目的 `.claude/` 目录下生成一个 `hookify.<规则名>.local.md`:YAML 头里写匹配条件(Python 正则),正文是命中时显示的提示。`action: warn` 只提醒,是默认值;`action: block` 直接拦下。改完立即生效,不用重启。 ```markdown --- name: block-force-push-main enabled: true event: bash pattern: git\s+push\b.*\s(--force|-f)\b.*\bmain\b action: block --- 不要 force push 到 main。确实需要时,先打 tag 备份,再让我手动执行。 ``` 常用命令:`/hookify:list` 列出所有规则,`/hookify:configure` 开关规则;不带参数运行 `/hookify`,它会回看最近的对话,找出你纠正过 Claude 的地方,建议把它们变成规则。 两个要注意的地方:hookify 的 hook 是 Python 脚本,本机要有 Python 3;所有规则都靠 hookify 插件本身的 hook 执行,插件一旦被关掉(比如被切换工具改了 `enabledPlugins`),所有规则会一起失效,而且没有任何提示。体检时要把“hookify 是否启用”也算进去。我还在试它的写法和误报率,结论可能会变。 ## hook 的局限 [#hook-的局限] - **只看得到 Claude Code 的工具调用。** 你自己在终端敲的命令、CI、其他 agent 都不经过它,所以应用层的备份不能省 - **没挂载就不生效。** 脚本还在、配置没了,hook 就不存在。定期用 `/hooks` 看一眼,或者交给体检脚本 - **能被整体关掉。** `disableAllHooks` 设置和 `--bare` 启动模式都会跳过 hook - **以你的完整用户权限运行。** 只挂你读过的脚本;别人仓库里带的 hook,看过再信任 - **PostToolUse 撤销不了。** 那时动作已经发生了。要拦,只能用 PreToolUse - **匹配的仍然是文本。** 正则比前缀规则灵活,但换一种写法照样能绕过。hook 是网,不是墙 ## 常见坑 [#常见坑] - [本地数据库也要按生产对待](/docs/pitfalls/local-db-is-prod) - [防护规则会悄悄失效](/docs/pitfalls/guardrails-decay) - [切换工具会整份覆盖设置](/docs/pitfalls/config-overwrite) ## 相关 [#相关] - [三层护栏](/docs/guardrails) - [权限规则:deny、ask、allow](/docs/guardrails/permissions) - [护栏体检:防止静默失效](/docs/guardrails/health-check) - [第 0 步:起步](/docs/product/day-0) # 三层护栏 (/docs/guardrails) > 应用层、权限规则、hook 三层叠加,任何一层失效都还有兜底 破坏性操作要过三层护栏:**应用层**(脚本和 Makefile 自己先备份)、**权限规则**(`settings.json` 里的 deny 和 ask)、**hook**(PreToolUse 自动兜底)。三层各有盲区,叠在一起才可靠。但三层都会悄悄失效,所以还要第四件事:定期体检。 ## 为什么要三层 [#为什么要三层] 写在 CLAUDE.md 里的“不要删库”只是建议。官方文档说得很清楚:权限规则由 Claude Code 执行,不由模型执行;提示词和 CLAUDE.md 影响的是 Claude 想做什么,改变不了 Claude Code 允许它做什么([原文](https://code.claude.com/docs/en/permissions))。所以能机械判断的规则,要写进系统。 但系统里的每一层也都有盲区: | 层 | 在哪 | 管什么 | 盲区 | |---|---|---|---| | 应用层 | 脚本、Makefile、迁移工具 | 不管谁来执行(你、agent、CI),都先备份、先校验 | 只覆盖走这个入口的操作,agent 绕开 Makefile 直接敲 `psql` 就失效;fork 里的改动会被上游合并冲掉 | | 权限规则 | `settings.json` 的 deny、ask、allow | Claude Code 里哪些命令绝对不行、哪些必须你确认 | 按命令文本匹配,换个写法就可能漏掉;只管 Claude Code;会被配置工具整份覆盖 | | hook | `settings.json` 的 hooks,或插件 | 工具调用之前执行任意脚本:自动备份、按正则拦截 | 只看得到 Claude Code 的工具调用;脚本在磁盘上但没挂载,就等于没有 | 三层的分工:应用层保证“不管谁来做都先有备份,备份失败就不执行”,权限规则负责“卡人”(让你来决定),hook 负责“兜底”:你没注意到的时候尽力多备份一份,但它不拦任何命令,也只覆盖它知道的那个库。真正能拦住破坏的,是前两层。 ## 一次三层全部失效 [#一次三层全部失效] 本地数据库被一条 reset 命令清空过一次:几个演示用的工作区、几十个 agent 配置,没有任何备份。那个库里是真实的运营资产,不是测试数据。之后我加了三层防护:reset 脚本先备份,权限规则要求确认,PreToolUse hook 自动备份。 半年后,2026 年 10 月的一次环境排查,发现三层全没了: 1. **应用层**:Makefile 里的备份步骤,在一次上游大合并中被冲掉 2. **权限规则**:被一个模型供应商切换工具连同整个 `settings.json` 一起覆盖 3. **hook**:脚本文件还在,但没有挂到任何事件上 整整一段时间,没有人发现。复盘里甚至写过检查命令,但它只是一段文字,没人去跑。完整经过见[防护规则会悄悄失效](/docs/pitfalls/guardrails-decay)。 教训:**护栏不会报错,只会消失**。每一层都要有[体检](/docs/guardrails/health-check)。 ## 按档位配置 [#按档位配置] | 档位 | 应用层 | 权限规则 | hook | 体检 | |---|---|---|---|---| | 小工具 | 可选 | 5 条 deny,见[最小护栏](/docs/tool/guardrails) | 可选 | 改过配置后看一眼 | | 产品 | 破坏性脚本先备份,失败就退出 | deny,加上部署、删库、合并 PR 的 ask | 数据库兜底备份(尽力而为) | 会话开始自动检查 | | 组织 | 同上,共享文件加 CI 断言 | 关键 deny 放托管设置 | 同上,打包进组织插件 | 会话开始检查、CI 断言、定期全面体检 | 应用层最简单:破坏性脚本的第一步就是备份,备份失败就停下。 ```bash #!/usr/bin/env bash # scripts/db-reset.sh:先备份,备份失败就退出,后面的 reset 不会执行 set -euo pipefail : "${DATABASE_URL:?DATABASE_URL 未设置,停止 reset}" umask 077 dir="$HOME/db-backups" mkdir -p "$dir" && chmod 700 "$dir" tmp="$(mktemp "$dir/.pre-reset.XXXXXX")" if ! pg_dump -Fc -d "$DATABASE_URL" -f "$tmp"; then rm -f "$tmp" echo "备份失败,停止 reset" >&2 exit 1 fi backup="$dir/pre-reset-$(date +%Y%m%d-%H%M%S)-$$.dump" mv "$tmp" "$backup" echo "已备份到 $backup" # 从这里往下,才是真正的 reset 步骤 ``` 再把 Makefile 的 `db-reset` 目标改成调用这个脚本。这样不管是你、agent 还是 CI 执行 reset,都会先留一份备份;备份失败,reset 根本不会执行。文件名带时间戳和进程号,先写临时文件再改名,几次备份不会互相覆盖;目录 700、文件 600,只有你自己能读。这一层是否真的有效,用[体检](/docs/guardrails/health-check)里的行为断言来守。 ## 常见坑 [#常见坑] - [防护规则会悄悄失效](/docs/pitfalls/guardrails-decay) - [本地数据库也要按生产对待](/docs/pitfalls/local-db-is-prod) - [切换工具会整份覆盖设置](/docs/pitfalls/config-overwrite) - [不让 agent 动 git 历史](/docs/pitfalls/git-history-no-surgery) ## 相关 [#相关] # 权限规则:deny、ask、allow (/docs/guardrails/permissions) > 用 settings.json 把“绝对不行”和“必须确认”写进系统,而不是写进提示词 把“绝对不行”写进 deny,“必须我点头”写进 ask,只读和本地开发的命令写进 allow。这些规则由 Claude Code 执行,不靠模型自觉:CLAUDE.md 里写“不要 force push”只是建议,写进 deny 才是规则。 ## 规则怎么生效 [#规则怎么生效] - **顺序固定:先 deny,再 ask,最后 allow。** 第一个命中的说了算,和规则写得多具体无关:宽泛的 deny 会盖过具体的 allow,ask 也会盖过 allow - **多个文件的规则会合并,不是覆盖。** 任何一个文件里的 deny,别的文件里的 allow 都放不开 - **写法是前缀加通配。** `Bash(git push --force *)` 里,第一个 `*` 之前的部分按原样匹配;末尾的“空格 + `*`”也能匹配不带参数的命令本身,所以 `Bash(wrangler deploy *)` 连光秃秃的 `wrangler deploy` 也会拦住 - **复合命令拆开匹配。** `cd app && rm -rf build` 里任何一段命中 deny 或 ask,整条命令都会被拦下 随时可以用 `/permissions` 查看所有规则,它会标出每条规则来自哪个文件。细节见[官方文档](https://code.claude.com/docs/en/permissions)。 ## 我实际用的规则 [#我实际用的规则] ```json { "permissions": { "deny": [ "Bash(rm -rf /)", "Bash(rm -rf ~)", "Bash(sudo rm -rf *)", "Bash(git push --force origin main *)", "Bash(git reset --hard origin/main *)" ], "ask": [ "Bash(gh api * -X DELETE *)", "Bash(gh repo delete *)", "Bash(gh pr merge *)", "Bash(make db-reset *)", "Bash(docker volume rm *)", "Bash(docker compose down -v *)", "Bash(psql * -c DROP*)", "Bash(wrangler deploy *)", "Bash(vercel --prod *)", "Bash(wrangler d1 execute * --remote *)" ], "allow": [ "Bash(wrangler whoami)", "Bash(vercel ls *)", "Bash(gh pr view *)", "Bash(gh run list *)" ] } } ``` 三组规则的逻辑: - **deny**:不可逆,而且 agent 永远没有正当理由去做的事:删根目录和家目录、force push 到 main、把 main 硬重置成远端的样子 - **ask**:正当但影响大的事:通过 API 删除资源、删仓库、合并 PR、重置或删除数据库、删 Docker 卷、部署生产、往远端数据库写数据。这些我要亲自点头 - **allow**:只读和本地开发的命令。放行它们是为了少弹窗。弹窗少了,剩下那几个你才会认真看 想从历史记录里自动整理出常用只读命令的放行列表,可以用内置的 `/fewer-permission-prompts`。 ## 这些规则拦不住什么 [#这些规则拦不住什么] Bash 规则匹配的是命令文本,官方文档明确说它**不是程序级的安全边界**:`Bash(rm *)` 拦得住 `rm -rf build/`,拦不住 `/bin/rm -rf build/` 和 `bash -c 'rm -rf build/'`;`Bash(git push *)` 拦不住 `git -C . push`。 我自己的规则里就有写得不够好的。按官方文档的匹配规则推算: - `Bash(gh api * -X DELETE *)` 有两个通配,要求 `-X DELETE` 前后都还有内容。最常见的 `gh api -X DELETE repos/o/r` 和 `gh api repos/o/r -X DELETE` 都匹配不上,`--method DELETE` 也不行。改成 `Bash(gh api *DELETE*)` 更稳,误报的代价只是多问一次 - `Bash(psql * -c DROP*)` 要求 `-c` 后面紧跟大写的 `DROP`。真实命令几乎都带引号(`-c "DROP TABLE ..."`),写成小写也很常见,很可能匹配不上 - ask 里只写了 `Bash(wrangler deploy *)`,没写 `Bash(bunx wrangler deploy *)`。规则按命令文本匹配,不会自动去掉 `bunx` 这类前缀,用 bunx 部署时这条拦不住,两种写法都要列(见[小工具上线](/docs/tool/ship)) 所以权限规则只能拦住 agent 通常的写法。需要正则、不区分大小写这类更强的匹配,交给 [hook](/docs/guardrails/hooks);需要真正的隔离,用官方的沙箱(`/sandbox`)。 ## 放在哪个文件 [#放在哪个文件] | 文件 | 适合放什么 | |---|---| | `~/.claude/settings.json`(用户级) | 对所有项目都成立的 deny:删家目录、force push 到 main | | `.claude/settings.json`(项目级,进 git) | 这个仓库特有的 ask:部署、数据库命令,团队共享 | | `.claude/settings.local.json`(项目级,不进 git) | 只对你本机成立的 allow | | 托管设置 | 最关键的几条 deny,普通工具改不到 | 用户级文件有个弱点:配置切换工具会整份重写的,正是这个文件(见[切换工具会整份覆盖设置](/docs/pitfalls/config-overwrite))。 ### 关键规则放托管设置 [#关键规则放托管设置] 托管设置本来是企业管理员下发策略用的,优先级最高,用户级、项目级设置和命令行参数都覆盖不了它。一个人用也可以借这个机制:把最关键的几条 deny 放进去。写这个目录需要管理员权限,平时用的工具碰不到它。这是我在三层护栏全部失效之后的补法,还在试。 | 系统 | 路径 | |---|---| | macOS | `/Library/Application Support/ClaudeCode/managed-settings.json` | | Linux、WSL | `/etc/claude-code/managed-settings.json` | | Windows | `C:\Program Files\ClaudeCode\managed-settings.json` | 动手之前先确认这个文件存不存在。**已经存在、而且不是你写的**(公司电脑、管理员下发的策略),就交给管理员,不要自己改,改了也可能被下一次下发覆盖。下面以 macOS 为例。 文件不存在时才新建。这段命令自带检查,文件已经存在就什么都不改,只把内容打印出来: ```bash f="/Library/Application Support/ClaudeCode/managed-settings.json" if [ -e "$f" ]; then echo "托管设置已经存在,没有改动。先看看内容:" && sudo cat "$f" else sudo mkdir -p "$(dirname "$f")" sudo tee "$f" > /dev/null <<'EOF' { "permissions": { "deny": [ "Bash(rm -rf /)", "Bash(rm -rf ~)", "Bash(git push --force origin main *)", "Bash(git reset --hard origin/main *)" ] } } EOF fi ``` 文件已经存在、而且是你自己以前写的:先备份,再把新规则合并进去,不要整份覆盖: ```bash f="/Library/Application Support/ClaudeCode/managed-settings.json" sudo cp "$f" "$f.bak-$(date +%Y%m%d-%H%M%S)" tmp="$(mktemp)" sudo cat "$f" | jq --argjson add '["Bash(rm -rf /)","Bash(rm -rf ~)","Bash(git push --force origin main *)","Bash(git reset --hard origin/main *)"]' \ '.permissions.deny = (((.permissions.deny // []) + $add) | unique)' > "$tmp" \ && sudo cp "$tmp" "$f" rm -f "$tmp" sudo cat "$f" | jq empty && echo "JSON 有效" ``` 最后一行别省:托管设置不是合法的 JSON 时,Claude Code 会直接拒绝启动。然后新开一个会话,运行 `/status`:`Setting sources` 一行出现 `Enterprise managed settings (file)`,就说明生效了(见[官方文档](https://code.claude.com/docs/en/managed-settings))。 两点提醒:托管设置对这台机器上的所有项目都生效;本机管理员仍然能改它,所以它防的是工具,不是你自己。另外,不要在个人电脑上设 `allowManagedPermissionRulesOnly`,它会让你在其他文件里写的权限规则全部失效。 ## bypass 模式下,ask 规则靠得住吗 [#bypass-模式下ask-规则靠得住吗] 这一条请你自己验证,不要直接相信我或任何一篇文章。 官方文档(截至 2026-10)的说法是:deny 规则在所有模式下都生效,包括 bypassPermissions;命中 ask 规则的操作,在任何模式下都不会被自动放行,也包括 bypassPermissions([原文](https://code.claude.com/docs/en/permission-modes#actions-no-mode-auto-approves))。但 bypass 模式的实际行为在过去一年里随版本变过不止一次,官方仓库里有[一长串相关 issue](https://github.com/anthropics/claude-code/issues/39523)。如果你和我一样习惯开着 bypass 图省事,就别把关键防线押在 ask 上。 用一条无害的规则,测一下你当前的版本和配置: 在 `.claude/settings.local.json` 里加一条测试规则(已经有 `permissions` 的话合并进去): ```json { "permissions": { "ask": ["Bash(echo ask-check *)"] } } ``` 用你平时的模式启动 Claude Code,让它运行 `echo ask-check hello`。 弹出确认,说明 ask 在你的环境里有效;直接执行了,说明不能依赖它。测完删掉这条规则。 不管结果如何,分工都一样:不可逆的放 deny,需要兜底的放 hook。官方文档写明,PreToolUse hook 返回 deny 时,即使在 bypass 模式下也会拦下。想少弹窗又不想完全放开,官方更推荐 auto 模式:由一个分类器在后台审查每个动作。 ## 硬规则下沉 [#硬规则下沉] 判断标准:**能机械验证的进系统,需要判断的留在提示词里。** | 规则 | 放哪 | |---|---| | 某条命令绝对不能执行 | deny | | 某类操作必须我确认 | ask | | 执行之前必须先做某件事,比如备份 | hook | | 某些文件不能读、不能改 | deny 里加 `Read(./.env)`、`Edit(./secrets/**)` 这类规则 | | 需要判断的事:什么算 trivial 修复、什么时候必须先写 spec | CLAUDE.md | ## 常见坑 [#常见坑] - [不让 agent 动 git 历史](/docs/pitfalls/git-history-no-surgery) - [切换工具会整份覆盖设置](/docs/pitfalls/config-overwrite) - [防护规则会悄悄失效](/docs/pitfalls/guardrails-decay) ## 相关 [#相关] - [三层护栏](/docs/guardrails) - [用 hook 兜底](/docs/guardrails/hooks) - [小工具的最小护栏](/docs/tool/guardrails) - [护栏体检:防止静默失效](/docs/guardrails/health-check) # 密钥与配置:别让工具覆盖你的设置 (/docs/guardrails/secrets) > 密钥只放环境变量或钥匙串,配置切换工具可能整份重写你的设置 密钥只放两个地方:**环境变量**(本地是不进 git 的 `.env`,线上是部署平台的环境变量)和**系统钥匙串**。不要写进代码、CLAUDE.md、`settings.json`,或任何会被同步、备份、复制的配置文件。另外要防两件容易忽略的事:配置切换工具可能整份重写你的 `~/.claude/settings.json`;各种备份文件里,常常躺着明文密钥。 ## 密钥放哪 [#密钥放哪] | 场景 | 放哪 | |---|---| | 项目运行时用的密钥(数据库、第三方 API) | `.env`,第一天就加进 `.gitignore`;线上用部署平台的环境变量 | | 本机命令行工具的 token | macOS 钥匙串,用的时候再取 | | MCP 服务的凭证 | 优先用 OAuth,在 `/mcp` 里授权;必须用 token 时,在项目的 `.mcp.json` 里写 `${API_KEY}`,引用环境变量 | | CI | 代码托管平台的 secrets | 注意 `claude mcp add` 的 `-H "Authorization: Bearer ..."` 和 `-e KEY=...`:它们会把值明文写进 `~/.claude.json`,用户级和本地级的 MCP 配置都存在这个文件里(见[官方文档](https://code.claude.com/docs/en/mcp))。 ## macOS 钥匙串:security 命令 [#macos-钥匙串security-命令] ```bash # 存入。-w 放在最后,会提示你输入,密钥不会留在 shell 历史里 security add-generic-password -a "$USER" -s cloudflare-api-token -w # 更新已有的条目:加 -U security add-generic-password -U -a "$USER" -s cloudflare-api-token -w # 取出:只输出密钥本身 security find-generic-password -a "$USER" -s cloudflare-api-token -w # 删除 security delete-generic-password -a "$USER" -s cloudflare-api-token ``` 用的时候只在那一条命令里取,不要导出成全局环境变量: ```bash CLOUDFLARE_API_TOKEN="$(security find-generic-password -a "$USER" -s cloudflare-api-token -w)" wrangler deploy ``` Claude 运行命令的输出会进对话记录,而对话记录以 jsonl 文件保存在 `~/.claude/projects/` 下。让它单独执行一次 `security find-generic-password ... -w`,密钥就留在了对话记录里。只在 `$(...)` 里取用;更稳的做法是给这条命令加一条 ask 规则 `Bash(security find-generic-password *)`。ask 规则对 `$(...)` 里的子命令同样生效,Claude 每次要取密钥都得你点头。 ## 配置切换工具会整份覆盖设置 [#配置切换工具会整份覆盖设置] 我用一个模型供应商切换工具([CC Switch](https://github.com/farion1231/cc-switch) 这类)从第三方模型切回官方时,它把 `~/.claude/settings.json` 整份重写了:权限规则、hook、插件启用状态全部丢失。表面症状只是“所有插件都关了”,过了很久我才意识到,护栏也跟着没了(见[切换工具会整份覆盖设置](/docs/pitfalls/config-overwrite))。 公平地说,CC Switch 现在的文档(截至 2026-10)写的是:切换时只改连接相关的字段,权限、hook、插件启用状态都不动。但这类工具的合并逻辑会随版本变化,也可能有 bug。规则不变:**切换之后检查一遍。** ```bash # 切换后,看权限、hook、插件还在不在 jq '{deny: .permissions.deny, hooks: (.hooks // {} | keys), plugins: .enabledPlugins}' ~/.claude/settings.json ``` 更彻底的做法有两个: - 关键的 deny 规则和体检 hook 放进托管设置。切换工具只写用户级文件,碰不到它(写法见[权限规则](/docs/guardrails/permissions)) - 不让工具改 `settings.json`。Claude Code 也从环境变量读 `ANTHROPIC_BASE_URL` 和 `ANTHROPIC_AUTH_TOKEN`,可以给每个供应商写一个 shell 函数,token 放钥匙串,启动时临时注入。前提是 `settings.json` 的 `env` 里没有残留的同名变量 ```bash # 放进 ~/.zshrc;地址换成供应商给你的 claude-alt() { ANTHROPIC_BASE_URL="https://api.example.com" \ ANTHROPIC_AUTH_TOKEN="$(security find-generic-password -a "$USER" -s alt-provider-token -w)" \ claude "$@" } ``` ## 备份文件里也可能留着明文密钥 [#备份文件里也可能留着明文密钥] 密钥常常藏在你想不到的地方: - **`~/.claude/settings.json` 的 `env`**:供应商切换工具会把第三方的 key 明文写在这里 - **这个文件的各种副本**:你手动备份的 `settings.json.bak`,以及切换工具自己的备份。据 CC Switch 的文档,它第一次改写配置前会备份原文件,数据库和备份都放在 `~/.cc-switch/` 下 - **`~/.claude.json`**:用 `-H`、`-e` 添加的 MCP 凭证。Claude Code 每次写这个文件之前,会在 `~/.claude/backups/` 里留一份备份,保留最近 5 份 - **对话记录**:`~/.claude/projects/` 下的 jsonl,前提是密钥曾经被打印出来 - **shell 历史**:直接敲过的 `export TOKEN=...`,或者把密钥写在 `-w` 后面的命令 查一下哪些文件里有疑似密钥的字段。`-l` 只列文件名,不会把内容打印出来: ```bash grep -rlE 'TOKEN|API_KEY|SECRET|PASSWORD' ~/.claude/settings.json ~/.claude.json ~/.claude/backups ~/.cc-switch 2>/dev/null ``` 找到之后,**先轮换密钥,再删文件**。密钥一旦落进备份、同步盘或别人可能看到的地方,删掉文件也收不回来。之后把密钥搬进钥匙串或环境变量,旧备份定期清理。如果你用 dotfiles 仓库同步 `~/.claude/`,把 `settings.json` 的 `env`、`~/.claude.json` 和 `backups/` 都排除在外。 ## 常见坑 [#常见坑] - [切换工具会整份覆盖设置](/docs/pitfalls/config-overwrite) - [防护规则会悄悄失效](/docs/pitfalls/guardrails-decay) ## 相关 [#相关] - [权限规则:deny、ask、allow](/docs/guardrails/permissions) - [护栏体检:防止静默失效](/docs/guardrails/health-check) - [小工具的最小护栏](/docs/tool/guardrails) # 开始 (/docs) > 这本手册写给谁、怎么读、从哪一档开始 这是一本用 Claude Code 做产品的实战手册。它不罗列工具,而是回答一个更实际的问题:**一个人加上 AI,怎么把想法做成产品,再把产品做成一个能协作的组织**。里面的每条规则,背后都有一次真实的事故。 ## 先选你在哪一档 [#先选你在哪一档] 拿不准就看[选档](/docs/tiers):三个信号判断你在哪一档,以及什么时候该升档。 ## 三种读法 [#三种读法] - **起一个新项目**:打开[启动器](/docs/launcher),选好档位,照着清单一步步勾。每一步都有可复制的命令。 - **系统地读**:从[为什么写这本手册](/docs/why)开始,按左侧目录往下读。产品篇是主干,组织篇是这本手册最独特的部分。 - **只看踩坑**:[坑库](/docs/pitfalls)里有 25 张卡片,每张都来自真实复盘:发生了什么、为什么、怎么防。 ## 可信度标签 [#可信度标签] 每一页、每一张卡片都标了可信度。没亲自验证过的做法,不会写成“亲历”。 | 标签 | 含义 | |---|---| | ✅ 亲历 | 我在真实项目里用过、踩过,有复盘为证 | | 🧪 试用中 | 我正在试用,结论可能会变,变了会更新 | | 📚 业界做法 | 来自官方文档或业界实践,我还没有亲自验证 | 一个例子:我用了一年的流程框架 superpowers 标 ✅;2026 年 10 月刚切过去的 Matt Pocock skills 标 🧪。为什么换、怎么换,写在[流程引擎对比](/docs/workflow/superpowers-vs-matt)里。 ## 让 Claude 直接用这本手册 [#让-claude-直接用这本手册] 这本手册同时是一个 Claude Code 插件。装好以后,可以让 Claude 按手册的方法给你的环境体检、配置工具链、推荐方案、起新项目、查坑、提炼复盘: ```bash claude plugin marketplace add https://ainative.jubao.ai/marketplace.json claude plugin install ainative@ainative ``` 详见[插件说明](/docs/reference/plugin)。如果你用的是别的 AI 工具,可以直接读 [`/llms.txt`](https://ainative.jubao.ai/llms.txt)(目录)或 [`/llms-full.txt`](https://ainative.jubao.ai/llms-full.txt)(全文);每一页顶部也有“复制 Markdown”按钮。 ## 这本手册不是什么 [#这本手册不是什么] - **不是工具大全**。只写我真正在用、或者认真评估过的工具,并说明每个工具负责哪一件事。 - **不是官方文档**。和 Anthropic、OpenAI 等公司没有关系;引用它们的方法论时都附了原文链接。 - **不是放之四海皆准**。我的技术栈是 Next.js、TypeScript、Tailwind、bun,部署在 Vercel 和 Cloudflare。原则是通用的,命令请按你的技术栈替换。 ## 相关 [#相关] - [选档:小工具、产品还是组织](/docs/tiers) - [启动器](/docs/launcher) - [工具分工总表](/docs/reference/toolchain) # 启动器 (/docs/launcher) > 选好档位,照着清单一步步起一个新项目,每一步都有可复制的命令 填上项目名和 GitHub 账号,选好档位,命令里的占位符会自动替换。档位切到“小工具”时,只显示最少的步骤;切到“组织”时,会多出 ops 仓和记忆相关的配置。每个阶段底部都有链接,指向手册里的完整说明。 # 让 ops 和项目一起进化 (/docs/org/evolve) > 模板继承、园丁 agent、护栏体检:让复盘变成会自动生效的规则 规则要双向流动:**项目里踩的坑,回流到 ops,变成 playbook、hook 和模板;ops 里的规则,自动下发到每个项目。** 我目前只做到了“写下来”这一半,缺的是“回流”。这一页的三个机制(模板继承、园丁 agent、护栏体检)是我正在补的,都还在试,所以整页标 🧪。 ## 我的现状:沉淀勤,回流缺 [#我的现状沉淀勤回流缺] 一年里我写了 70 多篇复盘,自动记忆攒了 200 多条,还有一批 playbook、runbook 和 ADR。按“有没有总结”来算,我做得不差。 但最近几件事接连暴露出问题: - 半年前给本地数据库加的三层防护,三层全没了,整整一段时间没人发现。复盘里甚至写过检查命令,只是没人去跑([防护规则会悄悄失效](/docs/pitfalls/guardrails-decay)) - 第二个组织的规则文件是从第一个复制的,6 处引用指向不存在的文件,“下次 review 日期”过期半年([模板复制后会各自漂移](/docs/pitfalls/template-copy-drift)) - ops 仓里的恢复手册,描述的是一个早已被改掉的 Makefile([跟代码绑定的文档跟代码放一起](/docs/pitfalls/code-coupled-docs)) 用双环学习的话说:我一直在做单环,修好这一次、写一篇复盘;很少做双环,去修改产生错误的那套规则和机制。复盘停留在文字里,下一次照样踩。 ## 双向流动 [#双向流动] | 方向 | 流动的是什么 | 靠什么机制 | |---|---|---| | 项目 → ops | 复盘、坑卡,以及“同一个坑出现第二次”的信号 | 园丁 agent 读复盘、提 PR;`/ainative:harvest` 把复盘提炼成坑卡草稿 | | ops → 项目 | 通用规则、hook、SOP、模板的更新 | 插件模板继承;代码仓 CLAUDE.md 里的指针 | | 回路检查 | 规则还在不在、有没有被覆盖 | 护栏体检 | ## 机制一:模板继承,而不是复制 [#机制一模板继承而不是复制] 把各组织共用的部分做成一个通用的 ops 插件,各组织在它之上派生,而不是各自复制一份: ```text ops-kit/ 通用模板,放在团队私有插件市场里 ├── .claude-plugin/plugin.json ├── agents/ops.md ops agent 的骨架 ├── skills/new-adr/ /ops-kit:new-adr ├── skills/new-retro/ /ops-kit:new-retro ├── skills/review/ 审查流程 ├── skills/doctor/ 护栏体检 └── hooks/hooks.json 通用拦截、数据库自动备份 org-a-ops/ 组织 A 派生,只写自己特有的部分 └── .claude-plugin/plugin.json 在 dependencies 里声明 ops-kit ``` 几个要点: - **用 `dependencies` 继承。** 插件清单的 `dependencies` 字段可以声明依赖同一个市场里的另一个插件,启用组织插件时,通用模板会一起启用 - **升级一次,全体生效。** 通用模板发一个新版本,各组织更新插件时一起拿到,不会再出现“两份一字不差的过期日期” - **权限规则要绕一下。** 插件的 `settings.json` 只认 `agent` 和 `subagentStatusLine` 两个键,带不了 deny 和 ask。通用的拦截只能做成插件里的 PreToolUse hook(返回 deny 时,即使开着 bypass 也会拦下),或者由一个 setup skill 写进各仓库的 `.claude/settings.json`,再交给体检确认它们一直在 ## 机制二:园丁 agent 每周跑一次 [#机制二园丁-agent-每周跑一次] 用 `/schedule` 建一个每周运行的云端 routine,给它三件活: 1. 读过去一周新增的复盘,把“下次怎么做”里还没进 playbook 的条目整理成 PR 2. 查失效链接(尤其是跳出仓库的相对链接)和过期的 review 日期 3. 同一类问题在两篇以上复盘里出现,就起草一个 hook 或 CI 检查,单独提一个 PR 它只提 PR,不直接改主分支,由人审查后合并。一个可以直接改着用的提示词: ```text 你是 org-ops 仓库的园丁,每周一运行。只提 PR,不要直接推送到 main。 1. 读 retros/ 下过去 7 天新增的复盘,找出"下次怎么做"里还没写进 playbooks/ 的条目,合并成一个 PR 2. 检查所有 .md 文件里的链接:跳出仓库的相对路径、指向不存在文件的链接,列在 PR 描述里 3. 找出 frontmatter 里 next_review 早于今天的文档,列在 PR 描述里 4. 如果同一类问题出现在两篇以上复盘里,起草一个 hook 或 CI 检查,单独提 PR,标题以 [draft] 开头 最后在 PR 描述里写清:做了什么、没做什么、哪些需要人来决定 ``` Routines 有几个限制,先知道再用(截至 2026-10,它还是研究预览,见[官方文档](https://code.claude.com/docs/en/routines)): - **跑在云端。** 每次运行都克隆你选的 GitHub 仓库,改动推到 `claude/` 开头的分支。它看不到你本机的文件和自动记忆,也用不了 `claude mcp add` 加的本地 MCP。所以园丁只能处理已经进了 git 的东西,这也是团队结论必须进 git 的又一个理由 - **网络有白名单。** 默认环境只放行常见的包管理和开发域名,要检查外部链接,先在环境设置里放开 - **门槛。** 最短间隔一小时;需要 Pro、Max、Team 或 Enterprise 订阅 - **绿灯不等于做对了。** 运行状态显示成功,只说明会话正常结束,要点进记录看它实际做了什么 ## 机制三:护栏体检 [#机制三护栏体检] 规则写进系统之后,还要确认它一直在:会话开始时跑一个脚本,断言关键的 deny 规则、hook、备份脚本都还在;上游会改的共享文件,在 CI 里断言你的定制还在;隔一段时间跑一次 `/ainative:doctor`。脚本和做法见[护栏体检:防止静默失效](/docs/guardrails/health-check)。 ## 怎么判断这三个机制有没有用 [#怎么判断这三个机制有没有用] 建议看四个指标: - 同一个坑重复出现的次数 - 从复盘写完到规则落地(PR 合并)的天数 - 由复盘生成的 hook 和 CI 检查的数量 - 体检抓到的失效次数 我会在跑满一个月之后,把自己的数据补在这里。 ## 常见坑 [#常见坑] - [防护规则会悄悄失效](/docs/pitfalls/guardrails-decay) - [模板复制后会各自漂移](/docs/pitfalls/template-copy-drift) - [跟代码绑定的文档跟代码放一起](/docs/pitfalls/code-coupled-docs) - [跨仓链接用完整地址](/docs/pitfalls/absolute-cross-repo-links) ## 相关 [#相关] - [护栏体检:防止静默失效](/docs/guardrails/health-check) - [组织 ops agent 的五个组成部分](/docs/org/ops-agent) - [背后的理念](/docs/reference/ideas) - [本手册的 Claude Code 插件](/docs/reference/plugin) # 组织:什么时候需要 ops (/docs/org) > 多仓库、多人协作之后,单靠每个仓库的 CLAUDE.md 不够用了 当同一个组织有了第二个要共享规则的代码仓库,或者有了不该让所有写代码的人看到的内容,单靠每个仓库各自的 CLAUDE.md 就管不住了。这时候要升到组织档,多做四件事:**建一个 ops 仓放跨仓库的结论,给组织配一个 ops agent,把记忆分成公开和私人两层,让规则能自动回流到每个项目。** ## 为什么每个仓库一份 CLAUDE.md 不够 [#为什么每个仓库一份-claudemd-不够] 我同时运营两个组织:十几个代码仓库、几十个 agent、几位协作者。在有 ops 之前,问题是一点点冒出来的: - 同一条规则在三个仓库的 CLAUDE.md 里各写一遍,改了一处,另外两处还是旧的 - 跨仓库的决策(命名、权限、谁负责什么)没有归宿,只能写在某个 PR 描述里,半年后谁也找不到 - 事故复盘里有客户和商业细节,放不进将来要开源的代码仓 - 在 A 仓库里开的会话,不知道 B 仓库上周刚定下的事 这些都不是“写得不够多”,而是**没有一个专门放“组织层面”东西的地方**。 ## 升档信号 [#升档信号] 下面三条满足任意一条,就该从产品档升到组织档(完整判断见[选档](/docs/tiers)): | 信号 | 你会看到的症状 | |---|---| | 同一组织有 2 个以上代码仓库,要共享规则和决策 | 同一段规则在多个 CLAUDE.md 里复制粘贴 | | 有不该让所有写代码的人看到的内容,或者代码仓是一个上游项目的 fork | 复盘、客户信息、权限清单不知道往哪放 | | 有不写代码的协作者(运营、市场、商务) | 他们要看 SOP,却得去代码仓里翻 | 反过来,只有一个仓库的产品不需要 ops 仓;只是打算开源、或者有长期有效的决策,在仓库里放一个 `docs/adr/` 就够了。这本手册自己就是产品档:它的写作规范放在仓库根目录的 `STANDARDS.md`,不需要 ops 仓。 ## 组织档要多做的四件事 [#组织档要多做的四件事] 这也是我建议的落地顺序:先建 ops 仓,把跨仓库的决策和复盘搬过去;再配 ops agent;记忆分层随用随整理;进化回路最后补,但不能不补。我自己就是前三件做得勤、第四件补得晚,结果吃了亏(见[让 ops 和项目一起进化](/docs/org/evolve))。 ## 我的结构 [#我的结构] ```text 个人总助手 跨组织路由:这件事归哪个组织、交给谁 ├── 组织 A 的 ops agent 这个组织的宪法、权限、复盘 │ ├── SOP skill │ └── SOP skill └── 组织 B 的 ops agent ├── SOP skill └── SOP skill ``` 三层各管一件事: - **个人总助手**:一个用户级 skill,只做路由。它不存任何组织的规则,只判断“这件事归谁”,然后交给对应组织的 ops agent - **ops agent**:每个组织一个。它知道这个组织的宪法(ADR、playbook、红线)放在哪,知道哪些事可以直接做、哪些必须先问人 - **SOP skill**:可重复的具体操作,比如打包、部署、合并上游、给新成员开权限。它们大多是从反复手工执行的操作里提炼出来的 粒度是**每个组织一个 ops agent,不是每个仓库一个**。权限、成员、跨仓库决策都是组织层面的;按仓库拆,同一份宪法会被复制成很多份,然后各自漂移。两个组织也不能共用一个:它们的权限边界和保密内容不同,混在一起,迟早会把一个组织的信息带进另一个组织的文档里。 ## 常见坑 [#常见坑] - [模板复制后会各自漂移](/docs/pitfalls/template-copy-drift):第二个组织的规则从第一个复制过来,半年后两边都过期了 - [同一个组织的记忆不要按目录分裂](/docs/pitfalls/split-memory) - [防护规则会悄悄失效](/docs/pitfalls/guardrails-decay):写进复盘不等于生效 ## 相关 [#相关] - [选档:小工具、产品还是组织](/docs/tiers) - [ops 放哪:独立仓还是放进项目](/docs/org/ops-repo) - [产品:AI-native 开发六阶段](/docs/product) # 记忆分层:公开的、私人的、别再加新的 (/docs/org/memory) > 团队结论进 git,个人判断留私人记忆,不要让存储越来越多 记忆只分两层:**团队要遵守的结论进 git**(ops 仓和代码仓的 `docs/`,走 PR 审查);**个人的判断和偏好留在私人记忆**(自动记忆、ops agent 的 `memory/`)。现有的五个存储已经够用,不要再引入第六个。同一个组织的所有仓库,共用一个自动记忆目录。 ## 五个存储,各放什么 [#五个存储各放什么] | 层 | 存储 | 谁写 | 放什么 | |---|---|---|---| | 公开 | ops 仓 | 人和 agent,经 PR 审查 | ADR、playbook、复盘、红线 | | 公开 | 代码仓 `docs/` | 人和 agent,经 PR 审查 | spec、plan、跟代码绑定的 runbook | | 私人 | 自动记忆 | Claude 自己 | 你纠正过它的事、你的偏好、项目里的小经验 | | 私人 | ops agent 的 `memory/` | ops agent | 你对组织事务的个人判断 | | 可选 | 一个跨项目的记忆 MCP | 视工具而定 | 需要跨组织检索的东西 | 自动记忆是 Claude Code 内置的:每个项目一个目录,默认在 `~/.claude/projects/<项目>/memory/`。索引文件 `MEMORY.md` 每次会话开始时只加载前 200 行或 25KB,超出的部分不会加载;具体的主题文件按需读取(见[官方文档](https://code.claude.com/docs/en/memory))。 ## 公开还是私人:问一句 [#公开还是私人问一句] **这条结论,别人也需要遵守吗?** 需要,就进 git:写成 ADR、playbook 或 runbook,经过审查。不需要,只是你的判断、倾向或还没验证的猜测,就留在私人记忆。 几个例子: - “生产发布必须人工确认”:公开。写进 ops 仓的红线,再落成 ask 规则 - “方案只给一个推荐、一个替代,不要平铺三四个”:私人。这是我的偏好,不是团队规则 - “这个上游项目每次大版本都会改 Makefile”:先放私人记忆;同样的事出现第二次,就升级成 runbook 和 CI 检查 私人记忆不经审查,里面可能有过时甚至错误的结论。这对个人无所谓,但不能拿它来约束团队。 ## 别再加第六个存储 [#别再加第六个存储] 工具总在给你新的地方存东西:gstack 的 `/learn` 记项目经验,Matt Pocock skills 会在仓库里维护术语表 GLOSSARY.md 和 ADR,各种记忆插件也各有一套。每多一个存储,就多一个要搜的地方、多一份会过时的副本。同一条经验散落在三处,谁也说不清哪份是对的。 规则是:**要么不用,要么明确它替代谁。** 比如决定用 GLOSSARY.md 当领域术语表,ops 仓里就不再另写一份术语表。 经验的复利只走一条路: ```text 反馈记忆(私人) → playbook / runbook(公开,经审查) → hook / CI(自动生效) ``` 每往上走一级,就把下一级那条删掉,或者改成一句指针。 ## 同一个组织,统一一个记忆目录 [#同一个组织统一一个记忆目录] 自动记忆按 git 仓库区分:同一个仓库的所有子目录和 worktree 共用一个;不在 git 仓库里时,按启动目录区分。这意味着,在组织的父目录启动和在某个子仓库里启动,看到的是两套完全不同的记忆。 我就是这样踩的坑:在组织父目录启动,有 200 多条自动记忆;在子仓库里启动,只有 8 条。两边互相看不到,同一个坑反复踩(见[同一个组织的记忆不要按目录分裂](/docs/pitfalls/split-memory))。 做法:在这个组织每个仓库的 `.claude/settings.local.json` 里,把 `autoMemoryDirectory` 指向同一个目录。路径必须是绝对路径,或者以 `~/` 开头: ```json { "autoMemoryDirectory": "~/.claude/org-memory/<组织名>" } ``` 放 `settings.local.json`,而不是进 git 的 `.claude/settings.json`,有两个原因:这是你本机的路径,不该强加给协作者;而且较早的版本不接受项目级 `.claude/settings.json` 里的这个设置(新版文档已改为信任目录之后生效)。 切换之前,先把几处已有的记忆合并到新目录:主题文件直接拷过去,`MEMORY.md` 手动合并、去重。合并时顺手清理一遍,因为索引只有前 200 行会被加载,条目越多,排在后面的越容易被截掉。 ## 记忆和 runbook 双写的代价 [#记忆和-runbook-双写的代价] 同一条经验,如果既在记忆里、又在 runbook 里,迟早会不一致:runbook 随代码更新了,记忆里还是旧说法。更麻烦的是,`MEMORY.md` 每次会话都会加载,runbook 只在需要时才读,**两边冲突时,agent 更容易照着过时的记忆做**。 所以经验升级成 runbook 之后,把记忆里那条改成指针: ```markdown - 本地数据库恢复:以 docs/runbooks/db-restore.md 为准,这里不再记步骤 ``` 有人说“之前是这样的”,道理也一样:记忆可能是错的,git 历史才是事实(见[“之前是这样的”先查 git](/docs/pitfalls/memory-vs-git))。 ## 可选:一个跨项目的记忆 MCP [#可选一个跨项目的记忆-mcp] 如果你需要跨组织检索,比如“另一个组织遇到过类似的问题吗”,可以加一个跨项目的记忆 MCP。它算五个存储之一,不是第六个,前提是分工清楚:它负责跨项目检索,不和自动记忆存两份一样的东西。 ## 常见坑 [#常见坑] - [同一个组织的记忆不要按目录分裂](/docs/pitfalls/split-memory) - [“之前是这样的”先查 git](/docs/pitfalls/memory-vs-git) ## 相关 [#相关] - [组织 ops agent 的五个组成部分](/docs/org/ops-agent) - [让 ops 和项目一起进化](/docs/org/evolve) - [运维:线上问题变成新的 intent](/docs/product/maintain) # 组织 ops agent 的五个组成部分 (/docs/org/ops-agent) > 身份、宪法、私人记忆、执行能力、进化回路,以及在 Claude Code 里怎么实现 一个组织的 ops agent 由五样东西组成:**身份与路由、宪法、私人记忆、执行能力、进化回路**。少了前两样,它只是一个会聊天的助手;少了后两样,它会和组织一起老化。每个组织配一个,不是每个仓库配一个。 ## 五件套 [#五件套] | 组成 | 作用 | 在 Claude Code 里怎么做 | |---|---|---| | ① 身份与路由 | 它是谁、哪些事归它管 | 一个 skill,或者 `.claude/agents/.md`;在 ops 仓设置 `agent` 字段,打开就是它 | | ② 宪法(公开) | 团队共同遵守的结论 | ops 仓里的 ADR、runbook、playbook、复盘、红线 | | ③ 私人记忆 | 你个人的判断和倾向 | skill 目录下的 `memory/`、自动记忆,或 subagent 的 `memory` 字段 | | ④ 执行能力 | 动手做事 | SOP skill、hook、CI 卡点、MCP,打包成插件,经团队私有插件市场分发 | | ⑤ 进化回路 | 规则随经验更新 | 复盘 → 规则 → hook;定期园丁(`/schedule`);护栏体检 | ## ① 身份与路由 [#-身份与路由] 身份要写清楚三件事:管什么、不管什么、什么时候必须停下来问人。实现方式有两种: 把 ops agent 写成一个 skill,放在 `~/.claude/skills/<名字>/SKILL.md`。在任何仓库里都能用 `/<名字>` 叫出来,描述命中时也会自动触发。它跑在 Claude Code 默认的系统提示词之上,只是多带了一份组织的上下文。我现在用的就是这种。 在 ops 仓的 `.claude/agents/org-a-ops.md` 里定义一个 subagent,再在 ops 仓的 `.claude/settings.json` 里写 `"agent": "org-a-ops"`。之后在 ops 仓里打开 Claude Code,主会话直接就是它,启动标题会显示 `@org-a-ops`;临时换一个 agent 用 `claude --agent <名字>`,命令行参数优先于设置。 要注意:以 agent 身份运行时,agent 文件的正文会**整个替换** Claude Code 默认的系统提示词(CLAUDE.md 照常加载),工具和模型也按 agent 的定义来。所以正文要写完整,不能只写一句“你是 ops agent”(见[官方文档](https://code.claude.com/docs/en/sub-agents))。 不管哪种实现,身份文件的内容都差不多。以组织 A 的 subagent 写法为例: ```markdown --- name: org-a-ops description: 组织 A 的 ops agent。处理跨仓库决策、成员与权限、发版部署 SOP、复盘归档。 memory: user --- 你是这个组织的 ops agent,在 ops 仓里工作。 ## 你管什么 - 跨仓库决策(decisions/)、协作剧本(playbooks/)、复盘(retros/) - 成员入职、权限变更、发版、部署:按对应的 SOP skill 执行,不临场发挥 ## 动手之前 1. 先读 CLAUDE.md 里的红线 2. 在 decisions/ 里找和这件事相关的 ADR;找不到就问,不要自己拍板 3. 涉及权限、删除、对外发布的操作,先列计划,等人确认 ## 不归你管 - 某个代码仓内部的实现 → 请用户到那个仓库里开会话 - 另一个组织的事 → 交回个人总助手 ``` **每个组织用一个唯一的名字**,比如 `org-a-ops`、`org-b-ops`。`memory: user` 的记忆目录按 agent 名区分,两个组织都叫 `org-ops`,就会共用同一份记忆,正好违反后面说的“两个组织不能混用”。如果这个 agent 只在 ops 仓里用,也可以改成 `memory: local`,让记忆按项目隔离。要注意,这只是把记忆分开存放,不是访问控制:同一台机器上的任何会话都读得到这些文件。真正需要隔离的内容,靠仓库权限和账号来分。 ## ② 宪法:团队共同遵守的结论 [#-宪法团队共同遵守的结论] 宪法放在 ops 仓,走 PR、经过审查,人人可查:ADR 记决策,playbook 记协作方式,runbook 记操作步骤,复盘记发生过的事,红线记绝对不能做的事。 ops agent 不需要背下宪法,只需要知道去哪找、什么时候必须找。这和 OpenAI 在《Harness engineering》里的做法一致:入口文件只写一页“地图”,细节放进结构化的 `docs/`,那里才是唯一的事实来源。 红线要尽量下沉成系统规则。能写成 deny 规则或 hook 的,就不要只写在文档里(见[权限规则](/docs/guardrails/permissions))。 ## ③ 私人记忆:你个人的判断 [#-私人记忆你个人的判断] 有些东西不该进宪法:你对某个合作方的判断、你偏好的决策方式、还没验证的猜测。它们放在私人记忆里,不进 git,不经审查。 我的做法是在 ops agent 的 skill 目录里放一个 `memory/`,在 SKILL.md 里写明什么时候读、什么时候写。Claude Code 也有原生的写法 :subagent 定义里加 `memory` 字段。`user` 存在 `~/.claude/agent-memory/<名字>/`,按 agent 名区分、跨项目、不进 git;`local` 存在项目的 `.claude/agent-memory-local/<名字>/`,按项目隔离、不进 git;`project` 存在 `.claude/agent-memory/<名字>/`,进 git、团队共享。前提是自动记忆没有关闭。 公开和私人怎么分、为什么不要再加新的存储,见[记忆分层](/docs/org/memory)。 ## ④ 执行能力:SOP 打包成插件 [#-执行能力sop-打包成插件] ops agent 动手做事,靠的是 SOP skill(打包、部署、合并上游、成员入职这类重复操作)、hook、CI 卡点和 MCP。只在你本机能用的 SOP,团队用不上。 把它们打包成插件,放进一个私有 GitHub 仓库做团队插件市场: 在私有仓库根目录写 `.claude-plugin/marketplace.json`,必填 `name`、`owner`、`plugins`,每个插件条目要有 `name` 和 `source`。写完用 `claude plugin validate .` 检查(见[官方文档](https://code.claude.com/docs/en/plugin-marketplaces))。 成员安装:先 `claude plugin marketplace add <组织>/<仓库>`,再 `claude plugin install <插件>@<市场名>`。私有仓库用成员本机的 git 凭证克隆,所以每个人都要有这个仓库的读权限。 也可以写进 ops 仓或代码仓的 `.claude/settings.json`,成员信任这个目录之后,就会自动注册市场、启用插件: ```json { "extraKnownMarketplaces": { "team-tools": { "source": { "source": "github", "repo": "<组织>/<插件市场仓库>" } } }, "enabledPlugins": { "org-a-ops@team-tools": true } } ``` 插件和市场放在同一个仓库里(`source` 写相对路径)最省事;插件在别的仓库时,成员还要手动运行一次 `claude plugin install <插件>@<市场名> --scope project`。 一个限制要提前知道:**插件里带不了权限规则**。插件的 `settings.json` 只认 `agent` 和 `subagentStatusLine` 两个键,通用的 deny 只能做成插件里的 hook,或者由一个 setup skill 写进各仓库的 settings(见[让 ops 和项目一起进化](/docs/org/evolve))。 ## ⑤ 进化回路 [#-进化回路] 宪法不会自己更新。ops agent 的最后一块,是让每次复盘真正改变点什么:复盘 → 规则 → hook;用 `/schedule` 建一个每周跑的园丁 agent,读新复盘、提 PR 更新 playbook、查失效链接;定期体检护栏还在不在。这三件事我还在试,单独写在[让 ops 和项目一起进化](/docs/org/evolve)。 ## 粒度:每个组织一个 [#粒度每个组织一个] - **按仓库拆**:宪法被复制成多份,各自漂移;跨仓库的问题没有人管 - **所有组织共用一个**:权限边界和保密内容混在一起,迟早串台 - **每个组织一个**:正好和权限边界、成员、决策的范围对齐 跨组织的事,交给最上面的个人总助手路由(结构见[组织篇首页](/docs/org))。 ## 起名:避开 AIOps [#起名避开-aiops] AIOps 在业界已经是固定术语,指用 AI 做 IT 运维:告警聚合、异常检测、根因分析。拿它给自己的 ops agent 起名,搜索、沟通、向别人解释的时候都会混淆。用“组织名 + ops”,或者干脆起一个独立的名字。 ## 业界对应的理念 [#业界对应的理念] | 理念 | 要点 | 对应五件套 | |---|---|---| | [Harness Engineering](https://openai.com/index/harness-engineering/)(OpenAI,2026-02) | 人掌舵、agent 执行;约 100 行的 AGENTS.md 当地图,`docs/` 是唯一事实来源;仓库之外的东西对 agent 等于不存在;定期运行的“文档园丁”自动提 PR 修过期文档;规则交给 linter 和 CI 机械执行 | ② 宪法、⑤ 园丁 | | [Compound Engineering](https://every.to/chain-of-thought/compound-engineering-how-every-codes-with-agents)(Every) | 每次纠正、决策、失败都写回 agent 读得到的地方;按 Plan → Work → Review → Compound 循环,让下一个功能比上一个更容易做 | ③ 记忆、⑤ 回路 | | [双环学习](https://hbr.org/1991/05/teaching-smart-people-how-to-learn)(Argyris 与 Schön) | 单环修正这一次的错误;双环修改产生错误的那条规则本身 | ⑤ 回路:复盘之后要改模板、hook、权限,而不只是记一笔 | 更完整的讨论见[背后的理念](/docs/reference/ideas)。 ## 常见坑 [#常见坑] - [模板复制后会各自漂移](/docs/pitfalls/template-copy-drift) - [同一个组织的记忆不要按目录分裂](/docs/pitfalls/split-memory) - [防护规则会悄悄失效](/docs/pitfalls/guardrails-decay) ## 相关 [#相关] - [ops 放哪:独立仓还是放进项目](/docs/org/ops-repo) - [记忆分层](/docs/org/memory) - [子 agent 提示词模板](/docs/templates/subagent-prompt) - [背后的理念](/docs/reference/ideas) # ops 放哪:独立仓还是放进项目 (/docs/org/ops-repo) > 一句话判断标准,加上独立 ops 仓的三个代价和补法 判断一份文档放哪,只问一句:**这份内容会不会因为改代码而需要跟着改?会,放代码仓;不会,放 ops 仓。** 组织档我用独立的 ops 仓,但它有三个代价:agent 看不见、跟代码绑定的文档会过时、跨仓相对链接会断。每一个都要提前补上。 ## 判断标准 [#判断标准] | 例子 | 会因为改代码而改吗 | 放哪 | |---|---|---| | 一个功能的 spec 和实现计划 | 会 | 代码仓 | | “怎么恢复本地数据库”,步骤依赖 Makefile | 会 | 代码仓 | | 两个仓库共用的命名规范、权限分工 | 不会 | ops 仓 | | 一次事故的复盘 | 不会,复盘写的是已经发生的事 | ops 仓 | | 一次技术选型调研 | 不会 | ops 仓 | 一篇复盘经常同时产出两样东西:复盘本身放 ops 仓;它要求修改的 runbook 或检查脚本,放回代码仓。 ## 三档各放哪 [#三档各放哪] | 档位 | ops 放哪 | 说明 | |---|---|---| | 小工具 | 不需要 | README + 一页 CLAUDE.md | | 产品 | 仓库内 `docs/` | specs、plans、adr、runbooks、retros,加上 `.claude/` | | 组织 | 独立 ops 仓 | 代码仓保留 spec、plan 和跟代码绑定的 runbook | ## 什么时候拆出独立的 ops 仓 [#什么时候拆出独立的-ops-仓] 出现下面任何一种情况,就该把 ops 从代码仓里拆出来: - 第二个代码仓库出现了,而且要共用决策 - 代码仓是一个上游开源项目的 fork,或者要开源,而你又有不该公开的治理文档。ops 内容放进去,要么和上游合并冲突,要么开源前得逐条清理 - 有些内容只该让一部分人看到:客户、商业、权限清单、事故细节 - 有不写代码的协作者要读写这些文档 我是第二条和第三条同时成立:其中一个代码仓就是 fork,复盘里又有不能公开的细节。 ## 独立 ops 仓的三个代价和补法 [#独立-ops-仓的三个代价和补法] ### 1. agent 看不见 [#1-agent-看不见] OpenAI 在《[Harness engineering](https://openai.com/index/harness-engineering/)》里说得很直接:仓库之外的东西,对 agent 来说等于不存在。你在代码仓里开会话,Claude 默认只能读这个仓库,ops 仓里写得再好,它也不知道。 补法分两步: 在代码仓的 CLAUDE.md 里写几行指针,告诉它规则在哪、什么时候该去读: ```markdown ## 组织规则在 ops 仓 - 跨仓决策:https://github.com/<组织>//tree/main/decisions - 本机路径:~/work/org-ops(已加入 additionalDirectories) - 涉及命名、权限、发版的改动,动手前先读 decisions/ 里相关的 ADR ``` 在代码仓的 `.claude/settings.local.json` 里,把 ops 仓加进可访问目录。路径因人而异,所以放在不进 git 的 local 文件里: ```json { "permissions": { "additionalDirectories": ["/Users/you/work/org-ops"] } } ``` 注意,`additionalDirectories` 只给文件读写权限,**不会加载 ops 仓里的 CLAUDE.md、skill 和 agent 定义**。要用 ops 仓里的 skill 和 subagent,改用 `claude --add-dir ~/work/org-ops` 启动;连它的 CLAUDE.md 也要加载,还得设环境变量 `CLAUDE_CODE_ADDITIONAL_DIRECTORIES_CLAUDE_MD=1`(见[官方文档](https://code.claude.com/docs/en/permissions#additional-directories-grant-file-access-not-configuration))。 ### 2. 跟代码绑定的文档会过时 [#2-跟代码绑定的文档会过时] 我吃过一次亏:一份数据库恢复手册放在 ops 仓,写着“Makefile 的 reset 会先备份”,还附了检查命令。代码仓里的 Makefile 早被一次上游合并改掉了,备份步骤已经不在,手册完全不知道。 补法: - 会因为改代码而改的文档,搬回代码仓,和代码在同一个 PR 里修改、审查 - 文档里的“检查步骤”改成 CI。与其写“请确认 Makefile 里有 pg_dump”,不如让 CI 每次都断言一遍(做法见[护栏体检](/docs/guardrails/health-check)) 详见[跟代码绑定的文档跟代码放一起](/docs/pitfalls/code-coupled-docs)。 ### 3. 跨仓相对链接会断 [#3-跨仓相对链接会断] 代码仓里曾经有 10 处 `../org-ops/...` 这样的相对链接,在我本机的主目录里点得开,换个地方就全断了: - **在 worktree 里**:`claude --worktree` 把 worktree 建在仓库内的 `.claude/worktrees/<名字>/` 下,`../` 指向的已经不是原来那个位置 - **在 GitHub 网页上**:相对路径只在同一个仓库里解析 - **在云端 agent 里**:云端会话只克隆了这一个仓库 补法:跨仓引用一律写完整 URL,再让园丁 agent 定期检查失效链接。先把现有的找出来: ```bash grep -rn --include='*.md' '](\.\./' . ``` 它会列出所有向上跳的相对链接,逐个看哪些跳出了仓库。详见[跨仓链接用完整地址](/docs/pitfalls/absolute-cross-repo-links)。 ### 外加一条:模板复制会漂移 [#外加一条模板复制会漂移] 第二个组织的 ops 规则文件,最初是从第一个组织复制过来的。半年后一查,里面 6 处引用指向不存在的文件;两边的“下次 review 日期”一字不差,而且都已经过期半年。从复制出去那一刻起,两份就开始各自漂移。 补法:共用的部分做成可继承的模板(插件),各组织只写自己特有的部分。做法见[让 ops 和项目一起进化](/docs/org/evolve),事故见[模板复制后会各自漂移](/docs/pitfalls/template-copy-drift)。 ## 替代方案:ops 作为目录放进主代码仓 [#替代方案ops-作为目录放进主代码仓] 适合有多个代码仓、有 fork、有保密内容的组织。权限可以单独控制,不写代码的人也能参与。代价就是上面三条,要一条条补上。这是我的选择。 只适合**只有一个主代码仓、而且它不是 fork** 的组织:在主仓里建一个 `ops/` 目录。agent 天然看得见,链接不会断,文档和代码一起审查。代价是做不了权限区分,能看代码的人就能看到全部 ops 内容;将来开源前,还得把整个目录清理掉。 ## 文档归属表 [#文档归属表] | 文档 | 放哪 | 命名 | |---|---|---| | Feature spec(开头一节写 intent) | 代码仓 `docs/specs/` | `YYYY-MM-DD_.md` | | 实现计划 | 代码仓 `docs/plans/` | `YYYY-MM-DD_-plan.md` | | 跟代码绑定的 runbook | 代码仓 `docs/runbooks/` | `.md` | | 跨仓、组织、商业决策 | ops 仓 `decisions/` | `ADR-NNN_.md` | | 协作剧本 | ops 仓 `playbooks/` | `.md` | | 一次性调研 | ops 仓 `research/` | `YYYY-MM-DD_.md` | | 复盘 | ops 仓 `retros/` | `YYYY-MM-DD_.md` | 单仓产品把以上全部放进仓库自己的 `docs/`,ADR 放 `docs/adr/`。 一个 ops 仓的骨架: ```text org-ops/ ├── CLAUDE.md 一页:这个仓放什么、红线、ops agent 是谁 ├── decisions/ ADR ├── playbooks/ 协作剧本 ├── research/ 一次性调研 ├── retros/ 复盘 └── .claude/ ├── settings.json 权限规则;可选的 agent 字段 └── agents/org-a-ops.md ops agent 定义,名字在所有组织里唯一 ``` ## 常见坑 [#常见坑] - [跨仓链接用完整地址](/docs/pitfalls/absolute-cross-repo-links) - [跟代码绑定的文档跟代码放一起](/docs/pitfalls/code-coupled-docs) - [模板复制后会各自漂移](/docs/pitfalls/template-copy-drift) ## 相关 [#相关] - [组织 ops agent 的五个组成部分](/docs/org/ops-agent) - [ADR 模板](/docs/templates/adr) - [复盘模板](/docs/templates/retro) - [组织:什么时候需要 ops](/docs/org) # 跨仓链接用完整地址 (/docs/pitfalls/absolute-cross-repo-links) > 指向 ops 仓的相对链接,换到 worktree、GitHub 网页或云端 agent 就全断,而且不报错 ## 发生了什么 [#发生了什么] 我的一个组织用独立的 ops 仓放决策、剧本和复盘。代码仓的文档里有 10 处链接指向 ops 仓,写的是相对路径,形如 `../..//...`,前提是两个仓放在同一个父目录下。 在我自己的电脑上,这些链接一直好好的。直到我开始用 `claude --worktree` 并行开发:worktree 建在代码仓内部的 `.claude/worktrees//` 下,同样的相对路径从那里往上数,落到了一个根本不存在的目录,10 处全部失效。接着又发现,在 GitHub 网页上点这些链接是 404;云端跑的 agent 只克隆了代码仓,同样打不开。 ## 为什么会这样 [#为什么会这样] 相对链接偷偷依赖了“我这台电脑的目录布局”:两个仓必须并排、目录名不能变、读的人必须在本机。这三个条件,在 worktree、GitHub 网页、CI 和云端会话里一个都不成立。GitHub 只能解析仓库内部的相对路径,跳出仓库根目录就找不到。 更麻烦的是,这种失效没有任何报错。人点开是 404 还会察觉,agent 读不到链接内容时只是少了一块上下文,然后照样往下做。 ## 怎么做 [#怎么做] **跨仓引用写完整 URL**,指向分支或固定的 commit: ```markdown 详见 [ADR-007](https://github.com/your-org/ops/blob/main/decisions/ADR-007_auth.md) ``` **让 CI 拦住仓外的相对链接**。CI 里只检出代码仓,`lychee --offline` 只检查本地文件链接,任何跳出仓库的相对链接都会因为目标不存在而报错: ```yaml # .github/workflows/links.yml 里的一个 step - uses: lycheeverse/lychee-action@v2 with: args: --offline --no-progress './**/*.md' ``` **完整 URL 交给园丁定期查**。私有仓的链接匿名访问是 404,用带权限的 `gh api` 逐条确认,累计所有失败,最后统一用退出码报告: ```bash #!/usr/bin/env bash # 检查文档里所有指向 ops 仓的完整 URL fail=0 while read -r url; do url=${url%%#*} # 去掉页内锚点 rest=${url#https://github.com/} # your-org/ops/blob/main/decisions/ADR-007_auth.md repo=${rest%%/blob/*} # your-org/ops ref=${rest#*/blob/}; path=${ref#*/}; ref=${ref%%/*} gh api "repos/$repo/contents/$path?ref=$ref" --silent \ || { echo "失效:$url" >&2; fail=1; } done < <(grep -rhoE 'https://github\.com/your-org/ops/blob/[^)[:space:]]+' docs/ | sort -u) exit $fail ``` 我把这一步放进每周的园丁任务里,和过期 review 日期一起查。 **agent 要读 ops 仓,显式接进来**。代码仓的 CLAUDE.md 只写一句指针(ops 仓的完整地址);本机会话需要读写 ops 仓时,用 `permissions.additionalDirectories` 把它加进来,而不是靠相对路径碰运气。 ## 相关 [#相关] - [ops 放哪:独立仓还是放进项目](/docs/org/ops-repo) - [让 ops 和项目一起进化](/docs/org/evolve) - [跟代码绑定的文档跟代码放一起](/docs/pitfalls/code-coupled-docs) - [模板复制后会各自漂移](/docs/pitfalls/template-copy-drift) # CI 绿了不等于能发版 (/docs/pitfalls/ci-green-not-ready) > 常年红着的检查会让人对红灯麻木,CI 本身也只覆盖一部分。防止拿 CI 状态代替发版前的全量验证 ## 发生了什么 [#发生了什么] 有一个 CI 检查,因为 CI 的环境和本地不一样,一直是红的。看久了,我们都默认它是“环境问题”,合并照合,版本照发。 后来那个版本出了问题。回头看,最要命的不是这一个检查,而是从它常年变红开始,CI 的状态就不再有人当真了:红着的那一项是不是正好在报真问题,没人知道。 ## 为什么会这样 [#为什么会这样] 两层原因。 第一,“环境问题”是一个标签,不是诊断。CI 和本地、生产之间的环境差异,恰恰是 CI 应该暴露的东西。一旦接受某个红灯是常态,红色就成了噪音,真正的失败也会混在里面被放过。 第二,CI 本来就只覆盖一部分。为了快,常见做法是按路径过滤、跳过慢测试和不稳定的测试、复用缓存。CI 全绿说明的是“这部分没坏”,不是“这个版本能发”。 ## 怎么做 [#怎么做] **红灯不能常驻**:要么限期修好,要么明确隔离,在 CI 配置里把它改成非必需,同时开 Issue 写清负责人和恢复条件(见[临时方案要写明撤销条件](/docs/pitfalls/temp-fix-revert-trigger))。不接受“心里知道它是红的”。 **红了先看日志,不靠猜**: ```bash gh pr checks # 当前分支 PR 的全部检查 gh run view --log-failed # 只看失败步骤的日志 ``` **发版前本地跑全量验证四件套**:单测、全量测试(含集成或 e2e)、类型检查、lint。串成一条命令,任何一步失败就停(脚本名按项目改): ```bash bun test && bun run test:e2e && bunx tsc --noEmit && bun run lint ``` **关键检查在分支保护里设为 required**,红着就合不进去。 ## 相关 [#相关] - [发布:AI 审查,人来批准](/docs/product/ship) - [发版靠清单,不靠感觉](/docs/pitfalls/release-checklist) - [亲眼看到才算完成](/docs/pitfalls/see-it-to-ship) - [临时方案要写明撤销条件](/docs/pitfalls/temp-fix-revert-trigger) # 跟代码绑定的文档跟代码放一起 (/docs/pitfalls/code-coupled-docs) > 恢复手册在 ops 仓里写着“Makefile 会先备份”,代码早被上游合并改掉,手册毫不知情 ## 发生了什么 [#发生了什么] 本地数据库被一条 reset 清空之后,我给 Makefile 的 reset 目标加了“先备份”,又在 ops 仓写了一份恢复手册:Makefile 会先 dump、备份放在哪、怎么恢复,末尾还附了一条检查命令。 半年后排查环境才发现,这段备份逻辑早没了。代码仓是一个上游开源项目的 fork,一次上游大合并把 Makefile 里的改动冲回了上游原样。ops 仓里的手册还一字不差地写着“会先备份”,那条检查命令也从来没人跑过。 ## 为什么会这样 [#为什么会这样] 这份手册描述的是代码的行为,却和代码分处两个仓库。改 Makefile 的 PR 不会提醒任何人去改另一个仓里的文档,审查的人也看不到它;上游合并解决冲突时只看代码,文档根本不在 diff 里。 至于“附了检查命令”:写在文档里的命令只是文字,不会自己执行。没人跑,就等于没有。 ## 怎么做 [#怎么做] **用一句话判断归属**:这份内容会不会因为改代码而需要跟着改?会,放代码仓的 `docs/runbooks/`;不会(决策、商业背景、跨仓剧本),留在 ops 仓。ops 仓原来的位置只留一行完整 URL 指过去。 **文档里的检查步骤搬进 CI**,每个 PR 都跑,而且查行为、不查关键字。只 grep 到 `pg_dump` 不代表备份真的先跑、失败了会停。下面模拟备份失败,断言删库那一步不会执行: ```bash #!/usr/bin/env bash # scripts/check-db-reset-backup.sh # 假的 pg_dump 直接失败,假的 dropdb 只记录自己被调用过 set -u stub=$(mktemp -d) printf '#!/bin/sh\nexit 1\n' > "$stub/pg_dump" printf '#!/bin/sh\ntouch "%s/dropdb-called"\n' "$stub" > "$stub/dropdb" chmod +x "$stub/pg_dump" "$stub/dropdb" if PATH="$stub:$PATH" make db-reset >/dev/null 2>&1; then echo "备份失败时 db-reset 不该成功" >&2; exit 1 fi [ ! -e "$stub/dropdb-called" ] || { echo "备份失败后仍执行了删库" >&2; exit 1; } ``` 桩命令按你的 Makefile 实际调用的命令替换。平时想快速看一眼步骤顺序,用 `make -n db-reset`:它只打印要执行的命令、不真跑,前置目标里的命令也会列出来。 **fork 的共享文件重点守**。上游也会改的文件(Makefile、部署脚本、配置模板)里的定制改动,每一处都配一条 CI 断言,否则下一次合并照样无声冲掉。 **手册里只写“怎么做”,不写“代码会怎样”**。描述代码行为的句子最容易过时;能用脚本断言的,就别用文字承诺。 ## 相关 [#相关] - [ops 放哪:独立仓还是放进项目](/docs/org/ops-repo) - [防护规则会悄悄失效](/docs/pitfalls/guardrails-decay) - [本地数据库也要按生产对待](/docs/pitfalls/local-db-is-prod) - [护栏体检:防止静默失效](/docs/guardrails/health-check) - [跨仓链接用完整地址](/docs/pitfalls/absolute-cross-repo-links) # 切换工具会整份覆盖设置 (/docs/pitfalls/config-overwrite) > 用模型供应商切换工具切回官方后,权限规则、hook、插件启用状态全丢了,表面症状只是“插件都关了” ## 发生了什么 [#发生了什么] 有段时间我用一个模型供应商切换工具,在官方模型和第三方模型之间来回切。有一次从第三方切回官方,打开 Claude Code,发现所有插件都是关着的。 我先以为是插件出了问题,查下去才发现 `~/.claude/settings.json` 被整份重写了:除了供应商相关的配置,权限规则(deny、ask)、hook、`enabledPlugins` 全部消失。“插件都关了”只是最显眼的症状,真正危险的是护栏跟着一起没了,而且没有任何提示(这一层护栏的下落,见[防护规则会悄悄失效](/docs/pitfalls/guardrails-decay))。 ## 为什么会这样 [#为什么会这样] 这类工具(比如 CC Switch)的工作方式,就是改写 `~/.claude/settings.json` 里的供应商配置:API 地址、密钥、模型。我遇到的那次,切换工具把 `~/.claude/settings.json` 整份重写了,权限、hook、插件启用状态全丢;这类工具的新版本声称只改连接相关字段。不管是哪种,切换后都要检查 permissions、hooks、enabledPlugins 还在不在。 偏偏用户级设置又是多数人放全局护栏的地方,一次“切模型”就可能顺手拆了护栏,而且没有任何报错。 ## 怎么做 [#怎么做] **切换前备份,切换后只比护栏字段**。这个文件的 `env` 里可能有供应商的密钥,备份设成只有自己能读,对比时也只取护栏相关的字段,别把密钥打到屏幕或日志里: ```bash # 切换前:备份,权限 600 install -m 600 ~/.claude/settings.json ~/.claude/settings.backup.json # 切换后:只比较 permissions、hooks、enabledPlugins diff <(jq -S '{permissions, hooks, enabledPlugins}' ~/.claude/settings.backup.json) \ <(jq -S '{permissions, hooks, enabledPlugins}' ~/.claude/settings.json) ``` **没有备份时,至少看一眼这三项**。哪一项变成 `null`,就是被冲掉了: ```bash jq '{permissions, hooks, enabledPlugins}' ~/.claude/settings.json ``` **最关键的护栏放进托管设置**。它优先级最高,写入要管理员权限,切换工具改不到。macOS 是 `/Library/Application Support/ClaudeCode/managed-settings.json`,Linux 是 `/etc/claude-code/managed-settings.json`: ```json { "permissions": { "deny": ["Bash(rm -rf ~)", "Bash(git push --force origin main *)"] } } ``` 在 Claude Code 里运行 `/status`,Setting sources 一行能确认它已生效。 **体检 hook 别放在会被覆盖的文件里**。放在 `~/.claude/settings.json` 的体检 hook,会和护栏一起被冲掉。放进项目级 `.claude/settings.json` 或托管设置,每次开会话自动检查。 ## 相关 [#相关] - [密钥与配置:别让工具覆盖你的设置](/docs/guardrails/secrets) - [防护规则会悄悄失效](/docs/pitfalls/guardrails-decay) - [护栏体检:防止静默失效](/docs/guardrails/health-check) - [权限规则:deny、ask、allow](/docs/guardrails/permissions) # 自己审自己等于没审 (/docs/pitfalls/cross-model-review) > 主力模型自审时倾向于认同自己。防止把自审当成独立审查,用异构二审和人工批准补上 ## 发生了什么 [#发生了什么] 主力模型写完代码,我让它自己再审一遍,结论往往是“没有大问题”。 后来改成换一个不同家族的模型独立审。有一次,它抓出了主力模型漏掉的 2 个高危安全问题。另一次是人工二审:4 个 commit 的文档里散落着约 85 处不该公开的内部信息,类型检查和测试全绿,一处也拦不住。 ## 为什么会这样 [#为什么会这样] 自审的模型和写代码的是同一套偏好。读到自己的实现时,它会顺着当初的思路去理解,“我这样写是因为……”读起来总是合理的。如果审查还在同一个会话里,上下文里的错误假设也会被原样继承。自审能挑出一些低级错误,但替代不了独立的批准。 换一个模型家族,训练数据和偏好都不一样,盲区未必重合。我手里只有几次成功的例子,证明不了“盲区一定不重合”;能说的是,异构审查多次带来了自审没给出的增量发现。至于信息泄漏这类语义问题,工具链本来就不管:类型对、测试过,不代表内容可以公开。 Anthropic 的 [The AI-native SDLC playbook](https://claude.com/resources/articles/the-ai-native-sdlc-playbook) 在发布阶段也设了同样的关卡:写代码的 agent 不能批准自己的改动。 ## 怎么做 [#怎么做] **主力模型写完,换一个模型家族审**。我用 Codex CLI: ```bash codex review --base main -c model_reasoning_effort=medium ``` 推理强度 medium 就够,xhigh 可能卡很久。装了 gstack 也可以直接用 `/codex`。Kimi、Gemini 也行,关键是不共享上下文,也不共享同一套模型偏见。 **审查者只拿 diff 和 spec,不拿对话记录**。它要知道“要做什么”和“改了什么”,不需要知道主力模型当时是怎么想的。 **plan 阶段就可以审一次**。跨字段的不变量问题,在计划里就能抓到,比写完代码再返工便宜得多。 **人最后拍板**。审查意见按严重程度列出,改哪些、不改哪些由人决定,结论留在 PR 里。涉及对外内容的改动,再加一轮人工通读。 **用数据评估这个组合值不值**。这一步我还没有系统做过。如果要长期用,建议每次二审记几笔:抓到几个主力模型漏掉的真问题,提了几个误报,花了多少时间和钱;再加上线后才暴露、两边都没审出来的漏报。攒一段时间,再决定换不换模型、是不是每次都审。 ## 相关 [#相关] - [发布:AI 审查,人来批准](/docs/product/ship) - [分段审过了,还要整分支终审](/docs/pitfalls/whole-branch-review) - [gstack:上线流水线怎么用](/docs/workflow/gstack) - [REVIEW.md 模板](/docs/templates/review) # 本机代理会让 DNS 检查失真 (/docs/pitfalls/dns-fake-ip) > 本机代理的 fake-ip 模式劫持了 DNS 查询,dig 返回的全是假地址,差点误判部署失败 ## 发生了什么 [#发生了什么] 一次部署后改完 DNS 记录,我按习惯用 `dig` 验证,返回的是 198.18 开头的地址,跟我配置的目标完全对不上。第一反应是记录配错了,或者部署出了问题,差点开始回滚。 后来才想起来,本机开着代理工具的 fake-ip 模式:DNS 查询被它截下,回给我的是一个假地址。换成 `dig @` 指定公共 DNS 服务器再查,结果一模一样。 ## 为什么会这样 [#为什么会这样] fake-ip 是一些本机代理工具常用的 DNS 模式:先给每个域名分配一个保留地址段里的假地址,等程序真正发起连接时,再按域名转发出去,省掉等待真实解析的时间。198.18 开头的地址属于 RFC 2544 留给网络设备基准测试的保留段,公网上不会出现,看到它基本就能断定是 fake-ip。 代理在系统层面接管了 53 端口的流量,所以不管你问哪台 DNS 服务器,查询都出不了本机。`dig` 本身没错,错在它的查询根本没出门。 ## 怎么做 [#怎么做] **先识别**:`dig +short example.com` 返回 198.18 开头的地址,就别再排查 DNS 记录了,问题在本机。 **用 DoH(DNS over HTTPS)查**。它走 443 端口的 HTTPS,不经过 53 端口,拿到的是真实记录: ```bash curl -s 'https://dns.google/resolve?name=example.com&type=A' | jq -r '.Answer[].data' curl -s -H 'accept: application/dns-json' \ 'https://cloudflare-dns.com/dns-query?name=example.com&type=CNAME' ``` 查 CNAME 往往比查 A 记录更能看出域名指向了哪个平台。 **需要完整的 `dig` 输出时**,临时关掉代理,或者换个网络(比如手机热点)再查。也可以把你常要验证的域名加进代理工具的 fake-ip 排除名单,让它们走真实解析。 **让 agent 也知道**。在 CLAUDE.md 写一句“本机开着 fake-ip 代理,验证 DNS 用 DoH,不要用 dig”,免得它根据假地址得出“部署失败”的结论,再自作主张去改配置。 ## 相关 [#相关] - [一个域名只挂一个平台](/docs/pitfalls/one-domain-one-platform) - [网络报错先查远端](/docs/pitfalls/verify-remote-first) - [小工具上线:静态站部署到 Cloudflare](/docs/tool/ship) - [选平台:Vercel 还是 Cloudflare](/docs/product/platform) # 不让 agent 动 git 历史 (/docs/pitfalls/git-history-no-surgery) > agent 为了“恢复状态”会自作主张 reset、rebase。用权限规则和提示词把改写历史留给人 ## 发生了什么 [#发生了什么] 我派一个子 agent 去做一项改动。做到一半,它认为工作区“状态不对”,为了恢复,自作主张跑了 `git reset`,丢掉了一个 commit。后面的 rebase 又让 5 个提交的哈希全变了。 出事的不是那项改动本身,而是它自己加上的那一步“恢复”。 ## 为什么会这样 [#为什么会这样] agent 的目标是让眼前的状态“看起来对”,`git reset` 是最短的路。它看不到这些提交在别处的分量:有没有推到远端,有没有被 PR、文档、别的会话引用,主会话是不是还指望着它。子 agent 只有自己那一小段上下文,更看不到。 改写历史的代价是延后出现的:本地看一切正常,损失要等别人拉代码、对哈希时才暴露。提示词里一句“不要 reset”只是软约束,agent 一旦认定自己在“修复问题”,就会说服自己破例。 ## 怎么做 [#怎么做] **用权限规则挡住常见写法**。写进 `.claude/settings.json`(项目级,进 git);想对所有项目生效,就在 `~/.claude/settings.json` 再写一份: ```json { "permissions": { "deny": [ "Bash(git reset --hard *)", "Bash(git push --force *)", "Bash(git push -f *)" ], "ask": [ "Bash(git rebase *)", "Bash(git commit --amend *)" ] } } ``` rebase 和 amend 放 ask 不放 deny,是因为整理还没推送的本地提交是正常需求,只是每次都要你点头。 **子 agent 提示词里写 CRITICAL do-not 段**。权限规则匹配的是命令文本,换个写法(比如 `git push origin main --force`)就拦不住,所以提示词这一层不能省: ```text CRITICAL — 不要做: - 不要运行 git reset、git rebase、git push --force、git commit --amend - 工作区有未提交的改动时,不要 checkout 或切换分支 - 觉得状态不对:停下,贴出 git status 和 git log --oneline -5,等我决定 ``` **确需改写历史,人在自己的终端里做,先留两条退路**。只打一个 tag 不够:tag 只保住提交,之后的 `git reset --hard` 照样会冲掉工作区里没提交的改动;固定名字的 tag 第二次创建还会失败。 ```bash git stash push -u -m "before-rewrite" # 没提交的改动和未跟踪的文件先存起来 git stash list # 最上面一条应该是 before-rewrite;没有就说明本来没改动 git branch rescue/$(date +%Y%m%d-%H%M%S) # 当前提交留一个带时间戳的分支 ``` 也可以把整个工作目录复制一份。出了问题:rebase 还没做完就 `git rebase --abort`;已经做完了,`git reset --hard rescue/<时间戳>` 回到原来的提交。最后再 `git stash pop` 取回改动,前提是第一步确实存了东西,否则会弹出一条更早的旧 stash。 **已经丢了,先查 reflog**:`git reflog` 能看到 reset 之前 HEAD 指向哪里,找到哈希后 `git branch rescue/found <哈希>` 就能捞回来。reflog 只记得提交过的东西;没提交的改动被 `git reset --hard` 覆盖之后,基本就找不回了,这也是上一步要先 stash 的原因。 ## 相关 [#相关] - [子 agent 提示词模板](/docs/templates/subagent-prompt) - [权限规则:deny、ask、allow](/docs/guardrails/permissions) - [小工具的最小护栏](/docs/tool/guardrails) - [网络报错先查远端](/docs/pitfalls/verify-remote-first) # 防护规则会悄悄失效 (/docs/pitfalls/guardrails-decay) > 护栏被上游合并冲掉、被工具整份覆盖时不会报错。用体检脚本和 CI 断言,让它失效时有人知道 ## 发生了什么 [#发生了什么] 本地数据库被一条 reset 命令清空之后(见[本地数据库也要按生产对待](/docs/pitfalls/local-db-is-prod)),我加了三层防护: - 应用层:reset 脚本先 `pg_dump` 备份,备份失败就停 - 权限层:reset 命令设成 ask,执行前必须我确认 - hook 层:PreToolUse hook 碰到破坏性数据库命令,先自动备份到本地目录 半年后,2026 年 10 月,一次环境排查时顺手查了一下:三层全没了。 - 脚本里的备份步骤,在一次上游大合并中被冲掉,回到了上游原样 - 权限规则被一个模型供应商切换工具连同整份 `~/.claude/settings.json` 重写掉了(见[切换工具会整份覆盖设置](/docs/pitfalls/config-overwrite)) - hook 脚本文件还在,但没有挂到任何事件上 它们是哪天没的,没人知道。更尴尬的是,当初的复盘里写过检查命令,可那只是一段文字,从来没人跑过。 ## 为什么会这样 [#为什么会这样] 护栏天生有个毛病:生效时什么也不发生,失效时也什么都不发生。没有报错,没有告警,直到下一次事故。 三层死于三条不同的路径,根子却是同一个:护栏写在了“别人也会写”的地方。 - 上游也会改的文件:合并时一旦取了上游版本,定制改动就没了 - 会被工具整份重写的配置:工具不知道哪几行是护栏 - 实现和注册分开的机制:脚本文件在,不等于 hook 在;挂载关系写在 `settings.json` 里,跟着配置一起丢 写在复盘里的检查命令也不算护栏,文字不会自己执行。 ## 怎么做 [#怎么做] 这套体检是事故之后补上的,还在打磨。 要检查行为,不要只检查文本。`grep` 到 `pg_dump` 不代表备份还会执行,它可能躺在注释里,也可能属于别的 target;脚本文件还在,也不代表 hook 会被触发。 **写体检脚本**,放在项目的 `.claude/hooks/guardrail-check.sh`。三项都看行为,缺一项报一项,全部通过时不输出: ```bash #!/usr/bin/env bash s="$HOME/.claude/settings.json" # 规则写在哪个文件,就查哪个 hook="$HOME/.claude/hooks/db-backup.sh" miss() { echo "护栏缺失:$1"; } # 1. ask 规则:按原文精确匹配 jq -e '(.permissions.ask // []) | index("Bash(make db-reset *)")' "$s" >/dev/null || miss "make db-reset 的 ask 规则" # 2. 备份 hook:已挂载,并且喂一条模拟输入时真的会调用 pg_dump(pg_dump 和 HOME 都换成临时的) jq -e '[.hooks.PreToolUse[]?.hooks[]?.command | strings] | any(test("db-backup"))' "$s" >/dev/null \ || miss "备份 hook 没挂到 PreToolUse" t=$(mktemp -d); printf '#!/bin/sh\ntouch "%s/called"\n' "$t" > "$t/pg_dump"; chmod +x "$t/pg_dump" echo '{"tool_input":{"command":"make db-reset"}}' \ | HOME="$t" PATH="$t:$PATH" DATABASE_URL=postgres://guard-check "$hook" >/dev/null 2>&1 [ -f "$t/called" ] || miss "备份 hook 收到 reset 命令时没有调用 pg_dump" rm -rf "$t" # 3. reset 目标:用 make -n 看实际步骤,pg_dump 必须排在 reset 之前 steps=$(make -n --no-print-directory -C "$CLAUDE_PROJECT_DIR" db-reset 2>/dev/null | grep -v '^[[:space:]]*#') d=$(grep -n 'pg_dump' <<<"$steps" | head -1 | cut -d: -f1) r=$(grep -n 'reset-db' <<<"$steps" | head -1 | cut -d: -f1) # 换成你的 reset 命令 [ -n "$d" ] && [ -n "$r" ] && [ "$d" -lt "$r" ] || miss "db-reset 不再先备份" exit 0 ``` `make -n` 只打印、不执行,但带 `+` 前缀或含 `$(MAKE)` 的行照样会执行,reset 目标里别这么写。 **挂到项目级 `.claude/settings.json` 的 SessionStart 上**。每次开会话跑一次,输出直接进入 Claude 的上下文。这个文件进 git,切换工具不会动它,有人改了也能在 diff 里看到: ```json { "hooks": { "SessionStart": [ { "hooks": [{ "type": "command", "command": "\"$CLAUDE_PROJECT_DIR\"/.claude/hooks/guardrail-check.sh" }] } ] } } ``` **上游也会改的文件,在 CI 里模拟一次备份失败**。CI 用的是一次性数据库,可以真跑:把 `pg_dump` 换成必然失败的假命令,断言 reset 停了下来。合并把定制改动冲掉,CI 就红: ```yaml - name: 护栏断言:备份失败时 reset 必须停下 run: | # DATABASE_URL 指向 CI 里的一次性数据库 make -n db-reset > /dev/null psql "$DATABASE_URL" -c 'create table guard_marker (id int)' shim=$(mktemp -d) && printf '#!/bin/sh\nexit 1\n' > "$shim/pg_dump" && chmod +x "$shim/pg_dump" PATH="$shim:$PATH" make db-reset && { echo "备份失败了,reset 却照样执行"; exit 1; } psql "$DATABASE_URL" -c 'select 1 from guard_marker' # 标记表还在,说明 reset 没跑 ``` **最关键的几条放进托管设置**。macOS 上是 `/Library/Application Support/ClaudeCode/managed-settings.json`,优先级最高,写入要管理员权限,普通工具改不到。在 Claude Code 里运行 `/status`,Setting sources 一行能看到它有没有生效。 本手册插件里的 `/ainative:doctor` 也会做这类检查。 ## 相关 [#相关] - [护栏体检:防止静默失效](/docs/guardrails/health-check) - [三层护栏](/docs/guardrails) - [本地数据库也要按生产对待](/docs/pitfalls/local-db-is-prod) - [切换工具会整份覆盖设置](/docs/pitfalls/config-overwrite) - [跟代码绑定的文档跟代码放一起](/docs/pitfalls/code-coupled-docs) - [本手册的 Claude Code 插件](/docs/reference/plugin) # 坑库 (/docs/pitfalls) > 每张卡片都来自真实复盘:发生了什么、为什么、怎么防 这里收的都是我真实踩过的坑。每张卡片固定四段:**发生了什么、为什么会这样、怎么做、相关**;最上面一句是可以直接照做的规则。按阶段或档位筛选,找到和你手上的事最相关的那几张。 如果装了[本手册的插件](/docs/reference/plugin),可以让 Claude 用 `/ainative:pitfall-check` 拿这些卡片逐条审查你当前的计划或改动。 # 本地数据库也要按生产对待 (/docs/pitfalls/local-db-is-prod) > 本地库里攒着别处没有的配置和演示数据时,它就是生产。防止一条 reset 把它们清空且无从恢复 ## 发生了什么 [#发生了什么] 一条数据库 reset 命令跑下去,本地库清空了。里面有几个演示用的工作区,还有几十个 agent 的配置,全部丢失,没有任何备份。 这些不是测试数据。演示工作区是一点点搭起来、拿去给别人看的;agent 配置是一轮轮调出来的。它们只存在于那个“本地”库里:没有 seed 脚本,也从没导出过。 ## 为什么会这样 [#为什么会这样] “本地”两个字让人放松警惕,人是这样,agent 也是。开发工具链默认本地库随时可以重来:reset、`docker compose down -v`、重跑迁移,都是家常便饭。可本地库里装的东西早就变了,手工攒下的配置和演示数据,在别处找不到第二份。 一条命令危不危险,要看数据有没有第二份、丢了要多久才补得回来,而不是看它跑在哪个环境。 ## 怎么做 [#怎么做] **reset 目标先备份,备份失败就退出**。make 遇到失败的命令会直接停下,走不到后面的 reset。“备份失败就不执行”靠的就是这一层: ```makefile BACKUP_DIR ?= $(HOME)/db-backups db-reset: @test -n "$(DATABASE_URL)" || { echo "DATABASE_URL 未设置"; exit 1; } @mkdir -p $(BACKUP_DIR) @pg_dump -Fc -d "$(DATABASE_URL)" -f $(BACKUP_DIR)/pre-reset-$$(date +%Y%m%d-%H%M%S).dump ./scripts/reset-db.sh ``` 行首的 `@` 让 make 不回显命令。没有它,展开后的连接串会原样打进终端、CI 日志和 agent 的对话。密码也不要放进命令参数:写进 `~/.pgpass`(格式 `主机:端口:库名:用户:密码`,前四个字段可以写 `*`;权限必须是 600,否则会被忽略),连接串里只留用户、主机和库名;也可以用 `PGPASSFILE` 环境变量指向一个不进 git 的密码文件。 **破坏性命令设成 ask**,agent 执行前必须你点头。写进项目的 `.claude/settings.json`,这个文件进 git,被改动时能在 diff 里看到: ```json { "permissions": { "ask": [ "Bash(make db-reset *)", "Bash(supabase db reset *)", "Bash(docker compose down -v *)", "Bash(docker volume rm *)" ] } } ``` **再加一层尽力而为的兜底**:PreToolUse hook 匹配到这些命令时先 `pg_dump` 一份,永远 `exit 0`,备份失败也照样放行。它替代不了第一步的 reset 脚本。写法见[用 hook 兜底](/docs/guardrails/hooks)。 **定期演练恢复**。`pg_restore --list` 只能列出归档里有什么,证明不了能恢复。真正的验证是找一个临时库(别用原来的库)实际恢复一次,再抽查关键数据: ```bash createdb restore_check pg_restore --no-owner -d restore_check <备份文件>.dump # 自定义格式(-Fc)用 pg_restore # 纯 SQL 格式的备份用 psql 恢复:psql -d restore_check -f <备份文件>.sql psql -d restore_check -c 'select count(*) from <关键表>' # 抽查关键数据 dropdb restore_check ``` 能脚本化的资产,比如演示数据、agent 配置,顺手导出成 seed 脚本放进 git。 后来我把这三层都加上了,半年后它们又悄悄失效了一次,见[防护规则会悄悄失效](/docs/pitfalls/guardrails-decay)。 ## 相关 [#相关] - [三层护栏](/docs/guardrails) - [权限规则:deny、ask、allow](/docs/guardrails/permissions) - [用 hook 兜底](/docs/guardrails/hooks) - [防护规则会悄悄失效](/docs/pitfalls/guardrails-decay) # “之前是这样的”先查 git (/docs/pitfalls/memory-vs-git) > 人的记忆会把想过的设计当成做过的功能。防止 agent 把“以前有过”当约束,照着不存在的旧版去“恢复” ## 发生了什么 [#发生了什么] 我跟 agent 说:“以前聊天和预览是并排显示的。”它立刻把任务理解成“恢复旧功能”,准备去翻旧代码,找是哪次改动把它弄丢的。 好在动手前查了一下 git 历史:这两个区域从来没有并排过。那是我脑子里的新设计,只是被我记成了“以前就有”。 ## 为什么会这样 [#为什么会这样] 人的记忆是重建出来的。想象过很多遍的画面,会和真实用过的界面混在一起,越熟悉的产品越容易混。 agent 默认把用户的话当事实。一旦接受了“以前有过”,任务的性质就变了:“恢复”意味着去找旧实现、照旧样子做,跳过新功能本该有的设计讨论。旧实现根本不存在时,它还可能从不相干的历史代码里拼出一个“原版”。 查一次 git 只要一分钟;按错误的前提干活,要搭进去几个小时。 ## 怎么做 [#怎么做] **先查历史,再当约束**: ```bash git log --oneline -- <文件路径> # 这个文件的所有提交 git log --all --oneline -S '<关键词>' # 哪些提交加过或删过这段代码,含其他分支 git show --stat # 某次提交改了哪些文件 ``` **查不到,就让人明确选**:是“记错了”,还是“这是新设计”。agent 不替人选,也不默认按“恢复”处理。 **选了新设计,就按新需求走**:先写 spec 再动手,不要顶着“恢复”的名义直接改(见[实质改动先留文档再动手](/docs/pitfalls/process-before-code))。 **写进 CLAUDE.md**: ```markdown - 任何人(包括我)说“之前是 X”,先用 git log 查证;查不到就按新需求处理,并向我确认 ``` ## 相关 [#相关] - [实质改动先留文档再动手](/docs/pitfalls/process-before-code) - [设计:从 intent 到 spec](/docs/product/design) - [一页 CLAUDE.md](/docs/templates/claude-md) - [对外内容先读权威文档](/docs/pitfalls/read-canonical-first) # 一个域名只挂一个平台 (/docs/pitfalls/one-domain-one-platform) > 子域名同时挂在两个托管平台上,清理旧平台时差点连主域名一起删,殃及另一个还在服务的子域名 ## 发生了什么 [#发生了什么] 我的一个子域名同时挂在两个托管平台上:新平台在正常服务,旧平台上还留着迁移前的部署和域名绑定。 清理时,我的第一反应是“干脆把整个主域名从旧平台移除”,一次清干净。动手前查了一遍同一主域下的依赖,才发现另一个子域名还在旧平台上提供服务。照原计划删,它会直接下线。 ## 为什么会这样 [#为什么会这样] 两件事叠在了一起。 第一,迁移只做了“加”没做“减”。新平台接上、DNS 一改,访问一切正常,旧平台上的绑定就没人管了。残留不会报错,所以看不见。 第二,有些平台的域名是按“主域名”管理的。以 Vercel 为例,域名加在账号(团队)层面,子域名挂在下面;从账号里删除一个主域名,会把它从所有关联项目里移除,别名也跟着失效。你以为在删一个子域名,实际删的是一整棵树。 ## 怎么做 [#怎么做] **定规则**:一个域名(包括每个子域名)只挂一个平台;DNS 统一在 Cloudflare 管,DNS 记录就是“谁在服务哪个域名”的唯一清单。 **删除前先列出主域下的全部记录**,看每条指向哪个平台。在 Cloudflare 后台的 DNS 页面看,或者用 API。记录多时要翻页,只看第一页就可能漏掉还在服务的子域名;每页都检查返回状态,并先确认操作的是哪个账号: ```bash #!/usr/bin/env bash # 列出一个 zone 的全部 DNS 记录:先确认账号,逐页拉取,每页检查 success set -euo pipefail cf() { curl -s "https://api.cloudflare.com/client/v4/$1" -H "Authorization: Bearer $CLOUDFLARE_API_TOKEN"; } ok() { jq -e '.success' >/dev/null <<<"$1" || { jq '.errors' <<<"$1" >&2; exit 1; }; } zone=$(cf "zones/$ZONE_ID"); ok "$zone" jq -r '.result | "zone: \(.name) account: \(.account.name)"' <<<"$zone" page=1 while :; do resp=$(cf "zones/$ZONE_ID/dns_records?per_page=100&page=$page"); ok "$resp" jq -r '.result[] | "\(.type)\t\(.name)\t\(.content)"' <<<"$resp" [ "$page" -ge "$(jq -r '.result_info.total_pages' <<<"$resp")" ] && break page=$((page + 1)) done ``` **再去旧平台看还有谁在用**。以 Vercel 为例,先确认登录的账号和团队,再按域名拉全部别名。`vercel alias ls` 一次最多列 100 条,用 `vercel api` 的 `--paginate` 取全: ```bash vercel whoami vercel api "/v4/aliases?domain=example.com" --paginate --scope your-team \ | jq -r '.. | .alias? | strings' | sort -u ``` 任何一步报错就停下,不要在不完整的结果上做删除决定。 **由小到大地删**:先解绑确认不用的子域名,观察几天访问日志或监控,确认没有流量了,再考虑删主域名。 **迁移清单里写上“旧平台解绑”**。新平台上线和旧平台解绑放在同一张清单里,一起打勾,别留到“以后再说”。 ## 相关 [#相关] - [选平台:Vercel 还是 Cloudflare](/docs/product/platform) - [小工具上线:静态站部署到 Cloudflare](/docs/tool/ship) - [本机代理会让 DNS 检查失真](/docs/pitfalls/dns-fake-ip) - [发版靠清单,不靠感觉](/docs/pitfalls/release-checklist) # 同一时间只让一套流程自动接管 (/docs/pitfalls/one-process-engine) > 两套流程框架同时开着,一句“帮我 debug”会被不同框架抢走。只留一套自动触发,其余改成手动调用 ## 发生了什么 [#发生了什么] 在两套流程框架之间切换的那段时间,我两套都开着。同样一句“帮我 debug 一下”,有时被这套框架的调试 skill 接走,有时被那套接走。同一个项目里,前后两次 debug 走的是两套不同的流程,留下的记录也对不上,回头复盘很难拼出完整过程,更没法比较哪套更好用。 ## 为什么会这样 [#为什么会这样] skill 能被模型自动触发,靠的是描述匹配。以我装过的为例:superpowers 的 `systematic-debugging` 写的是“遇到任何 bug、测试失败或异常行为时使用”,Matt Pocock skills 的 `diagnosing-bugs` 写的是“用户说 diagnose、debug this 时使用”,gstack 的 `/investigate` 也是系统化调试。三个都声称自己负责 debug,模型每次只能挑一个,挑哪个取决于你的措辞和当时的上下文。 两套框架的设计也不一样。superpowers 会在会话开始时用 SessionStart hook 注入一段引导,要求“哪怕只有 1% 的可能适用,也必须调用 skill”。Matt 的 27 个 skill 里有 16 个本来就只能手动调用(比如 `to-spec`、`grill-me`、`grill-with-docs`),会去抢触发的是 `diagnosing-bugs`、`tdd`、`code-review` 这类允许模型自动调用的(截至 2026-10,v1.3.1)。 ## 怎么做 [#怎么做] **定一个主引擎负责自动触发**,其余框架降为只能手动调用。我现在的主引擎是 Matt Pocock skills(试用中)。 **推荐:按项目只启用一套**。在项目的 `.claude/settings.json`(团队共享)或 `.claude/settings.local.json`(只对你生效)里,用 `enabledPlugins` 把另一套设为 `false`: ```json { "enabledPlugins": { "mattpocock-skills@claude-plugins-official": true, "superpowers@claude-plugins-official": false } } ``` 插件整个关掉,它的 skill 和 hook 都不会再加载。 **想保留手动调用、只禁止模型自动触发**:在 `permissions.deny` 里按插件名拦住 Skill 工具。模型调不了,你手动输入 `/superpowers:brainstorming` 这类命令仍然可用: ```json { "permissions": { "deny": ["Skill(superpowers:*)"] } } ``` 注意这条规则只拦 Skill 调用,superpowers 的 SessionStart hook 照常运行、照常注入引导。想彻底安静,用上一步的做法。 **`skillOverrides` 只管普通 skill**。它对插件里的 skill 无效,只作用于放在 `~/.claude/skills/` 或项目 `.claude/skills/` 下的 skill。比如 gstack 装在 `~/.claude/skills/` 下,设成 `user-invocable-only` 后模型看不到它,你仍然可以手动敲 `/investigate`: ```json { "skillOverrides": { "investigate": "user-invocable-only", "review": "user-invocable-only" } } ``` **写进 CLAUDE.md 并验证**。写明“本项目的流程引擎是哪一套、实质改动先走哪个命令”。改完开一个新会话,说一句“帮我 debug”,看接手的是不是你指定的那个 skill。 ## 相关 [#相关] - [从 superpowers 迁到 Matt](/docs/workflow/migrate) - [superpowers 与 Matt:完整对比](/docs/workflow/superpowers-vs-matt) - [流程引擎、流水线与专项工具](/docs/workflow) - [插件不是越多越好](/docs/pitfalls/plugin-bloat) # 性能修复先问六个问题 (/docs/pitfalls/perf-fix-six-questions) > 性能修复最容易“看起来快了”就放行。上线前用六个问题查它有没有砍掉保护、改漏地方、没法观测 ## 发生了什么 [#发生了什么] 这张卡不对应某一次事故,是我从几次性能修复的复盘里攒出来的一张检查单。 性能修复有个特点:“变快了”是能量出来的,基准数字一好看,审查就容易放行。而它可能带来的问题,比如拿掉了某个保护、引入了竞态、只改了一处,都不在那个数字里。让 agent 做性能优化时更要小心:它会如实报告耗时下降,却不一定主动说明为此改变了什么。 ## 为什么会这样 [#为什么会这样] 快和对是两个维度。很多优化手段本身就是在拿安全换速度:缓存可能读到旧数据,并发可能出现竞态,跳过校验或去掉锁等于直接砍掉保护,批处理一旦失败影响面更大。 测试通常只回答“功能还对不对”,回答不了“保护还在不在”“别处是不是也该改”“上线后怎么知道它在生效”。这些得靠人在上线前主动问。 ## 怎么做 [#怎么做] 把下面六个问题写进 PR 模板,性能相关的改动逐条回答: | 问题 | 要回答什么 | |---|---| | ① 修 bug 还是砍保护 | 变快是因为去掉了多余的工作,还是去掉了校验、锁、重试、限流 | | ② 有没有竞态 | 引入了缓存、并发或异步吗;两个请求同时到会怎样 | | ③ 覆盖范围 | 同样的慢写法在代码库里还有几处,改全了吗(先搜一遍再回答) | | ④ 能观测到生效吗 | 上线后看哪个指标、哪条日志,能确认新逻辑真的在跑 | | ⑤ 边界情况 | 空值、超大输入、unicode、错误输入,分别测过吗 | | ⑥ 怎么失败 | 失败时是报错、变慢还是静默返回错误结果;谁、多久能发现 | 审查时,让另一个模型家族的 agent 拿着这六问逐条核对 PR,而不是只看 diff 顺不顺。任何一条答不出来,就不上线。 ## 相关 [#相关] - [测试:让 Claude 能自己验证](/docs/product/test) - [自己审自己等于没审](/docs/pitfalls/cross-model-review) - [REVIEW.md 模板](/docs/templates/review) - [亲眼看到才算完成](/docs/pitfalls/see-it-to-ship) # 插件不是越多越好 (/docs/pitfalls/plugin-bloat) > 装了 39 个插件、73 个 subagent,90 天里真正在用的只有十几个:按调用数据和常驻成本做减法 ## 发生了什么 [#发生了什么] 过去一年,我看到好用的插件就装。到 2026 年 10 月做工具链大扫除时,手上有 39 个插件、80 多个 skill、73 个 subagent。我统计了 90 天的真实调用次数,真正被用过的只有十几个。 剩下的并不是“放着不用也无害”:它们的描述每个会话都要占上下文,还会在后台和常用的 skill 抢触发,同一句话有时被一个我早忘了的插件接走。按数据精简之后,剩 16 个插件、19 个 subagent。 ## 为什么会这样 [#为什么会这样] 装插件几乎零成本,卸载却要先确认“真的用不到”,于是只增不减。 每个 skill 的名字和描述默认都会进入 Claude 看到的技能列表。插件越多,描述相近的 skill 越容易互相抢;列表超出预算(约为上下文窗口的 1%)时,Claude Code 还会丢掉一部分描述,先丢调用最少的,Claude 就少了匹配你请求的关键词。 ## 怎么做 [#怎么做] **先看成本**。`/skill-doctor` 列出每个 skill 的上下文开销和使用频率,标出从没用过的,也列出最近没用的插件;单个插件看常驻成本: ```bash claude plugin details mattpocock-skills@claude-plugins-official ``` 它会列出组件清单和“每个会话常驻多少 token”(截至 2026-10,这个插件约 1.6k)。 **再看调用**。这段脚本只统计名字、不读内容,同时算上模型自动触发的 skill 和你手动敲的 `/` 命令,只靠前者会低估那些只能手动调用的 skill: ```python import collections, glob, json, os, re c, tag = collections.Counter(), re.compile(r'/?([^<]+)') for f in glob.glob(os.path.expanduser('~/.claude/projects/*/*.jsonl')): for line in open(f, encoding='utf-8', errors='ignore'): if '"Skill"' not in line and 'command-name' not in line: continue try: content = (json.loads(line).get('message') or {}).get('content') except ValueError: continue if isinstance(content, str): c.update('/' + n for n in tag.findall(content)) for b in content if isinstance(content, list) else []: if isinstance(b, dict) and b.get('name') == 'Skill': c[(b.get('input') or {}).get('skill')] += 1 for name, n in c.most_common(): print(n, name) ``` subagent 同理,统计 `Agent` 工具调用里的 `subagent_type`。注意会话记录默认只保留 30 天(`cleanupPeriodDays`),想看 90 天要提前调大。 **做减法**。插件先停用、观察两周再卸载: ```bash claude plugin disable @ claude plugin uninstall @ ``` 个人 skill 用 `skillOverrides` 设为 `off`,或设为 `name-only` 只留名字;用不到的 subagent 定义文件移出 `~/.claude/agents/`。 **定期复查**。每个季度跑一次,或直接用本手册插件的 `/ainative:doctor`。 ## 相关 [#相关] - [同一时间只让一套流程自动接管](/docs/pitfalls/one-process-engine) - [工具分工总表](/docs/reference/toolchain) - [流程引擎、流水线与专项工具](/docs/workflow) - [本手册的 Claude Code 插件](/docs/reference/plugin) # 实质改动先留文档再动手 (/docs/pitfalls/process-before-code) > 结果是对的,但 agent 直接改了代码、没留 spec 和 plan,事后没法审计、没法交接、没法请人 review ## 发生了什么 [#发生了什么] 这件事在我这里发生过很多次:agent 交回来的结果是对的,测试也过了,但它是直接上手改的代码,没有 spec,也没有 plan。 当下看不出问题。等到要审计(为什么这样改、考虑过哪些方案)、要把工作交给另一个会话或另一个人、要请别人 review 时,手里只有一个 diff。diff 能说明改了什么,说明不了为什么改、放弃了什么、怎么验证。 用 superpowers 的那一年,我最看重它的一点就是“强制走流程,不准直接上手改”。换成靠手动调用的流程引擎之后,这条约束得自己补上。 ## 为什么会这样 [#为什么会这样] agent 的默认倾向是尽快交付结果:需求一清楚,最短的路径就是直接改代码。写 spec 和 plan 对它来说是额外步骤,没有规则要求,就会被跳过。 这些文档的价值都在事后才体现,当下没人觉得缺。等需要的时候,当时的上下文已经找不回来了。 ## 怎么做 [#怎么做] **在 CLAUDE.md 写成硬规则,附上判定标准**: ```markdown ## 流程(硬规则) - 实质改动(新功能、改行为、跨文件重构):先写 docs/specs/YYYY-MM-DD_.md 和 docs/plans/YYYY-MM-DD_-plan.md,我确认后再按 TDD 实现 - 一行级 trivial 修复(拼写、注释、明显笔误)可以豁免,但在 commit message 里写一句原因 ``` **用 Matt Pocock skills 时**,先 `/mattpocock-skills:to-spec` 把对话整理成 spec,写进 `docs/specs/`,Issue 里只贴链接(to-spec 默认发到 Issue,改法见[迁移页](/docs/workflow/migrate)),再 `/mattpocock-skills:tdd` 实现。`to-spec` 只能手动调用,所以更需要上一步的规则提醒你。 **在 CI 里卡一道**。PR 模板里预留 `Spec:` 和 `Plan:` 两行,CI 检查它们指向的文件真的在仓库里。CI 检出的是合并后的代码,引用主分支上已有的文档也算数;trivial 修复改写一行 `Trivial: 原因`: ```bash #!/usr/bin/env bash # scripts/check-spec-plan.sh,PR_BODY 由 CI 从 PR 事件里传入 check() { # $1 = Spec 或 Plan,$2 = 应在的目录 path=$(printf '%s\n' "$PR_BODY" | tr -d '\r' | sed -n "s/^$1: *//p" | head -n1) case "$path" in "$2"/*.md) [ -f "$path" ] || { echo "$1 指向的文件不存在:$path" >&2; return 1; } ;; *) echo "PR 描述缺少一行 $1: $2/....md" >&2; return 1 ;; esac } printf '%s\n' "$PR_BODY" | tr -d '\r' | grep -q '^Trivial:' && exit 0 fail=0 check Spec docs/specs || fail=1 check Plan docs/plans || fail=1 exit $fail ``` 在 GitHub Actions 里这样传入 PR 描述: ```yaml - name: spec / plan 检查 env: PR_BODY: ${{ github.event.pull_request.body }} run: bash scripts/check-spec-plan.sh ``` **30 天后用数据复查**:多少实质改动留了 spec 和 plan,豁免是不是被滥用了。 ## 相关 [#相关] - [设计:从 intent 到 spec](/docs/product/design) - [spec 模板](/docs/templates/spec) - [plan 模板](/docs/templates/plan) - [从 superpowers 迁到 Matt](/docs/workflow/migrate) - [计划和执行分开会话](/docs/pitfalls/split-plan-exec) # 对外内容先读权威文档 (/docs/pitfalls/read-canonical-first) > 凭记忆写的对外材料,细节容易和最新版本对不上。防止过时的说法进入长期对外的文档 ## 发生了什么 [#发生了什么] 有一次写一份对外材料,没先去读文档,凭记忆就写了。写得很顺,读起来也像那么回事。可细节和最新版本对不上,有些还是旧版本的说法。差一点,它就进了对外的正式材料。 ## 为什么会这样 [#为什么会这样] 记忆是快照。人的记忆停在上次认真看文档的时候;模型的知识停在训练截止日,会话里存的记忆也可能是几周前的。产品却一直在变:版本、功能、命名、对外口径。 更麻烦的是,过时的细节和准确的细节读起来一样流畅,agent 写得越顺,越不容易让人起疑。对外文档又是长期存在、会被别人引用转述的,一处错误会被复制很多次。 ## 怎么做 [#怎么做] **动笔前先列出权威文档**:当前的 README、相关的 spec、最近的 ADR、CHANGELOG、官方文档。哪份算数,写之前就说清楚。 **把要求写进提示词**: ```text 写之前先读:README.md、docs/specs/ 下对应的 spec、docs/adr/ 里最近的决策、CHANGELOG.md。 写完附一张事实表:每个数字、版本号、名称后面写出处(文件路径或 URL)。 找不到出处的标“待核实”,不要凭印象补。 ``` **第三方库和工具的用法查最新文档**:用 context7 这类查文档的 MCP,或者直接读官方文档,不靠模型记忆。 **写进 CLAUDE.md**,让每次会话都照做:写对外文档前先读权威文档,凭记忆写的内容一律标“待核实”。 这本手册的写作规范里也有同一条:命令、版本号、日期和数字都要有出处,查不到就不写。 ## 相关 [#相关] - [一页 CLAUDE.md](/docs/templates/claude-md) - [记忆分层:公开的、私人的、别再加新的](/docs/org/memory) - [“之前是这样的”先查 git](/docs/pitfalls/memory-vs-git) - [自己审自己等于没审](/docs/pitfalls/cross-model-review) - [参考资料](/docs/reference/sources) # 发版靠清单,不靠感觉 (/docs/pitfalls/release-checklist) > 发版由一组互相独立的动作组成,漏掉一步不会报错。防止“看起来发完了”其实少了一块 ## 发生了什么 [#发生了什么] 一次客户端发版:安装包传了,云端也部署了,唯独漏传了 CDN 主源。客户端的自动更新走的是 CDN,于是用户一直卡在旧版本,升不上来。 ## 为什么会这样 [#为什么会这样] 发版不是一个动作,而是一组互相独立的动作:每个平台的安装包、CDN、云端部署、公告。哪一步漏掉都不会报错,只会安静地少一块。 看得见的部分成功了,release 页面有了,部署是绿的,就会给人“发完了”的错觉。而自动更新这条路径,开发者自己几乎从来不走,我们都是直接装新包。 凭感觉发版,漏掉的总是最不显眼的那一步。agent 也一样,它只做它知道的步骤,做完就报告“已发布”。 ## 怎么做 [#怎么做] **把清单写下来,每一项都带验证方法**: ```markdown ## 发版清单 vX.Y.Z - [ ] 每个平台的安装包都已上传,下载链接返回 200 - [ ] CDN 主源已更新,更新清单里的版本号是 X.Y.Z - [ ] 云端服务已部署,健康检查返回新版本号 - [ ] 公告已发 - [ ] 找一台装着旧版本的机器,走通一次自动更新 ``` 验证尽量是命令:`curl -sI <下载地址>` 看状态码,`curl -s <更新清单地址>` 看版本号。 **把清单固化进 skill**,放在 `.claude/skills/release/SKILL.md`,正文写步骤和每一项的验证命令。发版有副作用,设成只能手动 `/release` 触发: ```markdown --- name: release description: 按发版清单逐项发布并验证。任何一项没有验证通过,不得报告“已发布” disable-model-invocation: true --- ``` **最后一项永远站在用户这边验证**:不是“我上传了”,而是“装着旧版本的用户真的升上来了”。 gstack 的 `/ship`、`/land-and-deploy` 能覆盖合并、版本号、部署这些通用步骤,但你的产品特有的去处(比如 CDN 主源),只有你自己的清单知道。 ## 相关 [#相关] - [发布:AI 审查,人来批准](/docs/product/ship) - [gstack:上线流水线怎么用](/docs/workflow/gstack) - [网络报错先查远端](/docs/pitfalls/verify-remote-first) - [CI 绿了不等于能发版](/docs/pitfalls/ci-green-not-ready) # 亲眼看到才算完成 (/docs/pitfalls/see-it-to-ship) > 测试验证的是状态,用户看到的是渲染结果。防止“测试全绿、界面没变”就报告完成 ## 发生了什么 [#发生了什么] 一个“全屏”按钮。agent 实现完,补了单测:点一下,状态从“非全屏”切到“全屏”。测试全绿,它报告完成。 我自己打开页面点了一下,界面毫无变化。查下来是组件库默认样式的选择器优先级更高,把新加的全屏 class 盖掉了。状态确实变了,只是用户看不到。为这一个按钮,多花了一天,多开了两个 PR。 ## 为什么会这样 [#为什么会这样] 测试验证的是状态,用户看到的是渲染结果。从状态到画面还隔着好几环:class 加上没有,样式有没有被覆盖,布局有没有生效。单测一般跑在 jsdom 这类模拟 DOM 里,不做布局,样式表通常也不会真正加载,这几环它根本看不见。 agent 手里只有测试这一个反馈回路,测试绿了,它就有充分的理由说“完成”。真正的问题在“完成”的定义:它被定义成了“测试通过”,而不是“用户看到了变化”。 ## 怎么做 [#怎么做] **把“亲眼看到”写进 CLAUDE.md 的完成标准**: ```markdown ## 完成标准 - UI 改动:启动 dev server,在浏览器里走一遍改动涉及的流程,附截图,才能说完成 - 只有测试通过、没有截图的 UI 改动,视为未完成 ``` **让 agent 自己去看**。gstack 的 `/qa` 会在真实浏览器里把流程点一遍,发现问题直接修;只要报告用 `/qa-only`。没装 gstack,就手动走一遍 happy path 并截图。 **CSS 改动多查三处**:DevTools 的 Styles 面板里,你写的规则有没有被划掉(被覆盖);暗色模式下对不对;窄屏下对不对。 **想固化成自动化测试,就断言渲染结果而不是状态**,比如用 Playwright 的 `toHaveCSS` 或 `boundingBox()`,检查全屏后元素是否真的铺满了视口。 ## 相关 [#相关] - [测试:让 Claude 能自己验证](/docs/product/test) - [gstack:上线流水线怎么用](/docs/workflow/gstack) - [一页 CLAUDE.md](/docs/templates/claude-md) - [CI 绿了不等于能发版](/docs/pitfalls/ci-green-not-ready) # 同一个组织的记忆不要按目录分裂 (/docs/pitfalls/split-memory) > 在父目录启动有 200 多条记忆,进子仓库只剩 8 条:自动记忆按启动位置分家,同一个坑反复踩 ## 发生了什么 [#发生了什么] 我习惯在一个组织的父目录启动 Claude Code,做跨仓库的事。一年下来,那里攒了 200 多条自动记忆:踩过的坑、个人偏好、各种“别这么做”。 有一次我直接进某个代码仓启动,发现它对这些一无所知,这个仓库名下的记忆只有 8 条。两边互相看不到:在父目录会话里早就记下的坑,到了子仓库会话里又踩了一遍。 ## 为什么会这样 [#为什么会这样] 自动记忆默认存在 `~/.claude/projects//memory/`,`` 按 git 仓库来算:同一个仓库的子目录和 worktree 共用一份;不在 git 仓库里时(比如父目录),就按启动目录算。于是父目录一份、每个子仓库各一份,彼此隔离。 这种分裂不容易被发现,因为每个地方看起来都“有记忆”。另外,每次启动只加载 `MEMORY.md` 索引的前 200 行或前 25KB,条目多了,合并时还得顺手精简。 ## 怎么做 [#怎么做] **选一个统一目录,各仓库都指过去**。在这个组织每个仓库(包括父目录)的 `.claude/settings.local.json` 里写: ```json { "autoMemoryDirectory": "~/.claude/org-memory/<组织名>" } ``` 路径写绝对路径或以 `~/` 开头。推荐放在各仓库的 `.claude/settings.local.json`(不进 git)或用户级设置;部分版本会忽略项目级 `.claude/settings.json` 里的这个设置,出于安全考虑也不建议把它提交进仓库。放用户级 `~/.claude/settings.json` 时要注意,那样所有项目共用一份,两个组织的记忆会混在一起。 **合并已有记忆**。先整体备份,再用 `ls ~/.claude/projects/` 找到父目录和各子仓库对应的目录,把各自 `memory/` 下的主题文件拷进新目录。几份 `MEMORY.md` 索引让 Claude 合并去重,控制在 200 行以内。 **验证**。在子仓库开一个新会话,用 `/memory` 打开自动记忆文件夹,确认指向的是统一目录;再问一个只在父目录记过的坑,看它是否知道。 **不要再加新的存储**。团队结论进 ops 仓(经审查),个人判断留在这份自动记忆里。 ## 相关 [#相关] - [记忆分层:公开的、私人的、别再加新的](/docs/org/memory) - [组织 ops agent 的五个组成部分](/docs/org/ops-agent) - [ops 放哪:独立仓还是放进项目](/docs/org/ops-repo) - [“之前是这样的”先查 git](/docs/pitfalls/memory-vs-git) # 计划和执行分开会话 (/docs/pitfalls/split-plan-exec) > 大任务在同一个会话里先计划后执行,计划会把上下文烧光。防止执行阶段带着残余上下文越做越差 ## 发生了什么 [#发生了什么] 一次上游大合并,冲突有几百个。我在同一个会话里让 agent 先摸清冲突、写合并计划,然后接着执行。 计划本身写得不错,但为了写它,会话读了大量 diff 和冲突片段,上下文基本烧光了。进入执行阶段后,质量明显下降。 ## 为什么会这样 [#为什么会这样] 上下文窗口是有限的。计划阶段的探索,读 diff、翻历史、试几种思路又放弃,全都留在上下文里。等到执行,剩下的空间已经不多,自动压缩会把前面的细节概括掉,被否掉的思路和最终的决定也可能混在一起。 还有一个问题:计划只活在对话里,就没法审,也没法复用,会话一断就跟着没了。 拆成两个会话,等于逼着计划落成一个文件:它可以被审查、可以合并进仓库,执行会话也能带着完整的上下文空间从头开始。 ## 怎么做 [#怎么做] 先估规模。别在当前工作区里试合并:手上有没提交的改动时,`git merge --abort` 不保证能把它们原样恢复。开一个临时 worktree 去试,数完就删,当前工作区不受影响: ```bash git fetch upstream git worktree add --detach ../merge-probe HEAD git -C ../merge-probe merge --no-commit --no-ff upstream/main git -C ../merge-probe diff --name-only --diff-filter=U | wc -l # 冲突文件数 git -C ../merge-probe merge --abort git worktree remove ../merge-probe ``` 冲突 30 个以上建议拆,50 个以上必须拆。别的大任务同理:估计一个会话装不下,就拆。 **会话一只出计划**。用 Plan mode(`Shift+Tab`)探索,产出 `docs/plans/YYYY-MM-DD_-plan.md`:按模块分组,每组写清处理原则、顺序和验证命令。 **审计划,合并进仓库,关掉会话**。这一步就可以请另一个模型家族审一遍计划。 **会话二只读计划执行**。开新会话(或者 `/clear`),第一句话就交代清楚:读计划文件,从第 1 组开始,每组做完跑验证、提交,不要重新规划。 **执行中发现计划不对,就停下来回去改计划**,不在执行会话里临场重新规划。组数多就一组一个会话,交接可以用 `/mattpocock-skills:handoff` 压缩成交接文档。 ## 相关 [#相关] - [开发:先出计划,再写代码](/docs/product/build) - [plan 模板](/docs/templates/plan) - [自己审自己等于没审](/docs/pitfalls/cross-model-review) - [分段审过了,还要整分支终审](/docs/pitfalls/whole-branch-review) # 子 agent 别为省钱降级 (/docs/pitfalls/subagent-strongest-model) > 子 agent 降到小模型,单次看不出问题,累积下来跨字段不变量频繁被破坏,审查也兜不住 ## 发生了什么 [#发生了什么] 为了省钱,我曾经把不少子 agent 配成小模型。单看每一次的输出都过得去:代码能跑,测试也过。 累积一段时间后,问题浮出来了:跨字段的不变量频繁被破坏。比如两个字段必须同时改,某个状态只能在另一个条件成立时出现,小模型改了这边、漏了那边。审查也兜不住,因为这类问题分散在不同的 PR 里,每个 diff 单看都合理。 ## 为什么会这样 [#为什么会这样] 子 agent 只拿到截取的一段上下文,没写明的约束得靠它自己从代码里推断。这恰恰是强模型和小模型差距最大的地方:小模型能把眼前的指令执行对,却更容易漏掉要从代码里推出来的约束。 还有一个容易忽略的机制:在 Claude Code 里,主会话派子 agent 时可以按次传 `model` 参数,它的优先级高于子 agent 定义里的 `model` 字段。就算定义里写了强模型,主会话为了“省成本”也可能临时降级。 ## 怎么做 [#怎么做] **有不变量的子 agent 写死模型**。实现、重构、迁移、审查这类任务,在 `.claude/agents/.md` 里写 `model: inherit`(跟主会话一致)或 `model: opus`: ```markdown --- name: implementer description: 按 plan 实现改动,遵守仓库里的不变量 model: inherit --- ``` **拦住按次降级**。在权限规则里给小模型加 ask,主会话想降级时你要确认: ```json { "permissions": { "ask": ["Agent(model:*haiku*)"] } } ``` 想一刀切,可以设环境变量 `CLAUDE_CODE_SUBAGENT_MODEL_FORCE=1`(v2.1.257 起),除内置的 Explore 外,所有子 agent 都跑主会话的模型。 **纯机械任务单独开口子**。批量重命名、移动文件、格式化这类不需要判断的活,单独定义一个 `model: haiku` 的子 agent,提示词里写清楚“只做机械操作,遇到需要判断的就停下来报告”。 注意它和上一步的 FORCE 互斥:开了 FORCE,Claude Code 会忽略子 agent 定义里的 `model` 字段,这个例外不会生效。要么统一强制,要么只在需要强制的会话里用 `CLAUDE_CODE_SUBAGENT_MODEL_FORCE=1 claude` 启动,机械任务放在没开 FORCE 的会话里跑。 **这是保守默认,用评测来调**。这是我在当前工作负载下的选择:跨字段不变量多、返工贵,宁可多花 token。预算有限时,非交互运行可以用 `claude -p --max-budget-usd <金额>` 封顶,子 agent 的花费也计入。哪些子 agent 能降级,拿几个有代表性的历史任务,强模型和小模型各跑一遍,比较一次通过审查的比例和返工次数再定。运行中用 `/tasks` 核对实际模型。 ## 相关 [#相关] - [子 agent 提示词模板](/docs/templates/subagent-prompt) - [开发:先出计划,再写代码](/docs/product/build) - [自己审自己等于没审](/docs/pitfalls/cross-model-review) - [分段审过了,还要整分支终审](/docs/pitfalls/whole-branch-review) # 临时方案要写明撤销条件 (/docs/pitfalls/temp-fix-revert-trigger) > 为赶发版加的临时绕路,事后没人记得撤,成了长期隐患。防止“临时”悄悄变成永久 ## 发生了什么 [#发生了什么] 为了赶一次发版,我在安装流程里加了一个临时绕路,想着发完就撤。 发完之后,没有任何事情提醒我这件事。它能用,也就没人再看它,就这么从“临时”变成了长期隐患。 ## 为什么会这样 [#为什么会这样] 加和撤的成本严重不对称。赶时间的时候,`--no-verify` 跳过检查、写死一个兜底值,都是几秒钟的事;撤掉它却需要有人记得、有人负责,还得等到合适的时机。 临时方案通常缺三样东西:负责人、撤销条件、记录。“什么时候撤”只存在于加它的那个人脑子里,发版压力一过,再没有任何事件会让人想起它。 agent 让这件事更糟。新会话看不到“这是临时的”这段口头背景,只看到一段正常运行的代码,会把它当成既定设计,在上面接着搭。 ## 怎么做 [#怎么做] 适用范围:`--no-verify` 提交、硬编码的兜底值、为赶时间加的绕路、临时关掉的检查。 **在代码里标出来**,写明为什么加、什么条件下撤: ```ts // TEMP(#123): 安装时绕过 X,为赶 v1.4 发版 // 撤销条件:上游修复 X 并发版后,删除本段 ``` **PR 描述里单列一节**: ```markdown ## 临时方案 - 做了什么: - 为什么: - 撤销条件:(具体到版本、日期或事件) - 跟踪 Issue:#123 ``` **记入待撤清单**,用一个固定的 Issue 标签: ```bash gh label create temp-fix --description "待撤销的临时方案" # 只需建一次 gh issue create --title "撤销:安装流程临时绕路" --label temp-fix --body "撤销条件:……" gh issue list --label temp-fix # 待撤清单 git grep -n "TEMP(" # 代码里还剩哪些 ``` **定期过一遍**:放进每周复盘,或者用 `/schedule` 建一个定时运行的 agent,检查撤销条件是否已经满足。 ## 相关 [#相关] - [CI 绿了不等于能发版](/docs/pitfalls/ci-green-not-ready) - [发版靠清单,不靠感觉](/docs/pitfalls/release-checklist) - [复盘模板](/docs/templates/retro) - [运维:线上问题变成新的 intent](/docs/product/maintain) # 模板复制后会各自漂移 (/docs/pitfalls/template-copy-drift) > 第二个组织的规则文件复制自第一个,半年后 6 处引用指向不存在的文件,复审日期也过期半年 ## 发生了什么 [#发生了什么] 我同时运营两个组织。第二个组织搭 ops 仓时,我把第一个组织的规则文件整份复制过去,里面有 agent 的职责、审查流程、红线清单,改了改名字就开始用。 半年后做体检,这份文件里有 6 处引用指向不存在的文件:它们是第一个组织里的路径,在第二个组织从来没建过。文件末尾的“下次 review 日期”两边一字不差,而且已经过期半年。复制时连日期一起抄了过来,之后两边谁也没复审。 ## 为什么会这样 [#为什么会这样] 复制只发生一次,之后两份文件各自演化:第一个组织修了规则,第二个组织收不到;第二个组织踩了新坑,第一个组织也不知道。没有人负责“同步”,漂移就是默认结果,不是意外。 复制品里还夹带着只对原环境成立的东西:路径、文件名、日期。它们看起来像规则,其实是噪音,而 agent 会把噪音也当成规则来执行。指向不存在文件的引用不会报错,agent 读不到就跳过,没人察觉。 ## 怎么做 [#怎么做] **通用部分抽成一个 ops 插件**(下面叫 `ops-kit`):agent 定义、`/new-adr` 和 `/new-retro` 这类 SOP skill、审查流程、通用的拦截和备份 hook、体检脚本。插件带不了 deny / ask 规则,这部分交给 hook,或者由 setup skill 写进各仓库的设置。放进团队私有的插件市场,一个 git 仓库就够。 **各组织只写差异,用 `dependencies` 继承模板**。每个组织建一个自己的 ops 插件(比如 `org-a-ops`),在它的 `.claude-plugin/plugin.json` 里用 `dependencies` 声明依赖 `ops-kit`,启用组织插件时通用模板会一起启用(结构见[让 ops 和项目一起进化](/docs/org/evolve))。再在 ops 仓的 `.claude/settings.json`(进 git)里声明市场、启用组织插件: ```json { "extraKnownMarketplaces": { "team-tools": { "source": { "source": "github", "repo": "your-org/claude-plugins" } } }, "enabledPlugins": { "org-a-ops@team-tools": true } } ``` 插件用相对路径放在市场仓库里时,成员信任这个目录后就会自动加载。模板升级只改 `ops-kit` 一处,各组织运行 `claude plugin update ops-kit@team-tools` 拿到新版。 **给规则文件加一道引用体检**,放进 CI 或园丁任务,引用的文件不存在就报出来: ```bash grep -oE '`[A-Za-z0-9_./-]+\.(md|json|sh)`' CLAUDE.md | tr -d '`' | sort -u \ | while read -r p; do [ -e "$p" ] || echo "引用失效: $p"; done ``` **复审日期交给园丁**。每周扫一遍过期的“下次 review 日期”,过期就提醒或直接提 PR。 ## 相关 [#相关] - [让 ops 和项目一起进化](/docs/org/evolve) - [组织 ops agent 的五个组成部分](/docs/org/ops-agent) - [跨仓链接用完整地址](/docs/pitfalls/absolute-cross-repo-links) - [防护规则会悄悄失效](/docs/pitfalls/guardrails-decay) # 网络报错先查远端 (/docs/pitfalls/verify-remote-first) > 超时和 503 只说明“结果未知”,不说明“失败”。防止盲目重试造成重复推送、重复打 tag ## 发生了什么 [#发生了什么] 一次发版,push 和打 tag 连着遇到 503 超时。看到报错就重试,重试又超时,接着再试。 等网络恢复后对账才发现:有的请求其实已经在远端生效,只是响应没有回来。盲目重试的结果,是重复推送和重复打 tag。 ## 为什么会这样 [#为什么会这样] 超时和 503 的真实含义是“结果未知”。请求可能根本没到,也可能服务端已经处理完,只是响应在网关或网络上丢了。 重推同一个 ref 往往无害,但发版流程里有不少动作不是幂等的:脚本按“最新版本号加一”算出新 tag,调用 API 新建 release,tag 一推上去就触发发布流水线。agent 在这里尤其容易出事:看到报错,第一反应是重试,或者换个办法绕过去,比如换个 tag 名、加 `--force`。 ## 怎么做 [#怎么做] **先查远端,再决定**。分支、tag、release、流水线各有查法: ```bash git ls-remote origin refs/heads/main # 远端分支指向哪个提交,和 git rev-parse HEAD 对比 git ls-remote origin refs/tags/v1.4.2 # 远端有没有这个 tag gh release view v1.4.2 # release 建了没有 gh run list --limit 5 # 发布流水线是不是已经跑起来了 ``` **按结果分三条路**。加上 `--exit-code`,“没找到”和“连不上”的退出码就不一样了: ```bash tag=v1.4.2 git ls-remote --exit-code origin "refs/tags/$tag" >/dev/null case $? in 0) echo "远端已有 $tag,不要重试" ;; 2) echo "远端没有 $tag,用同一个名字重推" ;; *) echo "远端也查不到,等网络恢复,什么都别动" ;; esac ``` **写进 CLAUDE.md 和子 agent 提示词**:网络类状态变更(push、打 tag、建 release、部署)失败后,先查远端;不许换名重试,不许用 `--force` 绕过。 ## 相关 [#相关] - [发版靠清单,不靠感觉](/docs/pitfalls/release-checklist) - [不让 agent 动 git 历史](/docs/pitfalls/git-history-no-surgery) - [发布:AI 审查,人来批准](/docs/product/ship) - [子 agent 提示词模板](/docs/templates/subagent-prompt) # 分段审过了,还要整分支终审 (/docs/pitfalls/whole-branch-review) > 每个阶段单独审过,不代表合在一起没问题。防止跨阶段、跨文件的交互 bug 混进主干 ## 发生了什么 [#发生了什么] 一个多阶段的功能,每个阶段完成时,我都让另一个模型家族单独审一轮,发现的问题也都修了。 合并前,我对整个分支相对 main 的全部改动又做了一次终审,结果又抓出 5 个深层 bug。它们不在任何一个阶段的 diff 里,而是出在跨文件的交互上。 ## 为什么会这样 [#为什么会这样] 分阶段审查,每次看的都是局部 diff。每一段在自己的上下文里都是对的,bug 藏在段与段之间: - 后面的阶段改了前面阶段依赖的函数签名、默认值或数据形状 - 一个约束横跨好几个文件,没有哪一次 diff 能同时看到它的全部 - 早期阶段的审查结论,在后续改动之后已经过期,却没人重审 这和单元测试与集成测试的关系一样:每个零件都合格,装起来不一定能用。 ## 怎么做 [#怎么做] **合并前看整个分支**。三个点表示“从分叉点算起”的全部改动: ```bash git diff --stat main...HEAD # 先看范围 codex review --base main # 整个分支交给另一个模型家族审 ``` `codex review --base` 不能再附加自定义提示词,它会按自带的审查标准看整个分支。内置的 `/code-review` 后面跟 PR 号,也能审整个 PR。 **换一个新会话来审**。做阶段审查的会话装满了各阶段的细节,也容易沿用之前“已经审过”的结论。 **点名要看的交互**:共享状态、调用约定、错误处理链路,以及阶段之间的假设有没有被后来的改动推翻。这些写进终审的提示词里(用 `codex exec` 或 gstack 的 `/codex` 发起;`codex review --base` 带不了自定义提示词)。 **把终审写进 PR 模板,作为合并关卡**: ```markdown - [ ] 整分支终审:已做,发现 N 个问题,已处理 N 个 ``` ## 相关 [#相关] - [自己审自己等于没审](/docs/pitfalls/cross-model-review) - [发布:AI 审查,人来批准](/docs/product/ship) - [计划和执行分开会话](/docs/pitfalls/split-plan-exec) - [REVIEW.md 模板](/docs/templates/review) # 开发:先出计划,再写代码 (/docs/product/build) > Plan mode 出计划,你批准后再实现;大功能拆工单,长任务分会话,实现类子 agent 不并行 开发阶段的规矩只有一条:**先出计划,你批准了,Claude 才动文件**。计划存进 `docs/plans/YYYY-MM-DD_-plan.md`,和 spec 用同一个 slug。大功能先拆成工单;一个会话装不下就分会话;并行只用在互不相干的任务上。 | 产物 | 人工关卡 | 衡量指标 | |---|---|---| | plan 文件、代码 diff、测试 | 你批准计划:Plan mode 下批准之前,Claude 改不了文件 | 首轮实现就能合并的比例;合并后的代码和 plan 还对不对得上 | ## 为什么 [#为什么] Playbook 把“Plan mode 作为默认起点”列为开发阶段的第一招:计划要写清改哪些文件、按什么顺序、用哪些测试证明;反复追问,直到一个没看过这段对话的工程师只读 plan 就能实现;批准后的计划提交进仓库,实现跑偏了就在同一个提交里更新 plan。 道理很朴素:改计划比改代码便宜得多。计划阶段发现方向错了,损失几分钟;代码写完才发现,损失的是一整轮实现和审查。 ## 怎么做 [#怎么做] ### 用 Plan mode 出计划 [#用-plan-mode-出计划] 按 `Shift+Tab` 在几种权限模式之间循环切换,状态栏出现 `plan mode on` 就进入了 Plan mode;也可以直接在一句提示前面加 `/plan`: ```text /plan 读 docs/specs/2026-10-16_monthly-export.md,出一份实现计划:改哪些文件、按什么顺序、每一步用什么测试证明 ``` 批准之前追问三个问题:这个改动可能弄坏什么?哪一步风险最大?你考虑过但没选的方案是什么?批准前可以按 `Ctrl+G` 在编辑器里直接改计划。批准后让 Claude 把计划存成 `docs/plans/2026-10-16_monthly-export-plan.md` 并提交。 想让项目默认从 Plan mode 开始,并让计划文件直接写进仓库,在项目的 `.claude/settings.json` 里设: ```json { "permissions": { "defaultMode": "plan" }, "plansDirectory": "docs/plans" } ``` `plansDirectory` 不设时,计划文件存在 `~/.claude/plans/`,文件名随机生成;设了之后写进仓库的 `docs/plans/`,再按约定改名即可。 官方文档写明:在可以使用 bypass 权限的交互式会话里,Plan mode 不再拦截修改,Claude 在计划阶段尝试的编辑和命令会直接执行。想让“批准之前不能改文件”真正生效,就别用 bypass 启动。 ### 可选:让另一个模型审一遍计划 [#可选让另一个模型审一遍计划] 跨字段的不变量,比如“订单改成已退款时,金额和流水必须同时变”,在计划阶段就能抓到,比写完代码再审便宜得多。把计划交给另一个模型家族看一遍: ```bash codex exec "审查 docs/plans/2026-10-16_monthly-export-plan.md:找出遗漏的边界情况和会被破坏的不变量,只报告问题,不要改文件" ``` 为什么一定要换模型家族,见[发布:AI 审查,人来批准](/docs/product/ship)。 ### 按计划实现 [#按计划实现] ```text /mattpocock-skills:implement 按 docs/plans/2026-10-16_monthly-export-plan.md 实现 ``` implement 会在约定好的测试层用 tdd 一步步实现,过程中经常跑类型检查和单个测试文件,最后跑一次全量测试,再调用 code-review 审一遍,然后提交到当前分支。 需要某个库的最新用法时,让 Claude 用 context7 查,不要凭记忆写。装好 `context7@claude-plugins-official` 之后,在提示里说一句“用 context7 查一下这个库最新的用法”即可。 ### 大功能先拆工单 [#大功能先拆工单] 一个会话装不下的功能,用 to-tickets 拆成“曳光弹”式的竖切工单:每张工单都打通从数据到接口到界面再到测试的一条窄路径,能单独演示,大小正好装进一个新会话,并写明被哪些工单阻塞。 ```text /mattpocock-skills:to-tickets docs/specs/2026-10-16_monthly-export.md ``` 然后一张一张地 `/mattpocock-skills:implement`,每张之间用 `/clear` 清空上下文:工单本身是自包含的,上一张的上下文可以扔掉。 还有两个更重的选项: - `/mattpocock-skills:implement-spec`:把整个 spec 的工单当成依赖图,让多个后台子 agent 在各自的 worktree 里并行实现,再合到一条集成分支。这和我“实现类子 agent 不并行”的经验相冲突,只有工单之间确实不碰同一批文件时,我才会考虑用它。 - `/mattpocock-skills:wayfinder`:给一团迷雾的大工程用。它在 Issue 上维护一张决策地图,每个会话只解决一个决策,产出的是决定而不是代码;地图走清了,再回到 to-spec 和 to-tickets。 ## 长任务:计划和执行分开会话 [#长任务计划和执行分开会话] 写计划会烧掉大量上下文。我做过一次几百个冲突的上游大合并,在同一个会话里写计划又执行,计划把上下文烧光了,执行阶段质量明显下降。现在的规则:冲突 30 个以上建议拆,50 个以上必须拆。计划写完、审完、提交后关掉会话,开新会话只读计划执行。 Matt 的说法可以作为一般任务的参照:模型推理保持敏锐的窗口大约 15 万 token(他称为 smart zone),接近了就在最近的阶段边界收口。三种收口方式: - 计划文件本身:plan 已经在 `docs/plans/` 里,新会话只读它,这是最稳的 - 内置开关:在设置里加 `"showClearContextOnPlanAccept": true`,批准计划时会多一个“批准并清空上下文”的选项,只带着计划开始实现 - `/mattpocock-skills:handoff`:把当前会话压缩成一份交接文档,存在系统临时目录,不进仓库;文档里会写明下一个会话该调用哪些 skill ## 并行与子 agent [#并行与子-agent] - **互不相干的任务各开一个 worktree**:`claude -w export-csv`、`claude -w fix-rate-limit`(`-w` 是 `--worktree` 的简写),每个会话在自己的分支上干活,不会互相改到同一份文件。也可以用 `claude --bg` 开后台会话,`claude agents` 查看进度。 - **从两三个会话开始**:Playbook 的建议是审查跟得上再加;改同一批文件的任务放在一个会话里顺序做。 - **实现类子 agent 不并行,审查类可以**:并行实现改到同一处代码,冲突处理的成本比省下的时间还多。 - **子 agent 用最强的模型**:有工程不变量的任务降级到小模型,单次看不出问题,累积起来不变量频繁被破坏,审查兜不住。只有批量重命名、移动文件这类纯机械的任务例外。 派子 agent 时,提示词里必须自带这几样:任务原文(不要让它自己去读计划)、绝对路径的工作目录、CRITICAL do-not 段(禁止 reset、rebase、force push、amend、在有未提交改动时切分支)、关键约束的原文摘录、回报格式、自查清单。模板见[子 agent 提示词模板](/docs/templates/subagent-prompt)。 ## 常见坑 [#常见坑] - [计划和执行分开会话](/docs/pitfalls/split-plan-exec) - [不让 agent 动 git 历史](/docs/pitfalls/git-history-no-surgery) - [子 agent 别为省钱降级](/docs/pitfalls/subagent-strongest-model) - [本地数据库也要按生产对待](/docs/pitfalls/local-db-is-prod):开发时一条 reset 就能清空本地库里的真实资产 - [临时方案要写明撤销条件](/docs/pitfalls/temp-fix-revert-trigger) ## 相关 [#相关] - [plan 模板](/docs/templates/plan) - [子 agent 提示词模板](/docs/templates/subagent-prompt) - 上一步:[设计:从 intent 到 spec](/docs/product/design) - 下一步:[测试:让 Claude 能自己验证](/docs/product/test) # 第 0 步:起步 (/docs/product/day-0) > 建仓库、写一页 CLAUDE.md、装流程引擎、配护栏:第一天花一小时,后面每次会话都省事 产品档的第一天做四件事:**建仓库、写一页 CLAUDE.md、装好流程引擎、配好护栏**,大约一小时。这些东西每次会话都会用到:第一天不配,以后每次都要口头重复一遍,而且口头要求拦不住误操作。 | 产物 | 人工关卡 | 衡量指标 | |---|---|---| | 仓库、一页 CLAUDE.md、权限规则 | 你确认 CLAUDE.md 不超过一页,里面没有任何密钥 | 从建仓库到第一次部署用了多久 | ## 怎么做 [#怎么做] ### 建仓库 [#建仓库] ```bash bun create next-app my-app --yes cd my-app gh repo create my-app --private --source=. --push ``` `--yes` 直接用推荐的默认值:TypeScript、ESLint、Tailwind CSS、App Router,并生成一份写给 coding agent 的 AGENTS.md。create-next-app 会顺手做好第一次 git 提交,所以可以直接推到 GitHub。不想让 agent 准备匿名的 Next.js 反馈,加 `--no-agent-feedback`。用 shadcn/ui 的话再跑一次 `bunx shadcn@latest init`。 最后确认 `.gitignore` 里有 `.env*`:密钥只放 `.env.local` 和部署平台的环境变量里。 ### 写一页 CLAUDE.md [#写一页-claudemd] 在仓库里打开 Claude Code,运行 `/init` 生成初稿,再手动删到一页以内。只留每次会话都要遵守的东西: - 技术栈和目录结构,一两行 - 常用命令:开发、测试、类型检查、lint,每条附一句“正常输出长什么样” - 约定:命名、提交信息、文档放哪(`docs/specs/`、`docs/plans/`、`docs/adr/`) - 禁区:不许碰的目录、不许跑的命令 - 指针:更长的说明放进 `docs/`,这里只写路径 create-next-app 生成了 AGENTS.md 的话,在 CLAUDE.md 第一行写上 `@AGENTS.md`。原因:仓库里两个文件都有时,Claude Code 只读 CLAUDE.md,不加这行导入,AGENTS.md 就被忽略了。下次会话运行 `/context`,确认 CLAUDE.md 出现在 Memory files 里。 Anthropic 的 Playbook 给了两条好用的规矩:CLAUDE.md 控制在一页以内;同一个错误 Claude 犯第二次,就往里加一条纠正。模板见[一页 CLAUDE.md](/docs/templates/claude-md)。 ### 装流程引擎 [#装流程引擎] ```bash claude plugin install mattpocock-skills@claude-plugins-official ``` 然后在会话里跑一次 `/mattpocock-skills:setup-matt-pocock-skills`,每个仓库只需要一次。它会依次问三件事: - Issue 记在哪:GitHub Issues、GitLab,或者仓库里的本地 markdown(适合一个人、没有远端的仓库) - 分诊标签用什么:默认的五个标签直接接受即可 - 术语表和 ADR 放哪:默认仓库根目录的 `GLOSSARY.md` 和 `docs/adr/` 结果写进 `docs/agents/` 下的几个说明文件,并在 CLAUDE.md 里加一节 `## Agent skills` 指向它们。以后想改,直接编辑这些文件。 Matt 没有 hook,不会在会话开始时接管流程:16 个编排类 skill 只能手动调用,tdd、diagnosing-bugs 等 11 个纪律类 skill 模型可以自动调用。截至 2026-10,这个插件常驻上下文约 1.6k token,可以用 `claude plugin details mattpocock-skills@claude-plugins-official` 自己看。 ### 配护栏 [#配护栏] 项目级的 `.claude/settings.json` 跟着仓库进 git,对这个项目里的每个会话都生效: ```json { "permissions": { "deny": [ "Bash(git push --force origin main *)", "Bash(git reset --hard origin/main *)", "Read(./.env)", "Read(./.env.*)" ], "ask": [ "Bash(gh pr merge *)", "Bash(vercel --prod *)", "Bash(wrangler deploy *)", "Bash(bunx wrangler deploy *)" ], "allow": [ "Bash(gh pr view *)", "Bash(gh run list *)", "Bash(vercel ls *)" ] } } ``` deny 是绝对不行,ask 是每次都要你确认(合并、上线),allow 是只读命令免确认。删根目录这类对所有项目都通用的 deny 规则放用户级 `~/.claude/settings.json`,见[小工具的最小护栏](/docs/tool/guardrails)。规则按命令文本匹配,`bunx wrangler deploy` 要单独写一条;更多细节见[权限规则:deny、ask、allow](/docs/guardrails/permissions)。 想用一句话生成 hook,可以装 hookify: ```bash claude plugin install hookify@claude-plugins-official ``` 然后在会话里写 `/hookify 禁止用 git add 把 .env 开头的文件加进暂存区`。它会生成一个 `.claude/hookify.*.local.md` 规则文件,下一次工具调用就生效;规则可以设为只警告或直接阻止,`/hookify:list` 查看已有规则。 ### 可选:UI 约定与自动推荐 [#可选ui-约定与自动推荐] - 有 UI 的项目,装 ui-contract 管“新功能放页面哪个区域”,安装和用法见[设计:从 intent 到 spec](/docs/product/design)。 - 新仓库可以跑一次 claude-code-setup:它只读扫描仓库,推荐值得配的 hook、skill、MCP 和 subagent。 ```bash claude plugin install claude-code-setup@claude-plugins-official ``` 装好后问一句“这个仓库适合配哪些自动化”,或者直接运行 `/claude-code-setup:claude-automation-recommender`。用完就停用,免得它一直占上下文:`claude plugin disable claude-code-setup@claude-plugins-official`。 装了[本手册插件](/docs/reference/plugin)的话,`/ainative:new-project` 会按档位把这一页的步骤串起来跑一遍,每个写操作先问你。 ## CLAUDE.md、skill、hook 各放什么 [#claudemdskillhook-各放什么] | 放哪 | 放什么 | 性质 | 例子 | |---|---|---|---| | CLAUDE.md | 每次会话都要知道的:技术栈、命令、约定、禁区、文档指针 | 上下文,不是强制配置 | 测试用 `bun test`;spec 放 `docs/specs/` | | skill | 某一类任务才用到的做法 | 按需加载,是建议 | 发版清单、部署步骤、写复盘的格式 | | 权限规则、hook | 必须守住、而且能机械判断的规则 | 确定性执行,不靠模型自觉 | 禁止强推 main;上线前必须确认 | 判断顺序:先问“能不能机械判断”。能,就下沉成权限规则或 hook;不能,再问“是不是每次都要知道”。是,进 CLAUDE.md;只在某类任务里用到,做成 skill。 这个顺序有官方依据。Claude Code 文档写明:CLAUDE.md 被当作上下文,而不是强制执行的配置,要无论如何都拦住某个操作,用 PreToolUse hook。Anthropic 的 Playbook 也说 skill 是建议性的,必须守住的规则要再配一个 hook 或 PR 检查。我的经验是,CLAUDE.md 写得越长,里面每一条被遵守的概率越低。 ## 常见坑 [#常见坑] - [插件不是越多越好](/docs/pitfalls/plugin-bloat):我曾经装了 39 个插件,按 90 天的真实调用统计精简到 16 个 - [同一时间只让一套流程自动接管](/docs/pitfalls/one-process-engine):两套流程框架都开着,一句“帮我 debug”会被抢走 - [切换工具会整份覆盖设置](/docs/pitfalls/config-overwrite):权限规则和 hook 可能一次就全部消失 ## 相关 [#相关] - [一页 CLAUDE.md 模板](/docs/templates/claude-md) - [权限规则:deny、ask、allow](/docs/guardrails/permissions) - [从 superpowers 迁到 Matt](/docs/workflow/migrate):两套流程引擎共存时怎么配 - [选平台:Vercel 还是 Cloudflare](/docs/product/platform) - 下一步:[规划:先写 intent](/docs/product/plan) # 设计:从 intent 到 spec (/docs/product/design) > 一次会话里把 intent 拷问成可以开工的 spec,顺手留下术语表和 ADR;spec 以仓库里的文件为准 设计阶段把 intent 变成一份可以直接开工的 spec:**用户故事、实现决策、测试决策、不做的范围**,接在同一个文件的 intent 下面。讨论中定下的术语写进术语表,不好回头的决定写成 ADR。spec 以仓库里的文件为准,Issue 里只贴链接。 | 产物 | 人工关卡 | 衡量指标 | |---|---|---| | spec 文件 intent 之后的部分、`GLOSSARY.md`、`docs/adr/` | 你以产品负责人的身份签字:spec 对得上 intent,待定问题都有答案或明确延后 | 从 intent 提交到 spec 定稿的时间;开工后 spec 又被改了几次 | “先写 spec 再动手”这套做法我用了一年 ,2026-10 起具体命令换成了 Matt Pocock skills 。 ## 为什么 [#为什么] Playbook 的做法是把 spec 和 intent 一起提交,一个记录“要了什么”,一个记录“定了什么”。产品负责人审 spec 但不亲自写,原文的说法是:这个决定总是由一个人来做。它衡量这一招的滞后指标,是开工之后 spec 还被改了几次:改得越多,说明需求在开发中途返工。 没有 spec 就开工,事后没法审计、没法交接,也没法让另一个模型审“做出来的是不是要的”:Matt 的 code-review 有一个维度,专门拿 diff 对照 spec。 ## 怎么做 [#怎么做] ### 边拷问边沉淀:grill-with-docs [#边拷问边沉淀grill-with-docs] ```text /mattpocock-skills:grill-with-docs 读 docs/specs/2026-10-16_monthly-export.md 的 intent,开始设计 ``` 它同时调用 grilling 和 domain-modeling,一边拷问一边做两件事: - 你用的词和 `GLOSSARY.md` 冲突或者含糊时当场指出,比如“账户”到底指付费的客户还是登录的用户,定下来就立刻写进术语表 - 只给同时满足三个条件的决定写 ADR:难以回头;没有上下文会让后来的人意外;确实在几个方案之间做了取舍 文件都是用到才建:第一次定下术语时才建 `GLOSSARY.md`,第一份 ADR 才建 `docs/adr/`。术语开始打架、但不需要整轮拷问时,可以单独用 `/mattpocock-skills:domain-modeling`。 ### 整理成 spec:to-spec [#整理成-specto-spec] ```text /mattpocock-skills:to-spec ``` to-spec 不再提问,只把这次对话整理成 spec:问题、方案、用户故事(越全越好)、实现决策、测试决策、不做的范围、补充说明。动笔前它会先跟你确认在哪一层测试(Matt 称为 seam,越少越好)。它刻意不写具体文件路径和代码片段,因为这些很快就会过时。 它默认把 spec 发到 Issue tracker 并打上 `ready-for-agent` 标签。我的约定是以仓库里的文件为准:spec 写进 `docs/specs/` 那个文件的 intent 下面,Issue 里贴链接。做法是在 setup 生成的 `docs/agents/issue-tracker.md` 里加一句约定,例如“spec 先写入 `docs/specs/YYYY-MM-DD_.md`,再开 Issue 贴链接”;加完跑一次 to-spec,确认它先写文件再开 Issue。 分支名用同一个 slug,比如 `feature/monthly-export`:后面 Matt 的 code-review 找 spec 时,会在 `docs/` 下按分支名匹配。 ### 拿不准的地方,先做一次性原型 [#拿不准的地方先做一次性原型] ```text /mattpocock-skills:prototype ``` 两种情况用它: - 这个状态模型或业务逻辑对不对:生成一个单文件 HTML,可以点按钮推着状态机走一遍纸上推不清的情况 - 这个界面该长什么样:在同一个路由上生成几个差别很大的版本,用 URL 参数切换对比 原型从第一天起就是要扔的:不写测试,不做持久化。验证出来的结论写回 spec,必要时把关键的状态机或类型片段贴进实现决策;原型本身提交到一个不合并的分支留档。Matt 推荐的走法是先用 `/mattpocock-skills:handoff` 把当前讨论交接出去,在新会话里做原型,再把结论交接回来。 ### UI 项目:先定结构约定 [#ui-项目先定结构约定] 有 UI 的项目,agent 最常见的毛病是把新功能随手塞进某个角落,几轮之后页面就乱了。ui-contract 把“页面分成哪些区域、每个区域放什么”写成约定:`layout.md` 管结构,`design.md` 管视觉,再配上 token 文件、`RegionId` 类型和体检脚本。它是社区开源项目([github.com/yannikzz/ui-contract](https://github.com/yannikzz/ui-contract),MIT)。 只装到当前项目: ```bash claude plugin marketplace add yannikzz/ui-contract claude plugin install ui-contract@yannikzz --scope project ``` 第一行添加它的插件市场,第二行安装。装好后用 `/ui-contract:ui-contract` 定下页面分区和视觉规范;`/ui-contract:ui-contract-enforce` 把允许使用的区域名写成 `RegionId` 类型,写了不存在的区域名,类型检查就会报错;但它发现不了“功能放到了另一个合法区域”,放置是否合规,由体检脚本和评审来判断。 ### 可选:多视角评审 [#可选多视角评审] 方案涉及产品方向或架构取舍时,可以跑 gstack 的 `/autoplan`:它依次用 CEO、设计、工程、开发者体验四个视角评审方案,按预设的原则自动做决定,最后汇总给你。只想要其中一个视角,用 `/plan-eng-review` 或 `/plan-ceo-review`。 ## 人工关卡:签字之前查四件事 [#人工关卡签字之前查四件事] 1. spec 和 intent 对得上:intent 里的每一条约束,spec 里都有回应 2. intent 的待定问题,要么有了答案,要么明确写着延后 3. “不做的范围”比 intent 里写的更具体 4. 测试决策写清了在哪一层测、测什么行为 签字的动作就是提交 spec;用了 Issue 的话,再把 Issue 标成可以开工。签完字,开工后再改 spec 就算返工,要在提交信息里写清原因。 ## 常见坑 [#常见坑] - [“之前是这样的”先查 git](/docs/pitfalls/memory-vs-git):设计时有人(包括你自己)说“以前是 X”,先查 git 历史,再决定当不当约束 - [实质改动先留文档再动手](/docs/pitfalls/process-before-code) ## 相关 [#相关] - [spec 模板](/docs/templates/spec) - [ADR 模板](/docs/templates/adr) - [superpowers 与 Matt:完整对比](/docs/workflow/superpowers-vs-matt) - 上一步:[规划:先写 intent](/docs/product/plan) - 下一步:[开发:先出计划,再写代码](/docs/product/build) # 产品:AI-native 开发六阶段 (/docs/product) > 规划、设计、开发、测试、发布、运维:每个阶段留下什么产物、谁来把关、看哪个指标 有了真实用户,就不能再想到哪改到哪。产品档按六个阶段走:**规划 → 设计 → 开发 → 测试 → 发布 → 运维**,运维发现的问题再回到规划。每个阶段只要求两样东西:**一份提交进仓库的产物,一个由人把守的关卡**。写代码已经不是瓶颈,慢的是需求、验证和审批;这两样东西让这几步既快又不出事。 骨架来自 Anthropic 的 [The AI-native SDLC playbook](https://claude.com/resources/articles/the-ai-native-sdlc-playbook)(2026-08-21 发布,另有 [Claude Academy 课程版](https://academy.claude.com/courses/ai-native-sdlc-playbook))。它是写给企业工程团队的,每个阶段都有专门的负责人;我把它改成了一个人加 AI 也能执行的版本。 ## 六个阶段一览 [#六个阶段一览] | 阶段 | 产物(提交进仓库) | 人工关卡 | 看哪个指标 | |---|---|---|---| | [第 0 步:起步](/docs/product/day-0) | 仓库、一页 CLAUDE.md、权限规则 | 你确认 CLAUDE.md 不超过一页、没有密钥 | 从建仓库到第一次部署的时间 | | [规划](/docs/product/plan) | spec 文件的第一节:intent | 你确认做什么、为什么、不做什么 | 从第一次对话到 intent 写定的时间 | | [设计](/docs/product/design) | spec 的其余部分、术语表、ADR | 你以产品负责人的身份签字 | 开工之后 spec 又被改了几次 | | [开发](/docs/product/build) | plan 文件、代码 diff、测试 | 你批准计划,Claude 才能改文件 | 首轮实现就能合并的比例 | | [测试](/docs/product/test) | 测试输出、截图、eval 结果 | 你看证据,不听“我觉得没问题” | agent 改动的 CI 首次通过率 | | [发布](/docs/product/ship) | PR、审查记录、发布记录 | 你批准合并和上线 | 合并前抓到的问题与上线后才发现的问题之比 | | [运维](/docs/product/maintain) | 诊断记录、复盘、新的 intent | 你决定马上修、排期还是放弃 | 从发现问题到写出新 intent 的时间 | 指标大多改编自 Playbook 每一招后面的“怎么衡量”,都能从 git 和 PR 历史里直接算出来,不需要额外的系统。 ## 三条贯穿始终的原则 [#三条贯穿始终的原则] **一、每个阶段留一份产物,下一阶段读它。** intent → spec → plan → diff 与测试 → PR 与审查记录 → 诊断与新的 intent。Anthropic 的说法是,这些产物合起来就是审计轨迹。对一个人来说,它的价值更直接:一个月后你还知道当初为什么这么做;换一个会话、换一个 agent,也能从文件接着干,不用去聊天记录里捞。 **二、每个阶段有一个人工关卡。** 企业里,intent 由产品负责人确认,计划由工程师批准,上线由发布负责人授权。一个人做产品时,这些角色都是你,所以关卡要落成明确的动作:读完 spec 再提交,在 Plan mode 里点批准,亲手点合并,上线命令必须弹确认。 **三、写代码的 agent 不能批准自己的代码。** 这是 Playbook 里说得最硬的一条:写代码的 agent 没有办法批准它,从而保住职责分离;agent 可以一路做到生产关卡前,但过不去。落到实践就是[审查三角](/docs/product/ship):主力模型写完,另一个模型家族独立审,人拍板。 ## 一个人怎么执行:我的改动 [#一个人怎么执行我的改动] | Anthropic 的版本 | 我的版本 | 为什么 | |---|---|---| | 单独的 `intent.md` | intent 写在 spec 文件的第一节 | 一个人既提需求又做设计,两个文件来回切没有收益;“先写 intent、确认后再设计”的顺序不变 | | `spec.md`、`plan.md` | `docs/specs/YYYY-MM-DD_.md`、`docs/plans/YYYY-MM-DD_-plan.md` | 日期前缀按时间排序,同一个 slug 把 spec、plan 和分支串起来 | | 同事做人工审查 | 先由另一个模型家族独立审,再由你拍板 | 一个人没有同事,异构模型替你先筛一遍 | | 发布负责人在变更单上授权 | 上线命令放进 ask 规则,每次都要你点头 | 用权限规则和 hook 实现同一个关卡 | 仓库里的文档目录: ```text docs/ ├── specs/ # 2026-10-16_monthly-export.md(开头一节是 intent) ├── plans/ # 2026-10-16_monthly-export-plan.md ├── adr/ # 不好回头的决定 ├── runbooks/ # 跟代码绑定的操作手册 └── retros/ # 复盘 ``` ## 工具分工 [#工具分工] 同一件事只交给一个工具负责,否则几套工具会抢着触发,同一个项目里流程前后不一致。 | 角色 | 用什么 | 可信度 | |---|---|---| | 流程引擎:想清楚、写 spec、拆工单、实现、TDD、审查 | Matt Pocock skills(`/mattpocock-skills:*`) | 🧪 2026-10 起试用 | | 上线流水线:异构二审、安全审计、真实浏览器、发版 | gstack(`/codex`、`/cso`、`/qa`、`/ship`) | ✅ 部分命令亲历 | | 内置能力:计划、审查、并行、护栏、定时任务 | Plan mode、`/code-review`、`/security-review`、worktree、hook;定时任务 `/schedule` | ✅ 亲历;`/schedule` 🧪 试用中 | Matt 没有 hook,不会在会话开始时接管流程:16 个编排类 skill 只能手动调用,tdd、diagnosing-bugs 等 11 个纪律类 skill 模型可以自动调用;产物(术语表、ADR、Issue)跨会话保留。我用了约一年的上一代主引擎 superpowers 正好相反:会话一开始就自动接管,强制走完整流程。两者的取舍、为什么换、怎么换,见 [superpowers 与 Matt:完整对比](/docs/workflow/superpowers-vs-matt)。不知道某一步该用 Matt 的哪个 skill,直接问 `/mattpocock-skills:ask-matt`。gstack 只用它最强的几样,见 [gstack:上线流水线怎么用](/docs/workflow/gstack)。 ## 从一类低风险改动开始 [#从一类低风险改动开始] 不要第一天就把六个阶段全开、把权限全放。Playbook 建议先从没有前置依赖的几招入手:写 intent、默认用 Plan mode、写 CLAUDE.md、把规范做成 skill、给 Claude 反馈回路、用 hook 做审批关卡。 我的建议是再收窄一步:先挑一类低风险的改动,比如文案、文档、小的界面修复,把从 intent 到上线的整条链跑通一次。看哪一步卡住、哪个关卡形同虚设,修好之后再扩到更大的改动,再按数据逐步放权:首轮合并率稳定了,再考虑让 agent 并行;审查一直抓不到问题,再考虑放宽某一类改动的审查。 这本手册自己就是产品档:需求是先拷问出来的,经过见[规划](/docs/product/plan)。 ## 常见坑 [#常见坑] 每个阶段最容易踩的一个: - 起步:[插件不是越多越好](/docs/pitfalls/plugin-bloat) - 设计:[实质改动先留文档再动手](/docs/pitfalls/process-before-code) - 开发:[计划和执行分开会话](/docs/pitfalls/split-plan-exec) - 测试:[亲眼看到才算完成](/docs/pitfalls/see-it-to-ship) - 发布:[自己审自己等于没审](/docs/pitfalls/cross-model-review) - 运维:[防护规则会悄悄失效](/docs/pitfalls/guardrails-decay) ## 相关 [#相关] - [模板库](/docs/templates):intent、spec、plan、ADR、复盘、REVIEW.md - [选档:小工具、产品还是组织](/docs/tiers) # 运维:线上问题变成新的 intent (/docs/product/maintain) > 上线后盯住,出了问题先诊断再动手,把事故写成新的 intent 和复盘,再沉淀成会自动生效的规则 运维阶段把线上问题接回规划:**发现异常 → 只读诊断 → 写成新的 intent → 从规划重新走一遍**。真正的事故再写一篇复盘。复盘里的教训不能只停在文档里,要一级一级变成 playbook、规则和 hook,下次才会自动生效。 | 产物 | 人工关卡 | 衡量指标 | |---|---|---| | 诊断记录、新的 spec(开头是 intent)、复盘 | 你决定马上修、排期还是放弃;修复照样走发布关卡 | 从发现问题到写出新 intent 的时间;同一类事故有没有再发生 | ## 为什么 [#为什么] Playbook 的最后一招叫“闭合指标回路”:线上指标越过正常范围时,Claude 先只读诊断,只通过事先批准的路径行动(开 PR 进审查关卡,或者执行预先批准的 runbook,比如回滚),然后把发现写成新的 intent,回到第一阶段。人不再需要亲手开始每一项修复,只负责分诊和审查。 它衡量这一招的方式也很直接:从指标异常到 intent 进入分诊队列用了多久;有多少发现最终变成了合并的修复;同一类事故是不是越来越少。 ## 怎么做 [#怎么做] ### 上线后盯住 [#上线后盯住] gstack 的 `/canary ` 默认盯 10 分钟:定时截图、看控制台报错和性能,和上线前的基线比对。部署前先跑一次 `/canary --baseline` 留下基线;只想快速检查一遍,用 `--quick`。 Playbook 的做法更进一步:挑一个有稳定基线的指标,比如 CI 失败率、上线后的 5xx 比例、PR 周期,用确定性的脚本判断有没有越界,越界了再触发 Claude 诊断。“有没有异常”这一步不用模型判断。 ### 先诊断,再动手 [#先诊断再动手] ```text /investigate 上线后导出接口偶发 500,先找根因,不要改代码 ``` gstack 的 `/investigate` 和 Matt 的 `/mattpocock-skills:diagnosing-bugs` 做的是同一件事:先复现,再假设,再验证。两个选一个当默认,别让它们抢着触发。线上诊断只给读权限:读代码、读日志、跑只读命令;要改东西,开 PR 进审查关卡。 ### 写成新的 intent [#写成新的-intent] 诊断结论写成一份新 spec 的第一节,比如 `docs/specs/2026-10-20_export-500.md`。intent 里写清:异常现象和证据、期望的结果、受影响的部分、待定问题。然后由你分诊:马上修、排期,还是放弃。 修复照常走设计、开发、测试、发布,没有捷径。修好之后,把这次的复现变成一个回归测试或 eval,同类问题以后在 CI 里就能拦住。 ### 真正的事故,写复盘 [#真正的事故写复盘] 影响了用户、或者差点出事的,写一篇复盘:`docs/retros/YYYY-MM-DD_.md`。我一年写了 70 多篇复盘,模板里最有用的是“Harness 反馈”一节:这次的问题,本该被哪条规则、哪个 hook、哪份文档拦住,为什么没拦住,要补什么。模板见[复盘模板](/docs/templates/retro)。 Matt 的 `/mattpocock-skills:retro` 可以从会话记录里找改进点。它只看 agent 的环境,不看代码:导航指针够不够、有没有自动检查能拦住这次的错误、审查规则要不要加一条、CLAUDE.md 里有没有不起作用的指令。它的原则是:机械性的错误变成确定性的检查,需要判断的才写进规范。注意 gstack 也有一个 `/retro`(每周工程回顾),用 Matt 的要写全名。 ## 复利:教训 → playbook → hook [#复利教训--playbook--hook] 坦白说,我沉淀得很勤,回流做得不好:70 多篇复盘、200 多条记忆都在,可很多教训只是文字,下次照样踩。现在的规则是三级台阶: 1. **第一次踩**:写进复盘,记一条反馈 2. **有通用价值**:提炼进 playbook 或 runbook。跟代码绑定的 runbook 放代码仓的 `docs/runbooks/`,里面的检查步骤尽量变成 CI 3. **同一个坑出现第二次**:起草 hook 或权限规则,让它自动生效 沉淀只走这一条路,不要为了“记下来”再引入新的存储。装了[本手册插件](/docs/reference/plugin)的话,`/ainative:harvest` 能把一篇复盘提炼成坑卡草稿,顺带做脱敏检查。 ## 定期园丁 [#定期园丁] 有些维护活适合交给定时运行的云端 agent。内置的 `/schedule` 用来创建 routine(研究预览,Pro、Max、Team、Enterprise 计划可用):它在 Anthropic 的云端按计划运行,每次克隆你的仓库,改动推到 `claude/` 开头的分支,再由你像审其他 PR 一样审。我在试的园丁任务: - 每周读新增的复盘,提 PR 更新 playbook 和 CLAUDE.md - 查失效的链接和过期的“下次 review 日期” - 同一个坑出现了两次,起草一条 hook 规则 护栏本身也会悄悄失效,要定期体检:见[护栏体检](/docs/guardrails/health-check),或者运行 `/ainative:doctor`。 ## 看开销:session-report [#看开销session-report] 运维也包括 agent 自己的开销。session-report 从本机的会话记录生成一份可交互的 HTML 报告:token 用量、缓存命中、subagent 和 skill 的开销,以及最贵的那些提示词。 ```bash claude plugin install session-report@claude-plugins-official ``` 装好后运行 `/session-report:session-report`。看到某个 skill 或子 agent 特别贵,再决定是改提示词、换触发方式,还是干脆停用。 ## 常见坑 [#常见坑] - [防护规则会悄悄失效](/docs/pitfalls/guardrails-decay):三层防护半年后全没了,整段时间没人发现 - [跟代码绑定的文档跟代码放一起](/docs/pitfalls/code-coupled-docs):runbook 里写的检查,代码早就改了 - [性能修复先问六个问题](/docs/pitfalls/perf-fix-six-questions) ## 相关 [#相关] - [复盘模板](/docs/templates/retro) - [让 ops 和项目一起进化](/docs/org/evolve) - [背后的理念](/docs/reference/ideas):Compound Engineering 与双环学习 - 上一步:[发布:AI 审查,人来批准](/docs/product/ship) - 回到起点:[规划:先写 intent](/docs/product/plan) # 规划:先写 intent (/docs/product/plan) > 动手之前,先被拷问一轮,再用一页纸写清做什么、为什么、约束、不做什么和成功指标,由你确认 任何实质改动,先写 intent:**做什么、为什么、约束、不做什么、怎么算成功**。它就是 spec 文件的第一节,写在 `docs/specs/YYYY-MM-DD_.md` 的开头。先让 agent 拷问你一轮把想法问清楚,再落成文字;你确认之后,才进入设计。 | 产物 | 人工关卡 | 衡量指标 | |---|---|---| | spec 文件的第一节:intent | 你确认 intent:要做的事、原因、明确不做的部分 | 从第一次对话到 intent 提交用了多久;提交后又被推翻了几次 | ## 为什么 [#为什么] agent 最常见的失败不是写错代码,而是做了你没想要的东西。Matt Pocock 把这叫作对齐失败(misalignment),他的解法是 grilling:让 agent 反过来拷问你,直到双方对要做的事有同样的理解。 Anthropic 的 Playbook 把 intent 放在第一招:一个短小、进版本控制的文件,说清要什么、为什么、在什么约束下。来源可以是一个想法、一张工单,也可以是一条告警。它衡量这一招的领先指标是“从第一次对话到 intent 提交的时间”,预期从几周的需求往返缩短到几个小时。 我没有单独建 `intent.md`,而是把 intent 写成 spec 的第一节:一个人既提需求又做设计,两个文件来回切没有收益;同一个文件从上往下读,就是从“为什么”到“怎么做”。 ## 怎么做 [#怎么做] ### 先被拷问,再动笔 [#先被拷问再动笔] ```text /mattpocock-skills:grill-me 我想给产品加一个按月导出账单的功能 ``` grill-me 把你的想法当成一棵决策树,一轮一轮地问:每一轮把当前已经能问的问题一次问完,每题都附上它推荐的答案,你回答“是”就等于采纳。查事实是它的事(读代码、查文档),做决定是你的事。直到所有分支都问过、没有默认假设遗留,才算结束。 grill-me 只是手动调用的入口,背后是同一个 grilling skill,说一句“拷问我一下”也能触发。还在想“这件事值不值得做”的新方向,可以先用 gstack 的 `/office-hours`,它是 YC office hours 式的追问。 ### 把结论写成 intent [#把结论写成-intent] 让 Claude 按模板写 spec 文件的第一节,此时文件里只有这一节: ```markdown # 按月导出账单 ## Intent - 做什么:一句话说清 - 为什么:谁的什么问题,为什么是现在 - 约束:技术、合规、预算、时间 - 不做什么:明确排除的范围 - 成功指标:上线后看哪个数,目标是多少 - 待定问题:还没想清楚、留给设计阶段回答的 - 来源:想法、Issue 或告警的链接 ``` 完整模板见 [intent 模板](/docs/templates/intent)。 ### 人工关卡:你确认 [#人工关卡你确认] 逐条读,改掉 Claude 理解偏的地方,然后提交。确认的标准: - 一个没参与对话的人只读这一节,能说出要做什么、不做什么 - 成功指标能量化,上线后真的看得到 - “不做什么”至少写了一条 - 待定问题列出来了,而不是被悄悄假设掉 Playbook 里这一关由产品负责人把守,产品负责人审改 agent 写的 intent 之后才提交。一个人做产品,这个人就是你。提交就是确认,git 历史会记下时间和每一次修改。 ## 亲历:这本手册的需求是拷问出来的 [#亲历这本手册的需求是拷问出来的] 写这本手册之前,我先让 Claude 用 Matt 的 grilling 拷问了我几轮,最后落成一张 8 行的决策表:性质(个人项目、直接公开)、读者优先级、语言、公开边界(两个组织都不点名)、流程引擎、网站技术、可信度标签、附带插件。后面的写作分工、页面取舍,都以这张表为准。 这张表里,边界类的决定和“做什么”一样重要:两个组织都不点名,不做工具大全,不写没验证过的做法。intent 里的“不做什么”写清楚了,后面才有依据拒绝那些顺手想加进来的东西。 ## 什么时候可以跳过 [#什么时候可以跳过] 一行级的小修复,比如改错别字、调一个常量,可以不写 intent,但也在提交信息里留一句为什么改。判断标准:这个改动将来需不需要有人回头理解它的来龙去脉。需要,就写。 ## 常见坑 [#常见坑] - [实质改动先留文档再动手](/docs/pitfalls/process-before-code):结果是对的,但没留 spec,事后没法审计、没法交接 - [对外内容先读权威文档](/docs/pitfalls/read-canonical-first):intent 里引用的外部事实,先读原文再写,别凭记忆 ## 相关 [#相关] - [intent 模板](/docs/templates/intent) - [spec 模板](/docs/templates/spec) - 上一步:[第 0 步:起步](/docs/product/day-0) - 下一步:[设计:从 intent 到 spec](/docs/product/design) # 选平台:Vercel 还是 Cloudflare (/docs/product/platform) > Vercel 跑 Next.js 应用,Cloudflare 做底座:重叠在哪、各自强在哪,一个域名只挂一个平台 我的分工:**Vercel 跑 Next.js 应用,Cloudflare 做底座**。所有域名的 DNS、邮件路由、大文件分发、防火墙和人机验证、边缘 API 和定时任务、静态站,都放 Cloudflare;需要服务端渲染、ISR、Server Actions、每个 PR 一个预览环境的 Next.js 应用,放 Vercel。规则只有两条:**一个域名只挂一个平台;DNS 统一在 Cloudflare 管**。 ## 两者重叠在哪 [#两者重叠在哪] 截至 2026-10: | 能力 | Vercel | Cloudflare | 我放哪 | |---|---|---|---| | Next.js 全功能(SSR、ISR、Server Actions、图片优化) | 原生支持,新特性第一时间可用 | 通过 OpenNext 适配器 `@opennextjs/cloudflare`,部分新特性要等适配;图片优化要另配 Cloudflare Images | Vercel | | 每个 PR 的预览环境 | 连上 Git 就默认有 | Workers Builds 开启预览构建后也有([2026-09 推出 Worker Previews](https://developers.cloudflare.com/changelog/post/2026-09-22-worker-previews/)) | 跟着应用走 | | 静态站、报告、落地页 | 可以 | Workers 静态资源,一份配置就能部署 | Cloudflare | | 边缘 API、Webhook、定时任务 | Vercel Functions、Cron Jobs | Workers、Cron Triggers | Cloudflare | | WebSocket、有状态 agent | [2026-06 起 WebSocket 公测](https://vercel.com/changelog/websocket-support-is-now-in-public-beta),连接受函数最长运行时间限制,跨实例共享状态要外接存储 | Durable Objects,天然有状态,适合长连接 | Cloudflare | | 对象存储、大文件分发 | Vercel Blob | R2,出口流量免费 | Cloudflare | | DNS、邮件路由、WAF、人机验证 | 有 DNS 和防火墙 | DNS、Email Routing、WAF、Turnstile 都在一处 | Cloudflare | ## 推荐分工 [#推荐分工] **Vercel 跑应用**:主站、管理后台、SaaS 这类 Next.js 全功能产品。它对 Next.js 的支持最完整,每个 PR 自动生成预览环境,审查时直接点开看效果。 **Cloudflare 做底座**: - 全部域名的 DNS,一个地方管所有记录 - 邮件路由:把域名邮箱转发到你的收件箱 - R2:安装包、大文件分发,出口流量不收费 - WAF 和 Turnstile:防刷、人机验证 - Workers:边缘 API、Webhook、定时任务、WebSocket,以及用 Durable Objects 跑的有状态 agent - 静态页面与报告,比如这本手册,部署方法见[小工具上线](/docs/tool/ship) - 需要国内访问的项目:以我的经验放 Cloudflare 更合适。不过两边都不保证国内的速度和可用性,真正面向国内用户的业务,备案和国内云是另一个话题 ## 替代方案:全放 Cloudflare [#替代方案全放-cloudflare] 适合成本敏感、或者主要用户在国内的项目。代价是 Next.js 要通过 OpenNext 跑在 Workers 上:截至 2026-10,OpenNext 的文档里仍写着 15.2 引入的 Node Middleware 尚未支持,图片优化也要另外接 Cloudflare Images。 我的判断:应用依赖 Next.js 最新特性,就留在 Vercel;静态站或者简单的服务端渲染,全放 Cloudflare 没有问题。 ## DNS 在 Cloudflare、应用在 Vercel 时 [#dns-在-cloudflare应用在-vercel-时] 在 Vercel 项目的 Domains 设置里复制它给出的记录值,到 Cloudflare 添加,**代理状态选 DNS only(灰色云朵)**。这样配置更简单,也能避免 Cloudflare 的代理(橙色云朵)干扰 Vercel 的证书验证和它自己的安全防护;Vercel 官方也不建议在它前面再套一层反向代理。详见 Vercel 的[域名排障文档](https://vercel.com/docs/domains/troubleshooting)。 ## 一个域名只挂一个平台 [#一个域名只挂一个平台] 我踩过的坑:一个子域名同时挂在两个托管平台上,是旧平台的残留部署。清理时我准备连主域名一起从旧平台移除,查依赖才发现,同一主域下另一个子域名正在旧平台上服务,差点误删。 所以: - 一个域名(包括子域名)只挂在一个平台上,迁移完成就删掉旧平台上的绑定 - 删除任何绑定之前,把同一主域下的所有 DNS 记录列出来,逐条确认它指向哪个平台、还有没有流量 - DNS 统一在 Cloudflare 管,“这个域名在哪”永远只需要查一个地方 ## 让 Claude 直接改 DNS:Cloudflare 官方 MCP [#让-claude-直接改-dnscloudflare-官方-mcp] Cloudflare 官方的 API MCP server 用 `search` 和 `execute` 两个核心工具覆盖了全部 Cloudflare API(另有 `docs` 和 `whoami`):Claude 先用 search 找到要调用的接口,再用 execute 调用。我实测 DNS 记录的增删和 Zone 设置的写入都可用。 ```bash claude mcp add --transport http --scope user cloudflare-api https://mcp.cloudflare.com/mcp ``` 然后在会话里运行 `/mcp` 完成 OAuth 授权。授权时可以自己勾选给哪些权限,只给要用的。 改 DNS 会直接影响线上,我建议把 `execute` 放进 ask,在项目或用户的 settings.json 里: ```json { "permissions": { "ask": [ "mcp__cloudflare-api__execute" ] } } ``` 这样 search 和 docs 照常运行,真正调用 API 时(包括只读的查询)每次都要你确认。 改完验证解析时注意:本机代理的 fake-ip 模式会让 `dig` 的结果失真,用 DoH 查:`curl -s 'https://dns.google/resolve?name=example.com&type=A'`。 ## 常见坑 [#常见坑] - [一个域名只挂一个平台](/docs/pitfalls/one-domain-one-platform) - [本机代理会让 DNS 检查失真](/docs/pitfalls/dns-fake-ip) ## 相关 [#相关] - [小工具上线:静态站部署到 Cloudflare](/docs/tool/ship) - [发布:AI 审查,人来批准](/docs/product/ship) - [命令速查](/docs/reference/commands) - 官方文档:[OpenNext for Cloudflare](https://opennext.js.org/cloudflare)、[Cloudflare MCP server](https://github.com/cloudflare/mcp) # 发布:AI 审查,人来批准 (/docs/product/ship) > 审查三角(主力模型 → 异构模型 → 人)、整分支终审、发版清单,上线审批放在远端由人把关 发布阶段的核心是**审查三角:主力模型写完,另一个模型家族独立审,人拍板**。分阶段审过了,合并前还要整条分支再审一次;上线前本地跑全量验证,按清单逐项打勾;上线必须由人批准,审批要放在远端,本地规则只是第一道。写代码的 agent 不能批准自己的代码,也不能自己把代码推上生产。 | 产物 | 人工关卡 | 衡量指标 | |---|---|---| | PR(含审查记录和测试证据)、发布记录 | 你批准合并、批准上线 | 合并前抓到的问题与上线后才发现的问题之比 | ## 为什么:自己审自己等于没审 [#为什么自己审自己等于没审] Playbook 在发布阶段说得很硬:写代码的 agent 没有办法批准它;agent 可以一路做到生产关卡前,但过不去。 主力模型写完再自己审,倾向于认同自己。同一个模型家族共享同样的训练偏好和盲区,换一个会话、换一套审查提示词,只能去掉其中一部分。我的两次亲历: - 换一个不同家族的模型独立审查,抓出过主力模型漏掉的 2 个高危安全问题 - 一次人工二审,在 4 个 commit 里抓出约 85 处文档泄漏,类型检查完全看不到 ## 审查三角怎么跑 [#审查三角怎么跑] | 角色 | 负责什么 | 用什么 | |---|---|---| | 主力模型(写代码的那个) | 交出证据:测试、类型、lint 全过;用新的上下文自查一遍 | `/mattpocock-skills:code-review`、内置 `/code-review`、`/security-review` | | 异构模型(另一个模型家族) | 独立审查:不共享上下文,不共享模型偏见 | `codex review --base main`,或 gstack 的 `/codex` | | 人(你) | 拍板:看两份审查和证据,决定合并与上线 | 远端的合并与上线审批 | ### 第一角:主力模型自查,交出证据 [#第一角主力模型自查交出证据] ```text /mattpocock-skills:code-review main ``` Matt 的 code-review 用两个子 agent 并行审:Standards 看是否符合仓库成文的规范,Spec 看是否忠实实现了 spec(漏了、多了、错了)。两份报告分开呈现,免得一个维度掩盖另一个。 再加上 Claude Code 内置的两个命令: - `/code-review`:找正确性 bug,可以指定 PR 号、分支或路径;加 `--comment` 把意见发到 PR,加 `--fix` 直接改。它遵循 CLAUDE.md。 - `/security-review`:碰到鉴权、支付、密钥的改动必须跑;风险更高的项目再加跑 gstack 的 `/cso`。 这一角是同一模型家族的复查:上下文是新的,能抓到明显的问题,但不能当作二审。 ### 第二角:异构模型独立审 [#第二角异构模型独立审] ```bash codex review --base main -c model_reasoning_effort="medium" ``` 我用 OpenAI 的 Codex CLI 做二审,推理强度 medium 就够,xhigh 可能卡很久。也可以在 Claude Code 里用 gstack 的 `/codex`:`/codex review` 给出通过或不通过的结论,`/codex challenge` 专门想办法把代码弄坏。 两条原则: - **关键是“不同家族、不共享上下文”,不一定是 Codex**,Kimi、Gemini 都行。给它 spec 的路径和 diff,不要给它主力模型的聊天记录,否则就把偏见一起传过去了。 - **三个时机**:计划阶段审计划(跨字段的不变量这时最便宜,见[开发](/docs/product/build));每个阶段完成后审这一阶段的 diff;合并之前审整条分支。 ### 第三角:人拍板 [#第三角人拍板] 你要看的是: - 两份审查意见都被处理了吗:要么修了,要么写明了为什么不修 - 证据齐不齐:测试输出、截图、eval 结果 - 这是单向门还是双向门:回滚得了的风险低,删数据、改公开接口、数据库迁移这类回不了头的要格外小心(`/mattpocock-skills:pr` 写 PR 描述时专门有这一栏) 保证“只有人能批”分两层:本地用 ask 规则拦住 `gh pr merge`、用 deny 规则拦住强推 main;但本地规则管不到其他上线入口,真正的关卡要放在远端,见下文“卡住上线”一节。 ## 合并前:整分支终审 [#合并前整分支终审] 一个多阶段的功能,每个阶段都单独过了异构审查;合并前对整条分支做终审,又抓出 5 个跨文件交互的深层 bug。分段审查只看得到局部,跨文件的影响只有放在一起才看得见。 ```bash codex review --base main ``` 在功能分支上对整条分支跑一次,再走一遍第一角的自查。 ## 上线前:本地验证和发版清单 [#上线前本地验证和发版清单] - **CI 绿了不等于能发版**:我遇到过一个因环境差异一直红着的检查被当成“环境问题”忽略,版本照发,后来出了问题。发版前在本地跑一遍全量测试、类型检查、lint、单测,CI 只是下限。 - **发版靠清单,不靠感觉**:一次发版漏传了 CDN 主源,用户的自动更新卡在旧版本出不来。发布产物逐项打勾(安装包、CDN、云端部署、公告),清单固化进 skill。 - **网络报错先查远端**:push、打 tag 超时后盲目重试,可能重复推送、重复打 tag。先用 `git ls-remote origin` 或 `gh api` 确认远端真实状态,再决定重试还是放弃。 ## gstack 流水线:/ship 和 /land-and-deploy [#gstack-流水线ship-和-land-and-deploy] - `/ship`:检测并合并基线分支、跑测试、审查 diff、更新 VERSION 和 CHANGELOG、提交、推送、开 PR,一条命令走完。 - `/land-and-deploy`:接手 `/ship` 开的 PR,检查能否合并,经你批准后合并,等 CI 和部署完成,再到线上验证。第一次用之前先跑 `/setup-deploy` 配置部署平台。 两者都是流水线,不替代审查三角。 ## 卡住上线:本地规则加远端审批 [#卡住上线本地规则加远端审批] Playbook 把这一招叫“用 hook 做审批关卡”。本地这一层最简单:上线和合并命令放进 ask,Claude 每次执行都要你点头。 ```json { "permissions": { "ask": [ "Bash(vercel --prod *)", "Bash(wrangler deploy *)", "Bash(bunx wrangler deploy *)", "Bash(gh pr merge *)" ] } } ``` 规则按命令文本匹配:`bunx wrangler deploy` 不会被 `Bash(wrangler deploy *)` 拦住,两种写法都要列上。要按条件拒绝(比如不在 main 分支、工作区不干净),用 PreToolUse hook,见[用 hook 兜底](/docs/guardrails/hooks)。 **但本地规则只管得住 Claude 在你这台机器上执行的命令。** 上线还有很多别的入口:一次普通的 `git push` 推到生产分支,就可能触发 Vercel 或 Workers Builds 的自动部署;平台的 REST API、MCP 工具、CI 流水线也都能上线。所以真正的审批要放在远端: - **生产分支**:开分支保护或规则集,要求必须经过 PR、至少一人批准才能合并 - **部署环境**:在部署平台和 CI 里给生产环境加保护和审批,比如 GitHub Actions 的 environment 可以设置为指定的人批准后才执行部署 - **凭证**:按最小权限发,本地和 agent 用的令牌不带生产部署权限 这些远端能力是否可用,取决于你的 GitHub 计划、仓库可见性和部署平台。还要事先定清一件事:在你的项目里,**合并到生产分支是否就等于批准上线**。连了 Git 自动部署,答案就是“是”,合并那一下就是上线关卡,要按上线的标准审;如果不是,就要有一个独立的上线动作,这个动作同样要由人确认。 ## Claude GitHub Action:每个 PR 自动审 [#claude-github-action每个-pr-自动审] 在仓库里运行 `/install-github-app`,它会装好 Claude GitHub App、配置密钥、开一个加入工作流的 PR;合并后在 PR 或 Issue 里 @claude 就能让它干活,安装时也可以选上自动审查每个 PR 的工作流。我还没在自己的项目里长期跑过。 用 Team 或 Enterprise 计划的话,托管的 Code Review 服务会读仓库根目录的 REVIEW.md(本地的 `/code-review` 不读),在里面写清什么算严重问题。模板见 [REVIEW.md 模板](/docs/templates/review)。 ## 常见坑 [#常见坑] - [自己审自己等于没审](/docs/pitfalls/cross-model-review) - [分段审过了,还要整分支终审](/docs/pitfalls/whole-branch-review) - [CI 绿了不等于能发版](/docs/pitfalls/ci-green-not-ready) - [网络报错先查远端](/docs/pitfalls/verify-remote-first) - [发版靠清单,不靠感觉](/docs/pitfalls/release-checklist) ## 相关 [#相关] - [gstack:上线流水线怎么用](/docs/workflow/gstack) - [REVIEW.md 模板](/docs/templates/review) - [选平台:Vercel 还是 Cloudflare](/docs/product/platform) - 上一步:[测试:让 Claude 能自己验证](/docs/product/test) - 下一步:[运维:线上问题变成新的 intent](/docs/product/maintain) # 测试:让 Claude 能自己验证 (/docs/product/test) > 给 agent 一条能自己跑的反馈回路:一条命令验证、先写失败的测试、UI 改动亲眼看到,用证据判断完成 测试阶段要做到一件事:**Claude 不靠“我觉得没问题”判断完成**。测试、类型检查、lint 都能由它自己一条命令跑完;修 bug 先写一个会失败的测试;UI 改动必须真的打开看到。你在关卡上看的是证据:命令输出、截图、eval 结果。 | 产物 | 人工关卡 | 衡量指标 | |---|---|---| | 测试输出、截图、eval 结果,贴在 PR 里 | 你审阅证据,而不是听 agent 说“已完成” | agent 改动的 CI 首次通过率;上线后才发现的回归次数 | ## 为什么 [#为什么] Playbook 这一招的标题就是“给 Claude 一个反馈回路”:让它能验证自己的工作,机械的证据摆在那里,审阅的人才能把注意力放在意图和风险上。没有回路,agent 只能猜;它猜错了,你就得亲自当那个回路。 ## 怎么做 [#怎么做] ### 一条命令跑完验证,写进 CLAUDE.md [#一条命令跑完验证写进-claudemd] 把验证收拢成几条失败时返回非零的命令,写进 CLAUDE.md 的命令一节,并附上正常输出的样子: ```markdown ## 命令 - `bun test`:全部通过时显示 0 fail - `bunx tsc --noEmit`:没有输出即通过 - `bun run lint`:没有报错即通过 报告任何任务完成之前,先跑完这三条,并把输出贴出来。 ``` 最后一句来自 Playbook 的示例,作用是把“验证”变成“完成”定义的一部分。 ### 新行为用 TDD [#新行为用-tdd] ```text /mattpocock-skills:tdd 给账单导出加"按月筛选" ``` Matt 的 tdd 有三条规矩值得照搬: - **先约定在哪一层测**(seam):动手前列出要测的公开接口,你确认之后才写测试 - **先红后绿**:先写一个会失败的测试,再写刚好让它通过的代码,一次只做一个切片 - **重构不在这个循环里**:留到审查阶段做 好测试只通过公开接口验证行为。代码怎么重写,只要行为没变,测试就不该失败。 ### 修 bug:先写失败的测试,再改代码 [#修-bug先写失败的测试再改代码] 让 Claude 先写一个复现问题的测试,确认它因为预期的原因失败,提交;然后只改实现,不许改这个测试。Playbook 建议更进一步:修复任务期间用 hook 拦住对测试文件的修改,或者审查时直接拒绝动了测试的 diff。 难查的 bug 用 `/mattpocock-skills:diagnosing-bugs`。它最核心的是第一步:先造出一条又快又稳、能在这个 bug 上变红的命令;造不出来就停下来向你要环境或日志,绝不凭空猜。有了这条回路,再列 3 到 5 个可以证伪的假设逐个验证,调试日志统一打标记,修完一并清掉。gstack 的 `/investigate` 做的是同一件事,两者选一个当默认,别让两个都自动触发。 ### UI 改动:亲眼看到才算完成 [#ui-改动亲眼看到才算完成] 单测通过不代表界面变了。UI 改动必须真的启动、真的打开、亲眼看到结果: - 用 gstack 的 `/qa` 在真实浏览器里走一遍流程,发现问题直接修;只想要报告用 `/qa-only` - 或者手动走一遍主流程并截图,贴进 PR - 改了 CSS,额外看一眼样式优先级和暗色模式 ### AI 功能:先写 eval [#ai-功能先写-eval] 产品里有 AI 功能时,普通测试兜不住。Playbook 的做法:从最近的真实任务里挑 20 到 50 个,每个写成“提示词加验收检查”;在 CI 里定时跑,每次改提示词、skill、hook 也要重跑;通过率下降的改动先审再合并;每次线上事故都变成一个新的 eval。 如果你做的是 Claude Code 插件或 skill,`claude plugin eval` 可以跑插件自带的评测用例。 ## 补上“完成前验证” [#补上完成前验证] superpowers 有一个 verification-before-completion skill,强制 agent 在宣布完成之前拿出证据。Matt 的 skill 里没有直接对应的,我用三样东西补: - **CLAUDE.md 里的规则**:上面那句“先跑完这三条,并把输出贴出来” - **一个 hook**:会话里没跑过测试就不许结束。hookify 的 README 里有现成的 stop 规则示例 `require-tests-run`(默认不启用),把匹配的命令改成你的 `bun test` 就能用 - **UI 改动跑 gstack `/qa`** 内置的 `/goal` 也能起类似作用:给一个机器能判断的完成条件,例如 `/goal bun test 全部通过,且 bunx tsc --noEmit 没有报错`,每一轮结束后由另一个模型判断条件是否满足,没满足就继续做。 ## 性能修复:先测量,再问六个问题 [#性能修复先测量再问六个问题] 性能问题的日志往往没用。Matt 的 diagnosing-bugs 对性能回归的要求是先建立基线测量(计时、profiler、查询计划),再二分定位,先测量后修复。 修复上线之前,回答这六个问题,答不出就不上线: 1. 是在修一个 bug,还是砍掉了一个保护? 2. 有没有引入竞态? 3. 类似的地方都改全了吗? 4. 改完之后,能观测到它真的生效了吗? 5. 边界情况呢:空、超大、unicode、错误输入? 6. 它会怎么失败?失败了怎么发现? ## 常见坑 [#常见坑] - [亲眼看到才算完成](/docs/pitfalls/see-it-to-ship):一个全屏按钮的单测通过了,真实界面毫无变化 - [性能修复先问六个问题](/docs/pitfalls/perf-fix-six-questions) - [CI 绿了不等于能发版](/docs/pitfalls/ci-green-not-ready) ## 相关 [#相关] - [用 hook 兜底](/docs/guardrails/hooks) - [gstack:上线流水线怎么用](/docs/workflow/gstack) - 上一步:[开发:先出计划,再写代码](/docs/product/build) - 下一步:[发布:AI 审查,人来批准](/docs/product/ship) # 关于 (/docs/reference/about) > 作者、许可、写作标准与反馈方式 这本手册是我的个人作品:文字以 CC BY 4.0 开放,插件和代码用 MIT;所有页面遵守同一套写作标准,发现错误欢迎在 GitHub 上告诉我。 ## 作者 [#作者] Neo,GitHub [@0xNeoTian](https://github.com/0xNeoTian)。创始人,同时运营两个组织,日常用 Claude Code 写代码、写文档、做部署和运营。为什么写这本手册,见[这里](/docs/why)。 ## 许可 [#许可] - 文字内容:[CC BY 4.0](https://creativecommons.org/licenses/by/4.0/deed.zh-hans)。可以转载、改编、商用,请注明出处并附上链接。 - 插件与代码:MIT。 - 分享图使用的字体是 [Noto Sans SC](https://fonts.google.com/noto/specimen/Noto+Sans+SC),以 SIL Open Font License 1.1 授权。 ## 写作标准 [#写作标准] 所有页面遵守同一套标准: - **先结论,后理由**:每页第一段就告诉你要做什么 - **可操作**:能给命令就给命令,命令都核对过真实存在 - **诚实标注可信度**:✅ 亲历、🧪 试用中、📚 业界做法,没验证过的不写成亲历 - **不泄露隐私**:不出现组织名、客户、同事、服务器和账号信息,每次发布前自动扫描 ## 技术 [#技术] [Fumadocs](https://fumadocs.dev)(Next.js)静态导出,部署在 Cloudflare。网站、`llms.txt` 和插件安装包都来自同一份 Markdown 源文件。 ## 声明 [#声明] 本手册是个人作品,与 Anthropic、OpenAI 及文中提到的其他公司和开源项目没有任何关系。文中引用的工具名、产品名归各自所有者。工具和服务会变化,文中的命令和数字以“截至 2026-10”为准,使用前请核对官方文档。 ## 反馈 [#反馈] 发现错误或有建议,欢迎在 GitHub 上联系 [@0xNeoTian](https://github.com/0xNeoTian)。仓库开源后,可以直接提 issue 和 PR。 ## English summary [#english-summary] **AI Native Handbook** is a practical guide to building products with Claude Code, written in Chinese by Neo, a founder who runs two organizations largely together with Claude Code. It turns 70+ real incident retrospectives into a three-tier path (side tool → product → organization), a comparison of the superpowers and Matt Pocock skills workflow plugins, guardrails, 25 cards drawn from real retrospectives, reusable templates, and an installable Claude Code plugin. Every page carries a credibility label: lived, trial, or industry practice. An English edition is planned; meanwhile, the full Chinese text is available at [`/llms-full.txt`](https://ainative.jubao.ai/llms-full.txt) for your own AI tools to read and translate. ## 相关 [#相关] - [为什么写这本手册](/docs/why) - [更新日志](/docs/reference/changelog) - [参考资料](/docs/reference/sources) # 更新日志 (/docs/reference/changelog) > 每个版本改了什么 这一页记录每个版本的实质变化,最新的版本在最上面;措辞和排版上的小修正不单独记。 ## v0.1.2 · 2026-10-16 [#v012--2026-10-16] - [插件](/docs/reference/plugin) `ainative` 升到 0.1.2:根据另一个模型家族(Codex)的三轮独立审查,修复体检与配置合并脚本的隐私和健壮性问题——hook 命令不再输出参数、只统计真实的 skill 和命令调用事件、dry-run 与告警全部脱敏、严格校验 JSON、写入必须与确认过的计划完全一致、备份放在仓库之外。已安装的用户运行 `claude plugin marketplace update ainative` 和 `claude plugin update ainative@ainative` 即可更新 ## v0.1.0 · 2026-10-16 [#v010--2026-10-16] 第一个公开版本。 - 三档路径:[小工具](/docs/tool)、[产品](/docs/product)(AI-native 六阶段)、[组织](/docs/org)(ops 仓、组织级 ops agent、记忆分层、进化回路) - 专题:[流程引擎](/docs/workflow)(superpowers 与 Matt Pocock 的完整对比和迁移方法)、[护栏与安全](/docs/guardrails) - [坑库](/docs/pitfalls):25 张来自真实复盘的卡片,可按阶段和档位筛选 - [模板库](/docs/templates):一页 CLAUDE.md、intent、spec、plan、ADR、复盘、REVIEW.md、子 agent 提示词 - [启动器](/docs/launcher):按档位勾选的交互式清单 - [Claude Code 插件](/docs/reference/plugin) `ainative`:doctor、setup、recommend、new-project、pitfall-check、harvest - 给 AI 读的入口:`/llms.txt`、`/llms-full.txt`,每页可复制 Markdown ## 接下来 [#接下来] - 开源仓库,接受 issue 和 PR - 英文版(`/en/...`,中文链接保持不变):先翻首页、开始、坑库、流程引擎对比和插件说明 - 组织篇的三个进化机制(模板继承、园丁 agent、护栏体检)跑满一个月后,补上实测数据 - Matt Pocock skills 试用满 30 天后,更新对比结论 ## 相关 [#相关] - [开始](/docs) - [关于](/docs/reference/about) # 命令速查 (/docs/reference/commands) > 最常用的 Claude Code、插件、审查、部署与排障命令 这一页收最常用的命令,按场景分组;我还在试的标 🧪,还没亲自用过的标 📚。命令和参数截至 2026-10 核对过;工具更新很快,以 `--help` 和官方文档为准。 ## Claude Code 内置 [#claude-code-内置] | 命令 | 用途 | |---|---| | `Shift+Tab` | 循环切换权限模式,状态栏出现 plan mode on 即进入 Plan mode(也可以直接用 `/plan`):只读探索、先出计划,确认后再执行 | | `/init` | 生成 CLAUDE.md(生成后手动删到一页) | | `/code-review` | 审查当前改动或指定 PR;加 `--comment` 把意见发到 PR | | `/security-review` | 安全审查当前分支的改动 | | `/simplify` | 只做简化与复用清理,不找 bug | | `/goal` | 给一个目标,让 Claude 持续推进到完成(📚) | | `/schedule` | 创建定时运行的云端 agent(🧪) | | `/fewer-permission-prompts` | 扫描历史,生成常用只读命令的放行列表 | | `/install-github-app` | 安装 Claude GitHub App,PR 和 Issue 里可以 @claude(📚) | | `/plugin`、`/mcp`、`/hooks`、`/memory` | 管理插件、MCP、hook、记忆 | | `claude -w <名字>` | 新建一个 git worktree 并在里面开会话,适合并行任务 | | `claude --add-dir <目录>` | 本次会话额外允许访问一个目录(例如 ops 仓) | | `claude -c` | 继续最近一次会话 | ## 插件管理 [#插件管理] ```bash claude plugin install @ # 安装 claude plugin enable @ # 启用 claude plugin disable @ # 停用(不卸载,可随时开回来) claude plugin uninstall @ # 卸载 claude plugin details @ # 组件清单与常驻 token 成本 claude plugin marketplace add # 添加插件市场 claude plugin marketplace update [name] # 更新插件市场 claude plugin marketplace list # 列出插件市场 ``` ## 流程引擎(Matt Pocock skills,🧪 试用中) [#流程引擎matt-pocock-skills-试用中] | 命令 | 用途 | |---|---| | `/mattpocock-skills:grill-me` | 一轮轮拷问需求,每题给推荐答案 | | `/mattpocock-skills:grill-with-docs` | 拷问的同时写 ADR 和术语表 | | `/mattpocock-skills:to-spec` | 把对话整理成 spec | | `/mattpocock-skills:to-tickets` | 拆成带依赖关系的工单 | | `/mattpocock-skills:implement` | 按 spec 或工单实现 | | `/mattpocock-skills:tdd` | 先写失败的测试,再写实现让它通过;重构放到审查阶段(这是该 skill 自己的设计) | | `/mattpocock-skills:diagnosing-bugs` | 难 bug 诊断循环 | | `/mattpocock-skills:handoff` | 把会话压缩成交接文档 | | `/mattpocock-skills:ask-matt` | 不知道用哪个时问它 | ## 审查与上线(gstack) [#审查与上线gstack] | 命令 | 用途 | |---|---| | `/codex` | 用另一个模型家族做独立审查 | | `/cso` | 安全审计 | | `/qa` | 真实浏览器里走一遍流程并修复问题 | | `/review` | 合并前审查 | | `/investigate` | 系统化排查根因 | | `/ship` | 合并基线、跑测试、更新版本与 CHANGELOG、开 PR | | `/canary` | 上线后监控(📚) | ## 部署 [#部署] ```bash # Cloudflare(静态站、Workers) wrangler whoami wrangler deploy # 按 wrangler.jsonc 部署 wrangler tail # 实时日志 # Vercel(Next.js 应用) vercel # 预览部署 vercel --prod # 生产部署(建议放进 ask 规则,先确认) vercel logs --deployment <部署地址> ``` 上线命令放进 ask 规则,每次执行都要你确认;hookify 只能警告或阻止,做不了“确认后放行”。写进项目的 `.claude/settings.json`: ```json { "permissions": { "ask": [ "Bash(vercel --prod *)", "Bash(wrangler deploy *)", "Bash(bunx wrangler deploy *)" ] } } ``` ## 排障 [#排障] ```bash # 网络操作失败后,先确认远端真实状态,再决定要不要重试 git ls-remote origin refs/heads/main git ls-remote --tags origin # 本机代理可能劫持 DNS,用 DoH 验证解析结果 curl -s 'https://dns.google/resolve?name=example.com&type=A' # "之前是这样的":先查历史 git log --oneline -- <文件> git show --stat ``` ## 相关 [#相关] - [工具分工总表](/docs/reference/toolchain) - [启动器](/docs/launcher) # 背后的理念 (/docs/reference/ideas) > 手册借用的五个外部理念:各自的核心主张、用在了哪些页面、原文在哪 这本手册的骨架借了五个外部理念:OpenAI 的 Harness Engineering 决定“给 agent 搭什么环境”,Anthropic 的 AI-native SDLC 决定“产品篇每个阶段产出什么、谁来把关”,Every 的 Compound Engineering 和 Argyris 的双环学习决定“每次事故怎么变成下一次的规则”,Diátaxis 决定“内容怎么分页”。每节讲三件事:核心主张(我的转述,不是原文)、手册哪里用到它、原文链接。 | 理念 | 一句话 | 手册里对应 | |---|---|---| | Harness Engineering | 人掌舵,agent 执行;工程师的活是搭环境 | 一页 CLAUDE.md、护栏、ops 仓指针 | | AI-native SDLC | 每个阶段提交一个产物,关卡由人把守 | 产品篇六阶段、模板库 | | Compound Engineering | 每做完一件事,下一件应该更容易 | 坑库、复盘模板、进化回路 | | 双环学习 | 不只修这次的错,还要改产生错误的规则 | 每张卡的“为什么”和“怎么做” | | Diátaxis | 文档分四种,混在一起写哪种都写不好 | 全站的分区方式 | ## Harness Engineering(OpenAI) [#harness-engineeringopenai] **核心主张。** 2026 年 2 月,OpenAI 的 Ryan Lopopolo 发表了一篇实验报告:一个小团队从空仓库起步,五个月做出约 100 万行代码、合并约 1500 个 PR 的内部产品,没有一行代码是人手写的,全部由 Codex 生成。核心是“人掌舵,agent 执行”:工程师的主要工作变成设计环境、明确意图、搭建反馈回路。几个具体做法: - **给地图,不给说明书**:一个巨大的 AGENTS.md 失败了(挤占上下文、很快过时、没法校验),改成约 100 行的 AGENTS.md 当目录,知识放进结构化的 `docs/`,作为唯一的记录系统 - **agent 看不到的就不存在**:在线文档、聊天记录、人脑里的知识它都访问不到,要不断把上下文推进仓库 - **规则机械执行**:架构约束用自定义 linter 和结构测试强制,报错信息里直接写修复指引;一个定期运行的“文档园丁”agent 扫描过期文档并提 PR - **定期垃圾回收**:agent 连坏模式也照抄,他们把“黄金原则”写进仓库,让后台任务定期扫描偏差、提重构 PR - **卡住时问缺了什么**:缺工具、护栏还是文档,补进仓库,而不是让 agent“再努力一点” **手册哪里用到。** - [一页 CLAUDE.md](/docs/templates/claude-md):只放每次都要遵守的规则和指针,就是“给地图” - [ops 放哪](/docs/org/ops-repo) 和 [跨仓链接用完整地址](/docs/pitfalls/absolute-cross-repo-links):仓库之外 agent 看不见,独立 ops 仓要用指针和 `permissions.additionalDirectories` 显式接进来 - [权限规则](/docs/guardrails/permissions) 和 [用 hook 兜底](/docs/guardrails/hooks):能写进系统的规则,就不写进提示词 - [跟代码绑定的文档跟代码放一起](/docs/pitfalls/code-coupled-docs):文档里的检查步骤改成 CI - [园丁 agent](/docs/org/evolve):我还在试 **原文**:Ryan Lopopolo,[Harness engineering: leveraging Codex in an agent-first world](https://openai.com/index/harness-engineering/),OpenAI,2026-02-11。 ## AI-native SDLC(Anthropic) [#ai-native-sdlcanthropic] **核心主张。** 代码不再是瓶颈之后,瓶颈移到了构建前后仍按人的速度运转的环节:规划、审查和测试、发布。逐行人工审查、按周开会的审批,跟不上 agent 的产出。这份 playbook 把软件生命周期拆成 Plan、Design、Build、Test、Deploy、Maintain 六个阶段,给出 12 招,把流程从直线改成闭环: - 每个阶段结束时往版本库提交一个产物:intent.md、spec.md、plan.md、diff 和测试、带审查结论的 PR、事故记录。下一阶段从读它开始,提交链本身就是审计记录 - 人守在关卡上:产品负责人确认 intent、签字 spec,工程师确认 plan;写代码的 agent 没有办法批准自己的代码,审批经分支保护由人完成 - 线上指标越出正常范围时,诊断结果写成新的 intent.md,回到规划 - 先手动推进每一步,最终让每个被接受的产物自动触发下一道关卡;从依赖图里没有前置依赖的那几招开始 **手册哪里用到。** [产品篇](/docs/product) 的六阶段结构直接来自它;[intent](/docs/templates/intent)、[spec](/docs/templates/spec)、[plan](/docs/templates/plan) 模板对应前三个产物;[发布](/docs/product/ship) 和 [运维](/docs/product/maintain) 对应后面的关卡和闭环。我的主要改动是缩尺寸:原文写给大企业,尤其是受监管的行业,而这本手册的读者常常一个人兼任产品负责人、工程师和审批人。所以“人工关卡”变成“你必须在这几个点停下来看”,再用[异构模型二审](/docs/pitfalls/cross-model-review)补上第二双眼睛。 **原文**:Anthropic,[The AI-native SDLC playbook](https://claude.com/resources/articles/the-ai-native-sdlc-playbook)(作者 Louis Claxton,2026-08-21);课程版在 [Claude Academy](https://academy.claude.com/courses/ai-native-sdlc-playbook)。 ## Compound Engineering(Every) [#compound-engineeringevery] **核心主张。** 传统工程里,每加一个功能,下一个更难做;复利工程反过来,要求每个功能让下一个更容易。办法是建立学习回路:每个 bug、每次失败的测试、每个解决问题时的顿悟,都记录下来给以后的 agent 用。循环分四步:Plan(agent 调研并写出详细计划)、Work(agent 按计划写代码和测试)、Review(工程师审查产出,也审查从中得到的教训)、Compound(把结果喂回系统,让下一轮更好)。按他们的估计,大约 80% 的功夫在计划和审查,20% 在执行和沉淀。经验写成提示词,放进代码库或插件,团队每个人都能直接用上。Every 把这套流程做成了开源插件,其中 `/ce-compound` 把经验写进 `docs/solutions/`。 **手册哪里用到。** [坑库](/docs/pitfalls) 本身就是 Compound 这一步的产物:每张卡来自一次复盘,最后落到可执行的做法。[复盘模板](/docs/templates/retro) 留了一节“Harness 反馈”;[记忆分层](/docs/org/memory) 规定了沉淀路径:反馈记忆 → playbook / runbook → hook;[附带插件](/docs/reference/plugin) 里的 harvest skill 负责从复盘里提炼规则。 坦白说,我的短板正好在 Compound 的后半段:沉淀很勤,一年 70 多篇复盘、200 多条记忆,但回流不够。规则自动生效、定期体检、模板继承还在补,[组织篇](/docs/org/evolve) 里都标了试用中。 **原文**:Dan Shipper、Kieran Klaassen,[Compound Engineering: How Every Codes With Agents](https://every.to/chain-of-thought/compound-engineering-how-every-codes-with-agents)(Every);插件仓库 [EveryInc/compound-engineering-plugin](https://github.com/EveryInc/compound-engineering-plugin)。 ## 双环学习(Argyris 与 Schön) [#双环学习argyris-与-schön] **核心主张。** 单环学习是发现偏差后修正行动,但不质疑背后的目标和规则;双环学习是回头修改产生偏差的那条规则或假设。Argyris 用温控器打比方:温度低了就开暖气,是单环;会问“为什么设在这个温度,换一个是不是更合适”,才是双环。他在 1991 年的文章里还指出,最聪明、受过最好教育的专业人士,并不像大家以为的那样善于学习。 **手册哪里用到。** 每次事故都问两层:单环问“这次怎么修好”,双环问“是哪条规则(或者缺了哪条规则)让它发生,要改什么才不会再发生”。所以每张卡的“为什么会这样”要写到规则层面,“怎么做”要落到可执行的机制上:权限规则、hook、CI 断言、模板,而不是“下次注意”。例子是[防护规则会悄悄失效](/docs/pitfalls/guardrails-decay):单环是把三层护栏补回来;双环是承认“护栏会失效”本身需要机制,于是有了[护栏体检](/docs/guardrails/health-check),以及“同一个坑出现两次就起草 hook”的规定。 **原文**:Chris Argyris,[Double Loop Learning in Organizations](https://hbr.org/1977/09/double-loop-learning-in-organizations)(Harvard Business Review,1977 年 9 月);[Teaching Smart People How to Learn](https://hbr.org/1991/05/teaching-smart-people-how-to-learn)(Harvard Business Review,1991 年 5 月)。系统的理论见 Argyris 与 Donald Schön 1978 年合著的 *Organizational Learning: A Theory of Action Perspective*。 ## Diátaxis(Daniele Procida) [#diátaxisdaniele-procida] **核心主张。** 文档有四种,各自回应读者一种需要:教程带着学习者动手做一遍;操作指南帮已经会的人完成具体目标;参考提供准确完整、供查阅的事实;解释提供背景,回答“为什么”。教程和指南关乎“做”,参考和解释关乎“知道”;教程和解释服务于学习,指南和参考服务于干活。几种需要混在一页里写,哪种都满足不好。 **手册哪里用到。** 全站按这四类分区: - 教程:[小工具篇](/docs/tool) 的 30 分钟起步、[启动器](/docs/launcher) - 操作指南:[产品篇](/docs/product) 各阶段、[迁移指南](/docs/workflow/migrate)、每张坑卡的“怎么做” - 参考:[命令速查](/docs/reference/commands)、[工具分工总表](/docs/reference/toolchain)、[模板库](/docs/templates) - 解释:[为什么写这本手册](/docs/why)、本页 我自己的延伸:给 agent 看的文档也适用。CLAUDE.md 是参考(一张地图),runbook 是操作指南,ADR 是解释。一份文件只担一种角色,agent 才知道什么时候该读它。 **原文**:[diataxis.fr](https://diataxis.fr/),站点的 [Colophon](https://diataxis.fr/colophon/) 写明 Diátaxis 是 Daniele Procida 的工作。 ## 相关 [#相关] - [为什么写这本手册](/docs/why) - [参考资料](/docs/reference/sources) - [产品:AI-native 开发六阶段](/docs/product) - [让 ops 和项目一起进化](/docs/org/evolve) # 本手册的 Claude Code 插件 (/docs/reference/plugin) > 一条命令安装:体检、安装配置、推荐、新项目、坑检查、复盘提炼 这本手册同时是一个 Claude Code 插件,名字叫 `ainative`。装好之后,Claude 可以按手册的方法帮你做六件事:给环境体检、按档位配置工具链、推荐方案、起新项目、拿坑库审查改动、把复盘提炼成卡片。插件刚发布,标为 🧪 试用中。 ## 安装 [#安装] ```bash claude plugin marketplace add https://ainative.jubao.ai/marketplace.json claude plugin install ainative@ainative ``` 装完重启 Claude Code。安装包托管在本站,`marketplace.json` 里带有安装包的 sha256 校验值。 ## 六个 skill [#六个-skill] | 调用 | 做什么 | 会不会改你的东西 | |---|---|---| | `/ainative:doctor` | 体检:插件和 skill 是否冗余或互相抢触发、权限规则和 hook 是否还在、配置有没有被切换工具覆盖、当前项目处在哪一档、文档目录是否齐全 | 只读,不改任何文件 | | `/ainative:setup` | 按档位和流程引擎,装好推荐的插件、合并权限规则、设置 skill 开关 | 会改,但先出计划、先备份,等你确认后才执行 | | `/ainative:recommend` | 根据项目情况推荐档位、部署平台、流程引擎和插件组合,每项给一个推荐、一个替代 | 只读 | | `/ainative:new-project` | 按档位走完第 0 步:建仓库、一页 CLAUDE.md、intent、最小护栏 | 会改,每个写操作先确认 | | `/ainative:pitfall-check` | 用坑库逐条审查当前计划、spec 或分支改动,只报告真正命中的问题 | 只读 | | `/ainative:harvest` | 把一篇复盘提炼成坑卡草稿,并做脱敏检查 | 只把草稿写到你指定的目录 | ## 用法示例 [#用法示例] - 刚接手一台新电脑或一个老项目:先跑 `/ainative:doctor`,看 P0 问题。 - 要开新项目:`/ainative:recommend` 先定档位和平台,再 `/ainative:new-project`。 - 准备合并一个大分支:`/ainative:pitfall-check`,再走[发布流程](/docs/product/ship)里的异构模型二审。 - 刚写完一篇事故复盘:`/ainative:harvest`,把它变成下一次能用上的规则。 ## 隐私 [#隐私] 体检时,采集脚本会在本机统计最近一段时间里各个 skill 的调用次数,用来判断哪些插件真正在用。它只解析会话记录里的事件元数据(哪个 skill、哪个命令被调用),**不输出任何对话内容**;hook 命令只报告程序名和脚本路径,不输出参数;脚本本身也不联网。 需要说清楚的一点:体检结果(已对密钥打码)会交给你当前的 Claude Code 会话,由模型解读后给出建议。这和你平时发给模型的其他内容一样,受你所用服务的数据政策约束。介意的话,可以先单独运行采集脚本,自己看一遍输出再决定是否交给模型。 ## 更新与卸载 [#更新与卸载] ```bash claude plugin marketplace update ainative # 刷新插件市场的版本信息 claude plugin update ainative@ainative # 更新插件本身,重启 Claude Code 或运行 /reload-plugins 后生效 claude plugin uninstall ainative@ainative # 卸载 ``` ## 相关 [#相关] - [护栏体检:防止静默失效](/docs/guardrails/health-check) - [插件不是越多越好](/docs/pitfalls/plugin-bloat) - [工具分工总表](/docs/reference/toolchain) # 参考资料 (/docs/reference/sources) > 本手册引用的原始来源:方法论文章、Claude Code 官方文档、开源项目和平台文档 这一页按类别列出手册引用的原始来源,每条一句话说明它在手册里的用处。链接在 2026-10-16 逐一打开核对过;外部内容会更新,引用时以原文为准。方法论怎么被用到手册里,见[背后的理念](/docs/reference/ideas)。 ## 方法论与文章 [#方法论与文章] - [The AI-native SDLC playbook](https://claude.com/resources/articles/the-ai-native-sdlc-playbook):Anthropic,2026-08-21。六个阶段、12 招、每个阶段的产物和人工关卡,[产品篇](/docs/product)的骨架 - [The AI-native SDLC playbook(Claude Academy 课程版)](https://academy.claude.com/courses/ai-native-sdlc-playbook):同一内容按课时拆开,每招一课 - [Harness engineering: leveraging Codex in an agent-first world](https://openai.com/index/harness-engineering/):OpenAI,Ryan Lopopolo,2026-02-11。人掌舵、agent 执行;AGENTS.md 当地图,`docs/` 当记录系统 - [Compound Engineering: How Every Codes With Agents](https://every.to/chain-of-thought/compound-engineering-how-every-codes-with-agents):Every,Dan Shipper、Kieran Klaassen。Plan → Work → Review → Compound 的复利循环 - [EveryInc/compound-engineering-plugin](https://github.com/EveryInc/compound-engineering-plugin):复利工程的开源插件实现 - [Double Loop Learning in Organizations](https://hbr.org/1977/09/double-loop-learning-in-organizations):Chris Argyris,Harvard Business Review,1977 年 9 月。双环学习的出处 - [Teaching Smart People How to Learn](https://hbr.org/1991/05/teaching-smart-people-how-to-learn):Chris Argyris,Harvard Business Review,1991 年 5 月。温控器比喻、聪明人为什么不擅长学习 - [Diátaxis](https://diataxis.fr/):Daniele Procida 的文档框架,教程、操作指南、参考、解释四分类,本站分区的依据 ## Claude Code 官方文档 [#claude-code-官方文档] - [Settings](https://code.claude.com/docs/en/settings):用户级、项目级、local、托管设置的位置和优先级 - [Settings reference](https://code.claude.com/docs/en/settings-reference):每个设置项的作用域与取值,如 `skillOverrides`、`autoMemoryDirectory`、`enabledPlugins`、`cleanupPeriodDays` - [Permissions](https://code.claude.com/docs/en/permissions):deny / ask / allow 规则写法,按参数匹配的规则(如 `Agent(model:...)`) - [Hooks](https://code.claude.com/docs/en/hooks):hook 事件、输入输出、决策控制 - [Skills](https://code.claude.com/docs/en/skills):skill 如何被触发、`skillOverrides` 的范围(不作用于插件 skill)、`/skill-doctor` - [Subagents](https://code.claude.com/docs/en/sub-agents):子 agent 定义、模型选择顺序、`CLAUDE_CODE_SUBAGENT_MODEL_FORCE` - [Memory](https://code.claude.com/docs/en/memory):CLAUDE.md 与自动记忆、存储位置、`MEMORY.md` 的加载上限 - [Plugins](https://code.claude.com/docs/en/plugins):插件的安装、启用与组成 - [Plugin marketplaces](https://code.claude.com/docs/en/plugin-marketplaces):自建和分发插件市场 - [Manage plugins for your organization](https://code.claude.com/docs/en/plugins/org):在仓库设置里声明市场和插件,团队成员自动获得 - [Managed settings](https://code.claude.com/docs/en/managed-settings):托管设置的文件路径、下发方式和优先级 - [Worktrees](https://code.claude.com/docs/en/worktrees):`claude --worktree` 并行开发,worktree 建在 `.claude/worktrees/` 下 - [MCP](https://code.claude.com/docs/en/mcp):添加和授权 MCP 服务器 - [GitHub Actions](https://code.claude.com/docs/en/github-actions):在 PR 和 Issue 里使用 Claude - [Commands](https://code.claude.com/docs/en/commands):内置命令清单,如 `/context`、`/skills`、`/tasks`、`/status` - [Changelog](https://code.claude.com/docs/en/changelog):版本变更记录,核对“某功能从哪个版本开始” ## 流程引擎与插件 [#流程引擎与插件] - [mattpocock/skills](https://github.com/mattpocock/skills):Matt Pocock 的 skill 集合,当前的主流程引擎(试用中) - [obra/superpowers](https://github.com/obra/superpowers):用 SessionStart hook 自动注入、强制完整开发流程的上一代主引擎 - [garrytan/gstack](https://github.com/garrytan/gstack):按角色和流水线组织的 slash 命令,负责二审、安全审计、真实浏览器、发版 - [anthropics/claude-plugins-official](https://github.com/anthropics/claude-plugins-official):Claude Code 官方插件市场,hookify、session-report、security-guidance、claude-code-setup 都在这里 - [anthropics/claude-code-action](https://github.com/anthropics/claude-code-action):Claude 的 GitHub Action,每个 PR 自动审查 - [yannikzz/ui-contract](https://github.com/yannikzz/ui-contract):管“新功能放页面哪个区域”的结构约定 - [upstash/context7](https://github.com/upstash/context7):查询最新库文档的 MCP ## 其他工具 [#其他工具] - [openai/codex](https://github.com/openai/codex):OpenAI 的命令行 agent,用来做异构模型二审 - [cloudflare/mcp](https://github.com/cloudflare/mcp):Cloudflare 官方 API MCP 服务器,`search` 和 `execute` 两个工具覆盖整个 Cloudflare API - [Cloudflare's own MCP servers](https://developers.cloudflare.com/agents/model-context-protocol/cloudflare/servers-for-cloudflare/):Cloudflare 官方 MCP 服务器列表与接入说明 - [farion1231/cc-switch](https://github.com/farion1231/cc-switch):模型供应商切换工具,见[切换工具会整份覆盖设置](/docs/pitfalls/config-overwrite) - [lycheeverse/lychee](https://github.com/lycheeverse/lychee) 和 [lychee-action](https://github.com/lycheeverse/lychee-action):链接检查工具及其 GitHub Action - [Fumadocs](https://fumadocs.dev/):本站使用的文档框架 - [OpenNext for Cloudflare](https://opennext.js.org/cloudflare):把 Next.js 应用部署到 Cloudflare 的适配层 ## 平台与网络 [#平台与网络] - [vercel domains](https://vercel.com/docs/cli/domains) 和 [vercel alias](https://vercel.com/docs/cli/alias):Vercel CLI 的域名与别名命令 - [Removing a domain](https://vercel.com/docs/domains/working-with-domains/remove-a-domain):从项目移除和从账号移除域名的区别 - [List DNS Records](https://developers.cloudflare.com/api/resources/dns/subresources/records/methods/list/):Cloudflare API 列出一个 zone 下的全部 DNS 记录 - [Google Public DNS JSON API](https://developers.google.com/speed/public-dns/docs/doh/json):用 HTTPS 查询 DNS 的 JSON 接口,验证 DNS 时绕开本机代理 - [RFC 6890](https://www.rfc-editor.org/rfc/rfc6890.html) 和 [RFC 2544](https://www.rfc-editor.org/rfc/rfc2544.html):198.18 开头的地址段为网络基准测试保留 ## 对比与盘点(第三方) [#对比与盘点第三方] - [Superpowers vs Matt Pocock's skills: two opposite bets on who runs your agent](https://www.nocoders.com/blog/superpowers-vs-pocock-agent-skills/):nocoders,2026-06-26。自动注入与手动调用两种思路的对比 - [superpowersとmattpocock/skills 両方使って分かった哲学の違いと選び方](https://zenn.dev/kanagen/articles/claude-code-skills-superpowers-vs-mattpocock):Zenn(日文),2026-06-09。两者都用过之后的选择建议 - [superpowers vs gstack](https://www.agentiquette.com/compare/superpowers-vs-gstack):Agentiquette,2026-07-07 评分。流程纪律与流水线覆盖面的分项对比 - [The Best Claude Code Skills in 2026](https://www.buildthisnow.com/blog/guide/mechanics/best-claude-code-skills-2026):BuildThisNow,2026-09-24。按 token 成本挑 skill,gstack 建议只装用得到的几个 ## 相关 [#相关] - [背后的理念](/docs/reference/ideas) - [工具分工总表](/docs/reference/toolchain) - [命令速查](/docs/reference/commands) # 工具分工总表 (/docs/reference/toolchain) > 每件事由哪个工具负责,每个工具标了可信度和安装方式 **同一件事只交给一个工具负责。** 工具一多,最常见的问题不是缺功能,而是几个工具抢着做同一件事:一句“帮我 debug”被三个框架同时接住,流程前后不一致。下面这张表是我现在的分工,可信度标签说明了哪些是用了很久的,哪些还在试。 ## 按阶段分工 [#按阶段分工] | 阶段 | 主力 | 补充 | 人工关卡 | |---|---|---|---| | 起步 | 内置 `/init`、`/ainative:setup` | hookify 护栏、ui-contract(UI 项目) | 你确认 CLAUDE.md 不超过一页 | | 规划 | `/mattpocock-skills:grill-me` | gstack `/office-hours` | 你确认 intent | | 设计 | `/mattpocock-skills:grill-with-docs` → `to-spec` | `domain-modeling`、`prototype`、ui-contract | 产品负责人签字 | | 开发 | Plan mode → `/mattpocock-skills:implement` | `tdd`、`to-tickets`、`wayfinder`、worktree | 工程师确认计划 | | 测试 | `/mattpocock-skills:tdd` + gstack `/qa` | `diagnosing-bugs` | 代码所有者看证据 | | 发布 | 内置 `/code-review` + gstack `/codex` 异构二审 | `/security-review`、gstack `/cso`、`/ship` | 人批准,写代码的 agent 不能批自己 | | 运维 | gstack `/canary`、`/investigate` | `/ainative:harvest`、`/schedule` 园丁 | 服务负责人决定处置 | 流程引擎这一列以 Matt Pocock skills 为主。我用了一年的 superpowers 已经停用,两者的取舍见[完整对比](/docs/workflow/superpowers-vs-matt)。 ## 插件与工具清单 [#插件与工具清单] | 工具 | 负责什么 | 可信度 | 安装 | |---|---|---|---| | Matt Pocock skills | 流程引擎:拷问、spec、工单、实现、TDD、审查 | 🧪 试用中 | `claude plugin install mattpocock-skills@claude-plugins-official` | | superpowers | 上一代流程引擎:自动强制完整流程 | ✅ 亲历(已停用) | `claude plugin install superpowers@claude-plugins-official` | | gstack | 上线流水线:二审、安全审计、真实浏览器、发版 | ✅ 亲历(部分命令) | 见 [gstack 页](/docs/workflow/gstack) | | hookify | 用一句话生成 hook 护栏 | 🧪 试用中 | `claude plugin install hookify@claude-plugins-official` | | context7 | 查最新的库文档 | ✅ 亲历 | `claude plugin install context7@claude-plugins-official` | | typescript-lsp / gopls-lsp | 代码智能 | ✅ 亲历 | `claude plugin install typescript-lsp@claude-plugins-official` | | session-report | token、缓存、subagent 开销报告 | 🧪 试用中 | `claude plugin install session-report@claude-plugins-official` | | ui-contract | UI 结构约定:“新功能放页面哪里” | 🧪 试用中 | 见[设计阶段](/docs/product/design) | | Cloudflare 官方 MCP | 全量 Cloudflare API:DNS、Zone 设置、Workers、R2 | ✅ 亲历 | `claude mcp add --transport http --scope user cloudflare-api https://mcp.cloudflare.com/mcp` | | Codex CLI | 另一个模型家族的独立二审 | ✅ 亲历 | 见 [Codex CLI 官方仓库](https://github.com/openai/codex) | | claude-code-setup | 新仓库只读扫描,推荐 hook / skill / MCP | 📚 业界做法 | `claude plugin install claude-code-setup@claude-plugins-official` | | Claude GitHub Action | 每个 PR 自动 AI 审查 | 📚 业界做法 | 在仓库里运行 `/install-github-app` | | 本手册插件 ainative | 体检、配置、推荐、新项目、查坑、提炼复盘 | 🧪 试用中 | 见[插件说明](/docs/reference/plugin) | ## 不建议装的 [#不建议装的] - **和内置功能重复的插件**。Claude Code 已经内置 `/code-review`、`/simplify`、`/security-review`,再装同类插件只会多一份常驻上下文、多一个抢触发的对象。 - **一次性装一整个合集**。大合集里多数 skill 你一年也用不到一次。我曾经装了 39 个插件、73 个 subagent,按 90 天真实调用统计后精简到 16 个插件、19 个 subagent。见[插件不是越多越好](/docs/pitfalls/plugin-bloat)。 - **两套同时自动触发的流程框架**。要试新的,就把其中一套设为只能手动调用。见[迁移方法](/docs/workflow/migrate)。 ## 怎么检查自己的工具链 [#怎么检查自己的工具链] ```bash claude plugin details <插件名>@ # 组件清单与常驻 token 成本 ``` 或者装好[本手册插件](/docs/reference/plugin)后运行 `/ainative:doctor`:它会统计最近各个 skill 的调用次数,指出冗余、冲突和缺失的护栏。 ## 相关 [#相关] - [流程引擎、流水线与专项工具](/docs/workflow) - [命令速查](/docs/reference/commands) - [同一时间只让一套流程自动接管](/docs/pitfalls/one-process-engine) # ADR 模板 (/docs/templates/adr) > 记录一个决策:背景、决定、后果、为什么没选别的 ADR(Architecture Decision Record,架构决策记录)记一个决定:当时的背景、决定了什么、为什么没选别的、会带来什么后果。不是每个决定都值得写,只记那些半年后会有人问“当初为什么这样做”的。单仓产品放 `docs/adr/`,跨仓库、组织或商业层面的决定放 ops 仓的 `decisions/`,命名 `ADR-NNN_.md`。 ## 什么时候写 [#什么时候写] Matt Pocock 的 domain-modeling skill 给了一个好用的判断:三条同时成立才写。 - **难以逆转**:以后改主意的代价不小 - **没有上下文会让人困惑**:后来的人看到代码会想“为什么要这样做” - **是一次真实的取舍**:确实有别的选项,你出于具体原因选了这一个 三条缺一条就不用写:容易逆转的,改回来就是了;不让人意外的,没人会问;没有真实替代方案的,没什么可记。典型值得写的:技术选型里会被锁定的那部分(数据库、认证服务、部署平台),模块之间的边界,以及故意偏离常规做法的地方,比如“我们不用 ORM,因为……”。 ## 模板 [#模板] ```markdown # ADR-NNN:<一句话写清决定> - 状态:提议 / 已采纳 / 已废弃 / 被 ADR-NNN 取代 - 日期:YYYY-MM-DD - 决策人: - 相关:(spec、Issue、PR 的链接) ## 背景 (当时面对什么问题,有哪些约束,哪些是代码里看不出来的) ## 决定 (决定了什么,用肯定句写) ## 为什么没选别的 | 方案 | 没选的原因 | |---|---| ## 后果 - 好处: - 代价: - 什么情况下要重新考虑: ``` ## 示例 [#示例] ```markdown # ADR-007:标签存成独立的表,不用数组字段 - 状态:已采纳 - 日期:2026-10-16 - 决策人:技术负责人 - 相关:docs/specs/2026-10-16_todo-tags.md ## 背景 待办要支持标签和按标签筛选,后续可能做标签统计。每条待办最多 10 个标签,标签名不区分大小写。 ## 决定 新建 tags 表和 todo_tags 关联表,标签名存小写形式并加唯一约束。 ## 为什么没选别的 | 方案 | 没选的原因 | |---|---| | 在 todos 表加文本数组字段 | 改名要逐行更新;不区分大小写的去重和统计都麻烦 | | 存成 JSON 字段 | 这个项目要靠数据库约束保证标签名不重复,放进 JSON 就只能靠应用代码;标签改名要逐条改写待办里的 JSON;去重和校验逻辑散在应用里,长期维护成本高 | ## 后果 - 好处:去重靠数据库约束保证;按标签筛选可以走索引 - 代价:多一次关联查询;迁移多两张表 - 什么情况下要重新考虑:如果标签要支持层级(父子标签),重新评估数据结构 ``` ## 每一节怎么填 [#每一节怎么填] | 节 | 怎么填 | 最容易犯的错 | |---|---|---| | 标题 | 一句话写清决定本身 | 写成问题,比如“关于标签存储的讨论” | | 状态 | 提议、已采纳、已废弃、被取代 | 改主意时直接改旧 ADR 的内容。应该新写一篇,在旧的那篇标“被 ADR-NNN 取代” | | 背景 | 写当时的约束,尤其是代码里看不出来的(合规、合同、团队能力) | 只写决定不写背景,半年后没人知道当时为什么受限 | | 决定 | 用肯定句,一两句话 | 写成“倾向于”“可能会”,读完不知道到底定没定 | | 为什么没选别的 | 列出真正考虑过的方案和否掉的原因 | 不写被否的方案,过几个月又有人把它当新主意提出来 | | 后果 | 好处、代价都写,再写重新考虑的条件 | 只写好处;不写重新考虑的条件,决定就永远没人敢动 | ## 写短一点也没关系 [#写短一点也没关系] Matt 的写法更简:一个标题加一到三句话,说清背景、决定、原因就够了,状态、备选方案、后果只在有价值时才加。用 `/mattpocock-skills:grill-with-docs` 拷问时,它会在出现值得记录的决定时提议写 ADR,默认文件名是 `docs/adr/0001-.md` 这种四位编号。两种命名选一种,在同一个仓库里保持一致即可。 ## 相关 [#相关] # 一页 CLAUDE.md (/docs/templates/claude-md) > 只放每次都要遵守的规则:技术栈、命令、禁区和指针 CLAUDE.md 每个会话开头都会被读进上下文,所以只放“每次都要遵守”的东西:项目一句话、技术栈、常用命令、文档指针、工作流程硬规则、禁区。控制在一页以内。官方建议每个文件不超过 200 行,一页只是更严格的版本:写得越长,规则越容易被忽略。先用 `/init` 生成初稿,再按下面的模板删到一页。 ## 模板 [#模板] ```markdown title="CLAUDE.md" # 待办应用(todo-app) 给个人用户的待办清单 Web 应用,支持标签、筛选和提醒。 ## 技术栈 - Next.js(App Router)+ TypeScript strict + Tailwind CSS - Supabase(PostgreSQL + Auth) - 包管理用 bun,部署在 Vercel ## 常用命令 - 开发:bun dev - 测试:bun test - 类型检查:bunx tsc --noEmit - Lint:bun run lint - 本地数据库:bunx supabase start ## 文档在哪 - 需求与设计:docs/specs/(YYYY-MM-DD_.md,开头一节是 intent) - 实现计划:docs/plans/(YYYY-MM-DD_-plan.md) - 决策记录:docs/adr/;术语表:GLOSSARY.md - 运维手册:docs/runbooks/;审查规则:REVIEW.md ## 工作流程(硬规则) - 实质改动先有 spec 再动手;没有就停下来提醒我,不要直接改代码 - 先用 Plan mode 出计划,我确认后再执行 - 测试先行;说"完成"之前贴出测试、类型检查、lint 的命令和结果 - UI 改动要真启动、真打开页面看过,才算完成 ## 禁区(CRITICAL) - 不执行 git reset、git rebase、git push --force,不 amend 已推送的提交;确实需要时先停下问我 - 不提交 .env* 文件;密钥只从环境变量读 - 破坏性数据库操作(reset、DROP、删卷)之前先备份,并等我确认 - 不发布生产环境,由我手动发布 ``` 跑过 `/mattpocock-skills:setup-matt-pocock-skills` 之后,它会在末尾追加一个 `## Agent skills` 小节,指向 `docs/agents/` 下的约定文件,保留即可。 ## 每一节怎么填 [#每一节怎么填] | 节 | 怎么填 | 最容易犯的错 | |---|---|---| | 项目一句话 | 写给第一次打开这个仓库的人:它是什么、给谁用 | 写成一大段背景、愿景和路线图 | | 技术栈 | 只写会影响代码写法的选择:框架、语言模式、包管理、部署平台 | 把 `package.json` 里的依赖再抄一遍 | | 常用命令 | 写能直接复制运行的命令,agent 要靠它们自己验证结果 | 写“运行测试”而不写具体命令。官方文档举的正是这个例子:写“提交前运行 `npm test`”,而不是“测试你的改动” | | 文档在哪 | 只写路径和命名规则,不把内容抄进来 | 用 `@path` 引用整份文档。`@` 会在启动时把整个文件读进上下文;只想提一下路径,就用反引号包起来 | | 工作流程 | 写成能检查的规则,一条一行 | 写“注意代码质量”这类没法判断有没有做到的话 | | 禁区 | 写死不能做的操作,并说明确实需要时怎么办 | 只写在这里。CLAUDE.md 是上下文,不是强制配置,真正要拦住的操作还要配上[权限规则](/docs/guardrails/permissions)或 [hook](/docs/guardrails/hooks) | ## 不放什么 [#不放什么] - **只在某类任务里用到的方法论**:做成 skill,需要时才加载 - **只对部分目录有效的规则**:放进 `.claude/rules/`(用 `paths` 限定路径),或者写在子目录自己的 CLAUDE.md 里 - **个人偏好**:放 `~/.claude/CLAUDE.md`,不要塞进团队共享的文件 - **库的 API 用法**:让 Claude 用 context7 现查,不要凭记忆写进来 - **lint 和类型检查能管的格式规则**:交给工具,机械执行比文字提醒可靠 - **密钥、内部地址、账号**:永远不放,这个文件会进 git ## 和 AGENTS.md 一起用 [#和-agentsmd-一起用] 如果你还用 Codex 这类工具做二审,可以把共用的规则写在 `AGENTS.md`,CLAUDE.md 第一行写 `@AGENTS.md` 导入它,下面再写只给 Claude 的部分。注意 Claude Code 只在没有 CLAUDE.md 的时候才直接读 `AGENTS.md`,两个文件都有时要靠这一行导入。 ## 定期修剪 [#定期修剪] 规则会过时,也会互相打架。官方给了一个检查命令 `/doctor prompt-audit`(需要 Claude Code v2.1.283 或更高),它会找出过时的指令、引用了不存在的文件或命令、以及互相矛盾的地方,只出报告,不会自己改文件。装插件时也留意:有些插件的安装提示会让你往 CLAUDE.md 里加一大段说明,只留你真在用的部分。 ## 相关 [#相关] # 模板库 (/docs/templates) > 直接复制使用的文档模板 这里的 8 个模板覆盖从起步到运维的每个产物,每页都给出可以直接复制的完整正文,并说明每一节怎么填、最容易犯什么错。用法很简单:复制到仓库里约定的位置,删掉不适用的节,再让 Claude 和你一起把空填上。示例统一用“给待办应用加标签”这个通用功能。 ## 模板一览 [#模板一览] | 模板 | 什么时候用 | 放哪 | 命名 | 阶段 | |---|---|---|---|---| | [一页 CLAUDE.md](/docs/templates/claude-md) | 建仓库的第一天,之后持续修剪 | 仓库根目录 | `CLAUDE.md` | 起步 | | [intent](/docs/templates/intent) | 有了想法、工单或告警,动手之前 | spec 的第一节;线上问题回流时可以单独成文 | — | 规划 | | [spec](/docs/templates/spec) | intent 确认之后、实质改动之前 | `docs/specs/` | `YYYY-MM-DD_.md` | 设计 | | [plan](/docs/templates/plan) | spec 确认之后、写代码之前 | `docs/plans/` | `YYYY-MM-DD_-plan.md` | 开发 | | [ADR](/docs/templates/adr) | 做了一个以后会被问“为什么”的决定 | 单仓 `docs/adr/`;跨仓放 ops 仓 `decisions/` | `ADR-NNN_.md` | 设计 | | [复盘](/docs/templates/retro) | 事故之后、项目结束、试用期满 | 单仓 `docs/retros/`;组织放 ops 仓 `retros/` | `YYYY-MM-DD_.md` | 运维 | | [REVIEW.md](/docs/templates/review) | 开始用 AI 审查 PR 的时候 | 仓库根目录 | `REVIEW.md` | 发布 | | [子 agent 提示词](/docs/templates/subagent-prompt) | 每次派子 agent 干活 | 不必存档;常用的整理进 playbook | — | 开发 | `` 用小写英文加连字符,例如 `todo-tags`。同一个功能的 spec、plan、分支名用同一个 slug,agent 和 hook 都能按它找到对应文档。 ## 填模板的三条规矩 [#填模板的三条规矩] - **模板是起点,不是表格。** 删掉不适用的节,比硬填一句“无”强 - **具体到能检查。** “体验要好”没法验收,“一秒内显示”可以写成测试 - **改需求先改文档。** spec 和 plan 是活文档,实现中途发现要改,先改文档再改代码 ## 这些模板之间的关系 [#这些模板之间的关系] 一个功能的典型路径:intent 写在 spec 第一节,spec 确认后出 plan,按 plan 实现,PR 按 REVIEW.md 审查,上线后的问题写成复盘,复盘里的教训回流到 CLAUDE.md、hook 或新的 intent。实现阶段派子 agent 时,用子 agent 提示词模板交代任务。过程中做出的关键决定,单独写成 ADR。 ## 相关 [#相关] # intent 模板 (/docs/templates/intent) > 做什么、为什么、约束、不做什么、成功指标 动手之前,先用不到一页纸写清楚五件事:做什么、为什么、约束、不做什么、成功指标。产品档的项目把它写成 spec 的第一节(`docs/specs/YYYY-MM-DD_.md` 开头的“Intent”);线上问题回流到规划时,也可以先单独写一份,再扩成 spec。写完由你本人确认,这是规划阶段唯一的人工关卡。 ## 为什么要先写 intent [#为什么要先写-intent] Anthropic 的 [AI-native SDLC playbook](https://claude.com/resources/articles/the-ai-native-sdlc-playbook) 把它列为第一招:一份很短、进版本控制的文件,说清要什么、为什么、在什么约束下,然后在一次会话里和 Claude 一起把它变成需求和设计规格;线上指标出了问题,也写成一份新的 intent,重新进入规划。 我的体会是:写代码早就不是瓶颈,慢的是“到底要做什么”。intent 逼你在 agent 动手之前把这件事想清楚,也给后面的 spec、审查、复盘一个可以对照的原点。 ## 模板 [#模板] ```markdown ## Intent - 要做什么:(一句话,写结果,不写方案) - 为什么:(谁、遇到什么问题、为什么是现在) - 约束:(技术、合规、预算、时间,尽量写具体数字) - 不做什么:(明确排除的范围) - 成功指标:(上线后看哪个数、多久看、多少算成功) - 待定问题:(还没想清楚、留给设计阶段回答的) - 来源:(想法 / Issue 链接 / 告警链接) - 确认:(谁、哪天) ``` ## 示例 [#示例] ```markdown ## Intent - 要做什么:让用户给待办加标签,并按标签筛选列表 - 为什么:待办超过 50 条以后,用户反馈很难找到想要的那条;按标签筛选是 Issue 里被提到最多的需求 - 约束:不引入新的付费服务;每条待办最多 10 个标签;两周内上线 - 不做什么:不做标签颜色自定义,不做跨用户共享标签,不做标签批量重命名 - 成功指标:上线 30 天内,周活跃用户里使用过标签筛选的比例达到 20% - 待定问题:标签名要不要限制长度,留到设计阶段定 - 来源:Issue #42 - 确认:产品负责人,2026-10-16 ``` ## 每一项怎么填 [#每一项怎么填] | 项 | 怎么填 | 最容易犯的错 | |---|---|---| | 要做什么 | 一句话,写用户能感知到的结果 | 写成方案,比如“加一张 tags 表和三个接口”,那是 spec 的事 | | 为什么 | 谁、遇到了什么问题、为什么现在做 | 写“提升用户体验”这种没法证伪的话 | | 约束 | 技术、合规、预算、时间,能写数字就写数字 | 只写“尽快”,agent 没法据此取舍 | | 不做什么 | 列出容易被顺手做掉、但这次明确不做的事 | 留空。这一项最容易省略,也最有价值:agent 默认会“顺手”多做 | | 成功指标 | 上线后看哪个数、多久看、多少算成功 | 写“用户喜欢”,或者写了数字却没人会去看 | | 待定问题 | 还没想清楚、留给设计阶段回答的问题 | 不写,然后悄悄按自己的假设往下做 | | 来源 | 想法、Issue、告警的链接 | 不写来源,三个月后没人记得这件事为什么开始 | ## 怎么写出来 [#怎么写出来] 自己对着空白模板硬想,往往会漏掉关键问题。我的做法是先用 `/mattpocock-skills:grill-me` 让 Claude 拷问:它按轮次提问,每题给出推荐答案,问到每个分支都有答案为止,再让它把结论整理成上面的格式。这本手册的需求就是这么定下来的:读者是谁、公开边界在哪、流程引擎选哪个,全部在拷问里拍板,然后才动手。 拿不准值不值得做的新方向,也可以先跑一次 gstack 的 `/office-hours`,它会追问这件事是否真的值得做。 ## 相关 [#相关] # plan 模板 (/docs/templates/plan) > 要改哪些文件、按什么顺序、怎么验证 plan 回答“怎么做”:要改哪些文件、按什么顺序、每一步怎么验证。spec 确认之后,在 Plan mode(`Shift+Tab`)里让 Claude 读 spec 出计划,存到 `docs/plans/YYYY-MM-DD_-plan.md`;你确认计划和风险之后,才开始写代码。改动大的话,计划写完、审完就关掉这个会话,开一个新会话只读计划来执行。 ## 为什么要单独一份 plan [#为什么要单独一份-plan] spec 说的是要什么,不该写文件路径和代码;真正动手时,agent 需要知道改哪些文件、函数签名是什么、每一步用什么命令证明做对了。把这些写成一份能审的文档,有三个好处:你能在动手之前发现方向错了;执行可以交给新会话或子 agent,不依赖聊天记录;审查时可以逐条对照。 这份模板借鉴了我用了一年的 superpowers writing-plans 的两个做法:每一步都要有可检查的结果;单列一节“审查重点”。 ## 模板 [#模板] ```markdown # 实现计划:<功能名> - Spec:docs/specs/YYYY-MM-DD_.md - 分支:feature/ - 执行方式:单个会话 / 拆成工单 / 子 agent 逐个任务执行 ## 全局约束 (从 spec 原样抄过来的硬性要求:上限、命名、文案、版本) ## 文件清单 | 文件 | 新建或修改 | 负责什么 | |---|---|---| ## 任务 ### 任务 1:<名称> - 接口:用到哪些已有接口;产出哪些新接口(写清签名) - [ ] 写失败的测试:<测试名和断言> - [ ] 运行 <命令>,确认失败 - [ ] 实现 <函数签名> - [ ] 运行 <命令>,确认通过 - [ ] 提交 ## 审查重点 (spec 隐含、但上面的测试都没覆盖的输入或失败情况,最多 5 条,每条补一个测试到对应任务) ## 风险与回滚 - 风险: - 回滚办法: ## 验证 - 全量:<测试、类型检查、lint 命令> - 人工:<要亲眼看的页面或流程> ``` ## 示例 [#示例] ```markdown # 实现计划:待办标签 - Spec:docs/specs/2026-10-16_todo-tags.md - 分支:feature/todo-tags - 执行方式:单个会话,3 个任务依次执行 ## 全局约束 - 每条待办最多 10 个标签 - 只有大小写不同的标签名视为同一个 ## 文件清单 | 文件 | 新建或修改 | 负责什么 | |---|---|---| | supabase/migrations/20261016_tags.sql | 新建 | tags 表和关联表 | | src/lib/tags.ts | 新建 | 标签增删查的唯一入口 | | src/app/todos/[id]/tag-input.tsx | 新建 | 标签输入框 | | src/app/todos/page.tsx | 修改 | 按标签筛选 | ## 任务 ### 任务 1:数据层 - 接口:产出 addTag(todoId: string, name: string): Promise - [ ] 写失败的测试:同一条待办加第 11 个标签时抛出 TagLimitError - [ ] 运行 bun test src/lib/tags.test.ts,确认失败 - [ ] 实现 addTag,名称先转小写再查重 - [ ] 运行 bun test src/lib/tags.test.ts,确认通过 - [ ] 提交 ## 审查重点 - 标签名前后带空格:应先去掉空格再查重 - 两个标签页同时给同一条待办加标签:总数也不能超过 10 个 ## 风险与回滚 - 风险:迁移给 todos 加了外键,旧数据里有孤儿记录会导致迁移失败 - 回滚办法:迁移附带 down 脚本;先在本地库演练一遍 ## 验证 - 全量:bun test && bunx tsc --noEmit && bun run lint - 人工:本地打开 /todos,加标签、按标签筛选,截图贴进 PR ``` ## 每一节怎么填 [#每一节怎么填] | 节 | 怎么填 | 最容易犯的错 | |---|---|---| | 全局约束 | 从 spec 原样复制数字和规则 | 转述时丢了数字,比如把“最多 10 个”写成“数量有限制” | | 文件清单 | 每个文件只负责一件事,一起改的文件放在一起 | 漏列文件,执行时 agent 临时决定在哪改 | | 任务 | 每个任务自带测试,能独立审、独立通过;每一步是一个动作加一个可检查的结果 | 把计划写成代码誊抄。计划记录的是决定:签名、断言、要用的值,不是把实现提前写一遍 | | 审查重点 | spec 隐含、测试没覆盖的输入,比如空值、超长、并发、重复 | 空着不写。一份 spec 不可能列全所有输入,它没提到的输入并不等于可以崩溃 | | 风险与回滚 | 写清最坏情况和怎么退回去 | 只写“风险低” | | 验证 | 写可以直接运行的命令,加上要亲眼看的地方 | 只写“跑一下测试”;UI 改动不写人工验证 | 还有两个和计划本身无关、但最常出事的地方: - **没确认就执行。** 你点头同意的是方向,不是这份你还没看过的计划。存盘、读一遍、确认了再动手 - **计划和执行挤在一个会话里。** 大任务写计划就会耗掉大半上下文,执行阶段质量明显下降(见[计划和执行分开会话](/docs/pitfalls/split-plan-exec)) 大功能一份计划装不下时,用 `/mattpocock-skills:to-tickets` 拆成带依赖关系的工单,每张工单各自出计划;跨好几个会话的大工程,用 `/mattpocock-skills:wayfinder` 在 Issue 上维护决策地图。 ## 相关 [#相关] # 复盘模板 (/docs/templates/retro) > 做了什么、为什么、遇到什么、下次怎么做,外加一节 Harness 反馈 复盘写四件事:做了什么、为什么这么做、遇到了什么、下次怎么做;再加一节 **Harness 反馈**:这次的问题,该改 agent 工作环境里的哪个地方(CLAUDE.md、hook、权限、检查脚本、文档指针),才不会再犯。事故之后、项目结束、工具试用期满都写一篇。单仓产品放 `docs/retros/`,组织放 ops 仓的 `retros/`,命名 `YYYY-MM-DD_.md`。 ## 为什么要单列 Harness 反馈 [#为什么要单列-harness-反馈] 我一年写了 70 多篇复盘,教训写得很勤,但大部分停在“下次注意”,很少回流到 agent 每次开工都会读到、或者会被机械执行的地方。同一个坑踩第二次,才发现上次的教训只活在一份没人再打开的文档里。 这对应双环学习(Chris Argyris 和 Donald Schön):单环是修好这一次的错,双环是改掉产生这个错的规则本身。对用 agent 干活的人来说,“规则本身”就是 harness:agent 读到的说明、它能用的工具、拦住它的检查。 ## 模板 [#模板] ```markdown # 复盘:<事件> - 日期:YYYY-MM-DD - 类型:事故 / 项目 / 试用期评估 - 影响:(谁、多大范围、持续多久) - 相关:(PR、spec、告警的链接) ## 做了什么 (按时间顺序,事实,不带评价) ## 为什么这么做 (当时的判断和依据,包括当时不知道的信息) ## 遇到了什么 - 时间线: - 根因:(一直问"为什么",问到环境和规则层面) ## 下次怎么做 | 行动 | 负责人 | 截止 | 状态 | |---|---|---|---| ## Harness 反馈 | 类别 | 这次的问题 | 改哪里 | 状态 | |---|---|---|---| | 导航 | | | | | 自动检查 | | | | | 规则与审查 | | | | | 权限与护栏 | | | | | 工具与开销 | | | | | 信息获取 | | | | ## 数据(试用期评估时填) | 日期 | 任务 | 引擎 | 返工轮数 | 审查发现(高/中/低) | PR 合并周期 | 跳过流程 | 备注 | |---|---|---|---|---|---|---|---| ``` ## 示例:Harness 反馈 [#示例harness-反馈] 假设“待办标签”上线后,待办超过 1000 条的用户筛选明显变慢: ```markdown ## Harness 反馈 | 类别 | 这次的问题 | 改哪里 | 状态 | |---|---|---|---| | 导航 | agent 花了很久才找到筛选逻辑在哪个文件 | CLAUDE.md 的"文档在哪"加一行指针 | 已完成 | | 自动检查 | 没有任何测试覆盖 1000 条以上的列表 | CI 加一个大数据量的筛选测试 | 进行中 | | 规则与审查 | 审查没问"数据量大了会怎样" | REVIEW.md 的"每次都要检查"加一条 | 已完成 | | 信息获取 | agent 看不到线上慢查询日志,只能猜 | 给一个只读的日志查询入口 | 待定 | ``` ## Harness 反馈怎么写 [#harness-反馈怎么写] 这一节的写法我还在试,分类参考了 `/mattpocock-skills:retro` 检查 agent 工作环境时用的维度: | 类别 | 问自己 | 典型的改法 | |---|---|---| | 导航 | agent 是不是花了很久才找到该看的文件? | 在 CLAUDE.md 或相关文档里加一行指针 | | 自动检查 | 有没有一个检查本可以自动抓到这次的错? | 加测试、类型约束、lint 规则、CI 任务 | | 规则与审查 | 审查者该不该多一条规则?有没有该删的过时规则? | 改 REVIEW.md 或编码规范;能机械检查的直接做成检查 | | 权限与护栏 | 有没有危险操作没被拦住? | 加 deny 或 ask 规则、hook | | 工具与开销 | 有没有特别费 token 或特别慢的工具调用? | 换工具、精简输出、关掉用不到的插件 | | 信息获取 | 有没有关键信息 agent 根本拿不到? | 给只读权限、把日志接进来 | 三条原则: - **能机械执行的,就不要只写成文字。** 规则写进 CLAUDE.md 只是提醒;做成 hook、CI、权限规则才是拦截 - **同一个坑出现两次,就起草一个 hook。** 第一次可以是意外,第二次说明 harness 有缺口 - **每一行都要落到一个具体文件或配置。** “改哪里”那一栏写不出文件名,说明这条还没想清楚 `/mattpocock-skills:retro` 会读你指定会话的记录,按严重程度列出这几类改进建议,可以用它起草这一节。注意 gstack 也有一个 `/retro`,那是按周统计的工程复盘,是另一回事。 ## 每一节怎么填 [#每一节怎么填] | 节 | 怎么填 | 最容易犯的错 | |---|---|---| | 做了什么 | 按时间写事实 | 一边叙述一边下结论 | | 为什么这么做 | 还原当时的判断,承认当时不知道的事 | 用事后才知道的信息评价当时的决定 | | 遇到了什么 | 根因一直问到环境和规则层面 | 根因停在“agent 犯了错”。要接着问:为什么没有任何东西拦住它 | | 下次怎么做 | 每条都有负责人和截止日期 | 只写“下次注意”,这不是行动项 | | Harness 反馈 | 每一行落到一个文件或配置 | 只写在复盘里,没有真的去改 | 要公开分享的复盘,先删掉客户、同事、服务器、账号这些信息,只留通用的教训。 ## 相关 [#相关] # REVIEW.md 模板 (/docs/templates/review) > 写给 AI 审查者的规则:风险分级与谁有权批准 REVIEW.md 是写给 AI 审查者的规则:哪些问题算严重、哪些不用报、每一级风险的改动必须过哪些检查、由谁批准。放在仓库根目录。先弄清谁会读它:Claude 的 Code Review 服务(在 GitHub PR 上自动审查,面向 Team 和 Enterprise 计划)会自动读取;本地的 `/code-review` 命令**不读** REVIEW.md,只读 CLAUDE.md。所以每个审查者都必须遵守的规则写进 CLAUDE.md,只针对 PR 审查的规则写进 REVIEW.md。 ## 谁会读它 [#谁会读它] | 审查者 | 读不读 REVIEW.md | 怎么让规则生效 | |---|---|---| | Claude Code Review 服务 | 自动读根目录的 REVIEW.md,子目录也可以再放一份补充 | 从 PR 的目标分支或默认分支读取,不读 PR 自己的改动;保护好默认分支,否则“降低严重程度、排除路径、限制 Nit 数量”这几类指令不生效 | | 本地 `/code-review` | 不读,只读 CLAUDE.md | 必须遵守的规则写进 CLAUDE.md | | Matt 的 code-review | 会搜集仓库里写了编码规范的文件 | 调用时直接点名 REVIEW.md 最稳妥 | | 异构模型二审 | 看工具 | 发起审查时把 REVIEW.md 一并交给它 | 细节见官方的 [Code Review 定制说明](https://code.claude.com/docs/en/code-review-customize)。没有 Team 或 Enterprise 计划,也可以用 `/install-github-app` 装上 Claude GitHub App,再用 [anthropics/claude-code-action](https://github.com/anthropics/claude-code-action) 在每个 PR 上跑审查,在它的提示词里要求按 REVIEW.md 审查(我还没在自己的项目里用过)。 ## 模板 [#模板] ```markdown title="REVIEW.md" # 审查规则 ## 风险分级 | 级别 | 什么样的改动 | 合并前必须的检查 | 谁能批准 | |---|---|---|---| | L0 | 文档、注释、文案 | CI 通过 | 作者本人 | | L1 | 普通功能和修复 | 测试、内置 /code-review | 工程师 | | L2 | 鉴权、支付、数据结构、依赖升级、CI 和部署配置 | L1 + 另一个模型家族独立二审 + 安全审查 | 技术负责人 | | L3 | 不可逆或影响生产数据:删列、批量回填、权限模型变更 | L2 + 回滚方案 + 备份确认 | 技术负责人 + 一位没参与编写的人(一人团队见例外流程) | - 拿不准级别时,按高的算 - 写代码的 agent 不能批准、也不能合并自己的 PR - L3 的第二位批准人必须是人,可以是外部审阅者;另一个模型的二审是必须的检查,不算第二个人 ## 什么算 Important 只有会破坏功能、泄露数据或者阻碍回滚的问题才标 Important:逻辑错误、没按用户隔离的数据库查询、日志或报错里带个人信息、不向后兼容的迁移。风格、命名、重构建议最多算 Nit。 ## 每次都要检查 - 新增的 API 路由有集成测试 - 日志里不出现邮箱、用户 ID、请求体 - 数据库查询都按当前用户隔离 - 新的环境变量已登记在 .env.example,代码里没有硬编码密钥 - 数据量变大时(列表上千条)性能是否还能接受 - 依赖变化:新增或升级的包来源可信、版本跳动合理,锁文件的变化和 package.json 的改动对得上 ## 不要报告 - CI 已经检查的:lint、格式、类型错误 - 生成的文件:src/gen/ - 锁文件里纯格式、纯排序的变化;锁文件里的依赖变化照常审:异常版本、来源、完整性校验值、package.json 没要求的新依赖 - 测试代码里故意违反生产规则的写法 ## Nit 上限 每次审查最多报 5 条 Nit。 ## 证据要求 关于代码行为的结论,要给出"文件:行号",不能只凭命名推断。 ``` ## 每一节怎么填 [#每一节怎么填] | 节 | 怎么填 | 最容易犯的错 | |---|---|---| | 风险分级 | 按“改坏了的后果”分级,每级写清必须的检查和批准人 | 按改动行数分级。一行权限配置可能比一千行页面代码危险得多 | | 什么算 Important | 收窄定义,写清哪几类问题才阻塞合并 | 不写,结果每次审查都是一堆 Important,真正的问题被淹没 | | 每次都要检查 | 写你的项目特有、CI 管不到的规则 | 把 CI 已经管的东西再写一遍 | | 不要报告 | 列出生成文件、CI 已覆盖的类别;锁文件只排除格式噪音 | 不写,审查意见里一半是噪音;或者把锁文件整个排除,漏掉依赖风险 | | Nit 上限 | 给一个数字 | 不设上限,作者开始无视所有意见 | | 证据要求 | 要求给出文件和行号 | 不要求证据,审查者凭函数名猜行为,误报要来回好几轮 | 注意两种“等级”不是一回事:官方 Code Review 给每条发现标的严重程度是 🔴 Important、🟡 Nit、🟣 Pre-existing(原本就存在、不是这个 PR 引入的问题);风险分级 L0 到 L3 管的是这类改动合并前要过哪些关、谁来批准。 ## 一个人的团队怎么批准 [#一个人的团队怎么批准] 一人公司里,表里的“工程师”“技术负责人”都是你,但分级依然有用:它决定合并前必须跑哪些检查,以及哪些改动不许 agent 自己合并。我的默认做法是审查三角:主力模型写完,另一个模型家族独立审,人最后拍板。主力模型自己审自己,几乎没有价值(见[自己审自己等于没审](/docs/pitfalls/cross-model-review))。 L3 要求第二个人,一人公司满足不了时有两条路。一是请一位外部审阅者:顾问、信得过的同行,或者付费的代码审查。二是走有条件的单人例外,并在 PR 里写明“走了 L3 例外”: 1. 冷却期:写完至少隔一晚,第二天重新看一遍再批 2. 另一个模型家族独立审过,所有高危发现都已处理 3. 回滚方案演练过,备份确认能恢复 4. 发布后安排一段观察时间,盯住错误率和关键指标,异常就回滚 模型二审在这里是必须的检查项,不能冒充第二个人:它能找出代码里的问题,但替代不了一个会为后果负责、能追问“为什么现在做”的人。 “agent 不能合并自己的 PR”也要落到配置上:把 `Bash(gh pr merge *)` 写进 `.claude/settings.json` 的 `permissions.ask`,每次合并都要你点头(见[权限规则](/docs/guardrails/permissions))。 Anthropic 的 [AI-native SDLC playbook](https://claude.com/resources/articles/the-ai-native-sdlc-playbook) 里,“AI in the PR review loop”和“Hooks as approval gates”两招讲的就是这件事:AI 负责审,人负责批,关键动作用 hook 卡住等人确认。 ## 相关 [#相关] # spec 模板 (/docs/templates/spec) > 以 intent 开头的需求与设计规格,含验收标准 spec 回答“做成什么样才算对”:以 intent 开头,接着是用户故事、可以直接写成测试的验收标准、设计决定、测试决定和不在范围内的事。放在 `docs/specs/YYYY-MM-DD_.md`,以仓库里的这份为准,Issue 里只贴链接。产品负责人确认之后才进入开发;一人公司里,确认人就是你自己。 ## 模板 [#模板] ```markdown # <功能名> - 状态:草稿 / 已确认(确认人,日期) - Issue:#<编号> - 计划:docs/plans/YYYY-MM-DD_-plan.md(确认后再写) ## 1. Intent - 要做什么: - 为什么: - 约束: - 不做什么: - 成功指标: ## 2. 用户故事 1. 作为<角色>,我想<做什么>,以便<得到什么> ## 3. 验收标准 (每条都能直接写成一个测试;正常路径和异常路径都要有) - 当<触发条件>时,系统应<响应> - 如果<异常情况>,系统应<响应> - 在<某个状态>期间,系统应<响应> ## 4. 设计决定 - 涉及的模块和接口: - 数据结构变更: - 关键决定:(难以逆转的,另写 ADR 并在这里链接) ## 5. 测试决定 - 在哪些接口边界上测: - 参照仓库里已有的哪类测试: ## 6. 不在范围内 ## 7. 开放问题 ``` ## 示例:验收标准 [#示例验收标准] 接着 [intent 模板](/docs/templates/intent)里“给待办加标签”的例子: ```markdown ## 3. 验收标准 - 当用户在待办详情里输入一个新标签并按回车时,系统应把标签加到这条待办上,并在 1 秒内显示在列表里 - 当用户点击列表里的某个标签时,系统应只显示带有这个标签的待办 - 如果一条待办已经有 10 个标签,系统应拒绝新增,并提示"每条待办最多 10 个标签" - 如果标签名为空或只有空格,系统应拒绝保存 - 系统应把只有大小写不同的标签名视为同一个标签 - 在离线状态下,系统应禁用添加标签的输入框,并提示"联网后可添加" ``` ## 验收标准用 EARS 句式 [#验收标准用-ears-句式] EARS(Easy Approach to Requirements Syntax)是 Alistair Mavin 等人在 Rolls-Royce 提出的需求写法([出处](https://alistairmavin.com/ears/)),用几种固定句式约束需求,让每一条都只有一种读法: | 句式 | 写法 | 什么时候用 | |---|---|---| | 普遍 | 系统应…… | 任何时候都成立的要求 | | 事件 | 当……时,系统应…… | 某个动作或事件触发 | | 状态 | 在……期间,系统应…… | 只在某个状态下成立 | | 异常 | 如果……,系统应…… | 错误输入、超限、失败 | | 可选功能 | 在启用……的情况下,系统应…… | 只对部分配置成立 | 这种写法对 agent 特别友好:每一条都能一对一地变成一个测试,tdd 按条实现,审查时也能逐条对照。 ## 每一节怎么填 [#每一节怎么填] | 节 | 怎么填 | 最容易犯的错 | |---|---|---| | Intent | 从 intent 原样搬过来,不要改写 | 进入设计后悄悄改了范围,却没回头改 intent | | 用户故事 | 从用户视角写,一条一个能力 | 写成技术任务,比如“作为开发者,我想要一张表” | | 验收标准 | 用 EARS 句式,每条都能写成测试 | 写“体验流畅”这种没法测的话;只写正常路径,漏掉“如果……”那几条。agent 实现时最常漏的就是 spec 隐含、却没写出来的异常输入 | | 设计决定 | 写模块、接口、数据结构这些决定 | 写具体文件路径和代码片段,它们很快会过时,那是 plan 的事 | | 测试决定 | 写在哪些接口边界上测,只测外部行为 | 不先约定测试边界,结果测了一堆实现细节,一重构就全红 | | 不在范围内 | 明确列出这次不做的 | 省略,然后在审查时为“要不要顺手做”来回扯皮 | | 开放问题 | 还没定的事,以及谁来定 | 带着开放问题就进入开发 | ## 怎么写出来 [#怎么写出来] 1. 用 `/mattpocock-skills:grill-with-docs` 把需求问清楚,它会顺手更新术语表和 ADR 2. 用 `/mattpocock-skills:to-spec` 把对话整理成 spec。它默认发到 Issue,按[迁移页](/docs/workflow/migrate)的说明改成先写进 `docs/specs/` 3. 补上验收标准一节,逐条检查能不能写成测试 4. 确认后把状态改成“已确认”,再进入 [plan](/docs/templates/plan) to-spec 自带的结构是问题、方案、用户故事、实现决定、测试决定、不在范围内、补充说明。上面的模板在它的基础上多了 Intent 和验收标准两节,两者可以直接对应。 ## 相关 [#相关] # 子 agent 提示词模板 (/docs/templates/subagent-prompt) > 派子 agent 时提示词里必须有的七样东西 派子 agent 干活时,提示词里必须有七样东西:任务原文、绝对路径的工作目录、CRITICAL 禁止事项、关键约束的原文摘录、回报格式、自查清单、相关记忆的指针。新开上下文的普通子 agent 看不到你和主会话的聊天记录,提示词就是它知道的全部;少一样,它就会自己猜。fork 出来的子 agent 是例外,它会继承完整对话,所以做独立审查时别用 fork,免得带上主会话的判断和偏见。另外两条规矩:子 agent 用最强的模型,纯机械任务除外;实现类子 agent 不并行,审查类可以并行。 ## 模板 [#模板] ```markdown 你是<项目名>的<角色>子 agent,负责<计划里的哪个任务>。 ## 1. 任务原文 (从计划里原样粘贴这个任务的全部内容,不要只给链接) ## 2. 工作目录 - 仓库:<绝对路径> - 分支:<分支名>(已存在,不要新建或切换) - 只允许修改:<文件列表> ## 3. CRITICAL:不要做 - 不要执行 git reset、git rebase、git push --force、git commit --amend - 工作区有未提交改动时,不要 git checkout 或 git switch - 不要修改上面列表以外的文件;需要改别的文件,停下来回报 - 不要安装或升级依赖 - 不要为了让测试通过而删除、跳过或放宽测试 ## 4. 关键约束(原文摘录) > <从 spec、CLAUDE.md、ADR 里原样摘出的句子> ## 5. 回报格式(不超过 200 字) - 改了哪些文件:路径 + 一句话 - 测试命令和结果:原样粘贴最后 20 行输出 - 没完成的部分和原因 - 不确定、需要我决定的地方 ## 6. 自查清单(回报前逐项确认) - [ ] 只改了允许的文件(贴出 git status) - [ ] <测试命令> 全部通过 - [ ] <类型检查命令> 没有错误 - [ ] 没有留下 TODO、调试输出、被注释掉的代码 ## 7. 相关记忆 - <踩过的坑:一句话 + 文档路径> - <术语:以 GLOSSARY.md 为准> ``` ## 示例 [#示例] ```markdown 你是"待办应用"的实现子 agent,负责计划里的任务 2:标签输入框。 ## 1. 任务原文 ### 任务 2:标签输入框 - 接口:使用任务 1 产出的 addTag(todoId: string, name: string): Promise - [ ] 写失败的测试:输入"工作"并回车后,列表里出现"工作"标签 - [ ] 写失败的测试:已有 10 个标签时,输入框禁用并显示"每条待办最多 10 个标签" - [ ] 运行 bun test src/app/todos,确认失败 - [ ] 实现 TagInput 组件 - [ ] 运行 bun test src/app/todos,确认通过 - [ ] 提交 ## 2. 工作目录 - 仓库:/Users/you/code/todo-app - 分支:feature/todo-tags(已存在,不要新建或切换) - 只允许修改:src/app/todos/[id]/tag-input.tsx、src/app/todos/[id]/tag-input.test.tsx ## 3. CRITICAL:不要做 (同模板,原样保留) ## 4. 关键约束(原文摘录) > spec 第 3 节:如果一条待办已经有 10 个标签,系统应拒绝新增,并提示"每条待办最多 10 个标签" > CLAUDE.md:测试先行;UI 改动要真启动、真打开页面看过,才算完成 ## 5. 回报格式(不超过 200 字) (同模板) ## 6. 自查清单(回报前逐项确认) - [ ] 只改了允许的两个文件(贴出 git status) - [ ] bun test src/app/todos 全部通过 - [ ] bunx tsc --noEmit 没有错误 - [ ] 没有留下 TODO、console.log、被注释掉的代码 ## 7. 相关记忆 - 组件库的默认样式曾经盖掉新加的 class,改完样式要真打开页面看(docs/retros/2026-09-02_fullscreen-button.md) - "标签"在代码里叫 Tag,不叫 Label(见 GLOSSARY.md) ``` ## 每一样怎么写 [#每一样怎么写] | 项 | 为什么必须有 | 最容易犯的错 | |---|---|---| | 任务原文 | 普通子 agent 看不到你的对话,原文是它唯一的依据 | 只给计划文件的链接让它自己读,它会读出不同的重点,甚至做了别的任务 | | 绝对路径 | 子 agent 可能在别的目录或 worktree 里启动 | 写相对路径,或者不说明分支,结果改错了地方 | | CRITICAL 禁止事项 | 子 agent 为了“恢复状态”可能自作主张动 git 历史 | 不写,或者只写“小心操作”。真实发生过:一个子 agent 跑了 git reset,丢了一个提交,后续的 rebase 让 5 个提交的哈希全变了(见[不让 agent 动 git 历史](/docs/pitfalls/git-history-no-surgery)) | | 关键约束原文 | 数字、边界条件、措辞一转述就会走样 | 用自己的话概括,比如把“最多 10 个”写成“数量有上限” | | 回报格式 | 固定结构、限制字数,主会话的上下文才不会被回报撑爆 | 让它“汇报一下”,收回一大段过程描述,还得自己再提炼一遍 | | 自查清单 | 让子 agent 回报之前先自己对一遍 | 把它的回报当成事实。自查之后,主会话仍要自己跑一遍测试 | | 记忆指针 | 让它避开已经踩过的坑 | 把整篇复盘塞进去;给一句话加一个路径就够了 | 禁止事项写在提示词里只是提醒,真正兜底的是权限规则:把 `Bash(git reset --hard *)`、`Bash(git push --force *)` 这类命令写进 deny(见[权限规则](/docs/guardrails/permissions))。 ## 模型和并行 [#模型和并行] - **子 agent 用最强的模型。** 降级到小模型,单次看不出问题,累积下来跨字段的不变量会频繁被破坏,审查也兜不住(见[子 agent 别为省钱降级](/docs/pitfalls/subagent-strongest-model))。批量重命名、移动文件这类纯机械任务例外 - **实现类不并行。** 几个子 agent 同时改代码,冲突的概率很高,合并的成本往往比省下的时间还多 - **审查类可以并行。** 审查只读不写,几个角度同时看反而更快。Matt 的 code-review 就是派两个并行子 agent,分别查规范和 spec 经常用的子 agent 可以定义成 `.claude/agents/.md`(项目级,可以进 git 共享)或 `~/.claude/agents/.md`(用户级),在 frontmatter 的 `model` 字段里指定模型,可选值有 `sonnet`、`opus`、`haiku`、`inherit`(沿用主会话的模型)等,以[官方文档](https://code.claude.com/docs/en/sub-agents)为准。上面的模板是每次派活时的任务说明,和定义文件是两回事:定义文件写它是谁,任务说明写这一次干什么。 ## 相关 [#相关] # 选档:小工具、产品还是组织 (/docs/tiers) > 用三个信号判断项目处在哪一档,以及什么时候该升档 先判断项目在哪一档,再决定要做多少事。**小工具不需要 ops,组织不能只靠一个 CLAUDE.md**。按档位做事,既不会给一个周末项目套上整套流程,也不会让一个多人协作的组织靠记忆运转。 ## 三档的定义 [#三档的定义] | 档位 | 特征 | 规则和文档放哪 | 必备 | |---|---|---|---| | **小工具** | 一个人、一个仓库、没有长期用户 | README + 一页 CLAUDE.md | 最小护栏、先出计划再动手 | | **产品** | 有真实用户、要持续迭代,通常一个仓库 | 仓库里的 `docs/`:specs、plans、adr、runbooks、retros,加上 `.claude/` | 六阶段流程、异构模型审查、发版清单 | | **组织** | 多个代码仓库、多人协作、对内对外有权限差异 | 独立的 ops 仓 + 代码仓里保留 spec、plan 和跟代码绑定的 runbook | 组织级 ops agent、记忆分层、进化回路 | ## 什么时候升档 [#什么时候升档] **小工具 → 产品**:出现了真实用户。只要有人依赖它,就需要计划、审查和发版纪律。 **产品 → 组织**:下面三条满足任意一条: 1. **跨仓治理**:同一个组织有 2 个以上代码仓库,需要共用规则和决策 2. **权限隔离**:有不该让所有写代码的人看到的内容(成员权限、客户、商业信息、事故细节),或者代码仓是一个上游项目的 fork、需要和上游保持干净 3. **非代码协作**:有不写代码的协作者要参与治理(运营、市场、商务) 只是“打算开源”或者“有长期有效的决策”,单仓产品也会遇到,不构成升档理由:在仓库里放一个 `docs/adr/` 就够了。 升档不是一次性的大改造。从产品档升到组织档时,我的做法是先建 ops 仓,把跨仓库的决策和复盘搬过去,再逐步补上 ops agent 和体检机制。详见[组织篇](/docs/org)。 ## 每一档最容易犯的错 [#每一档最容易犯的错] - **小工具**:直接开干,不配任何护栏。一条 `rm -rf` 或 `git push --force` 就能毁掉一个下午。看[小工具的最小护栏](/docs/tool/guardrails)。 - **产品**:有流程但没有人工关卡,agent 自己写、自己审、自己合并。看[自己审自己等于没审](/docs/pitfalls/cross-model-review)。 - **组织**:经验写进了复盘,却没有变成会自动生效的规则,同一个坑反复踩。看[防护规则会悄悄失效](/docs/pitfalls/guardrails-decay)。 ## 这本手册自己在哪一档 [#这本手册自己在哪一档] 产品档:一个仓库、有读者、持续更新。它的写作规范放在仓库根目录的 `STANDARDS.md`,没有单独的 ops 仓。 ## 相关 [#相关] - [启动器](/docs/launcher):选好档位,照清单走 - [ops 放哪:独立仓还是放进项目](/docs/org/ops-repo) # 小工具的最小护栏 (/docs/tool/guardrails) > 五条 deny 规则拦住最致命的误操作,再加三个习惯:密钥不进仓库、git 历史只由你动、定期确认规则还在 小工具不需要整套护栏,但有五条规则第一天就该配上:把删根目录、删家目录、强推 main、硬重置 main 这几种最致命的命令写进 deny。再加三个习惯:**密钥不进仓库,git 历史只由你来动,隔一段时间确认规则还在**。完整版见[三层护栏](/docs/guardrails)。 ## 五条 deny 规则 [#五条-deny-规则] 写进用户级的 `~/.claude/settings.json`,对你所有的项目都生效: ```json { "permissions": { "deny": [ "Bash(rm -rf /)", "Bash(rm -rf ~)", "Bash(sudo rm -rf *)", "Bash(git push --force origin main *)", "Bash(git reset --hard origin/main *)" ] } } ``` 这是我自己在用的规则。几点说明: - 已经有 `settings.json` 的话,把 `deny` 数组合并进去,不要整份覆盖。 - 这个文件是严格 JSON:不能写注释,不能有尾随逗号。改完在会话里运行 `/status`,确认文件加载成功。 - 规则的判定顺序是 deny、ask、allow,先命中的说了算。deny 命中就直接拒绝,哪条 allow 规则都开不了口子。 - 结尾带空格和 `*` 的规则也匹配不带参数的命令:`Bash(git push --force origin main *)` 拦得住 `git push --force origin main` 本身。 ## 它拦得住什么,拦不住什么 [#它拦得住什么拦不住什么] 规则匹配的是 Claude 写出来的命令文本。Claude Code 会先把 `&&`、`;`、`|` 连起来的复合命令拆开逐个检查,所以 `cd app && git push --force origin main` 也会被拦住。 但换一种写法就拦不住了:`git push -f origin main`、`/bin/rm -rf /`、`bash -c '...'` 都不匹配上面的规则。deny 是兜住“Claude 最常写出来的那种写法”的安全网,不是安全边界。想再严一点,把强推整个禁掉: ```json { "permissions": { "deny": [ "Bash(git push --force *)", "Bash(git push -f *)" ] } } ``` 真正不依赖命令写法的隔离要靠沙箱或容器,见[权限规则:deny、ask、allow](/docs/guardrails/permissions)。 ## 习惯一:密钥不进仓库 [#习惯一密钥不进仓库] - 密钥只放环境变量或 `.env.local`,`.gitignore` 里忽略 `.env*`,只留 `!.env.example` 当示例 - 不要把密钥贴进对话、CLAUDE.md 或代码;程序需要时从环境变量读 - 再加两条 deny,让 Claude 的读文件工具碰不到 `.env`: ```json { "permissions": { "deny": [ "Read(./.env)", "Read(./.env.*)" ] } } ``` 这两条拦得住 Claude 自带的读文件工具,以及 `cat`、`head`、`tail` 这类常见命令,拦不住任意子进程。提交前看一眼 `git status`。万一密钥进了提交,第一件事是去服务商那里作废、重新生成,删提交是第二件事:推送出去的东西要当作已经泄露。 ## 习惯二:git 历史只由你来动 [#习惯二git-历史只由你来动] 我遇到过一个子 agent 为了“恢复状态”自作主张跑了 `git reset`,丢掉一个提交;后面的 rebase 又让 5 个提交的哈希全变了。 所以这几类操作一律不让 agent 自主执行:reset、rebase、force push、amend 已经推送的提交、在有未提交改动时切分支。在 CLAUDE.md 的禁区里写明,再配上面的 deny 规则。确实需要时由你来做,动手前先打一个 tag 备份: ```bash git tag backup/before-rebase-2026-10-16 ``` 小步提交本身也是护栏:每完成一步就提交,出了问题总能回到上一个干净的点。 ## 习惯三:隔一段时间确认规则还在 [#习惯三隔一段时间确认规则还在] 规则会悄无声息地消失。我用过一个模型供应商切换工具,从第三方模型切回官方时,它把 `~/.claude/settings.json` 整份重写:权限规则、hook、插件启用状态全没了,表面症状只是“插件怎么都关了”。 所以每次用过切换工具、手动改过设置之后,检查一遍: - 在会话里运行 `/permissions`,看 deny 规则还在不在 - 或者在终端里查(需要 jq):`jq '.permissions.deny' ~/.claude/settings.json` - 装了[本手册插件](/docs/reference/plugin)的话,`/ainative:doctor` 会检查权限规则和 hook 是否还在 ## 什么时候需要更多 [#什么时候需要更多] 开始连数据库、出现真实用户、要部署到生产时,只有 deny 规则就不够了:要补上应用层的备份、上线前的确认(ask 规则)和自动备份的 hook,三层叠加,任何一层失效都还有兜底。见[三层护栏](/docs/guardrails)和[用 hook 兜底](/docs/guardrails/hooks)。 ## 常见坑 [#常见坑] - [不让 agent 动 git 历史](/docs/pitfalls/git-history-no-surgery) - [切换工具会整份覆盖设置](/docs/pitfalls/config-overwrite) - [防护规则会悄悄失效](/docs/pitfalls/guardrails-decay) ## 相关 [#相关] - [三层护栏](/docs/guardrails) - [权限规则:deny、ask、allow](/docs/guardrails/permissions) - [密钥与配置:别让工具覆盖你的设置](/docs/guardrails/secrets) - [小工具:30 分钟起步](/docs/tool) # 小工具:30 分钟起步 (/docs/tool) > 一个人、一个仓库、没有长期用户:建仓、一页 CLAUDE.md、最小护栏、先出计划再动手,其余先不做 一个人、一个仓库、还没有人依赖它,就是小工具。小工具只需要四样东西:**一个 git 仓库、一页 CLAUDE.md、最小护栏、先出计划再动手的习惯**。spec、ADR、多模型审查、发版清单都先不用,等出现真实用户再补。30 分钟足够起步。 ## 什么算小工具 [#什么算小工具] - 脚本、命令行工具、个人自动化 - 一个静态页面、一份报告、一个落地页 - 周末项目、一次性原型、验证想法的 demo 判断标准只有一个:**有没有人依赖它**。坏了只影响你自己,就是小工具。 ## 30 分钟起步 [#30-分钟起步] 30 分钟从下面这些都准备好之后开始算: - 装好了 bun、git、Claude Code 和 GitHub CLI(`gh`) - Claude Code 已经登录,能正常开会话 - `gh auth status` 显示已登录 GitHub ### 建仓库(5 分钟) [#建仓库5-分钟] ```bash mkdir my-tool && cd my-tool git init bun init --yes printf '.env*\n!.env.example\n' >> .gitignore ``` `bun init` 生成 `package.json`、`tsconfig.json` 这些基础文件。最后一行把所有 `.env` 开头的文件加进 `.gitignore`,只保留 `.env.example` 当示例:密钥从第一天起就不进仓库。 ### 写一页 CLAUDE.md(10 分钟) [#写一页-claudemd10-分钟] 在仓库里打开 Claude Code,运行 `/init` 生成初稿,再删到一页以内。小工具的 CLAUDE.md 二三十行就够: ```markdown # my-tool 把 CSV 账单按月汇总成 Markdown 报告的命令行工具。 ## 命令 - 运行:`bun run src/index.ts <文件>` - 测试:`bun test`(全部通过时显示 0 fail) ## 约定 - TypeScript strict;引入新依赖前先问我 - 密钥只从环境变量读,不写进代码 ## 禁区 - 不要改 git 历史:reset、rebase、force push、amend 都由我来做 ``` 只写每次会话都要知道的事。CLAUDE.md 对 Claude 来说是上下文,不是强制配置,真正要拦住的操作交给下一步的权限规则。 ### 配最小护栏(5 分钟) [#配最小护栏5-分钟] 把五条 deny 规则写进 `~/.claude/settings.json`,拦住删根目录、强推 main 这类最致命的误操作。规则和三个配套习惯见[小工具的最小护栏](/docs/tool/guardrails)。 ### 第一个任务用 Plan mode(10 分钟) [#第一个任务用-plan-mode10-分钟] 按 `Shift+Tab` 在几种权限模式之间循环切换,状态栏出现 `plan mode on` 就进入了 Plan mode(也可以直接在提示前面加 `/plan`)。然后描述要做的事: ```text 读一下这个仓库,给我一个实现计划:支持传入多个 CSV 文件,按月份合并后输出一张表。先不要改代码。 ``` Plan mode 下 Claude 只读代码、出计划,不改文件。你看完计划,觉得对就批准,它才开始动手;不对就直接说哪里不对,让它重写计划。 小工具最大的浪费,是 agent 很努力地做了一个你不想要的东西。Plan mode 让这种偏差在几分钟内暴露,改计划比改代码便宜得多。注意:用 bypass 权限模式启动时,Plan mode 不再拦截修改,原因见[开发:先出计划,再写代码](/docs/product/build)。 ### 小步提交,推到私有仓库 [#小步提交推到私有仓库] ```bash git add -A && git commit -m "init" gh repo create my-tool --private --source=. --push ``` 之后每完成一步就提交一次。出了问题能回到上一个干净的点,这比任何护栏都管用。 装了[本手册插件](/docs/reference/plugin)的话,`/ainative:new-project` 会按档位把这些步骤串起来跑一遍,每个写操作先问你。 ## 可以先不做的 [#可以先不做的] | 先不做 | 什么时候补 | |---|---| | spec、plan 文档 | 改动开始影响别人,或者一个会话做不完 | | 异构模型审查 | 有了真实用户,或者涉及钱、数据、权限 | | 发版清单、上线监控 | 有人依赖它按时可用 | | 一大堆插件 | 先别装:每个启用的插件都在每个会话里占上下文 | ## 亲历:这本手册就是从小工具升上来的 [#亲历这本手册就是从小工具升上来的] 这本手册的第一版,是我桌面上的一个单页 HTML:按六个阶段列出命令和检查清单,自己建新项目时照着勾。那时它是典型的小工具:只有我一个读者,坏了也不影响任何人,所以没有 spec、没有审查,改完就用。 决定公开发布、有了读者之后,它才升到产品档:先用拷问把需求定下来,再补上写作规范、审查和部署流程。现在它的写作规范放在仓库根目录的 `STANDARDS.md`。 ## 什么时候升到产品档 [#什么时候升到产品档] 出现真实用户就升。几个具体的信号: - 有人开始依赖它,坏了会有人来找你 - 你改之前会犹豫“别弄坏了” - 它挂上了别人会访问的域名 - 你连续几周都在往里加功能 升档后照着[产品篇](/docs/product)走。四个升档信号和每一档的必备项见[选档](/docs/tiers)。 ## 常见坑 [#常见坑] - [插件不是越多越好](/docs/pitfalls/plugin-bloat):起步阶段最容易犯的错,是先装一整套合集 - [切换工具会整份覆盖设置](/docs/pitfalls/config-overwrite):刚配好的护栏,可能被别的工具一次清空 - [亲眼看到才算完成](/docs/pitfalls/see-it-to-ship):小工具也一样,测试通过不等于真的能用 ## 相关 [#相关] - [小工具的最小护栏](/docs/tool/guardrails) - [小工具上线:静态站部署到 Cloudflare](/docs/tool/ship) - [选档:小工具、产品还是组织](/docs/tiers) - [启动器](/docs/launcher):选“小工具”档,照清单勾 # 小工具上线:静态站部署到 Cloudflare (/docs/tool/ship) > 用 Workers 静态资源部署静态站:一份 wrangler.jsonc、一条部署命令,再绑定自己的域名 静态站、报告、落地页这类小工具,部署到 Cloudflare Workers 的静态资源最省事:**构建出静态文件,写一份 `wrangler.jsonc`,运行 `wrangler deploy`,再在 `routes` 里挂上自己的域名**。不需要写任何 Worker 代码。本站就是这样部署的。 ## 怎么做 [#怎么做] ### 构建出静态文件 [#构建出静态文件] 不同框架的输出目录不同:Next.js 在 `next.config` 里设 `output: 'export'`,构建产物在 `out/`;Vite、Astro 默认输出到 `dist/`。确认输出目录里有 `index.html`,最好也有一个 `404.html`。 ### 写 wrangler.jsonc [#写-wranglerjsonc] 在项目根目录新建 `wrangler.jsonc`: ```jsonc { "name": "my-tool", // 写你创建这份配置的日期 "compatibility_date": "2026-10-16", "assets": { "directory": "./out", "not_found_handling": "404-page" } } ``` 只部署静态资源时不需要 `main`(Worker 脚本),有 `assets.directory` 就够了。`not_found_handling` 决定访问不存在的路径时怎么办: | 取值 | 行为 | 适合 | |---|---|---| | `404-page` | 返回最近的 `404.html`,状态码 404 | 静态站、文档站(官方对静态生成站点的推荐) | | `single-page-application` | 返回 `index.html`,状态码 200 | 用前端路由的单页应用 | | `none`(默认) | 直接返回 404 | 不在乎 404 页面时 | 另一个选项 `html_handling` 保持默认的 `auto-trailing-slash` 即可:`foo.html` 用不带斜杠的地址访问,`foo/index.html` 用带斜杠的地址访问。 ### 登录并部署 [#登录并部署] ```bash bun add -d wrangler bunx wrangler login bunx wrangler deploy ``` 第一次部署会得到一个 `workers.dev` 子域名下的地址,先在那里检查一遍页面。 ### 绑定自己的域名 [#绑定自己的域名] 前提是域名已经托管在 Cloudflare(DNS 在 Cloudflare 上)。在 `wrangler.jsonc` 里加上 `routes`,再部署一次: ```jsonc { "name": "my-tool", "compatibility_date": "2026-10-16", "assets": { "directory": "./out", "not_found_handling": "404-page" }, "routes": [ { "pattern": "tool.example.com", "custom_domain": true } ] } ``` `custom_domain: true` 表示把整个主机名交给这个 Worker,Cloudflare 会自动创建 DNS 记录并签发证书。注意三点: - 这个主机名上如果已经有一条 CNAME 记录,绑定会失败,先删掉旧记录 - `pattern` 只写主机名,不能带路径,也不能用通配符 - 根域名和 `www` 是两个主机名,要么各绑一次,要么给其中一个做重定向 ### 验证 [#验证] ```bash curl -sI https://tool.example.com curl -s 'https://dns.google/resolve?name=tool.example.com&type=A' ``` 第一条看能不能访问、状态码对不对;第二条用 DoH(DNS over HTTPS)看解析结果。别只用 `dig`:本机代理开着 fake-ip 模式时,`dig` 拿到的是代理伪造的地址,会让你误以为部署失败。最后在浏览器里亲眼打开一次,点一遍主要页面。 ## 本站就是这样部署的 [#本站就是这样部署的] 这本手册用 Fumadocs(基于 Next.js)做静态导出,构建产物在 `out/`。部署配置和上面的例子几乎一样:`assets.directory` 指向 `./out`,`not_found_handling` 用 `404-page`,`routes` 里挂的是 `ainative.jubao.ai`。整个站点没有一行 Worker 代码,发布就是一次 `wrangler deploy`。 它同时说明了小工具和产品的界线不在技术上:同样的部署方式,这本手册有了读者,就按产品档管理,上线前要过审查。 ## 把部署命令放进 ask [#把部署命令放进-ask] 部署就是上线,小工具也值得多一次确认。在 `~/.claude/settings.json` 或项目的 `.claude/settings.json` 里: ```json { "permissions": { "ask": [ "Bash(wrangler deploy *)", "Bash(bunx wrangler deploy *)" ], "allow": [ "Bash(wrangler whoami)" ] } } ``` 两种写法都要列上:规则按命令文本匹配,Claude Code 不会自动去掉 `bunx` 这类前缀,只写 `Bash(wrangler deploy *)` 拦不住 `bunx wrangler deploy`。 ## 什么时候换平台 [#什么时候换平台] 需要服务端渲染、Server Actions、每个 PR 一个预览环境的 Next.js 应用,我放在 Vercel;静态站、边缘 API、定时任务、大文件分发放在 Cloudflare。完整的分工和取舍见[选平台:Vercel 还是 Cloudflare](/docs/product/platform)。 ## 常见坑 [#常见坑] - [本机代理会让 DNS 检查失真](/docs/pitfalls/dns-fake-ip) - [一个域名只挂一个平台](/docs/pitfalls/one-domain-one-platform) - [亲眼看到才算完成](/docs/pitfalls/see-it-to-ship) ## 相关 [#相关] - [选平台:Vercel 还是 Cloudflare](/docs/product/platform) - [权限规则:deny、ask、allow](/docs/guardrails/permissions) - [小工具的最小护栏](/docs/tool/guardrails) - 官方文档:[Workers 静态资源](https://developers.cloudflare.com/workers/static-assets/)、[Custom Domains](https://developers.cloudflare.com/workers/configuration/routing/custom-domains/) # 为什么写这本手册 (/docs/why) > 一个人加 AI 运营两个组织,一年 70 多篇复盘之后的整理 我同时运营两个组织:十几个代码仓库、几十个 agent、几位协作者。代码、文档、部署、日常运营,几乎都是我和 Claude Code 一起完成的。一年下来,我写了 70 多篇复盘。这本手册就是把这些复盘整理成**能照着做的流程、模板、规则和插件**。 ## 为什么要整理 [#为什么要整理] 复盘越写越多,同一类坑却还在踩。 最典型的一次:本地数据库被一条 reset 命令清空之后,我给它加了三层防护——脚本先备份、命令要人工确认、hook 自动兜底。半年后一次排查才发现,三层全没了:一层在上游合并时被冲掉,一层被一个配置切换工具整份覆盖,一层脚本还在但没挂上。复盘里甚至写过检查命令,只是没人去跑。(完整经过见[防护规则会悄悄失效](/docs/pitfalls/guardrails-decay)。) 问题不在于没总结,而在于**总结停留在文字里,没有变成会自动生效的东西**。所以这本手册里,能变成命令的写成命令,能变成模板的写成模板,能变成 hook 和 skill 的就做成插件。 ## 和现有资料有什么不同 [#和现有资料有什么不同] | 资料 | 是什么 | 本手册的关系 | |---|---|---| | Anthropic《AI-native SDLC playbook》 | 写给公司工程负责人的六阶段框架 | 产品篇以它为骨架,补上一个人怎么落地 | | superpowers、Matt Pocock skills、gstack 等 | 工具:告诉你用什么 | 说明每个工具负责哪件事、怎么组合、哪些不要同时开 | | OpenAI《Harness engineering》 | 一个团队用 agent 写完整个产品的实验 | 组织篇借用它的理念,并给出 Claude Code 里的实现 | | **这本手册** | 一个实践者从小工具到组织的完整路径 | 每条规则都有事故为证,每个建议都标了可信度 | 背后的理念另有一页:[背后的理念](/docs/reference/ideas)。 ## 这本手册是怎么做出来的 [#这本手册是怎么做出来的] 用手册里的方法,做这本手册: **先拷问,再动手**。用 `/mattpocock-skills:grilling` 一轮一轮问清楚:写给谁、公开到什么程度、两个组织要不要点名、直接公开还是软上线、流程引擎怎么写。答案就是这本手册的 intent。 **定标准,再分工**。主编(Claude 主会话)先写好[写作标准](/docs/reference/about)和任务说明,再派 6 个子 agent 并行写作:产品线、组织与护栏、流程与模板、两组坑卡、插件。每个子 agent 只能改自己负责的文件。 **多道审查**。敏感信息自动扫描;三个审查 agent 分别查脱敏、事实和编辑一致性;再交给另一个模型家族独立二审。 **静态构建,部署到 Cloudflare**。网站、llms.txt 和插件安装包来自同一份源文件。 ## 作者 [#作者] Neo,GitHub [@0xNeoTian](https://github.com/0xNeoTian)。手册会持续更新,变化记在[更新日志](/docs/reference/changelog)里。 ## 相关 [#相关] - [开始](/docs) - [坑库](/docs/pitfalls) - [背后的理念](/docs/reference/ideas) # gstack:上线流水线怎么用 (/docs/workflow/gstack) > 只用它最强的那几样:二审、安全审计、真实浏览器、发版 [gstack](https://github.com/garrytan/gstack) 是一组按角色和流水线组织的 slash 命令(MIT,截至 2026-10 约 13.7 万星)。我只用它管“上线流水线和质量”,常用的就 7 个:`/codex`、`/cso`、`/browse`、`/review`、`/investigate`、`/ship`、`/qa`。需求、spec、TDD 这些流程交给 Matt,不让 gstack 插手。 ## 为什么只用一部分 [#为什么只用一部分] - **和流程引擎大面积重叠。** gstack 有 50 多个 skill,从 `/office-hours`、`/autoplan` 到 `/canary`、`/retro`,覆盖整个开发周期 - **默认会主动调用。** `/investigate` 的说明写着“用户报错时直接调用它,不要自己调试”,`/ship` 写着“用户说代码好了就调用它”。它们和 Matt 的 diagnosing-bugs、pr 抢的是同一类请求 - **常驻成本。** 50 多个 skill 的描述每个会话都要付 ## 我常用的 7 个命令 [#我常用的-7-个命令] | 命令 | 做什么 | 我什么时候用 | |---|---|---| | `/codex` | 调用 OpenAI 的 Codex CLI 做独立审查。三种模式:review(给出通过或不通过结论的 diff 审查)、challenge(专门想办法弄坏你的代码)、consult(带上下文连续追问) | 重大改动合并前,做异构模型二审 | | `/cso` | 安全审计。默认做静态排查;`--diff` 只看本分支的改动;`--comprehensive` 在隔离环境里复现问题并给出修复候选 | 动到鉴权、支付、密钥、依赖的时候 | | `/browse` | 驱动真实浏览器:打开页面、点完整个流程、截图、看控制台报错 | 需要亲眼看到页面效果时 | | `/review` | 合并前审查 diff,重点查 SQL 安全、LLM 信任边界、带条件的副作用这类结构性问题 | 开 PR 之前 | | `/investigate` | 按“调查、分析、假设、修复”四步排查,没找到根因不许修;排查期间把编辑范围锁在相关模块 | 线上问题,“昨天还好好的”这类问题 | | `/ship` | 合并基线分支、跑测试、审查 diff、更新版本号和 CHANGELOG、提交、推送、开 PR | 功能做完、准备合并时 | | `/qa` | 在真实浏览器里测一遍,找到 bug 就修,每个修复单独提交;也能测 API、CLI、定时任务、webhook。只要报告不要修,用 `/qa-only` | UI 或流程类改动完成后 | `/codex` 需要先装好 Codex CLI 并登录。不走 gstack 也可以直接跑 `codex review --base main`。我的经验是推理强度用 medium 就够,xhigh 可能卡很久。 ## 成本 [#成本] 按 skill 文件的体积粗估(截至 2026-10,gstack v1.91): - **常驻**:50 多个 skill 的描述加起来约 1.3k token - **单次触发**:我常用的 7 个,每次约 4.5k–20k token;全套里最大的超过 3 万 两个开关能降成本、减少抢触发(来自 gstack 自带的配置说明,我目前都还是默认值): ```bash # 用不到的直接停用:不再注册,描述不再进上下文,Claude Code 里立即生效 ~/.claude/skills/gstack/bin/gstack-config set disabled_skills make-pdf,pair-agent # 只在你敲命令时运行,不再主动调用 ~/.claude/skills/gstack/bin/gstack-config set proactive false ``` `gstack-config set disabled_skills ""` 恢复全部。和 Matt 一起用时,关掉 proactive 能让边界最清楚:流程引擎可以自动触发,流水线只在你敲命令时运行。 ## 和 Matt、内置功能的分工 [#和-matt内置功能的分工] | 事情 | 交给谁 | 备注 | |---|---|---| | 需求、spec、计划、TDD | Matt | gstack 的 `/office-hours`、`/autoplan` 不作为默认流程 | | 开发中的 bug | Matt 的 diagnosing-bugs | 模型会自动调用 | | 线上问题 | gstack `/investigate` | 结论写成新的 intent,回到规划 | | 提交前的正确性审查 | 内置 `/code-review` | 加 `--comment` 可以把意见发到 PR 上 | | 对照 spec 审查 | Matt 的 code-review | 规范和 spec 两轴分开报告 | | 合并前的结构性审查 | gstack `/review` | | | 异构模型二审 | gstack `/codex` | 见[自己审自己等于没审](/docs/pitfalls/cross-model-review) | | 安全 | 内置 `/security-review`,高风险再加 `/cso` | | | 真实浏览器验证 | gstack `/browse`、`/qa` | 见[亲眼看到才算完成](/docs/pitfalls/see-it-to-ship) | | 发版 | gstack `/ship` 开 PR,人批准后合并 | | 注意重名:gstack 的 `/review` 和内置 `/code-review` 的别名 `/review` 撞名,gstack 的 `/retro` 和 Matt 的 retro 撞名。想彻底避免歧义,可以运行 `gstack-config set skill_prefix true`,命令会变成 `/gstack-review`、`/gstack-ship` 这种带前缀的名字。 ## 安装与升级 [#安装与升级] 首次安装需要 bun 1.4.2 或更高,先用 `bun --version` 确认: ```bash git clone --depth 1 https://github.com/garrytan/gstack.git ~/.claude/skills/gstack && cd ~/.claude/skills/gstack && ./setup ``` 它装在 `~/.claude/skills/` 下,作为个人 skill 对所有项目生效。之后注意这几点: - **用 `/gstack-upgrade` 升级。** 这个 skill 不能被停用。默认不会自动升级,有新版本时会提示 - **bun 版本别掉队。** 1.4.2 是 gstack 测试过的版本。低于 1.3.3 安装脚本会直接拒绝,因为更老的 bun 编译出的工具能读到项目里的 `.env`;介于两者之间会给警告。版本不够就 `bun upgrade` - **`/cso` 还需要本机编译工具链。** macOS 上是 Xcode 命令行工具。缺了它 `/cso` 会报 `not assessed`,其他功能照常 - **留意 CLAUDE.md。** 安装提示会让你在 CLAUDE.md 里加一段 gstack 说明,列出全部命令。只留你真在用的几个,别把[一页 CLAUDE.md](/docs/templates/claude-md) 撑长 ## 常见坑 [#常见坑] - [自己审自己等于没审](/docs/pitfalls/cross-model-review) - [分段审过了,还要整分支终审](/docs/pitfalls/whole-branch-review) - [亲眼看到才算完成](/docs/pitfalls/see-it-to-ship) - [插件不是越多越好](/docs/pitfalls/plugin-bloat) ## 相关 [#相关] # 流程引擎、流水线与专项工具 (/docs/workflow) > 把工具分成三类,各自只让一个负责,避免抢触发 把 Claude Code 生态里的插件和 skill 分成三类:**流程引擎**决定“先对齐、再写 spec、再实现、再审查”的顺序;**上线流水线**负责合并和发版前的检查;**专项工具**只解决一个具体问题。每一类只指定一个负责的工具,同一时间只让一套流程引擎自动接管。我现在的组合:流程引擎用 Matt Pocock skills ,上线流水线用 gstack 的几条命令,专项工具按需装;用了约一年的 superpowers 已经停用。 ## 为什么要分类 [#为什么要分类] 每个 skill 都在描述里写着“什么时候该用我”,模型据此自动挑选。几套工具都想管同一件事,结果就是抢触发。调试是最典型的例子:superpowers 的 systematic-debugging、Matt 的 diagnosing-bugs、gstack 的 `/investigate` 都声称自己负责调试,gstack 的说明里甚至写着“用户报错时直接调用它,不要自己调试”。三套同时开着,同一类问题每次走的流程可能都不一样,事后也说不清这次是谁在管(见[同一时间只让一套流程自动接管](/docs/pitfalls/one-process-engine))。 另一个代价是上下文。装着的 skill 每轮都要把描述放进上下文,不管用没用上。2026-10 我按 90 天的真实调用统计做了一次大扫除:插件从 39 个减到 16 个,subagent 从 73 个减到 19 个(见[插件不是越多越好](/docs/pitfalls/plugin-bloat))。 ## 三类工具怎么分工 [#三类工具怎么分工] | 类别 | 管什么 | 我现在用的 | 自动触发 | |---|---|---|---| | 流程引擎 | 需求对齐、spec、计划、TDD 实现、调试、审查的顺序 | Matt Pocock skills | 只允许一套 | | 上线流水线 | 异构二审、安全审计、真实浏览器 QA、发版 | gstack 的 7 个命令,加上内置的 `/code-review`、`/security-review` | 建议只在手动敲命令时运行 | | 专项工具 | 一个具体问题 | hookify(一句话生成 hook,🧪)、[ui-contract](https://github.com/yannikzz/ui-contract)(约定新功能放在页面哪个区域,🧪)、context7(查最新库文档)、session-report(看 token 开销,🧪) | 各管各的,不重叠 | 还有一层是 Claude Code 的内置功能:Plan mode(`Shift+Tab`)、`/code-review`、`/security-review`、`claude --worktree`、`/schedule`。它们不属于哪一类,哪套引擎都替代不了,始终打底。 ## 新工具该归到哪一类 [#新工具该归到哪一类] 拿到一个新插件,先问它想管什么: - **管“从需求到合并的顺序”**:这是流程引擎。已经有一套了,就只把它当参考,或者按项目切换(见[迁移页](/docs/workflow/migrate)) - **管“合并前、上线前的检查”**:这是流水线。先看它和现有命令有没有重叠,重叠的只留一个 - **只解决一个具体问题**:这是专项工具。装之前用 `claude plugin details @` 看它每个会话要占多少常驻 token ## 我的现状 [#我的现状] - **superpowers** :用了约一年,2026-10 停用。它最大的价值是强制走流程、不准直接上手改;最大的问题是会话一开始就接管,和其他 skill、我的自建 SOP 抢触发。完整对比见 [superpowers 与 Matt Pocock](/docs/workflow/superpowers-vs-matt) - **Matt Pocock skills** :2026-10 起作为主引擎试用。这本手册的需求就是先用 `/mattpocock-skills:grilling` 拷问出来、再动手写的。迁移和评估方法见[迁移页](/docs/workflow/migrate) - **gstack** :只用上线流水线相关的几条命令,见 [gstack 页](/docs/workflow/gstack) ## 常见坑 [#常见坑] - [同一时间只让一套流程自动接管](/docs/pitfalls/one-process-engine) - [插件不是越多越好](/docs/pitfalls/plugin-bloat) - [实质改动先留文档再动手](/docs/pitfalls/process-before-code) ## 相关 [#相关] # 从 superpowers 迁到 Matt (/docs/workflow/migrate) > 逐个环节的对应关系、两套共存的配置,以及怎么用数据决定留谁 迁移分四步:按映射表换命令;同一个项目只让一套引擎自动触发;用规则、hook 和合并关卡补回“自动强制”;每个任务记一行数据,30 天后决定留谁。注意:**`skillOverrides` 管不到插件里的 skill**,“把另一套设成 `user-invocable-only`”对插件版的 superpowers 和 Matt 都不生效(见第 2 节)。 ## 1. 映射表 [#1-映射表] 开始之前,每个仓库跑一次 `/mattpocock-skills:setup-matt-pocock-skills`,配置 Issue 和文档放在哪。 | 环节 | superpowers | Matt Pocock | 说明 | |---|---|---|---| | 想清楚需求 | brainstorming | grill-me、grill-with-docs | grill-with-docs 边问边更新术语表和 ADR | | 写计划 | writing-plans | to-spec;大工程再加 to-tickets、wayfinder | to-spec 产出的是 spec,不是逐文件计划;要计划就用内置 Plan mode 出,存进 `docs/plans/` | | 执行 | executing-plans、subagent-driven-development | implement、implement-spec | 配合内置 worktree 和后台 agent | | TDD | test-driven-development | tdd | | | 调试 | systematic-debugging | diagnosing-bugs | | | 审查 | requesting-code-review | code-review | 再加内置 `/code-review` 和异构模型二审 | | 完成前验证 | verification-before-completion | 无直接对应 | 用 CLAUDE.md 规则、Stop hook、gstack `/qa` 补 | | 收尾 | finishing-a-development-branch | pr | 再加 gstack `/ship` | | 写 skill | writing-skills | writing-for-agents | | | superpowers 没有的 | — | handoff、domain-modeling、prototype、wayfinder、triage、research | | Matt 的 skill 都用 `/mattpocock-skills:` 调用,其中 11 个模型可以自动调用,其余 16 个只能手动敲。 ## 2. 两套共存:同一个项目只让一套自动触发 [#2-两套共存同一个项目只让一套自动触发] 两套同时自动触发,一句“帮我 debug”会被随机抢走(见[同一时间只让一套流程自动接管](/docs/pitfalls/one-process-engine))。 官方文档写明:插件里的 skill 不受 `skillOverrides` 影响,要在 `/plugin` 里管理([skills 文档](https://code.claude.com/docs/en/skills#override-skill-visibility-from-settings))。在 Claude Code 2.1.301 上实测:把 `mattpocock-skills:tdd` 或 `tdd` 设成 `user-invocable-only`,模型照样能看到并调用它;同样的设置对项目里的普通 skill 立即生效。 可用的办法有三个,按推荐顺序排。 ### 方案 A:按项目选引擎(推荐) [#方案-a按项目选引擎推荐] 用 `enabledPlugins` 在用户级设默认引擎,在个别项目里覆盖;项目级设置优先于用户级([官方说明](https://code.claude.com/docs/en/settings-reference#enabledplugins))。这也是我现在的配置:Matt 全局启用,superpowers 装着但停用。 ```json title="~/.claude/settings.json" { "enabledPlugins": { "mattpocock-skills@claude-plugins-official": true, "superpowers@claude-plugins-official": false } } ``` 想在某个项目继续用 superpowers,就在项目里覆盖(只对自己生效写 `.claude/settings.local.json`,全队一致写 `.claude/settings.json`): ```json title=".claude/settings.local.json" { "enabledPlugins": { "superpowers@claude-plugins-official": true, "mattpocock-skills@claude-plugins-official": false } } ``` 也可以用命令:`claude plugin enable superpowers@claude-plugins-official --scope local`,再 `claude plugin disable mattpocock-skills@claude-plugins-official --scope local`,改完在会话里运行 `/reload-plugins`。停用插件时,它的 SessionStart hook 也一起停掉,这是方案 A 比其他办法干净的地方。 ### 方案 B:同一个项目里留一套只许手动的备用 [#方案-b同一个项目里留一套只许手动的备用] 在 `permissions.deny` 里写 `Skill(<插件>:)`,或用 `Skill(<插件>:*)` 覆盖整个插件。在 Claude Code 2.1.301 上实测:模型调用会被拦下(报错 “Skill execution blocked by permission rules”),你手动输入 `/<插件>:` 照常运行。两个副作用: - 被拒绝的 skill 即使由另一个 skill 转调也会被拦,而 Matt 的 grill-me 本身就是转调 grilling - 描述仍在 skill 列表里,常驻成本不变 Matt 的 16 个编排类 skill 本来就只能手动调用,只需拦住和 superpowers 重叠的纪律类: ```json title=".claude/settings.json" { "enabledPlugins": { "superpowers@claude-plugins-official": true, "mattpocock-skills@claude-plugins-official": true }, "permissions": { "deny": [ "Skill(mattpocock-skills:tdd)", "Skill(mattpocock-skills:diagnosing-bugs)", "Skill(mattpocock-skills:code-review)", "Skill(mattpocock-skills:writing-for-agents)" ] } } ``` 代价:这个项目里 `/mattpocock-skills:implement` 没法自动转调 tdd 和 code-review,需要时你自己敲。 ```json title=".claude/settings.json" { "enabledPlugins": { "mattpocock-skills@claude-plugins-official": true, "superpowers@claude-plugins-official": true }, "permissions": { "deny": ["Skill(superpowers:*)"] } } ``` 不推荐。superpowers 的 SessionStart hook 没法单独关(`disableAllHooks` 会连你自己的护栏 hook 一起关),它会继续注入“必须先调用 skill”的指令;手动调用它的 skill 也没法再转调其他 skill。备用的 superpowers 直接按方案 A 停用。 ### 方案 C:把备用引擎装成普通 skill [#方案-c把备用引擎装成普通-skill] `skillOverrides` 只对个人和项目 skill 生效。如果你用 Matt README 里的另一种装法 `npx skills@latest add mattpocock/skills` 把 skill 复制进项目,它们就是普通 skill,可以这样设: ```json title=".claude/settings.local.json" { "skillOverrides": { "tdd": "user-invocable-only", "diagnosing-bugs": "user-invocable-only" } } ``` 键名以 `/skills` 菜单里显示的为准;也可以在菜单里选中后按空格切换状态、按 Esc 保存。别同时装插件版和复制版,否则每个 skill 会出现两次。 ## 3. 补上“自动强制”的三个办法 [#3-补上自动强制的三个办法] superpowers 的“强制”来自 hook 注入的提示词和 skill 之间的连锁调用,本质是强引导,模型仍可能跳步。换到 Matt 之后,从软到硬加三层:第一层是提示,后两层才是机械关卡。 ### ① CLAUDE.md 硬规则 [#-claudemd-硬规则] ```markdown title="CLAUDE.md" ## 工作流程(硬规则) - 实质改动(新功能、改行为、改数据结构)写代码之前,docs/specs/ 里必须有对应的 spec。没有就停下,请我运行 /mattpocock-skills:grill-with-docs 和 /mattpocock-skills:to-spec - 有了 spec 再用 tdd skill 实现,一次一个切片 - 一行级的修复可以不写 spec,但提交信息里要写明原因 - 说"完成"之前,贴出全量测试、类型检查、lint 的命令和结果;UI 改动要真打开页面看过 ``` 为什么写“请我运行”而不是“先运行”:grill-with-docs 和 to-spec 设了 `disable-model-invocation: true`,模型去调用会被拒绝,报错原文就是让它请用户自己运行。tdd 是纪律类,模型可以直接调用。 但 CLAUDE.md 只是上下文,不是强制配置(官方文档原话),所以还要第二层。 ### ② hook 拦截 [#-hook-拦截] 两个脚本:当前分支没有 spec,不许改 `src/`;本次会话改过 `src/`(已经提交的也算)却没过测试,不许收工。脚本依赖 `jq`,写完运行 `chmod +x .claude/hooks/*.sh`。分支名按 `feature/` 约定,spec 按 `docs/specs/YYYY-MM-DD_.md` 命名。 ```bash title=".claude/hooks/require-spec.sh" #!/bin/bash # 当前分支没有对应的 spec,就不许改 src/ 下的文件 input=$(cat) file=$(jq -r '.tool_input.file_path // empty' <<<"$input") [[ "$file" == */src/* ]] || exit 0 # 只管业务代码 cd "$(jq -r '.cwd' <<<"$input")" 2>/dev/null || exit 0 root=$(git rev-parse --show-toplevel 2>/dev/null) || exit 0 branch=$(git -C "$root" rev-parse --abbrev-ref HEAD) [[ "$branch" == chore/* ]] && exit 0 # 杂务分支豁免 slug=${branch#*/} # feature/todo-tags → todo-tags ls "$root"/docs/specs/*_"$slug".md >/dev/null 2>&1 && exit 0 echo "分支 $branch 没有对应的 docs/specs/*_$slug.md。先停下,请用户运行 /mattpocock-skills:grill-with-docs 和 /mattpocock-skills:to-spec;一行级修复请改用 chore/ 分支。" >&2 exit 2 ``` ```bash title=".claude/hooks/verify-gate.sh" #!/bin/bash # 本次会话改过 src/,收工前必须过测试和类型检查 # 参数:start(SessionStart)、prompt(UserPromptSubmit)、stop(Stop) input=$(cat) sid=$(jq -r '.session_id' <<<"$input") cd "$(jq -r '.cwd' <<<"$input")" 2>/dev/null || exit 0 cd "$(git rev-parse --show-toplevel 2>/dev/null)" || exit 0 state="$(git rev-parse --git-common-dir)/claude-verify" mkdir -p "$state" case "$1" in start) # 记下会话开始时的 HEAD,只记第一次 [[ -f "$state/$sid.base" ]] || git rev-parse HEAD > "$state/$sid.base" ;; prompt) # 用户发"豁免验证:原因",本会话不再拦,并记一笔 prompt=$(jq -r '.prompt' <<<"$input") if [[ "$prompt" == 豁免验证* ]]; then echo "$(date +%F) $sid ${prompt%%$'\n'*}" >> "$state/waivers.log" touch "$state/$sid.waived" fi ;; stop) [[ -f "$state/$sid.waived" ]] && exit 0 base=$(cat "$state/$sid.base" 2>/dev/null || echo HEAD) changed=$(git diff --name-only "$base" -- src; git ls-files --others --exclude-standard -- src) [[ -z "$changed" ]] && exit 0 # 本次会话没动 src/(已提交的也算) out=$( { bun test && bunx tsc --noEmit; } 2>&1 ) && exit 0 if [[ "$(jq -r '.stop_hook_active' <<<"$input")" == "true" ]]; then # 已经拦过一次仍没通过:放行,但把决定交给用户 jq -n '{systemMessage: "本次会话改过 src/,测试或类型检查仍未通过。让 Claude 继续修,或者发一条以「豁免验证」开头、写明原因的消息。"}' exit 0 fi { echo "本次会话改过 src/,但测试或类型检查没通过。先修好再结束;修不好就停下,向用户说明原因。" echo "$out" | tail -20; } >&2 exit 2 ;; esac exit 0 ``` ```json title=".claude/settings.json" { "hooks": { "PreToolUse": [ { "matcher": "Edit|Write", "hooks": [ { "type": "command", "command": "${CLAUDE_PROJECT_DIR}/.claude/hooks/require-spec.sh" } ] } ], "SessionStart": [ { "hooks": [ { "type": "command", "command": "${CLAUDE_PROJECT_DIR}/.claude/hooks/verify-gate.sh start" } ] } ], "UserPromptSubmit": [ { "hooks": [ { "type": "command", "command": "${CLAUDE_PROJECT_DIR}/.claude/hooks/verify-gate.sh prompt" } ] } ], "Stop": [ { "hooks": [ { "type": "command", "command": "${CLAUDE_PROJECT_DIR}/.claude/hooks/verify-gate.sh stop" } ] } ] } } ``` 几点说明(细节见 [hooks 文档](https://code.claude.com/docs/en/hooks)): - PreToolUse hook 以退出码 2 结束,工具调用被拦下,stderr 交给模型 - 收工检查比较的是会话开始时记下的 HEAD 和当前代码,提交过的改动也算在内。第一次没通过,用退出码 2 让 Claude 接着修;再次尝试结束时仍没通过就放行,但用 `systemMessage` 明确提示你,由你决定继续修还是豁免 - 人工豁免的动作只有一个:你发一条以“豁免验证”开头、写明原因的消息。只有用户消息会触发 UserPromptSubmit;豁免只对本次会话有效,并记进 `.git/claude-verify/waivers.log`,30 天评估时算一次“流程被跳过” - 标记文件在 `.git/` 里,agent 理论上也能自己写。这道关防的是疏忽,不是恶意 - 脚本读 hook 输入里的 `cwd` 而不是 `CLAUDE_PROJECT_DIR`,因为进了 worktree 之后只有前者会跟着变;测试命令换成你项目的 两个脚本已在临时仓库里用 17 种输入验证过。hook 也会悄悄失效,记得纳入[护栏体检](/docs/guardrails/health-check)。 ### ③ 合并关卡 [#-合并关卡] 最后一道放在合并前,agent 和人都绕不过去: - PR 描述必须链接 `docs/specs/` 里的 spec。Matt 的 code-review 会按分支名去 `docs/` 下找 spec,找不到会先问你 spec 在哪;你确认没有,Spec 那一轴才报告没有 spec,把这当成阻塞项 - 重大改动由另一个模型家族独立二审,人最后拍板(见[自己审自己等于没审](/docs/pitfalls/cross-model-review)) - 把 `Bash(gh pr merge *)` 放进 ask 规则,合并必须你点头(见[权限规则](/docs/guardrails/permissions)) ## 4. 30 天评估法 [#4-30-天评估法] 切换前先写下判定标准,免得 30 天后凭感觉找理由。看四个指标: | 指标 | 怎么数 | 从哪拿 | |---|---|---| | 返工轮数 | 第一次提交到合并之间,因审查或自测不过而重做的轮数 | PR 审查记录、自己记 | | 审查发现数 | 各道审查发现的问题,按高、中、低分开记 | 审查报告 | | PR 合并周期 | PR 创建到合并;想从 spec 确认算起,再取 spec 首次提交的日期 | `gh pr list`、`git log` | | 流程被跳过次数 | 实质改动没先有 spec 就开工的次数,包括被 hook 拦下的和人工豁免的 | hook 报错、`waivers.log`、PR 有没有 spec 链接 | 记录方式:每个任务一行,写进复盘([复盘模板](/docs/templates/retro)里有这一节)。下面是示例: ```markdown | 日期 | 任务 | 引擎 | 返工轮数 | 审查发现(高/中/低) | PR 合并周期 | 跳过流程 | 备注 | |---|---|---|---|---|---|---|---| | 2026-10-20 | 待办加标签 | Matt | 1 | 0/2/3 | 1.5 天 | 否 | grill 问出了标签数量上限 | | 2026-10-22 | 修复筛选分页 | Matt | 2 | 1/1/0 | 0.5 天 | 是 | 没写 spec,被 hook 拦了一次 | ``` 几条现成的命令: ```bash # 最近 50 个已合并 PR 的创建和合并时间,用来算 PR 合并周期 gh pr list --state merged --limit 50 --json number,title,createdAt,mergedAt # 某份 spec 首次提交的日期,想从 spec 确认算起时用 git log --diff-filter=A --format=%ad --date=short -- docs/specs/2026-10-16_todo-tags.md # 最近 100 个已合并 PR 里,有多少没链接 spec gh pr list --state merged --limit 100 --json number,body \ --jq '[.[] | select((.body // "") | contains("docs/specs/") | not)] | length' ``` 基线:superpowers 时期的 PR 合并周期和审查轮次可以从 PR 历史里捞。再用 `/skill-doctor` 看各个 skill 实际被调用了多少次:30 天里 grill 和 to-spec 几乎没用过,说明“手动调用”在你身上不成立。 判定标准举例(要在开始前写好): - 跳过次数明显上升、返工变多:先加强 hook,再观察两周 - 加强之后还是不行:切回 superpowers,或者按项目混用(方案 A) - 指标持平或更好,自建 SOP 也不再被抢:留下 Matt ## 5. 文档输出路径统一 [#5-文档输出路径统一] | 文档 | superpowers 默认 | Matt 默认 | 统一到 | |---|---|---|---| | spec | `docs/superpowers/specs/YYYY-MM-DD--design.md` | Issue(本地模式是 `.scratch//spec.md`) | `docs/specs/YYYY-MM-DD_.md`,Issue 里只贴链接 | | 实现计划 | `docs/superpowers/plans/YYYY-MM-DD-.md` | 无,to-tickets 拆成工单 | `docs/plans/YYYY-MM-DD_-plan.md` | | ADR | 无 | `docs/adr/0001-.md` | `docs/adr/` | | 术语表 | 无 | `GLOSSARY.md` | `GLOSSARY.md` | | 交接文档 | 无 | 系统临时目录 | 要留存就移进 `docs/` | 两边都改得动: - **superpowers**:它的 skill 写明用户偏好优先于默认路径,在 CLAUDE.md 里写一行新路径即可 - **Matt**:Issue 的约定写在 setup 生成的 `docs/agents/issue-tracker.md`,可以直接改成“先写 `docs/specs/YYYY-MM-DD_.md` 并提交,再开 Issue 贴摘要和链接” 术语表是一个新的存储,引入之前想清楚它替代谁(见[记忆分层](/docs/org/memory))。 ## 常见坑 [#常见坑] - [同一时间只让一套流程自动接管](/docs/pitfalls/one-process-engine) - [实质改动先留文档再动手](/docs/pitfalls/process-before-code) - [防护规则会悄悄失效](/docs/pitfalls/guardrails-decay) - [计划和执行分开会话](/docs/pitfalls/split-plan-exec) ## 相关 [#相关] # superpowers 与 Matt:完整对比 (/docs/workflow/superpowers-vs-matt) > 自动注入流程 vs 手动调用 + 沉淀文档:用了一年 superpowers 之后为什么开始换 两者没有谁更好,区别在于**谁来决定什么时候走流程**。superpowers 在会话一开始就自动接管,默认强烈引导你走完“头脑风暴 → 计划 → TDD → 审查”;Matt Pocock skills 什么都不注入,编排类的 skill 只有你敲了才会跑,产物(术语表、ADR、Issue)留在仓库里给下一次会话用。我用了约一年 superpowers,2026-10 起切到 Matt 试用。 本页基于 superpowers v7.0.0 和 mattpocock-skills v1.3.1(截至 2026-10,两者 GitHub 星数都在 29 万以上)。细节变化很快,以官方仓库为准。 ## 两种设计哲学 [#两种设计哲学] **superpowers:自动注入,强引导流程。** 它带一个 SessionStart hook,每次启动、`/clear` 或上下文压缩之后,都把 using-superpowers 这个 skill 的全文注入上下文。核心规则是:只要有 1% 的可能某个 skill 适用,就必须先调用它,而且流程类 skill 优先。一个需求进来,会被依次带过头脑风暴、worktree 隔离、详细计划、强制 TDD、子 agent 执行、代码审查关卡,最后收尾分支,目标是让 agent 长时间自主运行也不走偏。注意这是注入的提示词,不是机械限制:模型多数时候会照做,但没有东西能硬性拦住它跳步;真正的机械关卡要靠 hook、权限规则和 CI,另外配置。 **Matt Pocock skills:手动调用,跨会话沉淀。** 没有 hook,什么都不注入。27 个 skill 分成两类:16 个编排类(grill-me、to-spec、to-tickets、implement、wayfinder、handoff 等)在 frontmatter 里设了 `disable-model-invocation: true`,模型看不到也调不动,只有你敲 `/mattpocock-skills:` 才会跑;11 个纪律类(tdd、diagnosing-bugs、code-review、grilling 等)模型可以在合适的时候自动调用。Matt 在 [README](https://github.com/mattpocock/skills) 开头就说:GSD、BMAD、Spec-Kit 这类方法靠“接管流程”来帮你,代价是拿走你的控制权,流程本身出了问题也很难修。 ## 对比表 [#对比表] | | superpowers | Matt Pocock skills | |---|---|---| | 触发方式 | SessionStart hook 自动注入;“1% 规则”让模型几乎在每个任务前先找 skill | 没有 hook;编排类只能手动 `/mattpocock-skills:`,纪律类可被模型自动调用 | | 流程强制力 | 强引导:注入的规则要求先调 skill 再动手,但这是提示词,不是机械限制 | 弱:跳过 skill 没有任何东西拦你,纪律要靠 CLAUDE.md 和 hook 自己补 | | 产物与沉淀 | 每个任务一份设计文档和计划(默认在 `docs/superpowers/`),服务这一次执行,做完即止 | 术语表 `GLOSSARY.md`、ADR(`docs/adr/`)、Issue 跨会话累积,后续 skill 会自动读;交接文档写到系统临时目录,不进仓库 | | 与其他技能共存 | 难:会话一开始就接管,和其他流程类 skill、自建 SOP 抢触发 | 好:编排类不会自己触发;纪律类(tdd、diagnosing-bugs、code-review)仍可能和别的同类 skill 重叠 | | 子 agent 与长时间执行 | 核心能力:每个任务派新的子 agent 执行和审查,能连续跑很久 | 部分 skill 用并行子 agent;没有统一的长时间执行框架 | | 适合的人和场景 | 想把纪律交给工具;大计划要长时间自主执行;团队要统一流程 | 想自己掌舵;需求常不清楚、要先对齐;重视长期沉淀;已有自建 SOP | | 上下文成本 | 常驻约 850 token(skill 描述),另加 hook 每次注入的 using-superpowers 全文(约 3 KB);单次触发约 1k–12k token | 常驻约 1,650 token(`claude plugin details` 估算,含 16 个只能手动调用的 skill 描述,实际进入上下文的更少);单次触发都在 4.2k token 以内 | 成本数字来自 `claude plugin details <插件>@claude-plugins-official` 的估算,有两处要校正:superpowers 的 hook 被记为“不占模型上下文”,其实每次都注入 using-superpowers 全文;Matt 那 16 个只能手动调用的 skill 描述被算进了常驻,按官方文档并不进上下文,分项相加后真正进上下文的约 870 token。两者都在一两千 token 以内,差别不在 token,而在谁来决定流程。 ## superpowers:用了一年的真实感受 [#superpowers用了一年的真实感受] **最有价值的一点:强制走流程,不准直接上手改。** 这一年里我好几次对 agent 不满,原因都一样:结果是对的,但它跳过流程直接改了代码,没留 spec 和 plan,事后没法审计、没法交接,也没法让别人 review(见[实质改动先留文档再动手](/docs/pitfalls/process-before-code))。开着 superpowers 的时候,这种事少得多。 我最常用的三个: - **writing-plans**:把 spec 拆成一步一步的计划,每一步都有可检查的结果,后面的实现和审查都有依据 - **systematic-debugging**:先找到根因再动手修,不允许“改改试试” - **executing-plans**:严格按计划逐个任务执行,不自由发挥 **不好的地方:会话一开始就接管。** 注入的指令要求“回答任何问题之前先检查 skill”,一句简单的提问也可能被拉进完整的头脑风暴。更麻烦的是抢触发:我有一批自建的运营 SOP skill(打包、部署、上游合并、成员入职),superpowers 明确规定流程类 skill 优先,经常抢在我的 SOP 前面接管。 公平地说,superpowers 一直在改进。2026-10 发布的 v7.0.0 重做了 brainstorming:先问清你要什么,再按工作量分档:简单的直接做,小改动在对话里对齐,项目级的才写设计文档。我停用时 v7 刚发布,上面这些缺点主要来自之前的版本。 ## Matt Pocock skills:试用到现在 [#matt-pocock-skills试用到现在] **拷问式对齐。** grilling 按轮次提问:每一轮把当前能问的问题一次问完,每题附上推荐答案,你回“是”就采纳推荐;需要查的事实它自己派子 agent 去查,只把决定留给你。这本手册就是这样定下来的:我先用 `/mattpocock-skills:grilling` 被拷问了一轮又一轮,读者是谁、公开边界在哪、流程引擎选哪个、可信度怎么标,全部拍板之后才开始写。 **沉淀。** `/mattpocock-skills:grill-with-docs` 边问边更新术语表和 ADR;之后 tdd、to-spec 等 skill 会先读术语表和 ADR,按项目自己的词汇命名。这对我很有吸引力:我一年写了 70 多篇复盘,沉淀很勤,但很少回流到 agent 每次开工都会读的地方,术语表和 ADR 至少是一条现成的回流通道。 **审查分两轴。** code-review 派两个并行子 agent,分别查“是否符合仓库规范”和“是否忠实实现了 spec”,互不影响。 试用中看到的不足: - **模型调不动编排类 skill**:在 CLAUDE.md 里写“先运行 to-spec”没用,模型只会请你自己去敲,规则要写成“停下来提醒我” - **spec 默认发到 Issue**:和“以仓库为准”的习惯冲突,需要改一下约定 - **没有“完成前验证”的对应物**:要用 hook 和 gstack `/qa` 补 这几条的补法都在[迁移页](/docs/workflow/migrate)。 ## 为什么切 [#为什么切] 1. **业界的重心在变:从“让 agent 自己跑”到“先对齐、再沉淀”。** Anthropic 的 [AI-native SDLC playbook](https://claude.com/resources/articles/the-ai-native-sdlc-playbook) 第一招就是先写一份很短、进版本控制的 intent.md;OpenAI 的 [Harness engineering](https://openai.com/index/harness-engineering/) 强调给 agent 一张地图而不是一本厚手册,仓库就是唯一事实来源。Matt 的产物模型正好落在这条线上 2. **手动调用更容易共存。** 我同时用 gstack 做上线流水线,还有一批自建 SOP skill。只要会话里有一套“1% 就必须调用”的引擎,别的 skill 就总在和它抢 3. **想验证拷问式对齐是否更适合创始人的决策。** 我的瓶颈早就不是写代码,而是“到底要做什么”。grilling 把查事实的活交给 agent,把每个决定留给我。这本手册就是第一个试验品 **最大的风险:失去自动强制。** 我在 superpowers 上最看重的恰恰是强制。所以切换不是装上就完:我的补法是用 CLAUDE.md 硬规则、hook 和合并关卡把强制补回来,每个任务记一行数据,30 天后按数据决定留谁。 ## 业界怎么看 [#业界怎么看] - **nocoders**(Mick Brzeziński,2026-06):把两者称为[两种相反的押注](https://www.nocoders.com/blog/superpowers-vs-pocock-agent-skills/),superpowers 像自动驾驶,Matt 像助力转向:前者治“模型爱跳步骤”,后者给“已经有判断力、要杠杆而不是监护人”的人。它也直说了各自的毛病:superpowers 会把一句话的问题拖进完整的头脑风暴;Matt 的纪律是可选的,跳过就没人拦 - **Zenn 上 kanagen 的对比**(2026-06):[superpowers 是“给 agent 强制纪律的装置”,Matt 是“把工程基本功做成 skill”](https://zenn.dev/kanagen/articles/claude-code-skills-superpowers-vs-mattpocock)。前者的产物按任务消耗,后者跨会话累积;两套哲学冲突,作者建议二选一 - **note 上アサヒ的切换记录**(2026-07):[从 superpowers 换到 Matt](https://note.com/spocal/n/nd17a3275b6f3) 之后 token 和时间都省了,结果“足够好”,记录都留在 GitHub Issues 里也不容易忘进度。他也承认 superpowers 能自主跑一个多小时,计划清楚到可以直接交给更便宜的模型执行 这几篇写于 superpowers 6.x、Matt 1.0 前后,功能已有变化,但结论一致:取决于你要防的是哪种失败。 ## 选择建议 [#选择建议] | 你的情况 | 选 | |---|---| | 主要问题是 agent 跳步骤、不写测试、过早宣布完成 | superpowers | | 要让 agent 长时间自主执行一个大计划(子 agent 并行、worktree 隔离) | superpowers | | 团队需要一套不靠每个人自觉的统一流程 | superpowers | | 主要问题是“做出来的不是我要的”,需要先对齐 | Matt | | 想自己掌舵、按需调用,重视术语表和 ADR 这类长期沉淀 | Matt | | 已有自建 SOP 或 gstack 这类流水线,要和流程引擎共存 | Matt | 两套都想要也可以,但**同一个项目里只让一套自动触发**:按项目选主引擎,另一套停用或只许手动调用,配置见[迁移页](/docs/workflow/migrate)。 ## 常见坑 [#常见坑] - [同一时间只让一套流程自动接管](/docs/pitfalls/one-process-engine) - [实质改动先留文档再动手](/docs/pitfalls/process-before-code) - [插件不是越多越好](/docs/pitfalls/plugin-bloat) ## 相关 [#相关]