What Are Hooks?
Hooks are event-driven automation features that execute custom commands at specific points during the agent lifecycle and tool execution. They enable security validation, logging, automatic formatting, context injection, and many other automation patterns.
Five Hook Types
| Hook Type | Trigger | Primary Use |
|---|---|---|
agentSpawn |
When agent starts | Environment info gathering, initialization |
userPromptSubmit |
When prompt is sent | Rule enforcement, context addition |
preToolUse |
Before tool execution | Validation, blocking |
postToolUse |
After tool execution | Logging, post-processing |
stop |
When assistant finishes responding | Test execution, cleanup |
Exit Code Behavior
| Exit Code | Behavior |
|---|---|
| 0 | Success. stdout is added to context |
| 2 | Block (preToolUse only). stderr is returned to the agent |
| Other | Warning displayed, execution continues |
Hook Configuration
Hooks are defined in the hooks field of agent configuration files:
{
"name": "secure-dev",
"hooks": {
"preToolUse": [
{
"command": "./scripts/validate-write.sh",
"matcher": "write"
}
],
"postToolUse": [
{
"command": "./scripts/log-tool-usage.sh",
"matcher": "*"
}
],
"stop": [
{
"command": "npm test"
}
]
}
}
Filtering with matcher
The matcher field specifies which tools trigger the hook:
| Pattern | Matches |
|---|---|
"write" |
write tool only |
"@git" |
All git MCP server tools |
"@git/status" |
Only the status tool from git server |
"*" |
All tools |
"@builtin" |
All built-in tools |
| Not specified | All events (universal) |
Note: stop hooks do not use matchers.
Timeout and Caching
{
"hooks": {
"preToolUse": [
{
"command": "./scripts/security-check.sh",
"matcher": "shell",
"timeout_ms": 10000,
"cache_ttl_seconds": 300
}
]
}
}
| Setting | Description | Default |
|---|---|---|
timeout_ms |
Timeout in milliseconds | 30000 |
cache_ttl_seconds |
Cache duration in seconds. 0 = no caching | 0 |
Setting cache_ttl_seconds caches results for identical inputs. agentSpawn hooks are never cached.
Hook Input Data
Hooks receive JSON data via stdin.
Common Fields
{
"hook_event_name": "preToolUse",
"cwd": "/home/user/my-project"
}
Tool-Related Hooks (preToolUse / postToolUse)
{
"hook_event_name": "preToolUse",
"cwd": "/home/user/my-project",
"tool_name": "shell",
"tool_input": {
"command": "rm -rf /tmp/data"
}
}
postToolUse Additional Fields
{
"hook_event_name": "postToolUse",
"cwd": "/home/user/my-project",
"tool_name": "write",
"tool_input": { "path": "src/index.ts", "content": "..." },
"tool_response": { "status": "success" }
}
Practical Hook Patterns
Security Validation (preToolUse)
Block dangerous commands:
#!/bin/bash
# scripts/validate-shell.sh
INPUT=$(cat)
COMMAND=$(echo "$INPUT" | jq -r '.tool_input.command // empty')
# Dangerous patterns
if echo "$COMMAND" | grep -qE '(rm -rf /|sudo|chmod 777|> /dev/)'; then
echo "BLOCKED: Dangerous command detected: $COMMAND" >&2
exit 2
fi
exit 0
{
"hooks": {
"preToolUse": [
{
"command": "./scripts/validate-shell.sh",
"matcher": "shell"
}
]
}
}
Auto Test Execution (stop)
Run tests after every assistant response:
{
"hooks": {
"stop": [
{
"command": "npm test -- --watchAll=false 2>&1 | tail -20"
}
]
}
}
Context Injection (userPromptSubmit)
Add project information when prompts are submitted:
#!/bin/bash
# scripts/add-context.sh
echo "Current branch: $(git branch --show-current)"
echo "Last commit: $(git log -1 --oneline)"
echo "Modified files: $(git diff --name-only | head -10)"
{
"hooks": {
"userPromptSubmit": [
{
"command": "./scripts/add-context.sh"
}
]
}
}
Tool Usage Logging (postToolUse)
Log all tool usage to a file:
#!/bin/bash
# scripts/log-tool-usage.sh
INPUT=$(cat)
TOOL=$(echo "$INPUT" | jq -r '.tool_name')
TIMESTAMP=$(date -u +"%Y-%m-%dT%H:%M:%SZ")
echo "$TIMESTAMP | $TOOL" >> .kiro/tool-usage.log
exit 0
{
"hooks": {
"postToolUse": [
{
"command": "./scripts/log-tool-usage.sh",
"matcher": "*"
}
]
}
}
Environment Collection (agentSpawn)
Gather environment information at agent startup:
#!/bin/bash
# scripts/collect-env.sh
echo "Node.js: $(node --version)"
echo "npm: $(npm --version)"
echo "Git branch: $(git branch --show-current)"
echo "Docker: $(docker --version 2>/dev/null || echo 'not installed')"
flowchart TB
subgraph Lifecycle["Agent Lifecycle"]
Spawn["agentSpawn<br/>At startup"]
Prompt["userPromptSubmit<br/>On prompt send"]
Pre["preToolUse<br/>Before tool execution"]
Tool["Tool Execution"]
Post["postToolUse<br/>After tool execution"]
Stop["stop<br/>Response complete"]
end
Spawn --> Prompt
Prompt --> Pre
Pre -->|"exit 0: Allow"| Tool
Pre -->|"exit 2: Block"| Block["Execution Blocked"]
Tool --> Post
Post --> Stop
style Spawn fill:#3b82f6,color:#fff
style Prompt fill:#8b5cf6,color:#fff
style Pre fill:#f59e0b,color:#fff
style Tool fill:#22c55e,color:#fff
style Post fill:#22c55e,color:#fff
style Stop fill:#ef4444,color:#fff
style Block fill:#ef4444,color:#fff
Subagents
Subagents are specialized agents that autonomously execute complex tasks with their own context and tool access. They operate independently from the main agent.
Subagent Characteristics
| Feature | Description |
|---|---|
| Autonomous execution | Operates independently based on agent config |
| Real-time progress | Status updates during execution |
| Tool access | File operations, commands, MCP tools |
| Parallel execution | Up to 4 subagents simultaneously |
| Result aggregation | Returns results to main agent on completion |
Execution Flow
- Task assignment β Describe the task; Kiro determines if subagent use is appropriate
- Initialization β Subagent spawns with its own context and configured tools
- Autonomous execution β Works independently, may pause for permissions
- Progress updates β Real-time status display
- Result return β Completed results return to the main agent
Available Tools
Supported: read, write, shell, code intelligence, MCP tools
Not supported: web_search, web_fetch, introspect, thinking, todo_list, use_aws, grep, glob
Controlling Subagents
Restrict which agents can run as subagents in agent configuration:
{
"toolsSettings": {
"subagent": {
"availableAgents": ["docs-writer", "test-runner", "code-analyzer"],
"trustedAgents": ["test-runner"]
}
}
}
| Setting | Description |
|---|---|
availableAgents |
Agents allowed as subagents (glob patterns supported) |
trustedAgents |
Agents that run without permission prompts |
Practical Example
> Generate a test coverage report while simultaneously updating documentation
Kiro delegates test execution and documentation updates to separate subagents, running them in parallel.
Delegate Feature
Delegate runs tasks asynchronously in the background. Similar to subagents, but it doesn't block the main conversation.
> Run the project-wide linter in the background
Kiro launches the task in the background using delegate, and you can continue your main conversation. You'll be notified when it completes.
Summary
| Topic | Details |
|---|---|
| Hooks | Event-driven custom command execution |
| Five types | agentSpawn, userPromptSubmit, preToolUse, postToolUse, stop |
| Exit code 2 | Blocks tool execution in preToolUse |
| matcher | Tool filtering with wildcard support |
| Subagents | Autonomous specialized agents, up to 4 in parallel |
| Control | availableAgents / trustedAgents |
| Delegate | Background async task execution |
In Day 10, you'll learn about settings, ACP, and real-world workflows.