Using Han with Kiro CLI

How to use Han's validation pipeline and plugin ecosystem with Kiro CLI using the bridge plugin.

Han works with Kiro CLI through a bridge plugin that translates Kiro's hook events into Han hook executions. Your existing Han plugins - validation, context injection, skills, disciplines - work in Kiro without modification.

How It Works

Kiro CLI uses a shell-based hook system where hooks are defined in agent JSON configs. The Han bridge is a CLI tool that Kiro hooks call:

  1. Kiro hooksHan hooks (PreToolUse, PostToolUse, Stop)
  2. agentSpawnCore guidelines (professional honesty, no excuses, skill selection)
  3. userPromptSubmitDatetime injection (current time on every prompt)
  4. preToolUseValidation gates (exit code 2 blocks tool execution)
Agent edits src/app.ts via fs_write
  -> Kiro fires postToolUse hook
  -> Bridge maps fs_write -> Write, finds matching Han hooks
  -> Runs biome, eslint, tsc in parallel
  -> Agent sees validation errors and fixes them

Setup

1. Install Han and plugins

curl -fsSL https://han.guru/install.sh | bash
han plugin install --auto

2. Add the Kiro agent config

Copy the Han agent config to your Kiro settings:

# Global (all projects)
mkdir -p ~/.kiro/agents
curl -fsSL https://raw.githubusercontent.com/TheBushidoCollective/han/main/plugins/bridges/kiro/kiro-agent.json \
  -o ~/.kiro/agents/han.json

# Or project-specific
mkdir -p .kiro/agents
curl -fsSL https://raw.githubusercontent.com/TheBushidoCollective/han/main/plugins/bridges/kiro/kiro-agent.json \
  -o .kiro/agents/han.json

3. Start Kiro with Han

kiro-cli chat --agent han

That's it. Your Han plugins now work in Kiro.

The shipped agent config declares the built-in tools the agent needs (fs_read, fs_write, execute_bash, glob, grep). Without a tools list Kiro gives a custom agent no tools at all, and the model prints fake <fs_write> blocks instead of writing files.

Kiro asks for approval before tool calls by default. To pre-approve tools, add an allowedTools list to the agent config, or run with kiro-cli chat --agent han --trust-all-tools (sandboxed environments only).

Coverage Matrix

The bridge maps Claude Code's hook events to Kiro's hook system:

Claude Code HookKiro EquivalentStatusNotes
PostToolUsepostToolUseImplementedPrimary validation path - per-file linting/formatting
PreToolUsepreToolUseImplementedPre-execution gates with exit code 2 blocking
StopstopImplementedFull project validation; failures emit {"decision":"block","reason":...} so the agent keeps working until validation passes
SessionStartagentSpawnImplementedCore guidelines injected on agent start
UserPromptSubmituserPromptSubmitImplementedCurrent datetime injected on every prompt
Event LoggingJSONL + coordinatorImplementedKiro sessions indexed as first-class sessions, attributed to the kiro harness
Permission denialExit code 2ImplementedKiro's native blocking mechanism
SubagentStart/StopNot availableNo Kiro equivalent
MCP tool events@mcp/tool matchersPartialKiro supports MCP tool matchers in hooks
PreCompactNot availableNo Kiro equivalent

What Works

PostToolUse Validation (Primary)

The most important feature. When the agent edits a file, Han's per-file validation hooks fire:

PluginWhat It Does
biomeLint and format JavaScript/TypeScript
eslintJavaScript/TypeScript linting
prettierCode formatting
typescriptType checking
clippyRust linting
pylintPython linting

Results are delivered to stdout and the agent sees them immediately after the edit.

PreToolUse Hooks (with Blocking)

Run before a tool executes via Kiro's preToolUse hook. Kiro supports exit code 2 for blocking tool execution - when a PreToolUse hook returns exit code 2, Kiro blocks the tool call and sends stderr to the LLM as the reason.

This is a capability OpenCode lacks. Han's PreToolUse hooks can enforce validation gates in Kiro.

Stop Validation (Secondary)

When the agent finishes a turn, broader project-level hooks run:

  • Full project linting
  • Type checking across the codebase
  • Test suite execution

If issues are found, the bridge exits with code 1, signaling the agent should continue.

