在模型与磁盘之间,有一个 hook。
Claude Code 提供模型及其工具。Nerviz 在其周围加入五类组件。其中四类引导模型;第五类在每个事件上以进程方式运行,并且可以拒绝该操作。
一个用例遇上 harness
bank-app 的 UC-005,从第一条提示到构建通过,共九步。终端显示运行了哪些 hook 模式以及它们的输出:拒绝信息就是 hook 自己的原文。
一条提示开启本轮
你输入 /new-feature。guard prompt 关闭上一个阶段,记录磁盘上已有的内容,并为 new-feature(类 orchestrator)打开一个阶段。skill 正文进入上下文,并保留到本次运行结束。
谁加载,谁调用,谁能说不
- CLAUDE.md
索引与路由表。规范本身位于它所指向的 rule 或 skill 中。
- 进入上下文
- 始终,在会话开始时
- 调用者
- 无人调用:自动加载
- 能否拦截
- 否
- rule
一条规范:必须成立的事。叶子节点:从不提及 skill、agent 或命令。
- 进入上下文
- 当匹配其
paths的文件被触及时 - 调用者
- 无人调用:自动加载
- 能否拦截
- 否
- skill
一段流程。它的类决定所用模型、正文的章节,以及可写入的位置。
- 进入上下文
- 被调用时加载,并保留到后续轮次
- 调用者
- 你(
/名称)或模型 - 能否拦截
- 否
- agent
隔离执行:独立的上下文、受限的工具、独立的模型。
- 进入上下文
- 被委派时,在全新的上下文中
- 调用者
- 某个 skill,通过 Agent 工具
- 能否拦截
- 否
- hookexit 2
ArchHook.jar:Java 实现,十一种模式,不依赖 shell。在settings.json中注册。- 进入上下文
- 从不以文本形式进入:作为进程运行
- 调用者
- 运行时,在事件发生时
- 能否拦截
- 能,exit 2
agent 只为三个理由之一而存在:保留上下文、限制工具,或切换模型。凡是必须始终成立的,都是 hook 或 permissions.deny 规则,而不是 markdown 里的文字。
有多少 skill 和 agent
nerviz 中的每个 skill 和 agent 都属于 extensions.json 中的一个类,任何未被类列出的文件都会让 schema 失败。因此类就是目录:这些数字读自最新发布版本中的类定义,从不手工填写。
其中 27 个会导出到每个生成的项目
design13orchestrator3build7observer2meta1ops4report2
其中 5 个会导出到每个生成的项目
driver1executor1installer4verifier1
project-config新2026-10-24platform-upgrade2026-10-19new-project2026-10-15mapstruct-installer2026-10-14ai-architect2026-10-13
读自 nerviz 发布版本 v0.44.0 的 extensions.json,发布于 2026-10-27。
三个命令,三条链
每个命令开启自己的一条链:
/init-project创建项目,只运行一次。/new-feature设计一个用例并交付规格,不写代码。/new-feature-implement根据已批准的规格构建代码。
虚线组件仅在适用时运行。
use-case-design00-caso-de-uso.mddomain-modeling10-dominio.mdrest-api-architect30-rest.md除非触发方式只有 GraphQLgraphql-api-architect31-graphql.md当触发方式包含 GraphQL 适配器时security-architect32-seguranca.md当访问控制需要超出 filter chain 已有的能力时http-client-architect28-cliente-http.md当某个端口通过 HTTP 调用其他系统时ai-architect29-ia.md当某个端口是 LLM 或向量库时search-architect23-busca.md当 Search index 行指定了投影时messaging-architect25-mensageria.md当事件需要通过 Kafka 投递时jobs-architect35-jobs.md定时任务、outbox relay、对账、重建索引或清理历史时persistence-architect20-persistencia.mdcache-architect22-cache.md当 Freshness 声明了容忍度时test-architect40-testes.md- 你批准 · 规格冻结
- skill
- agent
- 仅在适用时
每个类只写自己的路径
每个 skill 属于七个类之一,每个 agent 属于四个类之一。类在 extensions.json 中列出可写的路径,guard 拒绝其余一切,默认拒绝。选择一个类:
.claude/CLAUDE.mddocs/use-cases/BACKLOG.mduse-cases/UC-005-record-kyc-verdict/20-persistencia.mduse-cases/UC-005-record-kyc-verdict/UC-005-spec.mdlessons-learned/src/main/java/…/domain/model/Customer.javasrc/test/java/…/domain/model/CustomerTest.javapom.xmldocker-compose.yml.env.example
- 可写入
- 拒绝:超出写入范围
- 拒绝:规格已冻结
- 仅状态收尾与清单勾选
触及文件,即获得其规范
每条 rule 都声明 paths。当匹配的文件被触及时,rule 自动进入上下文,无需任何人记得引用它。这里是 bank-app 的 21 条 rule,其 glob 由 export 按它的蓝图写入。选择一个文件:
architecture-ddd.mdvalue-objects.mdnaming.mdcode-quality.mderror-handling.mdlogging.mdlombok.mdpersonal-data.mdsecrets.mdapi-rest.mdapi-graphql.mdinbound-admission.mdauthorization.mdobservability.mdpersistence.mdmessaging.mdscheduling.mdhttp-client.mdai.mdcaching.mdsearch.mdtesting.mdtransport-security.mdspec-diagrams.md00-index.md
每个事件,每种模式
生成的项目在 .claude/settings.json 中注册的内容。每一项都运行 java -jar .claude/hooks/ArchHook.jar <mode>,采用 exec 形式,在 Linux、macOS 和 Windows 上完全一致。选一个事件,看它何时触发。
一个回合中,事件触发的先后顺序
audit promptguard prompt你按下回车。hook 在 Claude 读到任何一个字之前运行。
你输入了
此事件上的模式
audit prompt当提示是一个被审计的 skill 时,建立本次运行的记录,以便把 token 和文件归到它名下。项目可关闭guard prompt关闭上一个阶段,打开提示所指的阶段,让各个 guard 知道正在运行哪个 skill。
guard callguard writeguard bashschemaaudit callaudit askClaude 即将使用一个工具。hook 仍来得及说不。
你输入了
persistence-architect 想写入 docker-compose.ymlguard write 检查它所属类别的领地此事件上的模式
guard call不让设计运行触及构建类 skill。可拦截拦截: 在设计运行打开期间,对构建类 skill 的
Skill调用。guard write每个 skill 和智能体只在自己类别的领地内写入,已批准的规格保持冻结。可拦截拦截: 对正在运行的 skill 或智能体领地之外的写入,以及对已批准用例的任何写入(规格的 status 收尾和清单勾选除外)。
guard bash同一项检查,从 shell 一侧进行:heredoc、sed -i或tee不能做 Write 不能做的事。可拦截拦截: 通过 shell 写入其类别不能写的位置或冻结的用例,以及任何写法的 force push。
schema保持 harness 的指令文件有效,让损坏的 skill、智能体或 hook 条目立刻失败,而不是在以后的运行中才暴露。可拦截拦截: 无效的
SKILL.md、智能体、规则或settings.json的 hook 条目,以及.mcp.json里的密钥。audit call把每次 Skill、Task 或 Agent 调用记为链上的一个节点。项目可关闭audit ask记下 Claude 正在等你,这段等待就不会被算作工作时间。项目可关闭
context subagenttests agent-startClaude 把工作交给子智能体。hook 可以在子智能体的第一个回合之前载入上下文。
你输入了
context subagent 交付设计模式目录此事件上的模式
context subagent在第一个回合之前,把设计模式目录交给类别需要它的每个智能体。其他智能体什么也收不到。tests agent-start记下有一个写入型子智能体正在运行,让测试等它。
checkschemaformataudit fileaudit answer一个工具刚刚运行完。改动已经发生,hook 来检查它。
你输入了
Customer.javacheck、format 和审计轨迹检查该文件此事件上的模式
check在写代码的同时守住架构:每次编辑都判断边界,而不是等到评审。可拦截拦截: 禁止的 import 或限定名,或所改模块的增量编译失败。文件已经写入,所以 Claude 被要求修复。
schema保持 harness 的指令文件有效,让损坏的 skill、智能体或 hook 条目立刻失败,而不是在以后的运行中才暴露。可拦截拦截: 无效的
SKILL.md、智能体、规则或settings.json的 hook 条目,以及.mcp.json里的密钥。format在被改动的模块上运行spotless:apply,格式化从不占用一个回合。audit file记录一次运行触及的每个文件。项目可关闭audit answer在报告中记录每个问题和你的回答(已脱敏)。项目可关闭
audit agenttests agent-end子智能体完成并交回结果。
你输入了
此事件上的模式
audit agent关闭子智能体的报告。它的 token 来自它自己的 transcript。项目可关闭tests agent-end写入型子智能体结束时,放行测试。
schemaguard sweepcompose gatetestsaudit flushClaude 认为自己做完了。这是回合结束前的最后一道关口。
你输入了
schema、guard sweep、compose gate 和 tests 检查真正发生的改动此事件上的模式
schema保持 harness 的指令文件有效,让损坏的 skill、智能体或 hook 条目立刻失败,而不是在以后的运行中才暴露。可拦截拦截: 无效的
SKILL.md、智能体、规则或settings.json的 hook 条目,以及.mcp.json里的密钥。guard sweep回合结束时的兜底:把磁盘与 git 基线比对,抓住工具时的 guard 读不出来的写入。可拦截拦截: 本回合中其类别不能写入的任何改动。它负责发现,不负责预防。
compose gate起不来的栈在回合结束时就被发现,而不是以后在某人的机器上。可拦截项目可调整拦截: 当某个 compose 服务处于
exited或dead时,回合的结束。tests回合不会在测试变红时结束。可拦截拦截: 当自
HEAD以来改动的模块上verify失败时,回合的结束。写入型子智能体运行期间它会等待。audit flush根据日志生成本次运行的报告,并写入台账行。项目可关闭
audit permaudit failaudit compactaudit stopfailaudit close六个安静的事件。它们只写入审计轨迹,没有一个会拦截。
你输入了
git push,它保持在 ask此事件上的模式
audit perm记录被请求或被拒绝的权限。项目可关闭audit fail把失败的工具记为返工。项目可关闭audit compact记录一次上下文压缩。项目可关闭audit stopfail记录停止时的失败。项目可关闭audit close会话结束时关闭仍打开的运行。项目可关闭
mode 可用 exit 2 拒绝 · mode 从不拦截 ·可拦截 项目可调整 项目可关闭
每种模式为何存在、拦截什么、项目能改什么:全部列在一张表里,并附详细说明。
打开模式目录 →上面的每一次拒绝都在 CI 中运行
validate.yml 在每次 push 和 pull request 时运行。hook 测试启动的正是注册项所运行的 java -jar .claude/hooks/ArchHook.jar,覆盖 Ubuntu、macOS 和 Windows。另一个 job 检查提示图的不变量,还有一个 job 把每个蓝图导出两次,并要求两棵目录树完全一致。
- hooks · ubuntu-latest1m32s
- hooks · macos-latest1m37s
- hooks · windows-latest3m15s
- design invariants33s
- export is reproducible and self-contained55s
- exemplar imports resolve against the real classpath6m13s
六个 job 并行运行。每个 hook job 都在测试之前运行 build --verify:提交的 jar 必须与源码编译结果逐字节一致,因此测试运行的是经过审查的字节。
自 2026-09-11 起 validate.yml 的运行通过。11 次失败,4 次取消。统计于 2026-10-13。
失败的运行在 Actions 中保持公开。上方徽章是实时的;数字是快照。
全部运行 →该运行的每一个 step,回放
validate.yml 中全部 58 个具名 step,使用 GitHub 为上面这次运行记录的时间,以 12 倍速播放。hooks job 在三个 runner 上运行每个 step,每个 runner 一个圆点:Ubuntu、macOS 和 Windows。
- Set up job · checkout · setup-java
- doctor
- committed ArchHook.jar is what the source compiles to
- the jar runs what the hooks run
- hook blocks forbidden import, from the payload and from argv
- format, check and tests hand Maven the module the edited file belongs to
- tests defers while a writer subagent of the session runs, and only then
- hook blocks a cwd-relative frontmatter injection
- schema blocks a migrations entry no project would see
- hook reports a compose image tag that disagrees with src/test
- guard keeps each skill inside its class's territory
- guard keeps each agent inside its class's territory
- guard bash refuses force pushes and holds shell writes to the phase
- guard sweep reports this turn's writes, never pre-existing dirt
- guard status prints the open phase the cockpit draws
- schema blocks a mod that would load half-way
- compose gate blocks a published service no host client can reach
- doctor gate fails on every gated line and only on those
- schema blocks a settings file that re-enables a colliding plugin
- doctor names a personal skill that shadows a project skill, and never gates
- doctor checks the agent instruction files against the blueprint, and never gates
- doctor sweeps every source file for forbidden imports, with check's own match
- export notes only real overwrites, and never guesses the stamp's commit
- context subagent hands the catalog to pattern_catalog agents only
- audit renders where the run spent, redacts tool errors, skips what class or project turns off
- audit genesis fills GENESIS from the transcripts, once
- Set up job · checkout · setup-java
- frontmatter schema (extensions.json is the single owner — invariant 10)
- decisions/ doesn't grow paths or enter 00-index.md
- no hardcoded Spring/Java version outside decisions/ (invariant 8)
- new blueprint doesn't touch prompts
- rules is a leaf of the graph
- norm contains no code boilerplate
- no new commands/
- exemplars have the .example suffix at the end
- exemplar bodies carry no comment but Javadoc
- XML exemplars are well-formed
- spec template diagrams name only what their text defines
- cache exemplars decide every library default, and only they cache
- AI exemplars decide every library default, and only they reach the library
- GraphQL exemplars decide every limit and batch every child list
- document-family exemplars name collection, alias and version, and run a replica set
- search exemplars keep the index a strict, versioned projection
- auditing exemplars keep the history whole, its actor named and its prune safe
- REST exemplars version every handler from one configuration
- admission exemplars keep one bounded limiter per caller and an inbound cap ahead of idempotency
- blueprint-declared templates exist on disk
- issue forms cited by skills exist
- compose service templates merge and parse
- each norm has a single owner
- no dependencies outside the Java ecosystem
- every norm `paths` matches some blueprint
- Set up job · checkout · setup-java
- export twice per blueprint, require identical trees
- the exported tree carries nothing that only exists here
- the exported tree passes its own schema
- re-export deletes what export.retired names
- Set up job · checkout · setup-java
- reference project from the Initializr
- build the classpath
- every exemplar import exists in a JAR
- exemplars don't use known deprecated symbols
播放器的每一步,以及证明它的测试
- 步骤 4
设计类 skill 无法写入
docker-compose.yml。引发这一切的那个案例就是其中一个用例。$ java .claude/.ci/SkillTerritoryTest.java✅ compose file outside the territory — blocked (exit 2)✅ compose allowed once docker-architect joined (exit 0)✅ the implement thread itself still may not write compose (exit 2)59 个用例,全部通过
同样的写入范围也适用于 shell 写入,所有 force push 写法都会被拒绝。
$ java .claude/.ci/BashGuardTest.java✅ `-f` — blocked✅ executor: `sed -i -e` on a file outside its territory — blocked29 个用例,全部通过
- 步骤 6
agent 按它自己的类判定,无论调用者留下了哪个阶段。
$ java .claude/.ci/AgentTerritoryTest.java✅ the executor writes main source (exit 0)✅ archunit-installer is refused docker-compose.yml (exit 2)37 个用例,全部通过
设计模式目录只会交给其类要求它的 agent。
$ java .claude/.ci/SubagentContextTest.java✅ general-purpose receives nothing✅ context subagent: catalog to pattern_catalog agents only, within max_chars.
- 步骤 7
禁止的 import 以 exit 2 拒绝,无论来自 hook 载荷还是
check <path>。$ java .claude/.ci/BoundaryTest.java ✓ stdin payload blocks the forbidden import ✓ check <path> blocks it with stdin left open✅ Boundary enforced: forbidden import blocked with exit 2, from the payload and from argv.
- 步骤 9
Stop的 sweep 只指出本轮写入的内容,而且不会重复拦截。$ java .claude/.ci/SweepTest.java✅ write outside the territory — reported, pre-existing dirt is not✅ stop_hook_active — does not block twice
tests在写入型 subagent 运行期间等待,且仅在此时等待。$ java .claude/.ci/TestsDeferTest.java✅ tests: deferred while a writer subagent runs, Maven called otherwise.
提示图,像代码一样被检查
design invariants job 把 harness 自身架构的每条规则变成一个会失败的步骤。其中一些,按 workflow 中的名称:
frontmatter schema (extensions.json is the single owner — invariant 10)rules is a leaf of the graphnew blueprint doesn't touch promptsno hardcoded Spring/Java version outside decisions/ (invariant 8)each norm has a single ownerevery norm `paths` matches some blueprint
在每个生成的项目中也是如此
项目自带 CI。它的 architectural boundaries job 运行 doctor gate:当 hook jar、hooks、schema 或边界损坏,或任何源文件包含禁止的 import 时,它就会失败。
- architectural boundaries
java .claude/hooks/ArchHook.java doctor gate10s - build and tests3m37s