Learn Kiro CLI in 10 DaysDay 9: Hooks & Subagents
books.chapter 9Learn Kiro CLI in 10 Days

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

  1. Task assignment β€” Describe the task; Kiro determines if subagent use is appropriate
  2. Initialization β€” Subagent spawns with its own context and configured tools
  3. Autonomous execution β€” Works independently, may pause for permissions
  4. Progress updates β€” Real-time status display
  5. 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.