SessionStart Context (Guidelines)

Core guidelines are injected when the agent starts via agentSpawn:

  • Professional honesty — Verify claims before accepting them
  • No time estimates — Use phase numbers and priority order instead
  • No excuses — Own every issue (Boy Scout Rule)
  • Date handling — Use injected datetime, never hardcode
  • Skill selection — Review available skills before starting work

UserPromptSubmit Context (Datetime)

Current local datetime is injected on every user prompt via userPromptSubmit, mirroring Claude Code's UserPromptSubmit hook.

Result Format

Hook results are structured so the agent can parse and act on them:

<han-post-tool-validation>
The following validation hooks reported issues after your last edit.
Please fix these issues before continuing:

<han-validation plugin="biome" hook="lint-async" status="failed">
src/app.ts:10:5 lint/correctness/noUnusedVariables
  This variable is unused.
</han-validation>
</han-post-tool-validation>

Tool Name Mapping

Kiro uses internal tool names that differ from Claude Code. The bridge maps them automatically:

Kiro ToolClaude Code Tool
fs_readRead
fs_writeWrite
execute_bashBash
globGlob
grepGrep
notebook_editNotebookEdit

How Plugins Stay Compatible

Han plugins don't need modification to work with Kiro. The bridge reads the same han-plugin.yml files that Claude Code uses:

# This config works in Claude Code, OpenCode, and Kiro
hooks:
  lint-async:
    event: PostToolUse
    command: "npx -y @biomejs/biome check --write ${HAN_FILES}"
    tool_filter: [Edit, Write, NotebookEdit]
    file_filter: ["**/*.{js,jsx,ts,tsx}"]
    dirs_with: ["biome.json"]

The difference is in who executes the hook:

  • Claude Code: Reads hooks.json, calls han hook run via shell
  • OpenCode: Bridge reads han-plugin.yml, runs command as in-process promise
  • Kiro: Bridge reads han-plugin.yml, runs command as child process

Same hook definition. Same validation. Different runtime.

Kiro Agent Config

The bridge provides a Kiro agent configuration (kiro-agent.json) that defines all the necessary hooks:

{
  "name": "han",
  "description": "Default coding agent with Han validation",
  "hooks": {
    "agentSpawn": [{ "command": "npx -y kiro-plugin-han agent-spawn" }],
    "userPromptSubmit": [{ "command": "npx -y kiro-plugin-han user-prompt-submit" }],
    "preToolUse": [{ "matcher": "*", "command": "npx -y kiro-plugin-han pre-tool-use" }],
    "postToolUse": [{ "matcher": "fs_write", "command": "npx -y kiro-plugin-han post-tool-use" }],
    "stop": [{ "command": "npx -y kiro-plugin-han stop", "timeout_ms": 120000 }]
  }
}

You can customize this by:

  • Adding more matchers to postToolUse (e.g., notebook_edit)
  • Adjusting timeouts
  • Merging hooks into your own custom agent

Event Logging and Metrics

The bridge writes Han-format JSONL events to ~/.han/kiro/projects/{slug}/{sessionId}-han.jsonl. Every event carries harness: "kiro", the canonical id Han uses for Kiro wherever it reports on a session.

Kiro writes no native transcript, so that events file is the session's entire record. Han indexes a *-han.jsonl file that has no sibling {sessionId}.jsonl as a session in its own right rather than as a supplement to a Claude Code transcript, and stamps the harness onto the session row. Kiro sessions show up in the Browse UI and in metrics queries beside Claude Code sessions, attributed to kiro rather than folded into it.

The coordinator finds the directory without being told about it. Every child of ~/.han holding a projects directory is a harness root, so a bridge needs no registration step and no watch flag. On agent start the bridge runs han coordinator ensure --background to make sure the coordinator is up.

For what the harness dimension buys you once the data is indexed, see Local Metrics.

Remaining Gaps

  • Skills/Disciplines tools: Currently injected as context only. Full tool registration would require a Kiro MCP server (planned).
  • Subagent hooks: Kiro custom agents don't have SubagentStart/SubagentStop equivalents.
  • Checkpoints: Session-scoped checkpoint filtering is not yet implemented.

Next Steps