Hooks
Hooks enforce quality automatically — running shell commands at phase boundaries and session events without configuration. They load learnings at startup, save checkpoints before compaction, block delivery without passing tests, and warn when knowledge would be lost. TRW ships 12 hooks that cover the full session lifecycle.
How Hooks Work
Claude Code fires hook events at specific points in its lifecycle — when a session starts, before a tool runs, after a file is modified, and when the session ends. TRW registers shell scripts against these events in .claude/settings.json. When an event fires, Claude Code runs the matching script and reads its output.
Each hook follows a fail-open pattern: if the script errors, it exits 0 silently so your session is never broken by hook infrastructure. Hooks that enforce gates (like the delivery blocker) use exit code 2 to signal a block with an explanation message.
Info
Hooks run in the project's git root directory. They use lib-trw.sh for shared utilities like finding the active run, reading config, and logging execution telemetry.
Hook Events
Claude Code provides the hook events. TRW registers scripts against each one.
Session
| Event | When it fires | What TRW does |
|---|---|---|
| SessionStart | Session opens (startup, resume, compact, clear) | Loads prior learnings, recovers interrupted runs, emits tier guidance |
| UserPromptSubmit | Before every user prompt is sent to the model | Injects phase-aware context reminders (research, plan, implement, etc.) |
| PreCompact | Before context window compaction | Saves emergency checkpoint so progress survives compaction |
| SessionEnd | Session closes normally | Warns if trw_deliver was not called, preventing knowledge loss |
| Stop | User presses Escape or session is interrupted | Blocks if delivery was skipped (max 2 blocks, then advisory) |
Tools
| Event | When it fires | What TRW does |
|---|---|---|
| PreToolUse | Before a tool call executes | Gates trw_deliver until build check passes; validates PRD write scope |
| PostToolUse | After Write or Edit tool completes | Logs file_modified events to the active run for change tracking |
Agents
| Event | When it fires | What TRW does |
|---|---|---|
| SubagentStart | A subagent is spawned | Injects abbreviated TRW protocol and active run context |
| SubagentStop | A subagent completes | Logs subagent completion and captures telemetry |
| TeammateIdle | An Agent Teams teammate has no pending tasks | Notifies the lead so work can be redistributed |
| TaskCompleted | An Agent Teams task finishes | Blocks teammates who skipped build check or checkpoints |
Warning
Hooks are synchronous — they block until the script completes or times out. Each hook has a configured timeout (3–10 seconds). Keep custom hooks fast to avoid delaying the agent's workflow.
Built-in Hooks
TRW ships these 12 hook scripts. They are installed into .claude/hooks/ and registered in .claude/settings.json automatically.
| Script | Event | Purpose |
|---|---|---|
| session-start.sh | SessionStart | Loads learnings, checks for interrupted runs, emits tier-calibrated ceremony guidance |
| user-prompt-submit.sh | UserPromptSubmit | Injects phase-specific reminders before each prompt (under 150 tokens) |
| pre-compact.sh | PreCompact | Saves active run state to a recovery file before context compaction |
| session-end.sh | SessionEnd | Warns if events were logged but trw_deliver was never called |
| stop-ceremony.sh | Stop | Blocks exit if delivery was skipped (max 2 blocks, then falls through) |
| pre-tool-deliver-gate.sh | PreToolUse | Blocks trw_deliver until trw_build_check has passed |
| post-tool-event.sh | PostToolUse | Logs file modifications after Write/Edit tool calls |
| validate-prd-write.sh | PreToolUse | Restricts planning agents to writing only PRD and run directory files |
| subagent-start.sh | SubagentStart | Injects TRW protocol context and phase guidance into spawned subagents |
| subagent-stop.sh | SubagentStop | Captures subagent completion telemetry and logs results |
| task-completed.sh | TaskCompleted | Quality gate for Agent Teams: blocks if build check or checkpoints are missing |
| teammate-idle.sh | TeammateIdle | Notifies the lead agent when a teammate has no remaining tasks |
Tip
The most impactful hook is pre-tool-deliver-gate.sh. It blocks trw_deliver until trw_build_check has passed, preventing the agent from closing a session with untested code. This single gate catches the most common failure mode in AI-assisted development.
Hook Registration
Hooks are registered in .claude/settings.json under the hooks key. Each event maps to an array of matchers, and each matcher contains a shell command and timeout. The TRW installer generates this configuration automatically.
{
"hooks": {
"SessionStart": [
{
"matcher": "startup",
"hooks": [{
"type": "command",
"command": "sh .claude/hooks/session-start.sh",
"timeout": 5000
}]
}
],
"PreToolUse": [
{
"matcher": "mcp__trw__trw_deliver",
"hooks": [{
"type": "command",
"command": "sh .claude/hooks/pre-tool-deliver-gate.sh",
"timeout": 5000
}]
}
],
"Stop": [
{
"matcher": "",
"hooks": [{
"type": "command",
"command": "sh .claude/hooks/stop-ceremony.sh",
"timeout": 10000
}]
}
]
}
}The matcher field filters when the hook fires. An empty string matches all events of that type. A specific value like mcp__trw__trw_deliver matches only that tool call. SessionStart uses source matchers ( startup, resume, compact, clear) to fire on each session source.
Custom Hooks
You can add your own hooks alongside TRW's built-in ones. Add a new entry to the appropriate event array in .claude/settings.json. Your hook script receives the same JSON payload from stdin that TRW's hooks receive.
// In .claude/settings.json, add to the PostToolUse array:
{
"matcher": "Bash",
"hooks": [{
"type": "command",
"command": "sh .claude/hooks/my-bash-audit.sh",
"timeout": 3000
}]
}Custom hooks follow the same conventions: exit 0 to allow, exit 2 to block (with a message on stderr). Use the fail-open pattern — trap 'exit 0' EXIT — so errors never break the agent's session.
Troubleshooting
Hooks not firing at all
Cause: The .claude/settings.json file is missing or the hooks section was not generated by the installer.
Fix: Re-run the TRW installer or copy the hooks config from settings.json into your project.
Hook exits with "permission denied"
Cause: Shell scripts need execute permissions on Unix systems.
Fix: Run chmod +x .claude/hooks/*.sh to fix permissions.
Hook times out (no output)
Cause: Hooks have timeouts (3-10 seconds). A slow filesystem or missing jq can cause delays.
Fix: Install jq for faster JSON parsing. Check that .trw/ directory exists and is not on a network mount.