↑ ↓ 移动 · Enter 打开 · Esc 关闭点按一个结果

返回 hook 地图
§ architecture · hook 模式

每一种 hook 模式,以及它为何存在

生成的项目只注册一个程序,ArchHook.jar,但注册多次,每次带一个不同的模式。一个模式就是一项工作:让 skill 留在自己的领地内、守住一条边界、运行测试、记录这次运行。本页列出全部模式:各自的用途、能否让工作停下,以及项目能否修改它。

目录

共 12 行。ArchHook.jar 有十一种模式,但 doctor、export 和 build 是手动运行的,不是 hook,所以不在这里。项目注册的 hook 是其余八种,其中 guard 拆成五个阶段。一行可以代表共用同一项工作的多个模式:tests 也涵盖 tests agent-start 和 tests agent-end,audit 涵盖它的十二个模式。

模式触发于为何存在会拦截?项目能改吗?
guard:每个部分留在自己的领地内
guard prompt
UserPromptSubmit
知道正在运行哪个 skill。从不不能
guard call
PreToolUse
让设计运行远离构建类 skill。在设计运行打开期间,对构建类 skill 的 Skill 调用。不能
guard write
PreToolUse
写入留在类别的领地内。对正在运行的 skill 或智能体领地之外的写入,以及对已批准用例的任何写入(规格的 status 收尾和清单勾选除外)。不能
guard bash
PreToolUse
同一项检查,经由 shell。通过 shell 写入其类别不能写的位置或冻结的用例,以及任何写法的 force push。不能
guard sweep
Stop
回合结束时的兜底。本回合中其类别不能写入的任何改动。它负责发现,不负责预防。不能
schema:指令文件保持有效
schema
PreToolUsePostToolUseStop
harness 自己的文件保持有效。无效的 SKILL.md、智能体、规则或 settings.json 的 hook 条目,以及 .mcp.json 里的密钥。不能
build:代码保持正确
check
PostToolUse
每次编辑都判断架构。禁止的 import 或限定名,或所改模块的增量编译失败。文件已经写入,所以 Claude 被要求修复。不能
format
PostToolUse
格式化从不占用一个回合。从不不能
tests
SubagentStartSubagentStopStop
回合不会在测试变红时结束。当自 HEAD 以来改动的模块上 verify 失败时,回合的结束。写入型子智能体运行期间它会等待。不能
compose:栈能启动
compose gate
Stop
起不来的栈被尽早发现。当某个 compose 服务处于 exited 或 dead 时,回合的结束。能,改一个值
context:智能体带着什么开始
context subagent
SubagentStart
智能体带着所需内容开始。从不不能
audit:每次运行的轨迹
audit
UserPromptSubmitPreToolUsePostToolUseSubagentStopStop六个安静的事件
每次运行的轨迹,零 token。从不能,可关闭

每个模式的详细说明

它读取什么、拒绝时做什么、为何存在。每一行都读自 nerviz 文档和 settings.json。

guard prompt

guard:每个部分留在自己的领地内

知道正在运行哪个 skill。

触发于
UserPromptSubmit
它拦截什么
从不拦截。它只记录或准备,工作继续。

当提示是 /<skill> 时,它关闭上一个阶段,并为该 skill 的类别打开一个阶段。它还会取一份 git 基线,供回合结束时的 guard sweep 比对。没有打开的阶段就没有限制:人手动编辑文件,不算 skill 越界。

项目能改吗?
不能。这个模式归 Nerviz 所有:它写在 .claude/settings.json 和 extensions.json 中,/arch-adopt 每次更新都会覆盖这两个文件。
来源
08-audit-usage.mdsettings.json.example

guard call

guard:每个部分留在自己的领地内

让设计运行远离构建类 skill。

触发于
PreToolUse
它拦截什么
在设计运行打开期间,对构建类 skill 的 Skill 调用。

一次 Skill 调用会打开阶段,而同一类别的 skill 不会取代已有阶段。设计运行打开期间,对 blocked_during_design 所列类别的 skill 发起调用,会以 exit 2 退出。Agent 调用不改变任何东西:子智能体的写入按它自己的类别来判断。

项目能改吗?
不能。这个模式归 Nerviz 所有:它写在 .claude/settings.json 和 extensions.json 中,/arch-adopt 每次更新都会覆盖这两个文件。
来源
08-audit-usage.mdsettings.json.example

guard write

guard:每个部分留在自己的领地内

写入留在类别的领地内。

触发于
PreToolUse
它拦截什么
对正在运行的 skill 或智能体领地之外的写入,以及对已批准用例的任何写入(规格的 status 收尾和清单勾选除外)。

