↑ ↓ to move · Enter to open · Esc to closeTap a result

Back to the hook map
§ architecture · the hook modes

Every hook mode, and why it exists

A generated project registers one program, ArchHook.jar, many times, each time with a different mode. A mode is one job: keep a skill inside its territory, hold a boundary, run the tests, record the run. This page lists them all: what each one is for, whether it can stop the work, and whether a project can change it.

The catalog

12 rows. ArchHook.jar has eleven modes, but doctor, export and build are run by hand and are not hooks, so they are not here. The hooks a project registers are the other eight, with guard split into its five phases. A row can stand for several modes that share one job: tests also covers tests agent-start and tests agent-end, and audit covers its twelve modes.

ModeFires onWhy it existsBlocks?Can a project change it?
guard: each piece stays inside its territory
guard prompt
UserPromptSubmit
Knows which skill is running.neverno
guard call
PreToolUse
Keeps a design run away from build skills.A Skill call to a build-class skill while a design run is open.no
guard write
PreToolUse
Writes stay inside the territory of the class.A write outside the territory of the running skill or agent, and any write into an approved use case except its status close and checklist toggles.no
guard bash
PreToolUse
The same check, from the shell.A shell write into a place its class cannot write or into a frozen use case, and a force push in any spelling.no
guard sweep
Stop
The backstop at the end of the turn.Any change this turn made that its class may not write. It detects; it does not prevent.no
schema: the instruction files stay valid
schema
PreToolUsePostToolUseStop
The harness's own files stay valid.An invalid SKILL.md, agent, rule or settings.json hook entry, and a secret in .mcp.json.no
build: the code stays correct
check
PostToolUse
The architecture is judged on each edit.A forbidden import or qualified name, or a failed incremental compile of the touched module. The file is already written, so Claude is told to fix it.no
format
PostToolUse
Formatting never costs a turn.neverno
tests
SubagentStartSubagentStopStop
A turn does not end on red tests.The end of the turn while verify fails on the modules changed since HEAD. It waits while a writer subagent runs.no
compose: the stack starts
compose gate
Stop
A stack that does not start is caught early.The end of the turn while a compose service is exited or dead.yes, one value
context: what an agent starts with
context subagent
SubagentStart
An agent starts with what it needs.neverno
audit: the trail of every run
audit
UserPromptSubmitPreToolUsePostToolUseSubagentStopStopsix quieter events
The trail of every run, at zero tokens.neveryes, switch off

Each mode, in depth

What it reads, what it does when it refuses, and why it exists. Every line is read from the nerviz documentation and settings.json.

guard prompt

guard

Knows which skill is running.

Fires on
UserPromptSubmit
What it blocks
Never blocks. It records or prepares, and the work goes on.

When a prompt is /<skill>, it closes the previous phase and opens one for that skill's class. It also takes the git baseline that guard sweep compares against at the end of the turn. No phase open means no restriction: a person editing a file by hand is not a skill overstepping.

Can a project change it?
No. Nerviz owns this mode: it is written to .claude/settings.json and extensions.json, and /arch-adopt overwrites both on every update.
Source
08-audit-usage.mdsettings.json.example

guard call

guard

Keeps a design run away from build skills.

Fires on
PreToolUse
What it blocks
A Skill call to a build-class skill while a design run is open.

A Skill call opens the phase, and a phase is never replaced by a skill of the same class. While a design run is open, a call to a skill of a class listed in blocked_during_design exits 2. An Agent call changes nothing: a subagent's writes are judged by its own class.

Can a project change it?
No. Nerviz owns this mode: it is written to .claude/settings.json and extensions.json, and /arch-adopt overwrites both on every update.
Source
08-audit-usage.mdsettings.json.example

guard write

guard

Writes stay inside the territory of the class.

Fires on
PreToolUse
What it blocks
A write outside the territory of the running skill or agent, and any write into an approved use case except its status close and checklist toggles.

