surface

Hooks.

Run reviewed automation at Code events, configure hook matching and timeouts, and distinguish blocking decisions from context and after-the-fact feedback.

Written for
Developers adding local automation around Code events.
You need
A reviewed local hook script; A trusted workspace for project hooks

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.
Blocking gates happen before the affected action; feedback after a tool cannot undo it.

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

Type at least two characters.