前两章讲了骨架与零件:四阶段流水线、七角色博弈、十个核心概念。这一章,把镜头对准地基——Harness 工程在磁盘上的布局。每个文件该放哪、该被谁读、该解决什么问题,在目录层面就已定型。不懂目录,你就无法判断"哪个文件是权威、哪个文件会被机器校验、哪个文件改了会触发什么"。
4.1.harness/与.claude/:两套目录,各司其事
打开 Harness 工程的根目录,你会看到两大配置目录并排:.harness/和.claude/。这两个名字容易让人以为"它们是一回事",但它们的职责有严格分工:
.harness/——Harness 的"数据与机器":放状态、契约、知识、脚本。这是 Harness 框架自己管理的东西——系统能力真相(specs/)、经验库(memory/)、任务看板(tasks/)、角色契约(workflow/)、自动化脚本(scripts/)、脚手架模板(templates/)。.它回答"系统现在知道什么、机器接下来要做什么"。.claude/——Claude Code 的"身份与行为":放角色定义、命令、规则、技能、钩子。这是 Claude Code 原生消费的配置——Agent 该如何行事(agents/)、用户如何触发(commands/)、不可碰的红线(rules/)、标准操作手册(skills/)、实时拦截(hooks/)。它回答"AI 是谁、它该怎么行动"。
一句话概括两者的分工:.harness/是"记忆与机器",.claude/是"身份与规则"。前者存"系统知道什么",后者存"AI 怎么做"。
下面这张目录树来自一个真实的 Harness 工程,我用它来实地讲解每个目录的职责:
请对照这张树,记住三个关键观察:
观察点一:目录结构本身就是四层元模型(第 3 章)的物理映射。你看——workflow/和config.json是契约层,agents/、commands/、skills/是行为层,specs/、memory/、codebase-guide/是知识层,scripts/、hooks/、rules/、tasks/是执行层。四层元模型不是抽象概念,你打开目录就能看到。理解了四层,你就知道任何一个文件该去哪、该怎么归类。
观察点二:.harness/agents/是指向.claude/agents/的符号链接。同一个角色定义只有一个权威源(在.claude/),.harness/agents/只是提供一条更符合"框架心智"的访问路径。这体现了单一真相源在文件系统层面的一种常见手法:用链接而不是副本——复制会制造双份真相,链接不会。
观察点三:deliverables/的"活目录 + 归档"设计。在途任务用deliverables/<task>/,归档后用_archive/<task>/,活目录定期清空、归档目录增量追加。这套设计我在第 10 章(Archive)会完整展开,这里你先种个印象:Harness 把"进行中"与"已沉淀"在磁盘上就分开了。
settings.json:Hook 是怎么被"注册"的
有一个文件值得单独看一眼——.claude/settings.json。它就是第 3 章讲的三个 Hook 的"注册表":Claude Code 通过它知道"哪个事件触发哪个脚本"。
{"hooks":{"PreToolUse":[{"matcher":"Edit|Write","hooks":[{"type":"command","command":"python3 .claude/hooks/pre_edit.py"}]}],"UserPromptSubmit":[{"matcher":"","hooks":[{"type":"command","command":"python3 .claude/hooks/pre_command.py"}]}],"PostToolUse":[{"matcher":"Agent","hooks":[{"type":"command","command":"python3 .claude/hooks/dev_gate.py"}]}]}}注意三个 Hook 的触发设计,每个都精心选择了时机和匹配范围:
这就是"纵深防御"在配置层面的形态:同一个规则(如分支合规)不靠一个检查点守住,而是靠多个 Hook、多个时机独立 enforce。细节在第 9 章展开。
4.2config.json——全局兜底配置与"单一真相源"的入口
在 4.1 的目录树里,我特意给config.json标了 ★。它只有几行,却是整个 Harness 最容易被误用的地方——也是最容易被"硬编码"毁掉的地方。先看它的真实内容:
{"apply-mode":"review","mainline-branch":"dev","description":"Apply 流程模式: auto=CR 通过后自动进入 TE(默认); review=CR 通过后暂停,等待人工审查通过后再进入 TE。任务级可用 proposal.md 的 flow-mode 字段覆盖。mainline-branch: 子工程主线分支(集成/同步/归档合并目标),子工程 .harness/build.json 的 mainline-branch 字段可覆盖,默认 dev。"}只有两个真正的配置项,我来逐一讲它们的设计意图:
mainline-branch:把"主线分支名"从代码里拔出来
想象一下没有这个配置的 Harness 会怎样:sync.py要同步到哪个分支?create_feat_branch.py从哪个分支建特性分支?archive.py要把 feat 分支合并到哪?verify.py检查"是否在集成分支"要看哪几个分支名?
所有这些脚本的答案,原本只能靠硬编码。而在一个演进中的工程里,"主线分支叫 dev 还是 develop 还是 release-2.x"是会变的。如果你把dev写死在 18 个脚本里,改一次主线分支名 = 改 18 处 + 祈祷没漏。
Harness 的做法是把这条信息收敛到一处(config.json),并设计了一套三级覆盖优先级:
- 大多数子工程不配置 → 用根 config.json 的
dev; - 某个子工程特殊(比如单独维护的 legacy 仓库用
release-x)→ 在自己 build.json 里覆盖; - 都没有 → 兜底默认
dev。
而所有脚本(sync / create_feat_branch / check_branch / verify / archive)都通过lib.py里唯一的get_mainline_branch(service_path)函数读取这个值——全世界只有一个地方知道"主线分支叫什么"。这就是单一真相源:不是"不要硬编码",而是"把硬编码收敛到一个地方,再让所有人读它"。
apply-mode:把"流程行为"收敛到配置文件
第二个配置项apply-mode控制的是 Apply 阶段的流程行为(这个我在第 2 章 2.4 已经接触过):
apply-mode: auto → CR 审查通过后,自动进入 TE apply-mode: review → CR 审查通过后,暂停,等待人工审查 code-review.md,人确认后再进 TE注意它的优先级设计(与 mainline-branch 同思路):
proposal.md 的 flow-mode(任务级) > .harness/config.json 的 apply-mode(全局) > 默认 auto这样设计的好处:"流程行为"这个本该人人皆知、处处一致的东西,有了一个权威来源。单任务特例(proposal 里写flow-mode: review)不会破坏全局;全局改档(config.json 改auto)不用逐个任务改。配置项的每一层决策,都发生在离决策最近的地方——这是配置设计的黄金法则。
一句话理解 config.json
config.json每个被放进这里的配置项,都回答同一个问题:“这个值,全系统都应该一致地知道,但它不藏在任何一个具体脚本里。” 当你发现某个值被 3 个以上脚本硬编码时,它就该被提升到 config.json。
4.3 跨平台兼容层:macOS 与 Windows 的"双系统纪律"
最后一块地基是跨平台兼容。你可能觉得这没什么好讲的——“脚本写好不就行了?”——但 Harness 面对的是一个极其刺眼的现实:团队里一半人用 macOS,一半人用 Windows。
- macOS 开发者习惯了
bash -lc、which、export PATH=、eval "$(...)"; - Windows 开发者面对的是
cmd、where、set、PowerShell 的$env:; - 路径分隔符一个
/一个\;行尾一个 LF 一个 CRLF;删文件一个rm -rf一个rmdir /s /q。
如果 Harness 的脚本是单平台写的,团队里必然有一半人每天的开工仪式是"先折腾环境"。Harness 用一整套设计把这件事制度化,核心是os-compatibility.md规则文件 +check_harness.py的跨平台扫描。
os-compatibility.md:写成"法律"的兼容纪律
Harness 把跨平台要求写成了强制规则(.claude/rules/os-compatibility.md)。注意它的措辞——不是"尽量兼容",而是"违反 → check_harness.py 跨平台扫描 FAIL"。我摘几条最硬的规定:
| 条款 | 禁止 | 强制 |
|---|---|---|
| Python 子进程调用 | 硬编码"python3"/"python"作为 program | 用sys.executable |
| 命令执行 | os.system、shell=True | subprocess/lib.run(list 形式) |
| 文件删除 | rm -rf/rm -r/rmdir | Python 内shutil.rmtree/Path.unlink |
| 脚本形态 | .harness/下新增.sh(除 git-hooks/) | 跨平台脚本一律 Python |
| 行尾 | CRLF | 框架脚本与 git hook 必须 LF;hook shebang#!/bin/sh+ python3/python 兜底 |
为什么这些条目能上"法律"?因为每一条都对应着一个真实事故:硬编码python3在 Windows 上不存在(是python.exe);os.system无法跨平台;rm -rf在 Windows 上会直接报错;CRLF 行尾会让 shebang 失效。这些事故足够痛,才值得写成 FAIL 级规则。
check_harness.py的跨平台扫描:机器来执法
光有规则文件不够——AI 可能看不见规则,人可能忘执行它。所以check_harness.py全量校验里内置了一个「🖥️ 跨平台兼容」检查段,用正则扫描的方式自动执法。让我把真实工程的执行结果展示给你看:
🛡️ Harness 系统完整性检查 ============================ ... 🔍 三边一致性校验... ✅ contract.json role [PM] ↔ project-manager.md ✅ contract.json role [BA] ↔ business-analyst.md ✅ contract.json role [SA] ↔ solution-architect.md ✅ contract.json role [RR] ↔ readiness-reviewer.md ✅ contract.json role [Dev] ↔ developer.md ✅ contract.json role [CR] ↔ code-reviewer.md ✅ contract.json role [TE] ↔ test-engineer.md 🖥️ 跨平台兼容检查(macOS + Windows) ✅ 跨平台扫描:0 ERROR / 0 WARNING(通过) ============================================ PASS: 66 FAIL: 0 ✅ 框架完整性检查全部通过这条规则是双重的:它强制框架本身跨平台(scripts/hooks 的代码风格),也强制"写文档的人别忘了给 Windows 留口子"——例如os-compatibility.md明确要求:命令文档里若含rm -rf等 POSIX 专属命令,必须注明 Windows 等价写法(rmdir /s /q/Remove-Item -Recurse -Force)。文档也是兼容层的一部分。
env_auto.py:跨平台兼容的"实战代表"
跨平台纪律不是为兼容而兼容——它服务于一个真实的强需求:零配置环境自动识别(第 7 章会完整展开)。这里我先看它跨平台的一面。env_auto.py站在每个子工程面前,自动回答三个问题:这是什么工程?需要什么版本?这台机器上哪个运行时满足?真实输出长这样(macOS):
$ python3 .harness/scripts/env_auto.py services/backend ✅ Java 1.8 → /Library/Java/JavaVirtualMachines/jdk1.8.0_191.jdk/Contents/Home ✅ Node >=14 → /opt/homebrew/bin backend: Java 1.8、Node >=14 — ✅ 环境就绪 [format=posix] export JAVA_HOME='/Library/Java/JavaVirtualMachines/jdk1.8.0_191.jdk/Contents/Home' export PATH='/Library/Java/JavaVirtualMachines/jdk1.8.0_191.jdk/Contents/Home/bin:$PATH' export PATH='/opt/homebrew/bin:$PATH'services/frontend就更薄——一个纯前端工程只需要 Node:
$ python3 .harness/scripts/env_auto.py services/frontend ✅ Node >=14 → /opt/homebrew/bin frontend: Node >=14 — ✅ 环境就绪 [format=posix] export PATH='/opt/homebrew/bin:$PATH'注意输出的最后一行:export语句本身,就是跨平台兼容的产物。export是 POSIX 语法(macOS/Linux),而 Windows 上是另一套。env_auto.py支持三种输出格式,按平台自动切换:
同样一份探测逻辑,三种 shell 各出一套加载语法——跨平台的本质不是写一套"哪里都能跑"的代码,而是把平台差异隔离在输出层,让上层逻辑完全一致。这就是为什么os-compatibility.md要求"新增 shell 输出型脚本时,参考 env_auto.py 的detect_format/fmt_exports实现"——它成了跨平台输出层的标杆实现。
跨平台兼容的三层防线总结
这三层分别解决了"意识的约束"、“执行的约束”、“设计的约束”——规则管想法、扫描管动作、模式管结构。
小结
这一章,我带你看了 Harness 的地基:
- 两套目录——
.harness/存"系统知道什么"(数据+机器),.claude/存"AI 怎么做"(身份+规则);目录结构本身就是四层元模型的物理映射; - config.json——把"主线分支名""流程模式"这类全局共识收敛到一处,用三级覆盖优先级让"单一真相源"落地;
- 跨平台兼容层——
os-compatibility.md规则 +check_harness.py机器扫描 +env_auto.py输出层模式,三层防线让 macOS/Windows 双平台团队共享同一套流程; - settings.json / templates/ git-hooks/——Hook 注册表、脚手架弹药库、提交门禁入口,各司其职。
下一章,走进这层地基里最重要的一根承重柱——Spec 系统:为什么系统能力需要一个"单一真相源"?GWT 格式为什么是"防 AI 作弊的物理锁"?跨域机制 FLOW 与 CSTR 如何不复制行为地编排全局?翻到第 5 章。