Territory is data, in extensions.json: skill_classes and agent_classes give each class its write_allow. It is an allowlist, deny by default, because the file that leaks is never the one somebody listed: a design run once wrote a service into docker-compose.yml. A subagent is judged by its own class, phase or not. A use case whose spec is approved, implemented or implemented-blocked is frozen, except the spec's status: move, a checklist toggle and the folder's CHANGELOG.md.

Can a project change it?
No. Nerviz owns this mode: it is written to .claude/settings.json and extensions.json, and /arch-adopt overwrites both on every update.
Source
08-audit-usage.mdsettings.json.example

guard bash

guard

The same check, from the shell.

Fires on
PreToolUse
What it blocks
A shell write into a place its class cannot write or into a frozen use case, and a force push in any spelling.

Every other enforcement matches a tool name, so a heredoc, sed -i or tee once wrote into a frozen use case with nothing objecting. This mode reads the command for the write shapes listed in guard.bash_write_shapes and applies the same two rules to each target it can read literally. A target it cannot resolve ($, a backtick, a glob) is skipped in silence, which keeps a hook that runs on every shell command from blocking a build. A force push in any spelling is refused.

Can a project change it?
No. Nerviz owns this mode: it is written to .claude/settings.json and extensions.json, and /arch-adopt overwrites both on every update.
Source
08-audit-usage.mdsettings.json.example

guard sweep

guard

The backstop at the end of the turn.

Fires on
Stop
What it blocks
Any change this turn made that its class may not write. It detects; it does not prevent.

It diffs the working tree against the baseline guard prompt took, and applies the same rules to whatever changed that no tool-time guard admitted, whichever tool wrote it. It detects, it does not prevent, and a path git ignores is never swept.

Can a project change it?
No. Nerviz owns this mode: it is written to .claude/settings.json and extensions.json, and /arch-adopt overwrites both on every update.
Source
08-audit-usage.mdsettings.json.example

schema

schema

The harness's own files stay valid.

Fires on
PreToolUsePostToolUseStop
What it blocks
An invalid SKILL.md, agent, rule or settings.json hook entry, and a secret in .mcp.json.

Every SKILL.md and agent must sit in exactly one class, carry its **Class:** line and have the sections that class requires, and an agent must not set permissionMode: bypassPermissions. It also checks rule frontmatter, the fields of .mcp.json with a scan for secrets in headers and env, the hook entries of settings.json, and the export manifest against the disk. It runs before a write, after one, and at the end of the turn.

Can a project change it?
No. Nerviz owns this mode: it is written to .claude/settings.json and extensions.json, and /arch-adopt overwrites both on every update.
Source
01-file-types.mdsettings.json.example

check

build

The architecture is judged on each edit.

Fires on
PostToolUse
What it blocks
A forbidden import or qualified name, or a failed incremental compile of the touched module. The file is already written, so Claude is told to fix it.

