Skip to content

fix(hooks): emit Kiro v1 hook documents#2095

Open
danielmeppiel wants to merge 5 commits into
mainfrom
fix/kiro-v1-hooks-2071
Open

fix(hooks): emit Kiro v1 hook documents#2095
danielmeppiel wants to merge 5 commits into
mainfrom
fix/kiro-v1-hooks-2071

Conversation

@danielmeppiel

@danielmeppiel danielmeppiel commented Jul 9, 2026

Copy link
Copy Markdown
Collaborator

fix(hooks): emit Kiro v1 hook documents

TL;DR

Kiro hook installation now emits the current v1 hooks array schema instead of the legacy when/then format. Portable event names, matchers, command timeouts, prompt actions, and native Kiro v1 inputs are translated without changing other target integrations. This removes the manual migration step Kiro 1.0 previously required.

Note

Closes #2071. The broader design of a new portable agent action remains outside this bug fix; existing askAgent inputs now render as Kiro v1 agent actions.

Problem (WHY)

  • Kiro 1.0 treats APM's generated when/then documents as legacy and does not run them as current v1 hooks.
  • Legacy camelCase events, patterns, and runCommand fields do not match Kiro v1's PascalCase trigger, matcher, and action contract.
  • Authors could not use native Kiro v1 files as a workaround because the shared parser rejected an array-valued hooks field.

These are the concrete failure modes and acceptance criteria documented in #2071.

Approach (WHAT)

# Fix
1 Render every generated Kiro file as { "version": "v1", "hooks": [...] }.
2 Canonicalize portable and legacy events to Kiro v1 trigger names, and translate matcher/action fields.
3 Allow array-valued hooks only on the Kiro path, normalize them, then reuse existing path rewriting and bundle copying.
4 Keep the shared parser strict for every other target.

Implementation (HOW)

File Change
src/apm_cli/integration/hook_integrator.py Updates Kiro event mappings to PascalCase v1 names and adds a Kiro-only parser opt-in for native v1 arrays.
src/apm_cli/integration/kiro_hook_integrator.py Converts portable and native inputs into one-hook v1 documents while preserving script rewriting, collision checks, permissions, and display payloads.
tests/unit/integration/test_kiro_target.py Replaces legacy-schema expectations with exact v1 documents and adds native-v1 and trigger-map regression coverage.
docs/src/content/docs/integrations/ide-tool-integration.md Documents the Kiro v1 output contract and native input support.
docs/src/content/docs/producer/author-primitives/hooks-and-commands.md Documents Kiro v1 authoring, trigger passthrough, and output mode.
packages/apm-guide/.apm/skills/apm-usage/package-authoring.md Synchronizes agent-facing package-authoring guidance with the new primitive format.
docs/src/content/docs/specs/openapm-v0.1.md Adds the normative Kiro v1 target-hook contract as req-tg-006.
docs/public/specs/manifests/openapm-v0.1.requirements.yml / tests/spec_conformance/test_manifest_reqs.py Binds the requirement to its conformance marker and generated statement artifacts.

Diagrams

Legend: Portable and native hook inputs converge before the existing rewrite and deployment path writes a Kiro v1 file.

flowchart LR
    subgraph Input[Package hook input]
        P[Claude or Copilot event map]
        N[Kiro v1 hooks array]
    end
    subgraph Transform[Target transform]
        Parse[_parse_hook_json]
        Normalize[_normalize_kiro_v1]
        Rewrite[_rewrite_hooks_data]
        Render[_kiro_hook_document]
    end
    subgraph Output[Kiro runtime]
        File[".kiro/hooks/*.json v1"]
    end
    P --> Parse
    N --> Parse
    Parse --> Rewrite
    Parse --> Normalize
    Normalize --> Rewrite
    Rewrite --> Render
    Render --> File
    classDef new stroke-dasharray: 5 5;
    class Normalize,Render new;
Loading

Trade-offs

  • Kiro-only array acceptance. Chose an explicit parser opt-in instead of relaxing shared validation, so malformed list-shaped inputs remain rejected for targets that require event maps.
  • One generated file per action. Retained the existing collision, ownership, and uninstall model instead of combining package hooks into one document.
  • Bounded action support. Reused the existing askAgent authoring path and rejected a new cross-target primitive design in this bug-fix scope.