领地是数据,位于 extensions.json:skill_classes 和 agent_classes 为每个类别给出 write_allow。这是白名单,默认拒绝,因为泄漏的文件从来不是某人列出来的那个:一次设计运行曾把一个服务写进 docker-compose.yml。子智能体按它自己的类别来判断,无论有没有阶段。规格处于 approved、implemented 或 implemented-blocked 的用例被冻结,只有规格的 status: 变更、清单勾选和该文件夹的 CHANGELOG.md 除外。

项目能改吗?
不能。这个模式归 Nerviz 所有:它写在 .claude/settings.json 和 extensions.json 中,/arch-adopt 每次更新都会覆盖这两个文件。
来源
08-audit-usage.mdsettings.json.example

guard bash

guard:每个部分留在自己的领地内

同一项检查,经由 shell。

触发于
PreToolUse
它拦截什么
通过 shell 写入其类别不能写的位置或冻结的用例,以及任何写法的 force push。

其他保护都按工具名匹配,所以 heredoc、sed -i 或 tee 曾经写进冻结的用例,却没有任何东西反对。此模式读取命令中 guard.bash_write_shapes 所列的写入形态,并对每个能按字面读出的目标应用同样的两条规则。无法解析的目标($、反引号、通配符)会被静默跳过,这样一个在每条 shell 命令上都运行的 hook 就不会拦住构建。任何写法的 force push 都会被拒绝。

项目能改吗?
不能。这个模式归 Nerviz 所有:它写在 .claude/settings.json 和 extensions.json 中,/arch-adopt 每次更新都会覆盖这两个文件。
来源
08-audit-usage.mdsettings.json.example

guard sweep

guard:每个部分留在自己的领地内

回合结束时的兜底。

触发于
Stop
它拦截什么
本回合中其类别不能写入的任何改动。它负责发现,不负责预防。

它把工作树与 guard prompt 取的基线做对比,对任何未被工具时的 guard 放行的改动应用同样的规则,无论是哪个工具写的。它负责发现,不负责预防,git 忽略的路径从不被扫描。

项目能改吗?
不能。这个模式归 Nerviz 所有:它写在 .claude/settings.json 和 extensions.json 中,/arch-adopt 每次更新都会覆盖这两个文件。
来源
08-audit-usage.mdsettings.json.example

schema

schema:指令文件保持有效

harness 自己的文件保持有效。

触发于
PreToolUsePostToolUseStop
它拦截什么
无效的 SKILL.md、智能体、规则或 settings.json 的 hook 条目,以及 .mcp.json 里的密钥。

每个 SKILL.md 和智能体必须恰好属于一个类别,带有 **Class:** 行以及该类别要求的章节,智能体不得设置 permissionMode: bypassPermissions。它还检查规则的 frontmatter、.mcp.json 的字段(并扫描 headers 和 env 中的密钥)、settings.json 的 hook 条目,以及 export 清单与磁盘是否一致。它在写入之前、写入之后和回合结束时运行。

项目能改吗?
不能。这个模式归 Nerviz 所有:它写在 .claude/settings.json 和 extensions.json 中,/arch-adopt 每次更新都会覆盖这两个文件。
来源
01-file-types.mdsettings.json.example

check

build:代码保持正确

每次编辑都判断架构。

触发于
PostToolUse
它拦截什么
禁止的 import 或限定名,或所改模块的增量编译失败。文件已经写入,所以 Claude 被要求修复。

