agentsmith Agent harness 操作系统
Agentsmith 不是又一个 prompt 集,而是把 Claude Code/Codex/Gemini 这类 agent 的规则、profile、验证、hook 和 handoff 打包成可重复安装的 harness。源码里最值得看的是:它把“好习惯”写成装配器和门禁,而不是留在 README 里。
它解决什么,凭什么值得拆
Agentsmith 的核心抽象不是“提示词更长”,而是把 agent 工作方式拆成可装配的静态规则、按任务切换的 profile、项目本地 verify gate 和提交前 hook。比如软件开发 profile 在 profiles/software-dev.md:11、profiles/software-dev.md:15、profiles/software-dev.md:46 明确要求先读代码、再用完整 verify 命令收口;通用原则在 core/20-principle-rules.md:13、core/20-principle-rules.md:23、core/20-principle-rules.md:35 把证据、端到端验证和完成前检查写成硬规则。
这套仓库值得拆,是因为它没有把“agent 应该谨慎”停留在口号。安全面由 scripts/secret-scan.sh:21、scripts/leak-gate.sh:73、scripts/install-git-hooks.sh:56 变成可执行检查;协作面由 core/10-operating-model.md:9、core/10-operating-model.md:49、core/40-subagents-and-tools.md:14 约束什么时候自主推进、什么时候暂停、什么时候并行。换句话说,它把模型外部的 90% 工作纪律做成了仓库结构。
▸核心数据
深度阅读 → 入口展开。
装配拓扑
源码拓扑可以分成三层:规则材料在 core/ 和 profiles/,装配器把它们写入项目,验证层再检查输出是否可信。core/10-operating-model.md:4、core/20-principle-rules.md:31、profiles/software-dev.md:8 负责定义“如何工作”,而 scripts/verify.sh:58、scripts/secret-scan.sh:65、scripts/leak-gate.sh:75 负责让这些要求可以被机器执行。
▸系统拓扑
▸模块清单
模块清单不是按目录名堆砌,而是按责任边界读:core 负责跨项目不变规则,profile 负责工作类型,scripts 负责把验证落地,hooks 负责把违规行为挡在提交前。core/20-principle-rules.md:78、profiles/software-dev.md:32、scripts/install-git-hooks.sh:35 说明它刻意把表面积控制住,再用 hook writer 统一生成 Git 入口。
35write_hook() { # <hookname> <body> — managed write w/ foreign-backup; empty body removes a stale managed hook 36 local name="$1" body="$2" f="$HOOKS_DIR/$1" marker="agentsmith $1" 37 # legacy pre-rebrand marker: still recognized as "ours" so old hooks migrate in place, never written 38 local legacy_marker="universal-claude-harness $1" 39 if [ -z "$body" ]; then 40 if [ -f "$f" ] && grep -q -e "$marker" -e "$legacy_marker" "$f"; then 41 rm -f "$f"; echo " removed managed $name (not selected)" 42 fi 43 return 0 # bare 'return' would propagate the failed test above and kill the set -e script 44 fi 45 [ -f "$f" ] && ! grep -q -e "$marker" -e "$legacy_marker" "$f" && { cp "$f" "$f.bak.$$"; echo " backed up foreign $name → $name.bak.$$"; } 46 { 47 echo "#!/usr/bin/env bash" 48 echo "# $marker — regenerate via scripts/install-git-hooks.sh. Bypass once: --no-verify" 49 echo "set -e" 50 echo 'ROOT="$(git rev-parse --show-toplevel)"' 51 printf '%s\n' "$body" 52 } > "$f" 53 chmod +x "$f"; echo " installed $name"
▸关键数据结构
4**Unit of work:** one tracked item (an issue, a ticket, a task, a deliverable) per session by 5default. Its description is the contract. Two or three closely-related items on the same branch 6or workspace is fine when they share scope naturally. For an obvious small fix, a one-line 7description instead of a formal ticket is acceptable. 8 9**Autonomy:** proceed through **plan → do → verify → finalize → hand off** without asking for 10approval between steps. Decide routing and scope calls yourself, explain the WHY in the 11commit/PR/summary, and move on. The autonomy is in the *quantity of un-gated steps*, never in 12the *quality bar* — the principle rules and the profile's gates still apply to every step. 13 14**When the item is ambiguous:** research the right answer (official docs, reputable sources, 15the codebase/asset itself) and pick the researched path. **Do not default to "most 16conservative" or pick at random.** Note what you researched in the commit/PR/summary so the 17choice is auditable later.
验证与安全模块
▸verify.sh 把“完成”变成项目本地阶段表
`scripts/verify.sh` 不内置任何语言假设,而是读取 `.harness/verify.conf` 的 “Label :: command” 行。scripts/verify.sh:52、scripts/verify.sh:58、scripts/verify.sh:84、scripts/verify.sh:87 显示它先确认配置存在,再解析阶段,最后逐个执行并在第一处失败退出。这和 profiles/software-dev.md:46、profiles/software-dev.md:48 的 profile 文案闭环:人和 agent 都跑同一个入口。
52if [ ! -f "$CONF" ]; then 53 echo "${RED}No phase config at .harness/verify.conf${RESET}" 54 echo "${YELLOW}Create it (see .harness/verify.conf.example) — list the commands that prove this project is shippable.${RESET}" 55 exit 2 56fi 57 58# Parse "Label :: command" lines (skip comments/blanks). 59LABELS=(); CMDS=() 60while IFS= read -r line; do 61 [ -z "${line//[[:space:]]/}" ] && continue 62 case "$line" in \#*) continue ;; esac 63 label="${line%%::*}"; cmd="${line#*::}" 64 label="$(echo "$label" | sed 's/[[:space:]]*$//;s/^[[:space:]]*//')" 65 cmd="$(echo "$cmd" | sed 's/^[[:space:]]*//')" 66 [ -z "$cmd" ] && continue 67 if [ -n "$ONLY" ] && [[ "$label" != *"$ONLY"* ]]; then continue; fi 68 LABELS+=("$label"); CMDS+=("$cmd") 69done < "$CONF" 70 71TOTAL=${#LABELS[@]} 72if [ "$TOTAL" -eq 0 ]; then 73 echo "${YELLOW}No matching phases.${RESET}"; exit 0 74fi 75 76if $LIST_ONLY; then 77 echo "${BOLD}Configured phases:${RESET}" 78 for i in "${!LABELS[@]}"; do printf ' %d. %s :: %s\n' "$((i+1))" "${LABELS[$i]}" "${CMDS[$i]}"; done 79 exit 0 80fi 81 82cd "$ROOT_DIR" 83START=$SECONDS 84for i in "${!LABELS[@]}"; do 85 echo; echo "${BOLD}${CYAN}[$((i+1))/$TOTAL] ${LABELS[$i]}${RESET}" 86 echo " ${CMDS[$i]}" 87 if ! bash -c "${CMDS[$i]}"; then 88 echo; echo "${BOLD}${RED}verify.sh: phase '${LABELS[$i]}' failed.${RESET}" 89 echo "${YELLOW}Run that command directly to iterate, then re-run verify.sh.${RESET}" 90 exit 1 91 fi 92done 93 94echo; echo "${BOLD}${GREEN}verify.sh: all $TOTAL phase(s) passed in $((SECONDS-START))s.${RESET}"
▸secret-scan / leak-gate 双门禁覆盖凭据和环境泄漏
Agentsmith 把安全拆成两个不同问题:`secret-scan` 看密钥形状,`leak-gate` 看人员、IP、邮箱和 home path 等环境特征。scripts/secret-scan.sh:20、scripts/secret-scan.sh:37、scripts/secret-scan.sh:77、scripts/leak-gate.sh:73、scripts/leak-gate.sh:121 共同形成“可快速跑、可在 hook 里跑、可用测试证明”的安全网。
20# Generic high-signal secret patterns (shapes, not values). 21PATTERNS=( 22 'BEGIN [A-Z ]*PRIVATE KEY' # PEM private keys (RSA/OPENSSH/EC/bare/ENCRYPTED) 23 'AKIA[0-9A-Z]{16}' # AWS access key id 24 'ASIA[0-9A-Z]{16}' # AWS temp key id 25 'gh[pousr]_[A-Za-z0-9]{20,}' # GitHub tokens 26 'xox[baprs]-[A-Za-z0-9-]{10,}' # Slack tokens 27 'sk-[A-Za-z0-9]{20,}' # OpenAI-style keys 28 'sk-ant-[A-Za-z0-9_-]{20,}' # Anthropic-style keys 29 'AIza[0-9A-Za-z_-]{35}' # Google API key 30 '(password|passwd|pwd|secret|token|api[_-]?key)["'"'"' ]*[:=][[:space:]]*["'"'"'][^"'"'"' ]{8,}' # assigned secret literal 31) 32 33# Patterns go to a temp file so the whole scan is ONE grep pass (-f ORs every line of the file). 34# Matching per-line in a shell loop costs a subprocess per line per pattern — imperceptible on 35# Linux (~1ms spawns), minutes on Windows/Git Bash (~30ms). This script runs as a pre-commit 36# hook, and a hook slow enough to be disabled is a guardrail that isn't there (R8). 37PATTERN_FILE="$(mktemp)" 38trap 'rm -f "$PATTERN_FILE"' EXIT 39printf '%s\n' "${PATTERNS[@]}" > "$PATTERN_FILE"
从安装到可交付的关键流
关键流从“选择 profile”开始,到“项目里出现可执行验证入口”结束。规则层在 core/10-operating-model.md:36、core/40-subagents-and-tools.md:24、core/20-principle-rules.md:39 定义工作方式;脚本层在 scripts/install-git-hooks.sh:56、scripts/install-git-hooks.sh:64、scripts/install-git-hooks.sh:67 把 pre-commit、commit-msg、pre-push 三个 Git 时机接起来。
73# check <label> <extended-regex> <exempt-regex|""> <hint> 74# Findings print as file:line:match, so <exempt-regex> can anchor on the match with $. 75check() { 76 local label="$1" ere="$2" exempt="$3" hint="$4" hits line 77 # -I skips binaries; -o prints just the match so exemptions test the match, not the whole 78 # line (a line holding both a safe and an unsafe value must still fail). 79 # `|| true` absorbs grep's exit-1-on-no-match, which pipefail would treat as a hard error. 80 hits="$(git grep -noIiE -- "$ere" -- . "${SCOPE[@]+"${SCOPE[@]}"}" 2>/dev/null || true)" 81 [ -n "$hits" ] || return 0 82 if [ -n "$exempt" ]; then 83 hits="$(printf '%s\n' "$hits" | grep -Evi "$exempt" || true)" 84 [ -n "$hits" ] || return 0 85 fi 86 hits="$(printf '%s\n' "$hits" | allow_filter || true)" 87 [ -n "$hits" ] || return 0 88 echo " ✗ $label — $hint" 89 while IFS= read -r line; do 90 echo " $line" 91 done <<<"$hits" 92 fail=1 93}
▸安装流:规则材料被装配成 managed block
▸验证流:同一入口服务人和 agent
测试如何证明 harness 没坏
测试部分很有工程味:它不是只测脚本能跑,而是测 harness 输出是否仍能被人和 agent 正确使用。scripts/test-assemble.sh:4、scripts/test-assemble.sh:37、scripts/test-assemble.sh:83 覆盖每个 profile 和 stacked profile;scripts/test-leak-gate.sh:4、scripts/test-leak-gate.sh:33、scripts/test-leak-gate.sh:64 用 throwaway repo 证明泄漏门禁真的会失败。
▸测试覆盖
`test-assemble` 的价值在 scripts/test-assemble.sh:61、scripts/test-assemble.sh:72、scripts/test-assemble.sh:76:它专门找未渲染 token 和不该出现的 TODO,而不是只看 `setup.sh` 退出码。这样 agent 读到半渲染规则前,CI 就先红。
45for p in "${profiles[@]}"; do 46 name="$(basename "$p" .md)" 47 out="$WORK/$name" 48 mkdir -p "$out" 49 if ! bash "$SETUP" --profile "$name" --assemble-only --target "$out" \ 50 --operator-name "Test" --tracker "Linear" >/dev/null 2>&1; then 51 bad "$name: assembly failed outright" 52 continue 53 fi 54 f="$out/CLAUDE.md" 55 if [ ! -s "$f" ]; then 56 bad "$name: produced no CLAUDE.md" 57 continue 58 fi 59 60 errs="" 61 # An unrendered token means the agent reads a literal "{{TRACKER}}" as if it were the rule. 62 # Never acceptable, in any profile. 63 leaked="$(grep -oE '\{\{[A-Z_]+\}\}' "$f" 2>/dev/null | sort -u | tr '\n' ' ')" 64 [ -n "$leaked" ] && errs="$errs unrendered:[$leaked]" 65 # [TODO: set X] means "the assembler had no value for X". Two very different cases: 66 # - X is flag-driven (below) → setup COULD have filled it and didn't. That's a bug: the agent 67 # gets a blank where a rule should be. This is the regression that would fire if a 68 # placeholder were renamed in core/ but not in fill_placeholders(). 69 # - X has no flag (BRAND_PALETTE, BRAND_FONT) → the TODO IS the product. It's the documented 70 # handoff to the human (INSTALL.md's placeholder table; setup's own "resolve any [TODO]" 71 # next-step). Flagging it would make this suite red by design and train people to ignore it. 72 for tok in OPERATOR_NAME OPERATOR_ROLE OPERATOR_BIO TRACKER TRACKER_POLICY; do 73 grep -qF "[TODO: set $tok]" "$f" 2>/dev/null && errs="$errs unfilled-flag-token:[$tok]" 74 done 75 76 if [ -n "$errs" ]; then 77 bad "$name: assembled with leaks —$errs" 78 else 79 ok "$name: assembles clean (no unrendered tokens, no TODO blanks)" 80 fi
▸已知边界 / 失败模式
- 如果 `.harness/verify.conf` 没有真实阶段,`scripts/verify.sh:52` 会直接提示缺配置;但配置里有占位阶段时,还需要 profile 约束和测试去防止“假绿色”。
- `scripts/secret-scan.sh:30` 用正则匹配 secret 形状,低误报和漏报之间必须持续调参,测试脚本要覆盖真实开发语言中的安全样例。
- `scripts/leak-gate.sh:31` 明确不做通用 hostname denylist,因为把内部域名写进公开仓库本身就是泄漏;这是安全模型里的有意识取舍。
- `core/40-subagents-and-tools.md:50` 把重复失败定义为停止信号,但实际执行仍依赖 agent 读懂并遵守,所以 verify gate 不能替代运行时判断。
源码亮点
scripts/verify.sh:84、scripts/verify.sh:87、profiles/software-dev.md:15,不是停留在 README 口号。scripts/secret-scan.sh:21、scripts/secret-scan.sh:69,环境泄漏在 scripts/leak-gate.sh:97、scripts/leak-gate.sh:104、scripts/leak-gate.sh:110,职责清晰。profiles/software-dev.md:19、profiles/software-dev.md:23、profiles/software-dev.md:40 把自动化检查和真实路径运行分开,避免“CI 绿但功能死”。core/20-principle-rules.md:47、core/20-principle-rules.md:68、core/10-operating-model.md:19 说明 harness 设计在吸收过去失败,而不是单次修 bug。13**2. Prove it — evidence before assertion.** Never claim something works, is fixed, or is 14correct without *evidence you actually produced*. For a bug, that means a check that **failed 15before your change and passes after** (a failing test, a reproduced error, a before/after 16screenshot, a diffed output). "It works in my head" / "it should be fine" / "this looks right" 17are not evidence. Two kinds of proof, and most real work needs both: **tests** for the 18deterministic parts (this input produces that output) and **evaluation** for the parts that 19require judgment (did it take the right approach, is the quality bar met) — a rubric, a second 20independent reviewer (human or an adversarial AI pass), a real run observed. The profile defines 21what counts as proof for this kind of work. 22 23**3. Verify the whole chain, not just your layer.** Work usually flows across layers (code → 24API → UI; source → draft → rendered doc; raw data → transform → chart; list → message → send). 25A change that's correct in one layer can be wrong by the time it reaches the end. Before 26declaring done, **trace one concrete example end-to-end** and confirm it lands correctly at the 27last layer the user actually sees. When a change fans out to many consumers (several pages, 28recipients, locales, output formats), check *every* consumer — "one of them works" does not 29satisfy this rule.
技术亮点之外,别忽略这些
风险主要来自脚本化 harness 的双刃剑:它能统一行为,也可能把错误规则统一扩散。core/20-principle-rules.md:78、scripts/install-git-hooks.sh:45、scripts/verify.sh:87 都体现了这个取舍:表面积要小,外部 hook 要备份,执行命令要读输出。
scripts/secret-scan.sh:20、scripts/leak-gate.sh:31 说明扫描器选择高信号规则,不能替代 secret manager、历史清理和人工审查。core/40-subagents-and-tools.md:18、core/40-subagents-and-tools.md:50 写了 subagent 和失败恢复纪律,但不同 agent 对规则遵守程度不同,真实项目仍要靠验证命令兜底。