After an edit to a .java file, it reads the forbidden imports (.claude/forbidden-imports.txt) and compiles the touched module incrementally. A violation exits 2 with the file and the rule. In PostToolUse the exit code does not undo the edit: the file is written, and the message reaches Claude so it fixes the cause. An if: Edit(**/*.java) filter keeps the JVM from starting for any other file.

Can a project change it?
No. Nerviz owns this mode: it is written to .claude/settings.json and extensions.json, and /arch-adopt overwrites both on every update.
Source
01-file-types.mdsettings.json.example

format

build

Formatting never costs a turn.

Fires on
PostToolUse
What it blocks
Never blocks. It records or prepares, and the work goes on.

It runs spotless:apply on the touched module after every Java edit, with the same if filter as check. It never blocks.

Can a project change it?
No. Nerviz owns this mode: it is written to .claude/settings.json and extensions.json, and /arch-adopt overwrites both on every update.
Source
01-file-types.mdsettings.json.example

tests

build

A turn does not end on red tests.

Fires on
SubagentStartSubagentStopStop
Modes
tests agent-starttests agent-endtests
What it blocks
The end of the turn while verify fails on the modules changed since HEAD. It waits while a writer subagent runs.

At the end of the turn it runs tests.stop_maven_args (verify -DskipITs -Djacoco.skip=true) on the modules changed since HEAD. While a writer subagent of the session is running, it waits, and only then: agent-start and agent-end mark that window.

Can a project change it?
No. Nerviz owns this mode: it is written to .claude/settings.json and extensions.json, and /arch-adopt overwrites both on every update.
Source
01-file-types.mdsettings.json.example

compose gate

compose

A stack that does not start is caught early.

Fires on
Stop
What it blocks
The end of the turn while a compose service is exited or dead.

It is the report doctor and the bare compose use, silent while healthy and exit 2 otherwise. It looks at services that are not running, at ports another container publishes, and at image: tags that disagree with the ones the tests pin. A port finding is only a warning while no container of this project exists. The check existed and nobody ran it, and a broker no host client could reach shipped on day one: that is why it is a gate.

Can a project change it?
Yes, one value: compose-gate, key exited, is block (the default) or warn.
Source
01-file-types.md16-project-config.mdsettings.json.example

context subagent

context

An agent starts with what it needs.

Fires on
SubagentStart
What it blocks
Never blocks. It records or prepares, and the work goes on.

At SubagentStart it hands the sections of the gof-design-patterns catalog that subagent_context names to every agent whose agent_classes entry says pattern_catalog: true, before its first turn, and prints nothing for any other agent. It exists because that skill is manual-only, and a manual-only skill cannot be preloaded through an agent's skills: field. There is no matcher on purpose: the flag in extensions.json is the filter.

Can a project change it?
No. Nerviz owns this mode: it is written to .claude/settings.json and extensions.json, and /arch-adopt overwrites both on every update.
Source
01-file-types.mdsettings.json.example

audit

audit

The trail of every run, at zero tokens.

Fires on
UserPromptSubmitPreToolUsePostToolUseSubagentStopStopsix quieter events
Modes
audit promptaudit callaudit askaudit fileaudit answeraudit agentaudit flushaudit failaudit permaudit compactaudit stopfailaudit close
What it blocks
Never blocks. It records or prepares, and the work goes on.

Twelve modes, on eleven events, feed one trail: a Markdown report per skill or agent run, with tokens per piece, the chain, the files touched and the questions asked, plus ledgers. Prompts and answers go through a redaction list. It exists only while .claude/audit-usage/ exists: without the folder every entry returns at once, so a project that does not use it pays a process start and nothing more.

Can a project change it?
Yes. Delete .claude/audit-usage/ to switch the trail off. audited.json picks which pieces it records.
Source
08-audit-usage.md16-project-config.mdsettings.json.example

What a project can change

Almost everything under a generated project's .claude/ belongs to Nerviz. Three small files belong to the project: export never names them, so an update never touches them, and while a file is absent the project gets what Nerviz ships.

SettingWhat it changesDefault
compose-gateWhether a compose service in exited or dead blocks the end of a turn: block or warn.block
auditedWhich skills and agents the audit trail records, one true or false per piece.each piece's class decides
plan-limitsThe billable-token budget behind the plan-window projection of the audit reports.unset: no projection

Changing one

  • config is the only writer. It builds the file as it would be after the change, checks it with the validator doctor uses, and on any problem writes nothing and exits 2.
  • guard refuses a direct Write, Edit or shell redirect into these files and prints the config set command instead, so a model cannot leave one half valid.
  • unset goes back to the default. An absent file means the default.
  • In Claude Code, /project-config does the same in conversation: it shows what is set, asks which change you want, and runs the command.
# the command works with or without an agent
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

# in Claude Code, the same in conversation
> /project-config

The settings, in the nerviz docs →Back to Architecture