Hooks.
Run reviewed automation at Code events, configure hook matching and timeouts, and distinguish blocking decisions from context and after-the-fact feedback.
Hooks run commands at defined session and tool events. They are operator automation with real shell effects, not another model prompt. Review the command and any script it invokes before enabling it. This guide covers CLI 0.9.0.
Place and approve the configuration
Personal hooks live in hooks.json beside Code's user settings. Project hooks
live in .kaitoi/hooks.json and require a trusted workspace plus approval of
that exact configuration file:
/hooks
/hooks approve
Changing the project hook file requires approval again. /hooks revoke removes
that approval. The approved hash covers hooks.json, not the contents of
scripts it invokes; review changes to those scripts as part of your project.
The following configuration calls a script you must supply and review:
{
"hooks": {
"PreToolUse": [
{
"matcher": "local\\.write_file",
"hooks": [
{
"type": "command",
"command": "python scripts/check_edit.py",
"timeout": 60
}
]
}
]
}
}
The matcher is a regular expression against the full tool name. An empty matcher
or * matches all tools; non-tool events ignore it. The example matches that
specific write tool, not every possible operation that changes files.
Choose the event
| Event | When it runs | Can block? |
|---|---|---|
SessionStart |
Startup, resume, clear, or compaction transition | No; it can supply context. |
UserPromptSubmit |
Before the submitted prompt proceeds | Yes. |
PreToolUse |
Before a tool call | Yes. |
PostToolUse |
After a tool result | No; it cannot undo the completed tool. |
Stop |
At the end of the turn | Yes; it can request bounded continuation. |
SessionStart supplies starting context. UserPromptSubmit can block a prompt. PreToolUse can block a tool before execution, while PostToolUse observes its result afterward. Stop can request bounded continuation at the turn's end. Hooks never grant a missing permission. Approval covers the hook configuration; scripts it calls remain separate files to review.
The completed-write example changes a README command to npm run dev before post-tool feedback. The blocked example never reaches the write, leaving npm dev in place; later event labels describe their lifecycle roles, not proof that a blocked tool executed.
Read input and return a decision
The command receives JSON on stdin describing the session, working directory,
event, and relevant tool input or bounded tool response. Environment variables
include KAITOI_PROJECT_DIR, KAITOI_SESSION_ID, and KAITOI_HOOK_EVENT.
Commands run sequentially in the workspace through the OS shell, outside the
model command sandbox, with a scrubbed environment.
Exit code 2 blocks events that support blocking. On exit 0, a JSON
response can provide decision: "block", a reason, or additionalContext
where supported. Other failures and timeouts warn rather than enforcing a
block. Do not rely on a crashing script as a fail-closed policy gate.
The default timeout is 60 seconds, capped at 600; output is bounded. Stop hooks can request at most three consecutive continuations. Hooks cannot approve a tool the operator has not authorized.
Diagnose the event you actually received
Inspect /hooks, the configuration approval, the full tool name, and the
event payload. A post-tool error does not roll back the tool. A changed script
does not automatically invalidate an unchanged hook configuration's approval.
Approved hooks can also run in ACP and served sessions; approve project hooks
in the terminal first. Brokered Crew children do not run hooks.
Last reviewed against Kaitoi on 24 October 2026. View this page as Markdown