Benefits

  1. Generated Kiro files contain version: "v1" and exactly one entry in hooks.
  2. PreToolUse, PostToolUse, UserPromptSubmit, Stop, task, file, and session events reach Kiro with canonical trigger names.
  3. Matchers and numeric timeouts survive translation into Kiro v1 actions.
  4. Native Kiro v1 command hooks use the same script-path rewrite and bundle-copy behavior as portable hooks.

Validation

uv run --extra dev pytest tests/unit/integration/test_kiro_target.py tests/unit/integration/test_hook_integrator.py tests/unit/integration/test_hook_integrator_defect_regression.py tests/unit/integration/test_hook_integrator_issue1892.py tests/unit/integration/test_hook_naked_format.py tests/unit/integration/test_hook_target_selection.py tests/unit/integration/test_hook_diagnostics.py tests/unit/test_install_hook_transparency.py -q:

241 passed in 32.51s

uv run --extra dev pytest -q:

29638 skipped, 173 deselected in 34.92s
CI lint mirror
All checks passed!
1410 files already formatted
Your code has been rated at 10.00/10
[+] auth-signal lint clean
CI grep guards passed

Mutation-break proof: changing generated version from v1 to v0 made test_kiro_hooks_expand_each_apm_hook_to_individual_json fail on the exact output contract.

uv run --extra dev pytest tests/spec_conformance -q and orphan alignment:

131 passed, 2 skipped
[+] orphan_check OK: 98 requirements aligned across anchors / manifest / Appendix C / pytest markers
[+] mode_b: spec-concurrent edit detected; orphan_check owns this PR

Scenario Evidence

