Hooks
Command hooks load from these files, later entries append:
~/.agents/hooks.json- every
~/.agents/hooks/*.json <workspace>/.agents/hooks.json<workspace>/.agents/hooks/*.json
A missing directory is an empty source. $HOME in a command string expands.
PreToolUse and PostToolUse run for write_file and run. A matcher of
write_file also matches Write, Edit, MultiEdit, write, and
search_replace. A matcher of run also matches Bash and
run_terminal_command. Reads, list_dir, ask, and use_skill skip
PreToolUse. Hooks write no cards.
Contract
- A
PreToolUsecommand receives{ "tool_name", "tool_input" }on stdin. Exit 2 denies the call: stderr is the tool result and the write or command does not run. A crash or a 30-second timeout denieswrite_fileandrun. - A
PostToolUsecommand receives the same plustool_result. Exit 2 is feedback the model reads on the next step; the tool already ran. Stopruns when the model callsfinish. Exit 2 keeps the session working, stderr is a tool result, and there is no proof event yet. A crash or timeout on Stop lets finish through.
Example
A sample ~/.agents/hooks.json:
{ "hooks": { "PreToolUse": [ { "matcher": "run", "hooks": [ { "type": "command", "command": "python3 $HOME/.agents/hooks/pre_tool_review_guard.py" } ] } ], "PostToolUse": [ { "matcher": "write_file", "hooks": [ { "type": "command", "command": "python3 $HOME/.agents/hooks/no_code_comments.py --hook" } ] }, { "matcher": "run", "hooks": [ { "type": "command", "command": "python3 $HOME/.agents/hooks/pr_size_warn.py" } ] } ], "Stop": [ { "hooks": [ { "type": "command", "command": "python3 $HOME/.agents/hooks/stop_closeout_guard.py" } ] } ] }}