编辑 .java 文件之后,它读取禁止的 import(.claude/forbidden-imports.txt),并对被改动的模块做增量编译。违规时以 exit 2 退出,并带上文件和规则。在 PostToolUse 中,退出码不会撤销编辑:文件已经写入,消息会送到 Claude,让它修复原因。if: Edit(**/*.java) 过滤器避免为其他文件启动 JVM。

项目能改吗?
不能。这个模式归 Nerviz 所有:它写在 .claude/settings.json 和 extensions.json 中,/arch-adopt 每次更新都会覆盖这两个文件。
来源
01-file-types.mdsettings.json.example

format

build:代码保持正确

格式化从不占用一个回合。

触发于
PostToolUse
它拦截什么
从不拦截。它只记录或准备,工作继续。

每次 Java 编辑之后,在被改动的模块上运行 spotless:apply,使用与 check 相同的 if 过滤器。它从不拦截。

项目能改吗?
不能。这个模式归 Nerviz 所有:它写在 .claude/settings.json 和 extensions.json 中,/arch-adopt 每次更新都会覆盖这两个文件。
来源
01-file-types.mdsettings.json.example

tests

build:代码保持正确

回合不会在测试变红时结束。

触发于
SubagentStartSubagentStopStop
模式
tests agent-starttests agent-endtests
它拦截什么
当自 HEAD 以来改动的模块上 verify 失败时,回合的结束。写入型子智能体运行期间它会等待。

回合结束时,它在自 HEAD 以来改动的模块上运行 tests.stop_maven_args(verify -DskipITs -Djacoco.skip=true)。会话中有写入型子智能体运行时它会等待,而且只在那时等待:agent-start 和 agent-end 标记这个时间窗。

项目能改吗?
不能。这个模式归 Nerviz 所有:它写在 .claude/settings.json 和 extensions.json 中,/arch-adopt 每次更新都会覆盖这两个文件。
来源
01-file-types.mdsettings.json.example

compose gate

compose:栈能启动

起不来的栈被尽早发现。

触发于
Stop
它拦截什么
当某个 compose 服务处于 exited 或 dead 时,回合的结束。

它就是 doctor 和单独的 compose 所用的报告:健康时静默,否则 exit 2。它检查未运行的服务、其他容器已发布的端口,以及与测试所固定的不一致的 image: 标签。在本项目还没有任何容器时,端口问题只是警告。这项检查早就存在,却没人运行,结果一个宿主机客户端都连不上的 broker 在第一天就被交付了:所以它成为一道关口。

项目能改吗?
能,改一个值:compose-gate 的键 exited 取 block(默认)或 warn。
来源
01-file-types.md16-project-config.mdsettings.json.example

context subagent

context:智能体带着什么开始

智能体带着所需内容开始。

触发于
SubagentStart
它拦截什么
从不拦截。它只记录或准备,工作继续。

在 SubagentStart 时,它把 subagent_context 所指的 gof-design-patterns 目录各节,在第一个回合之前交给其 agent_classes 条目写着 pattern_catalog: true 的每个智能体,对其他智能体则什么也不输出。它之所以存在,是因为那个 skill 只能手动调用,而只能手动调用的 skill 无法通过智能体的 skills: 字段预加载。特意没有 matcher:过滤器就是 extensions.json 中的标志。

项目能改吗?
不能。这个模式归 Nerviz 所有:它写在 .claude/settings.json 和 extensions.json 中,/arch-adopt 每次更新都会覆盖这两个文件。
来源
01-file-types.mdsettings.json.example

audit

audit:每次运行的轨迹

每次运行的轨迹,零 token。

触发于
UserPromptSubmitPreToolUsePostToolUseSubagentStopStop六个安静的事件
模式
audit promptaudit callaudit askaudit fileaudit answeraudit agentaudit flushaudit failaudit permaudit compactaudit stopfailaudit close
它拦截什么
从不拦截。它只记录或准备,工作继续。

十二个模式、覆盖十一个事件,汇成一条轨迹:每次 skill 或智能体运行一份 Markdown 报告,含每个部分的 token、调用链、触及的文件和提出的问题,外加台账。提示和回答会经过脱敏列表。它只在 .claude/audit-usage/ 存在时才存在:没有这个文件夹,每个条目立刻返回,所以不使用它的项目只付出一次进程启动的代价。

项目能改吗?
能。删除 .claude/audit-usage/ 即可关闭轨迹。audited.json 决定它记录哪些部分。
来源
08-audit-usage.md16-project-config.mdsettings.json.example

项目能改什么

生成项目的 .claude/ 下几乎所有内容都归 Nerviz。有三个小文件归项目所有:export 从不提及它们,所以更新永远不会碰它们,文件不存在时项目得到 Nerviz 默认提供的行为。

设置它改变什么默认
compose-gate处于 exited 或 dead 的 compose 服务是否拦截回合的结束:block 或 warn。block
audited审计轨迹记录哪些 skill 和智能体,每个部分一个 true 或 false。由各部分的类别决定
plan-limits审计报告中套餐窗口预测所依据的可计费 token 预算。未设置:不做预测

如何修改

  • config 是唯一的写入者。它先构造修改后的文件,用 doctor 所用的校验器检查,一旦有问题就什么也不写,并以 exit 2 退出。
  • guard 会拒绝直接对这些文件的 Write、Edit 或 shell 重定向,并改为打印 config set 命令,所以模型无法把其中一个留成半有效状态。
  • unset 恢复默认。文件不存在就表示默认。
  • 在 Claude Code 中,/project-config 以对话方式完成同样的事:显示已设置的内容,询问你要做哪项修改,然后运行命令。
# 无论有没有智能体,该命令都可用
java -jar .claude/hooks/ArchHook.jar config list
java -jar .claude/hooks/ArchHook.jar config set compose-gate exited warn
java -jar .claude/hooks/ArchHook.jar config set audited skills.report-issue false
java -jar .claude/hooks/ArchHook.jar config unset compose-gate exited

# 在 Claude Code 中,以对话方式完成同样的事
> /project-config

nerviz 文档中的设置 →返回 Architecture