# Hooks

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

Source: https://kaitoi.io/docs/cli/hooks/
Section: Kaitoi CLI / Extending Kaitoi Code
Written for: Developers adding local automation around Code events.
Prerequisites: A reviewed local hook script; A trusted workspace for project hooks
Last reviewed: 2026-10-24

---

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:

```text
/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:

```json
{
	"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.

*Figure: Blocking gates happen before the affected action; feedback after a tool cannot undo it.*

## 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.
