New to Kiro CLI V3? This page covers migration from CLI 2.x Hooks. For the current standalone format reference, see Hooks →.
Tip: Run
/upgrade-agentfirst. It converts object-form Hooks to a profile-scoped inline array and reports any triggers or matchers it could not convert safely.
CLI V3 supports two current placements. Agent profiles can keep profile-scoped Hooks in a flat hooks array. For automation that should work independently of a particular profile or across IDE and CLI, place the same Hook definitions in standalone .kiro/hooks/*.json files. The legacy object form remains accepted as compatibility input, but use the current array form when you revise migrated definitions.
CLI 2.x Hooks used an object keyed by camelCase trigger names:
{ "hooks": { "agentSpawn": [{ "command": "echo 'starting'" }], "preToolUse": [{ "command": "npm run lint", "matcher": "fs_read" }] } }
/upgrade-agent flattens the legacy object into an array in the agent profile. It gives each Hook a name and keeps the compatible camelCase trigger alias:
{ "hooks": [ { "name": "agentSpawn-0", "trigger": "agentSpawn", "action": { "type": "command", "command": "echo 'starting'" }, "timeout": 10 }, { "name": "preToolUse-0", "trigger": "preToolUse", "matcher": "read", "action": { "type": "command", "command": "npm run lint" }, "timeout": 10 } ] }
The converter preserves array-form Hooks. It drops a Hook that V3 cannot represent and reports a warning instead of writing an invalid profile.
A standalone .kiro/hooks/*.json file wraps the same Hook definitions in a versioned document. Use PascalCase trigger names when you create or revise a standalone Hook:
{ "version": "v1", "hooks": [ { "name": "lint-before-read", "trigger": "PreToolUse", "matcher": "read", "action": { "type": "command", "command": "npm run lint" }, "timeout": 30, "enabled": true } ] }
In the V2 terminal UI, both the V2 and V3 engines can match an exact tool name or a shared tool group. The table uses the V2 names for each tool:
| Matcher | Tools in the V2 group |
|---|---|
read | fs_read, grep, glob, code, introspect, tool_search |
write | fs_write, code |
shell | execute_bash |
web | web_fetch, web_search |
subagent | use_subagent |
The Classic engine treats read, write, shell, and subagent as aliases for one tool. It does not support the @mcp matcher or tag globs.
/upgrade-agent rewrites known CLI 2.x names to shared groups. For example, fs_read becomes read, and execute_cmd becomes shell. It warns when a group covers more tools than the old name. The fs_read rewrite also matches grep, glob, code, introspect, and tool_search.
Array-form matchers that are valid V3 tool IDs stay as authored. Kiro reports matchers that only one engine can evaluate.
Tool Hooks running through the V2 engine receive tool_tags with tool_name and tool_input. Use the tags when a script should treat every tool in a group the same way:
{ "tool_name": "fs_read", "tool_tags": ["read", "@builtin"], "tool_input": {} }
The Classic and V3 engines do not send tool_tags.
CLI V3 supports these Hook triggers in inline profiles and standalone files:
| Trigger | Fires when | Matcher matches | Can block? |
|---|---|---|---|
SessionStart | A session begins | Not evaluated | No |
UserPromptSubmit | The user submits a prompt | Not evaluated | No |
PreToolUse | Before a tool executes | Tool name or group | Yes |
PostToolUse | After a tool executes | Tool name or group | No |
PostFileCreate | After Kiro creates a file | File path | No |
PostFileSave | After Kiro saves or edits a file | File path | No |
PostFileDelete | After Kiro deletes a file | File path | No |
PreTaskExec | Before a spec task executes | Not evaluated | Yes |
PostTaskExec | After a spec task completes | Not evaluated | No |
Stop | Kiro finishes responding | Not evaluated | No |
For Stop, No means the Hook cannot reject an event with exit code 2. A CLI V3 Stop command Hook can exit with code 1 or return {"decision":"block","reason":"..."} to ask Kiro to continue for another turn. For UserPromptSubmit, No means CLI V3 sends the prompt regardless of the exit code; a non-zero exit forwards the Hook output and exit code to the agent as context instead of rejecting the prompt.
File triggers respond to changes made by Kiro, and task triggers wrap spec task execution. Existing Manual Hooks are an IDE 0.x feature; you cannot create a new Manual-trigger Hook. See Hook types for the cross-surface table.
| CLI 2.x trigger | V3 trigger |
|---|---|
agentSpawn | SessionStart |
userPromptSubmit | UserPromptSubmit |
preToolUse | PreToolUse |
postToolUse | PostToolUse |
stop | Stop |
Store workspace Hooks in .kiro/hooks/. To run the same V3 Hook in every workspace, place it in ~/.kiro/hooks/. Global and workspace Hooks run alongside each other. See the full Hooks reference → for schema details, locations, and action types.
Hooks migration