# Scenario (user promise) Principle(s) Test(s) proving it Type
1 Installing a portable hook for Kiro 1.0 produces a runnable v1 document with matcher, timeout, and rewritten command Portability by manifest, Multi-harness support tests/unit/integration/test_kiro_target.py::test_kiro_hooks_expand_each_apm_hook_to_individual_json (regression-trap for #2071) integration
2 A Kiro-targeted package can ship a native v1 hook and its script bundle Portability by manifest, OSS / community-driven tests/unit/integration/test_kiro_target.py::test_kiro_hooks_accept_native_v1_documents integration
3 Portable, legacy, and Kiro-only events resolve to canonical Kiro v1 triggers Multi-harness support tests/unit/integration/test_kiro_target.py::test_kiro_v1_event_map_uses_canonical_trigger_names unit
4 Existing prompt actions become Kiro v1 agent actions Multi-harness support tests/unit/integration/test_kiro_target.py::test_kiro_hooks_convert_prompt_actions_to_ask_agent integration

How to test

  • Install a package with a PreToolUse command hook into a project containing .kiro/; confirm the generated file has version: "v1" and a hooks array.
  • Confirm the generated entry uses trigger, optional matcher, and action, with no when, then, or runCommand fields.
  • Install a native Kiro v1 hook using PreTaskExec; confirm the trigger and name are preserved and referenced scripts are copied under .kiro/hooks/<package>/.
  • Re-run the focused Kiro target test file and expect all 12 tests to pass.

Co-authored-by: Copilot 223556219+Copilot@users.noreply.github.com

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot AI review requested due to automatic review settings July 9, 2026 22:17

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Updates the Kiro hook integration to emit Kiro IDE/CLI 1.0’s v1 hook document schema ({"version":"v1","hooks":[...]}) instead of the legacy when/then format, and allows Kiro-targeted packages to provide native v1 hook arrays that APM can rewrite/deploy.

Changes:

  • Canonicalizes Kiro event names to v1 PascalCase trigger names and updates casing expectations.
  • Adds a Kiro-only parser opt-in for native v1 hooks: [...] documents and normalizes them into the internal event-map shape.
  • Updates unit tests and documentation to assert and describe the v1 output contract and native v1 input support.
Show a summary per file
File Description
src/apm_cli/integration/hook_integrator.py Updates Kiro event mapping to v1 triggers and adds _parse_hook_json(..., allow_kiro_v1=...) support.
src/apm_cli/integration/kiro_hook_integrator.py Implements v1 document rendering, matcher/action translation, and native-v1 normalization on the Kiro path.
tests/unit/integration/test_kiro_target.py Replaces legacy-schema assertions with exact v1 documents and adds regression coverage for native v1 + trigger mapping.
docs/src/content/docs/integrations/ide-tool-integration.md Documents Kiro v1 output and native v1 input acceptance at the integration overview level.
docs/src/content/docs/producer/author-primitives/hooks-and-commands.md Documents Kiro v1 authoring/output behavior and trigger passthrough for Kiro-only events.
packages/apm-guide/.apm/skills/apm-usage/package-authoring.md Syncs agent-facing package-authoring guidance with the Kiro v1 hook document shape.

Review details

  • Files reviewed: 6/6 changed files
  • Comments generated: 1
  • Review effort level: Low

Comment on lines +55 to +59
prompt = action.get("prompt")
if action.get("type") == "askAgent" or isinstance(prompt, str):
if action.get("type") in {"agent", "askAgent"} or isinstance(prompt, str):
prompt_text = prompt if isinstance(prompt, str) else action.get("command")
if isinstance(prompt_text, str) and prompt_text.strip():
return {"type": "askAgent", "prompt": prompt_text}
return {"type": "agent", "prompt": prompt_text}
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@danielmeppiel

Copy link
Copy Markdown
Collaborator Author

APM Spec Guardian: fold_and_ship

Scope: editorial-patch; diff = +22/-3 lines across 1 in-scope file. Shocked-meter avg: 7.5/10.

All four panels found no critical issues. The amendment now scopes the obligation directly to Kiro v1, rather than relying on an undefined generic "current registered schema," and defines timeout as an optional numeric field inside a command action. Broader registry, malformed-input, unknown-field, and future-version policy remain outside this confirmed bug fix.

Convergence

Panel Signal Shocked New B New R New N
Swagger / OpenAPI editor ship_with_followups 8/10 0 3 0
OCI distribution editor ship_with_followups 8/10 0 3 0
Package-manager contract editor ship_with_followups 7/10 0 4 0
Web-platform architect ship_with_followups 7/10 0 3 0

B = new critical findings, R = new recommended findings, N = new nits. Counts are advisory signal only. The maintainer ships.

Convergent themes

  • T1 -- Schema-version source: all four panels flagged the generic phrase "current registered schema" as undefined. Folded by making req-tg-006 explicitly require the Kiro v1 hook schema.
  • T2 -- Timeout structure: three panels asked where timeout lives. Folded by specifying an optional numeric timeout inside a command action.
  • T3 -- Scope discipline: target-specific layering and future schema evolution are useful follow-ups, not requirements for this Kiro v1 correction.

Defer to a later amendment

  • Define cross-target malformed native-input and unknown-field policy after the portable contract is designed.
  • Revisit future target-schema version discovery when a registry or machine-readable target contract exists.

Linter notes (2 checks noted)

  • [7] The checklist's mechanical heading-slug algorithm reports existing numbered-heading links because it strips punctuation differently from the documentation renderer; this amendment adds no heading links.
  • [11] This PR also modifies Python implementation and tests, so the general code-review and CI lint paths apply in parallel.

Checks 1-6 and 9-10 pass; check 8 is not applicable because the spec has no Mermaid blocks. The full spec-conformance suite passes (131 passed, 2 skipped), orphan alignment reports 98 requirements, generated artifacts are clean, and Mode B delegates to orphan alignment for this spec-concurrent change.


Full per-panel findings

Swagger / OpenAPI editor -- shocked_meter 8/10

No critical issues. Recommended defining the schema-version source, locating timeout structurally, and keeping generic requirements separate from Kiro details.

OCI distribution editor -- shocked_meter 8/10

No critical issues. Recommended defining the schema-version source and timeout bounds; integrity-domain suggestions were outside this hook-schema change.

Package-manager contract editor -- shocked_meter 7/10

No critical issues. Recommended future malformed-input and unknown-field policy. Those cross-target contracts are deferred rather than inferred in this bug fix.

Web-platform architect -- shocked_meter 7/10

No critical issues. Recommended avoiding coupling generic normative language to Kiro version churn and making timeout structural. Both points were addressed by the scoped wording.

This panel is advisory. Re-apply the spec-review label to run it again.

Move timeout to the hook entry, preserve native v1 metadata, and add an empirical install regression test. Addresses review panel findings on Kiro runtime correctness and integration coverage.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@danielmeppiel

Copy link
Copy Markdown
Collaborator Author

APM Review Panel: ship_now

Kiro v1 hook installation now matches the documented runtime schema and has empirical install coverage.

cc @sergio-sisternes-epam -- a fresh advisory pass is ready for your review.

The panel found two correctness gaps in the prior revision: Kiro v1 places timeout beside action, and native v1 description, timeout, and enabled fields must survive normalization. Commit 5f8a6b11e folds both, canonicalizes native triggers, adds normalization diagnostics, updates the spec and author guidance, and commits a subprocess install regression test that checks exact runtime JSON, script deployment, and preservation of an unrelated user hook.

Dissent. Two personas raised stale generated filenames after event renames. Existing install reconciliation owns managed-file cleanup; adding target-local deletion without a failing reproduction would risk user-owned files. The new integration test explicitly protects unrelated configuration.

Aligned with: portability by manifest, secure defaults, multi-harness support, and a one-command install experience.

Panel summary

Persona B R N Takeaway
Python Architect 0 1 2 Trigger canonicalization folded; architecture remains target-local.
CLI Logging Expert 0 1 1 Native normalization now emits debug evidence.
DevX UX Expert 0 1 2 Empirical install coverage now protects the user promise.
Supply Chain Security Expert 0 0 2 Path containment and command rewriting remain intact.
OSS Growth Hacker 0 0 2 Changelog and a native Kiro example now lead with usable value.
Doc Writer 2 0 0 Runtime hierarchy and native field preservation corrected.
Test Coverage Expert 0 1 0 Real apm install --target kiro regression test committed.

B = blocking-severity findings, R = recommended, N = nits.
Counts are signal strength, not gates. The maintainer ships.

Recommendation

All in-scope findings from this pass are folded on 5f8a6b11e. Focused evidence is 373 passed and 2 skipped; the mutation break changes generated version to v0 and makes the empirical install test fail on the exact runtime contract. Ship after CI confirms this SHA.


Full per-persona findings
  • Runtime correctness: timeout moved from action to the hook entry; native description, timeout, and enabled are preserved.
  • Architecture: native trigger aliases are canonicalized through the Kiro event map.
  • Diagnostics: native v1 normalization logs file and hook count at debug level.
  • Documentation: spec, producer guide, integration guide, package-authoring skill, and changelog now match implementation.
  • Coverage: tests/integration/test_kiro_hook_install_e2e.py executes the real local install flow and preserves unrelated configuration.
  • Auth and performance personas were inactive because those surfaces are unchanged.

This panel is advisory. It does not block merge. Re-apply the panel-review label after addressing feedback to re-run.

danielmeppiel and others added 2 commits July 10, 2026 03:44
Clarify hook-level fields and log unsupported native actions. Addresses final panel polish findings without changing the runtime contract.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Bound native v1 support to command and agent actions and warn when a file contributes neither. Addresses the final documentation panel findings with regression coverage.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@danielmeppiel

Copy link
Copy Markdown
Collaborator Author

APM Review Panel: ship_now

Kiro hooks now emit the official v1 runtime shape with hook-level timeout, canonical triggers, and native-document preservation.

cc @sergio-sisternes-epam -- the terminal advisory pass is ready for review.

The panel converged with every in-scope finding folded at 383d6e080b0c79985c16dbb4ed2ae7cac3cbac5a. The implementation emits hook-level timeout, preserves native description, timeout, and enabled fields, canonicalizes triggers, and warns when a native file contributes no supported command or agent action. The empirical subprocess install test proves exact runtime JSON, script deployment, and preservation of an unrelated user hook.

Aligned with: portability by manifest, multi-harness fidelity, secure defaults, and a one-command install experience.

Panel summary

Persona B R N Takeaway
Python Architect 0 0 0 Target adapter remains bounded and explicit.
CLI Logging Expert 0 0 0 Debug and warning paths match the install contract.
DevX UX Expert 0 0 0 Real install behavior and non-destructive configuration are proven.
Supply Chain Security Expert 0 0 0 Existing containment and rewrite guards remain intact.
OSS Growth Hacker 0 0 0 Changelog and runnable example are user-facing.
Doc Writer 0 0 0 Spec, docs, and implementation agree on supported v1 actions.
Test Coverage Expert 0 0 0 Integration and mutation-break gates are independently reproducible.

B = blocking-severity findings, R = recommended, N = nits.
Counts are signal strength, not gates. The maintainer ships.

Recommendation

Ship now. Exact-SHA CI is green: https://github.com/microsoft/apm/actions/runs/29063433020. Local relevant tests report 145 passed and 2 skipped, and the full lint chain is silent. Mutation proofs: changing generated version from v1 to v0 fails the install e2e assertion; downgrading the unsupported-action warning to debug fails its regression test.


Full per-persona findings

No current-SHA findings remain. Auth and performance personas were inactive because those surfaces are unchanged.

This panel is advisory. It does not block merge. Re-apply the panel-review label after addressing feedback to re-run.

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.

[BUG] Kiro hook integrator emits the legacy pre-1.0 hook schema

2 participants