fix(hooks): emit Kiro v1 hook documents#2095
Conversation
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
There was a problem hiding this comment.
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
| 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>
APM Spec Guardian:
|
| 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-006explicitly require the Kiro v1 hook schema. - T2 -- Timeout structure: three panels asked where
timeoutlives. Folded by specifying an optional numerictimeoutinside a commandaction. - 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>
APM Review Panel:
|
| 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
actionto the hook entry; nativedescription,timeout, andenabledare 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.pyexecutes 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.
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>
APM Review Panel:
|
| 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.
fix(hooks): emit Kiro v1 hook documents
TL;DR
Kiro hook installation now emits the current v1
hooksarray schema instead of the legacywhen/thenformat. 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
agentaction remains outside this bug fix; existingaskAgentinputs now render as Kiro v1agentactions.Problem (WHY)
when/thendocuments as legacy and does not run them as current v1 hooks.patterns, andrunCommandfields do not match Kiro v1's PascalCasetrigger,matcher, andactioncontract.hooksfield.These are the concrete failure modes and acceptance criteria documented in #2071.
Approach (WHAT)
{ "version": "v1", "hooks": [...] }.Implementation (HOW)
src/apm_cli/integration/hook_integrator.pysrc/apm_cli/integration/kiro_hook_integrator.pytests/unit/integration/test_kiro_target.pydocs/src/content/docs/integrations/ide-tool-integration.mddocs/src/content/docs/producer/author-primitives/hooks-and-commands.mdpackages/apm-guide/.apm/skills/apm-usage/package-authoring.mddocs/src/content/docs/specs/openapm-v0.1.mdreq-tg-006.docs/public/specs/manifests/openapm-v0.1.requirements.yml/tests/spec_conformance/test_manifest_reqs.pyDiagrams
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;Trade-offs
askAgentauthoring path and rejected a new cross-target primitive design in this bug-fix scope.Benefits
version: "v1"and exactly one entry inhooks.PreToolUse,PostToolUse,UserPromptSubmit,Stop, task, file, and session events reach Kiro with canonical trigger names.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:uv run --extra dev pytest -q:CI lint mirror
Mutation-break proof: changing generated
versionfromv1tov0madetest_kiro_hooks_expand_each_apm_hook_to_individual_jsonfail on the exact output contract.uv run --extra dev pytest tests/spec_conformance -qand orphan alignment:Scenario Evidence
tests/unit/integration/test_kiro_target.py::test_kiro_hooks_expand_each_apm_hook_to_individual_json(regression-trap for #2071)tests/unit/integration/test_kiro_target.py::test_kiro_hooks_accept_native_v1_documentstests/unit/integration/test_kiro_target.py::test_kiro_v1_event_map_uses_canonical_trigger_namestests/unit/integration/test_kiro_target.py::test_kiro_hooks_convert_prompt_actions_to_ask_agentHow to test
PreToolUsecommand hook into a project containing.kiro/; confirm the generated file hasversion: "v1"and ahooksarray.trigger, optionalmatcher, andaction, with nowhen,then, orrunCommandfields.PreTaskExec; confirm the trigger and name are preserved and referenced scripts are copied under.kiro/hooks/<package>/.Co-authored-by: Copilot 223556219+Copilot@users.noreply.github.com