Skip to content

fix(kiro-cli): emit the standalone hooks format Kiro CLI 3.0 reads - #2609

Merged
dyoshikawa merged 2 commits into
mainfrom
resolve-issue-2408-kiro-cli-hooks-v3
Aug 7, 2026
Merged

fix(kiro-cli): emit the standalone hooks format Kiro CLI 3.0 reads#2609
dyoshikawa merged 2 commits into
mainfrom
resolve-issue-2408-kiro-cli-hooks-v3

Conversation

@dyoshikawa

Copy link
Copy Markdown
Owner

Summary

src/features/hooks/kiro-cli-hooks.ts was a one-line subclass of the legacy KiroHooks, emitting camelCase hooks into the embedded .kiro/agents/default.json agent config. Kiro's hooks migration guide states that format "does not work in 3.0", so the kiro-cli hooks output was not merely stale — it was dead on the current CLI.

This repoints the kiro-cli target at the KiroIdeHooks emitter. Both products read the same standalone {"version": "v1", "hooks": [ … ]} file under .kiro/hooks/, per docs/hooks, which is the basis for every judgment call below.

  • The emitter is parameterized by override key, so kiro-cli.hooks still wins over kiro-ide.hooks in both directions.
  • Its static factories now construct through new this(...) / this.getSettablePaths(...). Worth calling out: the old subclass did not do this — KiroCliHooks.fromFile returned a KiroHooks instance, so toRulesyncHooks read the override key off the parent and routed imported kiro-cli overrides into the kiro block. That defect goes away with the rewrite.
  • The processor entry mirrors the kiro-ide one: KIRO_IDE_HOOK_EVENTS, command + prompt hook types, matcher support, passthrough override events, and global scope (the same file exists at ~/.kiro/hooks/, added in CLI 2.13.0).
  • The legacy embedded writer stays on the deprecated kiro alias, with its now-misleading "Kiro CLI" doc comments corrected. The e2e cache_ttl_seconds round-trip moved to kiro, since that field belongs to the embedded format.

One behavior worth naming: kiro-cli and kiro-ide now write the same .kiro/hooks/rulesync.json. With both targets enabled the shared hooks are identical, but divergent override blocks are last-writer-wins. A distinct filename would be worse — Kiro runs every *.json in the directory and both products read the same one, so two files would run every hook twice. This mirrors the existing kiro / kiro-cli sharing of default.json, and it is documented in the note.

Scope

This fixes the dead-format bug only. It leaves gap 4 of #2408 open — the ~/.kiro/hooks file-sharing design question is not resolved here, and the argument that this repoint settles it is the re-check comment's own reasoning rather than a maintainer ruling. Gap 2 (the five triggers reachable only through the override block) is likewise untouched: reusing KIRO_IDE_HOOK_EVENTS unchanged is the whole move.

Testing

  • pnpm cicheck (full: code + content)
  • npx vitest run --config vitest.e2e.config.ts src/e2e/e2e-hooks.spec.ts — the matrix asserts exact output paths, so kiro-cli moved to the v1 path and into the standalone-format assertion branch, and it was added to the global matrix.
  • kiro-cli-hooks.test.ts rewritten for the v1 format: settable paths, the override key in both directions (including a PostFileSave trigger that can only survive in the override block), subclass identity, and global scope.
  • pnpm run generate:tables picked up the new global support for kiro-cli hooks; pnpm dev gitignore reports no change, since kiro-ide already emits this path.

Part of #2408

🤖 Generated with Claude Code

kiro-cli-hooks.ts was a one-line subclass of the legacy KiroHooks, writing
camelCase hooks into the embedded .kiro/agents/default.json agent config. Kiro's
hooks migration guide states that format does not work in 3.0, so the kiro-cli
hooks output was not merely stale but dead.

Repoint the kiro-cli target at the KiroIdeHooks emitter: both products read the
same standalone {"version": "v1"} file under .kiro/hooks/. The emitter is
parameterized by override key so kiro-cli.hooks still wins over kiro-ide.hooks,
and its static factories now construct via `new this` so the subclass keeps its
own identity — the previous subclass returned KiroHooks instances, which sent
imported overrides to the kiro block instead of kiro-cli.

The legacy embedded writer stays on the deprecated kiro alias. Global scope
follows from the repoint, since the same file exists at ~/.kiro/hooks/.

Part of #2408.
Addresses review findings on PR #2609. The README and supported-tools prose
still described kiro-cli as writing hooks into .kiro/agents/default.json, which
this PR makes false, and docs/** is embedded into the distributed docs bundle so
the error would reach users. Rewrites those paragraphs plus the stale clause in
the file-formats hooks intro.

Adds the migration guidance the repoint needs: an earlier rulesync left a hooks
block in .kiro/agents/default.json that nothing removes (the file is shared with
permissions and subagents), and Kiro CLI 2.x reads both formats, so the block
has to be deleted by hand or every hook fires twice. Also records that importing
those old hooks now needs --targets kiro, and that sessionEnd and cacheTtl have
no counterpart in the standalone format.

Rounds out the stale comments in src/types/hooks.ts and kiro-paths.ts, replaces
the duplicated override-key union with a shared type alias, drops the now
single-valued override-key indirection from the legacy writer, and adds tests
for prompt hooks, forDeletion identity, the dropped sessionEnd, and the IDE side
of the override-key split.
@dyoshikawa
dyoshikawa merged commit 6b77699 into main Aug 7, 2026
9 checks passed
@dyoshikawa
dyoshikawa deleted the resolve-issue-2408-kiro-cli-hooks-v3 branch August 7, 2026 09:19
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants