@event4u/agent-config 14.19.0 → 14.21.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (161) hide show
  1. package/.augment-plugin/marketplace.json +3 -3
  2. package/.augment-plugin/plugin.json +1 -1
  3. package/.claude-plugin/marketplace.json +1 -1
  4. package/CHANGELOG.md +351 -156
  5. package/README.md +1 -1
  6. package/agents/templates/.ai-council.yml.example +10 -0
  7. package/dist/agent-src/commands/agent-handoff.md +42 -41
  8. package/dist/agent-src/commands/analyze/inbox.md +1 -1
  9. package/dist/agent-src/commands/analyze/{reference-repo.md → repo.md} +247 -32
  10. package/dist/agent-src/commands/analyze/roadmap-repos.md +129 -0
  11. package/dist/agent-src/commands/analyze.md +12 -7
  12. package/dist/agent-src/commands/feature/plan.md +55 -16
  13. package/dist/agent-src/commands/feature/refactor.md +8 -3
  14. package/dist/agent-src/commands/humanize.md +48 -4
  15. package/dist/agent-src/contexts/execution/contract-decision-sheet.md +22 -1
  16. package/dist/agent-src/contexts/execution/host-capability-manifest.md +11 -2
  17. package/dist/agent-src/contexts/execution/roadmap-process-loop.md +35 -2
  18. package/dist/agent-src/contexts/execution/terminal-states.md +4 -1
  19. package/dist/agent-src/rules/evaluator-independence.md +4 -4
  20. package/dist/agent-src/rules/external-reference-deep-dive.md +2 -2
  21. package/dist/agent-src/rules/untrusted-input-defense.md +0 -2
  22. package/dist/agent-src/skills/competitive-positioning/SKILL.md +2 -2
  23. package/dist/agent-src/skills/evaluate-llm-feature/SKILL.md +1 -1
  24. package/dist/agent-src/skills/humanizer/references/anti-aiisms.md +27 -11
  25. package/dist/agent-src/skills/learning-to-rule-or-skill/SKILL.md +1 -1
  26. package/dist/agent-src/skills/markitdown/SKILL.md +2 -2
  27. package/dist/agent-src/skills/repomix-packer/SKILL.md +1 -1
  28. package/dist/agent-src/skills/skill-improvement-pipeline/SKILL.md +28 -6
  29. package/dist/agent-src/skills/technical-specification/SKILL.md +4 -0
  30. package/dist/agent-src/skills/test-driven-development/SKILL.md +1 -3
  31. package/dist/agent-src/templates/agents/agent-project-settings.example.yml +1 -1
  32. package/dist/agent-src/templates/features.md +5 -0
  33. package/dist/agent-src/templates/roadmaps.md +29 -1
  34. package/dist/agent-src/templates/scripts/telemetry/mcp_lite.ts +213 -0
  35. package/dist/agent-src/templates/scripts/telemetry/report_renderer.ts +16 -0
  36. package/dist/agent-src/templates/scripts/telemetry_report.ts +22 -2
  37. package/dist/cli/mcp/dispatch.js +10 -0
  38. package/dist/cli/mcp/stdio.js +33 -2
  39. package/dist/cli/mcp/telemetry.js +227 -0
  40. package/dist/cli-delegate/{chunk-KPBWFOPZ.js → chunk-2FTMENJL.js} +194 -37
  41. package/dist/cli-delegate/{chunk-PMEKGDED.js → chunk-2TAQ2K4V.js} +166 -1
  42. package/dist/cli-delegate/{chunk-GZTMRYCN.js → chunk-643Z7FIC.js} +79 -12
  43. package/dist/cli-delegate/{chunk-CYH5SP6M.js → chunk-I6RHFQEG.js} +151 -16
  44. package/dist/cli-delegate/{chunk-IDHUQIXP.js → chunk-J3RFNKG4.js} +41 -5
  45. package/dist/cli-delegate/{chunk-7PRE6ZV2.js → chunk-YS6XTLEK.js} +199 -4
  46. package/dist/cli-delegate/chunk-ZVBOHSVF.js +1109 -0
  47. package/dist/cli-delegate/cmd_conformance.js +88 -110
  48. package/dist/cli-delegate/cmd_doctor.js +3 -3
  49. package/dist/cli-delegate/cmd_export.js +2 -2
  50. package/dist/cli-delegate/cmd_handoff.js +42 -12
  51. package/dist/cli-delegate/cmd_memory_get.js +1 -1
  52. package/dist/cli-delegate/cmd_prune.js +2 -2
  53. package/dist/cli-delegate/cmd_route_audit.js +1 -1
  54. package/dist/cli-delegate/cmd_session_recycle.js +59 -902
  55. package/dist/cli-delegate/cmd_settings_migrate.js +2 -2
  56. package/dist/cli-delegate/cmd_sync.js +2 -2
  57. package/dist/cli-delegate/cmd_uninstall.js +2 -2
  58. package/dist/cli-delegate/cmd_validate.js +2 -2
  59. package/dist/discovery/deprecation-report.md +1 -1
  60. package/dist/discovery/discovery-manifest.json +62 -31
  61. package/dist/discovery/discovery-manifest.json.sha256 +1 -1
  62. package/dist/discovery/discovery-manifest.summary.md +3 -3
  63. package/dist/discovery/dormancy-report.md +1 -1
  64. package/dist/discovery/orphan-report.md +1 -1
  65. package/dist/discovery/packs.json +7 -6
  66. package/dist/discovery/trust-report.md +2 -2
  67. package/dist/discovery/workspaces.json +6 -5
  68. package/dist/hooks/dispatch.js +3801 -2803
  69. package/dist/install/install.mjs +396 -168
  70. package/dist/mcp/registry-manifest.json +3 -3
  71. package/dist/mcp/server.json +2 -2
  72. package/dist/mcp/server.mjs +809 -180
  73. package/dist/scripts/ai_council/content_ceiling.js +63 -0
  74. package/dist/scripts/ai_council/seat_policy.js +106 -0
  75. package/dist/scripts/ai_council/transport_resolver.js +21 -0
  76. package/dist/scripts/mcp_server/telemetry.js +148 -0
  77. package/docs/guidelines/agent-infra/naming.md +1 -1
  78. package/docs/guidelines/agent-infra/security-lint-containment.md +46 -6
  79. package/docs/guidelines/agent-infra/self-improvement-pipeline.md +4 -4
  80. package/docs/guidelines/agent-infra/untrusted-input-spotlighting.md +1 -1
  81. package/docs/guidelines/redundancy-taxonomy.md +28 -0
  82. package/llms.txt +14 -14
  83. package/package.json +1 -1
  84. package/src/agent-src/templates/scripts/telemetry/mcp_lite.ts +213 -0
  85. package/src/agent-src/templates/scripts/telemetry/report_renderer.ts +16 -0
  86. package/src/agent-src/templates/scripts/telemetry_report.ts +22 -2
  87. package/src/config/assurance-capability-registry.json +9 -0
  88. package/src/config/gate-coverage.yml +55 -0
  89. package/src/config/gate-violation-baselines.json +18 -6
  90. package/src/config/release-gate-locality.yml +4 -3
  91. package/src/scripts/_cli/cmd_session_recycle.ts +51 -3
  92. package/src/scripts/_lib/audit_field_provenance.ts +44 -3
  93. package/src/scripts/_lib/blocked_by_marker.ts +189 -0
  94. package/src/scripts/_lib/host_capability.ts +76 -1
  95. package/src/scripts/_lib/install_reach_checks.ts +33 -1
  96. package/src/scripts/_lib/mcp_bridge.ts +222 -10
  97. package/src/scripts/_lib/mcp_consent_residual.ts +173 -0
  98. package/src/scripts/_lib/orchestration_record.ts +23 -1
  99. package/src/scripts/_lib/recycle_envelope_paths.ts +190 -0
  100. package/src/scripts/_lib/release_highlights.ts +19 -211
  101. package/src/scripts/_lib/release_material.ts +27 -77
  102. package/src/scripts/_lib/release_position.ts +96 -0
  103. package/src/scripts/_lib/review_skipped_record.ts +17 -1
  104. package/src/scripts/_lib/security_lint.ts +179 -7
  105. package/src/scripts/_lib/self_repair.ts +141 -6
  106. package/src/scripts/_lib/self_repair_store.ts +273 -7
  107. package/src/scripts/_lib/structured_ask.ts +117 -0
  108. package/src/scripts/_lib/subagent_capsule.ts +155 -3
  109. package/src/scripts/_lib/tty_prompt.ts +76 -0
  110. package/src/scripts/ai_council/api_transport.ts +163 -0
  111. package/src/scripts/ai_council/clients.ts +58 -63
  112. package/src/scripts/ai_council/config.ts +13 -0
  113. package/src/scripts/ai_council/content_ceiling.ts +79 -0
  114. package/src/scripts/ai_council/jury_aggregate.ts +178 -0
  115. package/src/scripts/ai_council/seat_policy.ts +137 -0
  116. package/src/scripts/ai_council/status_surface.ts +79 -0
  117. package/src/scripts/ai_council/transport_resolver.ts +59 -1
  118. package/src/scripts/ai_tells_rules.ts +446 -5
  119. package/src/scripts/ask_block_census.ts +499 -0
  120. package/src/scripts/bench_humanizer_eval.ts +264 -40
  121. package/src/scripts/bench_prose_tells_fp.ts +198 -0
  122. package/src/scripts/build_rule_trigger_matrix.ts +5 -0
  123. package/src/scripts/check_branch_work_committed.ts +234 -0
  124. package/src/scripts/check_mcp_doc_drift.ts +217 -0
  125. package/src/scripts/check_pack_size.ts +321 -3
  126. package/src/scripts/check_release_highlights.ts +0 -157
  127. package/src/scripts/council_cli.ts +18 -27
  128. package/src/scripts/detect_ai_tells.ts +142 -20
  129. package/src/scripts/handoff_context_hook.ts +54 -7
  130. package/src/scripts/harvest_reference_tokens.ts +698 -0
  131. package/src/scripts/hook_manifest.json +1 -1
  132. package/src/scripts/hook_manifest.yaml +31 -1
  133. package/src/scripts/hooks/concern_registry.ts +2 -0
  134. package/src/scripts/hooks/delegation_nudge_hook.ts +45 -1
  135. package/src/scripts/hooks/one_question_per_ask_hook.ts +191 -0
  136. package/src/scripts/hooks/session_eol_hook.ts +18 -7
  137. package/src/scripts/install-hooks.sh +52 -0
  138. package/src/scripts/install.ts +4 -4
  139. package/src/scripts/lint_agent_security.ts +316 -25
  140. package/src/scripts/lint_confusables.ts +42 -6
  141. package/src/scripts/lint_handoffs.ts +0 -132
  142. package/src/scripts/lint_hidden_unicode.ts +49 -7
  143. package/src/scripts/lint_instruction_smuggling.ts +42 -6
  144. package/src/scripts/lint_mcp_config_security.ts +42 -6
  145. package/src/scripts/lint_roadmap_blockers.ts +51 -1
  146. package/src/scripts/lint_roadmap_later_disposition.ts +217 -27
  147. package/src/scripts/lint_skill_frontmatter_safety.ts +43 -7
  148. package/src/scripts/mcp_server/resources.ts +41 -0
  149. package/src/scripts/mcp_server/telemetry.ts +19 -4
  150. package/src/scripts/migrate_command_suggestions.ts +1 -1
  151. package/src/scripts/orchestration_record.ts +12 -1
  152. package/src/scripts/probe_unblocked_ask.ts +135 -2
  153. package/src/scripts/release.ts +50 -95
  154. package/src/scripts/release_drill.ts +6 -10
  155. package/src/scripts/release_env.ts +1 -0
  156. package/src/scripts/release_publication.ts +40 -31
  157. package/src/scripts/self_repair_cli.ts +31 -1
  158. package/src/scripts/self_review_gate.ts +409 -15
  159. package/src/scripts/skill_scout.ts +69 -0
  160. package/dist/cli-delegate/chunk-2GNWGMAL.js +0 -172
  161. package/dist/cli-delegate/chunk-LPPWO5CE.js +0 -161
@@ -1 +1 @@
1
- {"fingerprint":"8ca65564:83643","manifest":{"schema_version":1,"concerns":{"chat-history":{"script":"src/scripts/chat_history.ts","args":["hook-dispatch"],"fail_closed":false,"severity":"advisory","needs_payload_bodies":["result"]},"hot-context":{"script":"src/scripts/hot_context_hook.ts","args":[],"fail_closed":false,"severity":"advisory"},"handoff-context":{"script":"src/scripts/handoff_context_hook.ts","args":[],"fail_closed":false,"severity":"advisory"},"roadmap-progress":{"script":"src/scripts/roadmap_progress_hook.ts","args":[],"fail_closed":false,"severity":"advisory","needs_payload_bodies":["input"]},"onboarding-gate":{"script":"src/scripts/onboarding_gate_hook.ts","args":[],"fail_closed":false,"severity":"advisory"},"context-hygiene":{"script":"src/scripts/context_hygiene_hook.ts","args":[],"fail_closed":false,"severity":"advisory"},"verify-before-complete":{"script":"src/scripts/before_complete_hook.ts","args":[],"fail_closed":false,"severity":"advisory","needs_payload_bodies":["input","result"]},"ship-diff-volume":{"script":"src/scripts/hooks/ship_diff_volume_hook.ts","args":[],"fail_closed":false,"severity":"advisory","needs_payload_bodies":["input"]},"minimal-safe-diff":{"script":"src/scripts/minimal_safe_diff_hook.ts","args":[],"fail_closed":false,"severity":"advisory","needs_payload_bodies":["input"]},"injection-scan":{"script":"src/scripts/injection_scan_hook.ts","args":[],"fail_closed":false,"severity":"advisory","needs_payload_bodies":["input","result"]},"block-no-verify":{"script":"src/scripts/hooks/block_no_verify.ts","args":[],"fail_closed":true,"severity":"blocking","needs_payload_bodies":["input"]},"block-kernel-rule-writes":{"script":"src/scripts/hooks/block_kernel_rule_writes.ts","args":[],"fail_closed":true,"severity":"blocking","needs_payload_bodies":["input"]},"block-speaking-inbox-dir":{"script":"src/scripts/hooks/block_speaking_inbox_dir.ts","args":[],"fail_closed":false,"severity":"blocking","needs_payload_bodies":["input"]},"block-config-weakening":{"script":"src/scripts/hooks/block_config_weakening.ts","args":[],"fail_closed":false,"severity":"blocking","needs_payload_bodies":["input"]},"rtk-wrap":{"script":"src/scripts/hooks/rtk_wrap_hook.ts","args":[],"fail_closed":false,"severity":"advisory","needs_payload_bodies":["input"]},"design-slop":{"script":"src/scripts/hooks/design_slop_hook.ts","args":[],"fail_closed":false,"severity":"advisory","needs_payload_bodies":["input"]},"design-pass":{"script":"src/scripts/hooks/design_pass_hook.ts","args":[],"fail_closed":false,"severity":"advisory","needs_payload_bodies":["input"]},"design-pass-stop":{"script":"src/scripts/hooks/design_pass_hook.ts","args":["--slot","stop"],"fail_closed":false,"severity":"advisory"},"ui-route-nudge":{"script":"src/scripts/hooks/ui_route_nudge_hook.ts","args":[],"fail_closed":false,"severity":"advisory","needs_payload_bodies":["input"]},"suggestion-capture":{"script":"src/scripts/hooks/suggestion_capture_hook.ts","args":[],"fail_closed":false,"severity":"advisory"},"code-graph-nudge":{"script":"src/scripts/hooks/code_graph_nudge_hook.ts","args":[],"fail_closed":false,"severity":"advisory","tools":["Grep","Glob","Read"],"needs_payload_bodies":["input"]},"memory-learn":{"script":"src/scripts/memory_learn_hook.ts","args":[],"fail_closed":false,"severity":"advisory"},"first-run-gate":{"script":"src/scripts/first_run_gate_hook.ts","args":[],"fail_closed":false,"severity":"advisory"},"profile-staleness":{"script":"src/scripts/profile_staleness_hook.ts","args":[],"fail_closed":false,"severity":"advisory"},"wrapper-freshness":{"script":"src/scripts/wrapper_freshness_hook.ts","args":[],"fail_closed":false,"severity":"advisory"},"surface-probe":{"script":"src/scripts/surface_probe_hook.ts","args":[],"fail_closed":false,"severity":"advisory"},"team-review-gate":{"script":"src/scripts/team_review_gate_hook.ts","args":[],"fail_closed":false,"severity":"advisory"},"pr-url-reminder":{"script":"src/scripts/pr_url_reminder_hook.ts","args":[],"fail_closed":false,"severity":"advisory","needs_payload_bodies":["input","result"]},"push-settle":{"script":"src/scripts/hooks/push_settle_hook.ts","args":[],"fail_closed":false,"severity":"advisory","needs_payload_bodies":["input","result"]},"language-mirror":{"script":"src/scripts/language_mirror_hook.ts","args":[],"fail_closed":false,"severity":"advisory"},"git-authorization":{"script":"src/scripts/git_authorization_hook.ts","args":[],"fail_closed":false,"severity":"advisory"},"evidence-independence":{"script":"src/scripts/hooks/evidence_independence.ts","args":[],"fail_closed":false,"severity":"blocking","needs_payload_bodies":["input"]},"session-canary":{"script":"src/scripts/session_canary_hook.ts","args":[],"fail_closed":false,"severity":"advisory"},"council-availability":{"script":"src/scripts/council_availability_hook.ts","args":[],"fail_closed":false,"severity":"advisory"},"telemetry-disclosure":{"script":"src/scripts/telemetry_disclosure_hook.ts","args":[],"fail_closed":false,"severity":"advisory"},"telemetry-flush":{"script":"src/scripts/hooks/telemetry_flush_hook.ts","args":[],"fail_closed":false,"severity":"advisory"},"self-repair":{"script":"src/scripts/self_repair_hook.ts","args":[],"fail_closed":false,"severity":"advisory"},"session-register":{"script":"src/scripts/session_register_hook.ts","args":[],"fail_closed":false,"severity":"advisory"},"orchestration-record":{"script":"src/scripts/hooks/orchestration_record_hook.ts","args":[],"fail_closed":false,"severity":"advisory","tools":["Agent","Task"],"needs_payload_bodies":["input","result"]},"telemetry-usage":{"script":"src/scripts/hooks/telemetry_usage_hook.ts","args":[],"fail_closed":false,"severity":"advisory","tools":["Skill"],"needs_payload_bodies":["input"]},"delegation-nudge":{"script":"src/scripts/hooks/delegation_nudge_hook.ts","args":[],"fail_closed":false,"severity":"advisory","nudge_rank":1},"skill-route":{"script":"src/scripts/hooks/skill_route_hook.ts","args":[],"fail_closed":false,"severity":"advisory","nudge_rank":2},"rule-inject":{"script":"src/scripts/hooks/rule_inject_hook.ts","args":[],"fail_closed":false,"severity":"advisory","needs_payload_bodies":["input"]},"end-review-nudge":{"script":"src/scripts/hooks/end_review_nudge_hook.ts","args":[],"fail_closed":false,"severity":"advisory","skip_on_refusal_retry":true},"turn-end-gate":{"script":"src/scripts/hooks/turn_end_gate_hook.ts","args":[],"fail_closed":false,"severity":"blocking"},"comment-discipline":{"script":"src/scripts/hooks/comment_discipline_hook.ts","args":[],"fail_closed":false,"severity":"advisory","tools":["Write","Edit"],"needs_payload_bodies":["input"]},"edit-shape":{"script":"src/scripts/hooks/edit_shape_hook.ts","args":[],"fail_closed":false,"severity":"advisory","tools":["Write"],"needs_payload_bodies":["input"]},"reread-guard":{"script":"src/scripts/hooks/reread_guard_hook.ts","args":[],"fail_closed":false,"severity":"advisory","tools":["Read","Edit","Write"],"needs_payload_bodies":["input"]},"session-eol":{"script":"src/scripts/hooks/session_eol_hook.ts","args":[],"fail_closed":false,"severity":"advisory"},"run-continuation":{"script":"src/scripts/hooks/run_continuation_hook.ts","args":[],"fail_closed":false,"severity":"blocking"},"interruption-ledger":{"script":"src/scripts/hooks/interruption_ledger_hook.ts","args":[],"fail_closed":false,"severity":"advisory","skip_on_refusal_retry":true},"subagent-ledger":{"script":"src/scripts/hooks/subagent_ledger_hook.ts","args":[],"fail_closed":false,"severity":"advisory"},"tool-result-bytes":{"script":"src/scripts/hooks/tool_result_bytes_hook.ts","args":[],"fail_closed":false,"severity":"advisory"},"spawn-guard-shadow":{"script":"src/scripts/hooks/spawn_guard_shadow_hook.ts","args":[],"fail_closed":false,"severity":"advisory","tools":["Agent","Task"]},"source-first-gate":{"script":"src/scripts/hooks/source_first_gate_hook.ts","args":[],"fail_closed":false,"severity":"advisory","needs_payload_bodies":["input"]},"journal-record":{"script":"src/scripts/hooks/journal_record_hook.ts","args":[],"fail_closed":false,"severity":"advisory"}},"roles":{"worker":{"drop":["delegation-nudge","skill-route","end-review-nudge","council-availability","team-review-gate","self-repair","session-eol","interruption-ledger"]}},"platforms":{"augment":{"session_start":["chat-history","hot-context","handoff-context","session-canary","council-availability","telemetry-disclosure","first-run-gate","onboarding-gate","verify-before-complete","minimal-safe-diff","profile-staleness","wrapper-freshness","surface-probe","session-register"],"session_end":["chat-history","memory-learn","session-register","roadmap-progress","telemetry-flush"],"stop":["chat-history","hot-context","verify-before-complete","self-repair","session-register","roadmap-progress","design-pass-stop"],"pre_tool_use":["block-no-verify","evidence-independence","block-kernel-rule-writes","block-config-weakening","block-speaking-inbox-dir","rtk-wrap","design-slop","ui-route-nudge","code-graph-nudge","ship-diff-volume","reread-guard"],"post_tool_use":["chat-history","roadmap-progress","context-hygiene","verify-before-complete","minimal-safe-diff","injection-scan","pr-url-reminder","push-settle","orchestration-record","telemetry-usage","tool-result-bytes","edit-shape","comment-discipline","design-pass"]},"claude":{"session_start":["chat-history","hot-context","handoff-context","session-canary","council-availability","telemetry-disclosure","first-run-gate","onboarding-gate","verify-before-complete","minimal-safe-diff","profile-staleness","wrapper-freshness","surface-probe","session-register","journal-record"],"session_end":["chat-history","memory-learn","session-register","roadmap-progress","telemetry-flush","journal-record"],"stop":["chat-history","hot-context","verify-before-complete","team-review-gate","end-review-nudge","turn-end-gate","self-repair","session-register","session-eol","interruption-ledger","roadmap-progress","design-pass-stop","suggestion-capture","journal-record","run-continuation"],"user_prompt_submit":["chat-history","verify-before-complete","minimal-safe-diff","language-mirror","delegation-nudge","skill-route","git-authorization","session-canary","self-repair","session-register","rule-inject","suggestion-capture","journal-record"],"pre_tool_use":["block-no-verify","evidence-independence","block-kernel-rule-writes","block-config-weakening","block-speaking-inbox-dir","rtk-wrap","design-slop","ui-route-nudge","code-graph-nudge","ship-diff-volume","reread-guard","spawn-guard-shadow","source-first-gate","rule-inject"],"post_tool_use":["chat-history","roadmap-progress","context-hygiene","verify-before-complete","minimal-safe-diff","injection-scan","pr-url-reminder","push-settle","orchestration-record","telemetry-usage","tool-result-bytes","edit-shape","comment-discipline","language-mirror","design-pass","journal-record"],"pre_compact":["language-mirror","hot-context","rule-inject","journal-record"],"subagent_start":["subagent-ledger","journal-record"],"subagent_stop":["subagent-ledger","journal-record"]},"cowork":{"session_start":["chat-history","hot-context","handoff-context","session-canary","council-availability","telemetry-disclosure","first-run-gate","onboarding-gate","verify-before-complete","minimal-safe-diff","profile-staleness","wrapper-freshness","surface-probe","session-register"],"session_end":["chat-history","memory-learn","session-register","roadmap-progress","telemetry-flush"],"stop":["chat-history","hot-context","verify-before-complete","self-repair","session-register","roadmap-progress","design-pass-stop"],"user_prompt_submit":["chat-history","verify-before-complete","minimal-safe-diff","language-mirror","git-authorization","session-canary","self-repair","session-register"],"pre_tool_use":["block-no-verify","evidence-independence","block-kernel-rule-writes","block-config-weakening","block-speaking-inbox-dir","rtk-wrap","design-slop","ui-route-nudge","code-graph-nudge","ship-diff-volume","reread-guard","spawn-guard-shadow","source-first-gate"],"post_tool_use":["chat-history","roadmap-progress","context-hygiene","verify-before-complete","minimal-safe-diff","injection-scan","pr-url-reminder","push-settle","orchestration-record","telemetry-usage","tool-result-bytes","edit-shape","comment-discipline","design-pass"],"subagent_start":["subagent-ledger"],"subagent_stop":["subagent-ledger"]},"cursor":{"session_start":["chat-history","hot-context","handoff-context","session-canary","council-availability","telemetry-disclosure","first-run-gate","onboarding-gate","verify-before-complete","minimal-safe-diff","profile-staleness","wrapper-freshness","surface-probe","session-register"],"session_end":["chat-history","memory-learn","session-register","roadmap-progress","telemetry-flush"],"stop":["chat-history","hot-context","verify-before-complete","self-repair","session-register","roadmap-progress","design-pass-stop"],"user_prompt_submit":["chat-history","verify-before-complete","minimal-safe-diff","language-mirror","git-authorization","session-canary","self-repair","session-register"],"post_tool_use":["chat-history","roadmap-progress","context-hygiene","verify-before-complete","minimal-safe-diff","injection-scan","pr-url-reminder","push-settle","orchestration-record","telemetry-usage","tool-result-bytes","edit-shape","comment-discipline","design-pass"]},"cline":{"session_start":["chat-history","hot-context","handoff-context","session-canary","council-availability","telemetry-disclosure","first-run-gate","onboarding-gate","verify-before-complete","minimal-safe-diff","profile-staleness","wrapper-freshness","surface-probe","session-register"],"session_end":["chat-history","memory-learn","session-register","roadmap-progress","telemetry-flush"],"stop":["chat-history","hot-context","verify-before-complete","self-repair","session-register","roadmap-progress","design-pass-stop"],"user_prompt_submit":["chat-history","verify-before-complete","minimal-safe-diff","language-mirror","git-authorization","session-canary","self-repair","session-register"],"post_tool_use":["chat-history","roadmap-progress","context-hygiene","verify-before-complete","minimal-safe-diff","injection-scan","pr-url-reminder","push-settle","orchestration-record","telemetry-usage","tool-result-bytes","edit-shape","comment-discipline","design-pass"]},"windsurf":{"session_start":["chat-history","hot-context","handoff-context","session-canary","council-availability","telemetry-disclosure","first-run-gate","onboarding-gate","verify-before-complete","profile-staleness","wrapper-freshness","surface-probe","session-register"],"stop":["chat-history","hot-context","verify-before-complete","self-repair","session-register","design-pass-stop"],"user_prompt_submit":["chat-history","verify-before-complete","language-mirror","git-authorization","session-canary","self-repair","session-register"]},"gemini":{"session_start":["chat-history","hot-context","handoff-context","session-canary","council-availability","telemetry-disclosure","first-run-gate","onboarding-gate","verify-before-complete","minimal-safe-diff","profile-staleness","wrapper-freshness","surface-probe","session-register"],"session_end":["chat-history","memory-learn","session-register","roadmap-progress","telemetry-flush"],"stop":["chat-history","hot-context","verify-before-complete","self-repair","session-register","roadmap-progress","design-pass-stop"],"user_prompt_submit":["chat-history","verify-before-complete","minimal-safe-diff","language-mirror","git-authorization","session-canary","self-repair","session-register"],"post_tool_use":["chat-history","roadmap-progress","context-hygiene","verify-before-complete","minimal-safe-diff","injection-scan","pr-url-reminder","push-settle","orchestration-record","telemetry-usage","tool-result-bytes","edit-shape","comment-discipline","design-pass"]},"copilot":{"fallback_only":true}},"native_event_aliases":{"augment":{"SessionStart":"session_start","SessionEnd":"session_end","Stop":"stop","PostToolUse":"post_tool_use","PreToolUse":"pre_tool_use"},"claude":{"SessionStart":"session_start","SessionEnd":"session_end","Stop":"stop","UserPromptSubmit":"user_prompt_submit","PostToolUse":"post_tool_use","PreToolUse":"pre_tool_use","PreCompact":"pre_compact","SubagentStart":"subagent_start","SubagentStop":"subagent_stop"},"cowork":{"SessionStart":"session_start","SessionEnd":"session_end","Stop":"stop","UserPromptSubmit":"user_prompt_submit","PostToolUse":"post_tool_use","PreToolUse":"pre_tool_use","PreCompact":"pre_compact","SubagentStart":"subagent_start","SubagentStop":"subagent_stop"},"cursor":{"sessionStart":"session_start","sessionEnd":"session_end","stop":"stop","beforeSubmitPrompt":"user_prompt_submit","postToolUse":"post_tool_use","preToolUse":"pre_tool_use","preCompact":"pre_compact"},"cline":{"TaskStart":"session_start","TaskResume":"session_start","TaskComplete":"session_end","TaskCancel":"stop","UserPromptSubmit":"user_prompt_submit","PostToolUse":"post_tool_use","PreToolUse":"pre_tool_use","PreCompact":"pre_compact"},"windsurf":{"pre_user_prompt":"user_prompt_submit","post_cascade_response":"stop","post_setup_worktree":"session_start"},"gemini":{"SessionStart":"session_start","SessionEnd":"session_end","BeforeAgent":"user_prompt_submit","AfterAgent":"stop","BeforeTool":"pre_tool_use","AfterTool":"post_tool_use"}}}}
1
+ {"fingerprint":"5a4e9186:85470","manifest":{"schema_version":1,"concerns":{"chat-history":{"script":"src/scripts/chat_history.ts","args":["hook-dispatch"],"fail_closed":false,"severity":"advisory","needs_payload_bodies":["result"]},"hot-context":{"script":"src/scripts/hot_context_hook.ts","args":[],"fail_closed":false,"severity":"advisory"},"handoff-context":{"script":"src/scripts/handoff_context_hook.ts","args":[],"fail_closed":false,"severity":"advisory"},"roadmap-progress":{"script":"src/scripts/roadmap_progress_hook.ts","args":[],"fail_closed":false,"severity":"advisory","needs_payload_bodies":["input"]},"onboarding-gate":{"script":"src/scripts/onboarding_gate_hook.ts","args":[],"fail_closed":false,"severity":"advisory"},"context-hygiene":{"script":"src/scripts/context_hygiene_hook.ts","args":[],"fail_closed":false,"severity":"advisory"},"verify-before-complete":{"script":"src/scripts/before_complete_hook.ts","args":[],"fail_closed":false,"severity":"advisory","needs_payload_bodies":["input","result"]},"ship-diff-volume":{"script":"src/scripts/hooks/ship_diff_volume_hook.ts","args":[],"fail_closed":false,"severity":"advisory","needs_payload_bodies":["input"]},"minimal-safe-diff":{"script":"src/scripts/minimal_safe_diff_hook.ts","args":[],"fail_closed":false,"severity":"advisory","needs_payload_bodies":["input"]},"injection-scan":{"script":"src/scripts/injection_scan_hook.ts","args":[],"fail_closed":false,"severity":"advisory","needs_payload_bodies":["input","result"]},"block-no-verify":{"script":"src/scripts/hooks/block_no_verify.ts","args":[],"fail_closed":true,"severity":"blocking","needs_payload_bodies":["input"]},"block-kernel-rule-writes":{"script":"src/scripts/hooks/block_kernel_rule_writes.ts","args":[],"fail_closed":true,"severity":"blocking","needs_payload_bodies":["input"]},"one-question-per-ask":{"script":"src/scripts/hooks/one_question_per_ask_hook.ts","args":[],"fail_closed":false,"severity":"blocking","tools":["AskUserQuestion","AskQuestion","UserQuestion","ask_user_question","ask_question","user_question"],"needs_payload_bodies":["input"]},"block-speaking-inbox-dir":{"script":"src/scripts/hooks/block_speaking_inbox_dir.ts","args":[],"fail_closed":false,"severity":"blocking","needs_payload_bodies":["input"]},"block-config-weakening":{"script":"src/scripts/hooks/block_config_weakening.ts","args":[],"fail_closed":false,"severity":"blocking","needs_payload_bodies":["input"]},"rtk-wrap":{"script":"src/scripts/hooks/rtk_wrap_hook.ts","args":[],"fail_closed":false,"severity":"advisory","needs_payload_bodies":["input"]},"design-slop":{"script":"src/scripts/hooks/design_slop_hook.ts","args":[],"fail_closed":false,"severity":"advisory","needs_payload_bodies":["input"]},"design-pass":{"script":"src/scripts/hooks/design_pass_hook.ts","args":[],"fail_closed":false,"severity":"advisory","needs_payload_bodies":["input"]},"design-pass-stop":{"script":"src/scripts/hooks/design_pass_hook.ts","args":["--slot","stop"],"fail_closed":false,"severity":"advisory"},"ui-route-nudge":{"script":"src/scripts/hooks/ui_route_nudge_hook.ts","args":[],"fail_closed":false,"severity":"advisory","needs_payload_bodies":["input"]},"suggestion-capture":{"script":"src/scripts/hooks/suggestion_capture_hook.ts","args":[],"fail_closed":false,"severity":"advisory"},"code-graph-nudge":{"script":"src/scripts/hooks/code_graph_nudge_hook.ts","args":[],"fail_closed":false,"severity":"advisory","tools":["Grep","Glob","Read"],"needs_payload_bodies":["input"]},"memory-learn":{"script":"src/scripts/memory_learn_hook.ts","args":[],"fail_closed":false,"severity":"advisory"},"first-run-gate":{"script":"src/scripts/first_run_gate_hook.ts","args":[],"fail_closed":false,"severity":"advisory"},"profile-staleness":{"script":"src/scripts/profile_staleness_hook.ts","args":[],"fail_closed":false,"severity":"advisory"},"wrapper-freshness":{"script":"src/scripts/wrapper_freshness_hook.ts","args":[],"fail_closed":false,"severity":"advisory"},"surface-probe":{"script":"src/scripts/surface_probe_hook.ts","args":[],"fail_closed":false,"severity":"advisory"},"team-review-gate":{"script":"src/scripts/team_review_gate_hook.ts","args":[],"fail_closed":false,"severity":"advisory"},"pr-url-reminder":{"script":"src/scripts/pr_url_reminder_hook.ts","args":[],"fail_closed":false,"severity":"advisory","needs_payload_bodies":["input","result"]},"push-settle":{"script":"src/scripts/hooks/push_settle_hook.ts","args":[],"fail_closed":false,"severity":"advisory","needs_payload_bodies":["input","result"]},"language-mirror":{"script":"src/scripts/language_mirror_hook.ts","args":[],"fail_closed":false,"severity":"advisory"},"git-authorization":{"script":"src/scripts/git_authorization_hook.ts","args":[],"fail_closed":false,"severity":"advisory"},"evidence-independence":{"script":"src/scripts/hooks/evidence_independence.ts","args":[],"fail_closed":false,"severity":"blocking","needs_payload_bodies":["input"]},"session-canary":{"script":"src/scripts/session_canary_hook.ts","args":[],"fail_closed":false,"severity":"advisory"},"council-availability":{"script":"src/scripts/council_availability_hook.ts","args":[],"fail_closed":false,"severity":"advisory"},"telemetry-disclosure":{"script":"src/scripts/telemetry_disclosure_hook.ts","args":[],"fail_closed":false,"severity":"advisory"},"telemetry-flush":{"script":"src/scripts/hooks/telemetry_flush_hook.ts","args":[],"fail_closed":false,"severity":"advisory"},"self-repair":{"script":"src/scripts/self_repair_hook.ts","args":[],"fail_closed":false,"severity":"advisory"},"session-register":{"script":"src/scripts/session_register_hook.ts","args":[],"fail_closed":false,"severity":"advisory"},"orchestration-record":{"script":"src/scripts/hooks/orchestration_record_hook.ts","args":[],"fail_closed":false,"severity":"advisory","tools":["Agent","Task"],"needs_payload_bodies":["input","result"]},"telemetry-usage":{"script":"src/scripts/hooks/telemetry_usage_hook.ts","args":[],"fail_closed":false,"severity":"advisory","tools":["Skill"],"needs_payload_bodies":["input"]},"delegation-nudge":{"script":"src/scripts/hooks/delegation_nudge_hook.ts","args":[],"fail_closed":false,"severity":"advisory","nudge_rank":1},"skill-route":{"script":"src/scripts/hooks/skill_route_hook.ts","args":[],"fail_closed":false,"severity":"advisory","nudge_rank":2},"rule-inject":{"script":"src/scripts/hooks/rule_inject_hook.ts","args":[],"fail_closed":false,"severity":"advisory","needs_payload_bodies":["input"]},"end-review-nudge":{"script":"src/scripts/hooks/end_review_nudge_hook.ts","args":[],"fail_closed":false,"severity":"advisory","skip_on_refusal_retry":true},"turn-end-gate":{"script":"src/scripts/hooks/turn_end_gate_hook.ts","args":[],"fail_closed":false,"severity":"blocking"},"comment-discipline":{"script":"src/scripts/hooks/comment_discipline_hook.ts","args":[],"fail_closed":false,"severity":"advisory","tools":["Write","Edit"],"needs_payload_bodies":["input"]},"edit-shape":{"script":"src/scripts/hooks/edit_shape_hook.ts","args":[],"fail_closed":false,"severity":"advisory","tools":["Write"],"needs_payload_bodies":["input"]},"reread-guard":{"script":"src/scripts/hooks/reread_guard_hook.ts","args":[],"fail_closed":false,"severity":"advisory","tools":["Read","Edit","Write"],"needs_payload_bodies":["input"]},"session-eol":{"script":"src/scripts/hooks/session_eol_hook.ts","args":[],"fail_closed":false,"severity":"advisory"},"run-continuation":{"script":"src/scripts/hooks/run_continuation_hook.ts","args":[],"fail_closed":false,"severity":"blocking"},"interruption-ledger":{"script":"src/scripts/hooks/interruption_ledger_hook.ts","args":[],"fail_closed":false,"severity":"advisory","skip_on_refusal_retry":true},"subagent-ledger":{"script":"src/scripts/hooks/subagent_ledger_hook.ts","args":[],"fail_closed":false,"severity":"advisory"},"tool-result-bytes":{"script":"src/scripts/hooks/tool_result_bytes_hook.ts","args":[],"fail_closed":false,"severity":"advisory"},"spawn-guard-shadow":{"script":"src/scripts/hooks/spawn_guard_shadow_hook.ts","args":[],"fail_closed":false,"severity":"advisory","tools":["Agent","Task"]},"source-first-gate":{"script":"src/scripts/hooks/source_first_gate_hook.ts","args":[],"fail_closed":false,"severity":"advisory","needs_payload_bodies":["input"]},"journal-record":{"script":"src/scripts/hooks/journal_record_hook.ts","args":[],"fail_closed":false,"severity":"advisory"}},"roles":{"worker":{"drop":["delegation-nudge","skill-route","end-review-nudge","council-availability","team-review-gate","self-repair","session-eol","interruption-ledger"]}},"platforms":{"augment":{"session_start":["chat-history","hot-context","handoff-context","session-canary","council-availability","telemetry-disclosure","first-run-gate","onboarding-gate","verify-before-complete","minimal-safe-diff","profile-staleness","wrapper-freshness","surface-probe","session-register"],"session_end":["chat-history","memory-learn","session-register","roadmap-progress","telemetry-flush"],"stop":["chat-history","hot-context","verify-before-complete","self-repair","session-register","roadmap-progress","design-pass-stop"],"pre_tool_use":["block-no-verify","evidence-independence","block-kernel-rule-writes","block-config-weakening","block-speaking-inbox-dir","rtk-wrap","design-slop","ui-route-nudge","code-graph-nudge","ship-diff-volume","reread-guard"],"post_tool_use":["chat-history","roadmap-progress","context-hygiene","verify-before-complete","minimal-safe-diff","injection-scan","pr-url-reminder","push-settle","orchestration-record","telemetry-usage","tool-result-bytes","edit-shape","comment-discipline","design-pass"]},"claude":{"session_start":["chat-history","hot-context","handoff-context","session-canary","council-availability","telemetry-disclosure","first-run-gate","onboarding-gate","verify-before-complete","minimal-safe-diff","profile-staleness","wrapper-freshness","surface-probe","session-register","journal-record"],"session_end":["chat-history","memory-learn","session-register","roadmap-progress","telemetry-flush","journal-record"],"stop":["chat-history","hot-context","verify-before-complete","team-review-gate","end-review-nudge","turn-end-gate","self-repair","session-register","session-eol","interruption-ledger","roadmap-progress","design-pass-stop","suggestion-capture","journal-record","run-continuation"],"user_prompt_submit":["chat-history","verify-before-complete","minimal-safe-diff","language-mirror","delegation-nudge","skill-route","git-authorization","session-canary","self-repair","session-register","rule-inject","suggestion-capture","journal-record"],"pre_tool_use":["block-no-verify","evidence-independence","block-kernel-rule-writes","block-config-weakening","block-speaking-inbox-dir","one-question-per-ask","rtk-wrap","design-slop","ui-route-nudge","code-graph-nudge","ship-diff-volume","reread-guard","spawn-guard-shadow","source-first-gate","rule-inject"],"post_tool_use":["chat-history","roadmap-progress","context-hygiene","verify-before-complete","minimal-safe-diff","injection-scan","pr-url-reminder","push-settle","orchestration-record","telemetry-usage","tool-result-bytes","edit-shape","comment-discipline","language-mirror","design-pass","journal-record"],"pre_compact":["language-mirror","hot-context","rule-inject","journal-record"],"subagent_start":["subagent-ledger","journal-record"],"subagent_stop":["subagent-ledger","journal-record"]},"cowork":{"session_start":["chat-history","hot-context","handoff-context","session-canary","council-availability","telemetry-disclosure","first-run-gate","onboarding-gate","verify-before-complete","minimal-safe-diff","profile-staleness","wrapper-freshness","surface-probe","session-register"],"session_end":["chat-history","memory-learn","session-register","roadmap-progress","telemetry-flush"],"stop":["chat-history","hot-context","verify-before-complete","self-repair","session-register","roadmap-progress","design-pass-stop"],"user_prompt_submit":["chat-history","verify-before-complete","minimal-safe-diff","language-mirror","git-authorization","session-canary","self-repair","session-register"],"pre_tool_use":["block-no-verify","evidence-independence","block-kernel-rule-writes","block-config-weakening","block-speaking-inbox-dir","rtk-wrap","design-slop","ui-route-nudge","code-graph-nudge","ship-diff-volume","reread-guard","spawn-guard-shadow","source-first-gate"],"post_tool_use":["chat-history","roadmap-progress","context-hygiene","verify-before-complete","minimal-safe-diff","injection-scan","pr-url-reminder","push-settle","orchestration-record","telemetry-usage","tool-result-bytes","edit-shape","comment-discipline","design-pass"],"subagent_start":["subagent-ledger"],"subagent_stop":["subagent-ledger"]},"cursor":{"session_start":["chat-history","hot-context","handoff-context","session-canary","council-availability","telemetry-disclosure","first-run-gate","onboarding-gate","verify-before-complete","minimal-safe-diff","profile-staleness","wrapper-freshness","surface-probe","session-register"],"session_end":["chat-history","memory-learn","session-register","roadmap-progress","telemetry-flush"],"stop":["chat-history","hot-context","verify-before-complete","self-repair","session-register","roadmap-progress","design-pass-stop"],"user_prompt_submit":["chat-history","verify-before-complete","minimal-safe-diff","language-mirror","git-authorization","session-canary","self-repair","session-register"],"post_tool_use":["chat-history","roadmap-progress","context-hygiene","verify-before-complete","minimal-safe-diff","injection-scan","pr-url-reminder","push-settle","orchestration-record","telemetry-usage","tool-result-bytes","edit-shape","comment-discipline","design-pass"]},"cline":{"session_start":["chat-history","hot-context","handoff-context","session-canary","council-availability","telemetry-disclosure","first-run-gate","onboarding-gate","verify-before-complete","minimal-safe-diff","profile-staleness","wrapper-freshness","surface-probe","session-register"],"session_end":["chat-history","memory-learn","session-register","roadmap-progress","telemetry-flush"],"stop":["chat-history","hot-context","verify-before-complete","self-repair","session-register","roadmap-progress","design-pass-stop"],"user_prompt_submit":["chat-history","verify-before-complete","minimal-safe-diff","language-mirror","git-authorization","session-canary","self-repair","session-register"],"post_tool_use":["chat-history","roadmap-progress","context-hygiene","verify-before-complete","minimal-safe-diff","injection-scan","pr-url-reminder","push-settle","orchestration-record","telemetry-usage","tool-result-bytes","edit-shape","comment-discipline","design-pass"]},"windsurf":{"session_start":["chat-history","hot-context","handoff-context","session-canary","council-availability","telemetry-disclosure","first-run-gate","onboarding-gate","verify-before-complete","profile-staleness","wrapper-freshness","surface-probe","session-register"],"stop":["chat-history","hot-context","verify-before-complete","self-repair","session-register","design-pass-stop"],"user_prompt_submit":["chat-history","verify-before-complete","language-mirror","git-authorization","session-canary","self-repair","session-register"]},"gemini":{"session_start":["chat-history","hot-context","handoff-context","session-canary","council-availability","telemetry-disclosure","first-run-gate","onboarding-gate","verify-before-complete","minimal-safe-diff","profile-staleness","wrapper-freshness","surface-probe","session-register"],"session_end":["chat-history","memory-learn","session-register","roadmap-progress","telemetry-flush"],"stop":["chat-history","hot-context","verify-before-complete","self-repair","session-register","roadmap-progress","design-pass-stop"],"user_prompt_submit":["chat-history","verify-before-complete","minimal-safe-diff","language-mirror","git-authorization","session-canary","self-repair","session-register"],"post_tool_use":["chat-history","roadmap-progress","context-hygiene","verify-before-complete","minimal-safe-diff","injection-scan","pr-url-reminder","push-settle","orchestration-record","telemetry-usage","tool-result-bytes","edit-shape","comment-discipline","design-pass"]},"copilot":{"fallback_only":true}},"native_event_aliases":{"augment":{"SessionStart":"session_start","SessionEnd":"session_end","Stop":"stop","PostToolUse":"post_tool_use","PreToolUse":"pre_tool_use"},"claude":{"SessionStart":"session_start","SessionEnd":"session_end","Stop":"stop","UserPromptSubmit":"user_prompt_submit","PostToolUse":"post_tool_use","PreToolUse":"pre_tool_use","PreCompact":"pre_compact","SubagentStart":"subagent_start","SubagentStop":"subagent_stop"},"cowork":{"SessionStart":"session_start","SessionEnd":"session_end","Stop":"stop","UserPromptSubmit":"user_prompt_submit","PostToolUse":"post_tool_use","PreToolUse":"pre_tool_use","PreCompact":"pre_compact","SubagentStart":"subagent_start","SubagentStop":"subagent_stop"},"cursor":{"sessionStart":"session_start","sessionEnd":"session_end","stop":"stop","beforeSubmitPrompt":"user_prompt_submit","postToolUse":"post_tool_use","preToolUse":"pre_tool_use","preCompact":"pre_compact"},"cline":{"TaskStart":"session_start","TaskResume":"session_start","TaskComplete":"session_end","TaskCancel":"stop","UserPromptSubmit":"user_prompt_submit","PostToolUse":"post_tool_use","PreToolUse":"pre_tool_use","PreCompact":"pre_compact"},"windsurf":{"pre_user_prompt":"user_prompt_submit","post_cascade_response":"stop","post_setup_worktree":"session_start"},"gemini":{"SessionStart":"session_start","SessionEnd":"session_end","BeforeAgent":"user_prompt_submit","AfterAgent":"stop","BeforeTool":"pre_tool_use","AfterTool":"post_tool_use"}}}}
@@ -187,6 +187,36 @@ concerns:
187
187
  fail_closed: true
188
188
  severity: blocking
189
189
  needs_payload_bodies: [input]
190
+ # road-to-asked-not-parked Phase 5.1 — one question per structured-ask call.
191
+ # PreToolUse guard: DENIES a call to a host's native question picker whose
192
+ # payload carries more than one question. `ask-when-uncertain`'s Iron Law is
193
+ # one question per turn and `user-interaction` narrows "one" to one decision
194
+ # point; a picker makes N-in-one cheap, and the user then answers a form
195
+ # instead of a question. Denies with a reason rather than truncating to the
196
+ # first question — a truncation hides the decisions that were dropped.
197
+ #
198
+ # fail_closed: false, DELIBERATELY, and the direction is the opposite of
199
+ # block-no-verify's. There the guard must not become the bypass. Here a
200
+ # parse failure means an unrecognised picker shape, and blocking what it
201
+ # cannot read would turn an unknown payload into a wedged session for a
202
+ # SHAPE defect, not a safety one. The hook allows what it cannot parse and
203
+ # says so in its own header.
204
+ #
205
+ # It fires on nothing today, and that is the honest state rather than a
206
+ # defect: `_lib/structured_ask.ts` carries no OBSERVED per-host picker, so
207
+ # the `tools:` filter below lists the candidate NAMES that library matches —
208
+ # it is a narrowing filter, never a claim that any host emits one of them.
209
+ # Bound on `claude` only: it is the one platform that both binds
210
+ # pre_tool_use and honours a deny (hook-architecture-v1.md § Which hosts
211
+ # carry pre_tool_use), and a deny bound where the verdict is discarded would
212
+ # be dead weight wearing a guard's name.
213
+ one-question-per-ask:
214
+ script: src/scripts/hooks/one_question_per_ask_hook.ts
215
+ args: []
216
+ fail_closed: false
217
+ severity: blocking
218
+ tools: [AskUserQuestion, AskQuestion, UserQuestion, ask_user_question, ask_question, user_question]
219
+ needs_payload_bodies: [input]
190
220
  # road-to-source-silence Phase 4.2 — the write-time half of source
191
221
  # confidentiality. Every other gate in that programme catches the QUOTE of a
192
222
  # speaking inbox directory name; this catches the NAME, at the only moment
@@ -1189,7 +1219,7 @@ platforms:
1189
1219
  session_end: [chat-history, memory-learn, session-register, roadmap-progress, telemetry-flush, journal-record]
1190
1220
  stop: [chat-history, hot-context, verify-before-complete, team-review-gate, end-review-nudge, turn-end-gate, self-repair, session-register, session-eol, interruption-ledger, roadmap-progress, design-pass-stop, suggestion-capture, journal-record, run-continuation]
1191
1221
  user_prompt_submit: [chat-history, verify-before-complete, minimal-safe-diff, language-mirror, delegation-nudge, skill-route, git-authorization, session-canary, self-repair, session-register, rule-inject, suggestion-capture, journal-record]
1192
- pre_tool_use: [block-no-verify, evidence-independence, block-kernel-rule-writes, block-config-weakening, block-speaking-inbox-dir, rtk-wrap, design-slop, ui-route-nudge, code-graph-nudge, ship-diff-volume, reread-guard, spawn-guard-shadow, source-first-gate, rule-inject]
1222
+ pre_tool_use: [block-no-verify, evidence-independence, block-kernel-rule-writes, block-config-weakening, block-speaking-inbox-dir, one-question-per-ask, rtk-wrap, design-slop, ui-route-nudge, code-graph-nudge, ship-diff-volume, reread-guard, spawn-guard-shadow, source-first-gate, rule-inject]
1193
1223
  post_tool_use: [chat-history, roadmap-progress, context-hygiene, verify-before-complete, minimal-safe-diff, injection-scan, pr-url-reminder, push-settle, orchestration-record, telemetry-usage, tool-result-bytes, edit-shape, comment-discipline, language-mirror, design-pass, journal-record]
1194
1224
  # `language-mirror` — round-5 § 6.1. `pre_compact` sets a pin-lost marker;
1195
1225
  # the `post_tool_use` entry above re-emits the pin exactly once while that
@@ -54,6 +54,7 @@ import { main as blockNoVerifyMain } from './block_no_verify.js';
54
54
  import { main as blockKernelRuleWritesMain } from './block_kernel_rule_writes.js';
55
55
  import { main as blockConfigWeakeningMain } from './block_config_weakening.js';
56
56
  import { main as blockSpeakingInboxDirMain } from './block_speaking_inbox_dir.js';
57
+ import { main as oneQuestionPerAskMain } from './one_question_per_ask_hook.js';
57
58
  import { main as rtkWrapMain } from './rtk_wrap_hook.js';
58
59
  import { _main as designPassMain } from './design_pass_hook.js';
59
60
  import { main as designSlopMain } from './design_slop_hook.js';
@@ -115,6 +116,7 @@ export const CONCERN_REGISTRY: Readonly<Record<string, ConcernMain>> = {
115
116
  'src/scripts/hooks/block_kernel_rule_writes.ts': blockKernelRuleWritesMain as ConcernMain,
116
117
  'src/scripts/hooks/block_config_weakening.ts': blockConfigWeakeningMain as ConcernMain,
117
118
  'src/scripts/hooks/block_speaking_inbox_dir.ts': blockSpeakingInboxDirMain as ConcernMain,
119
+ 'src/scripts/hooks/one_question_per_ask_hook.ts': oneQuestionPerAskMain as ConcernMain,
118
120
  'src/scripts/hooks/rtk_wrap_hook.ts': rtkWrapMain as ConcernMain,
119
121
  'src/scripts/hooks/design_pass_hook.ts': designPassMain as ConcernMain,
120
122
  'src/scripts/hooks/design_slop_hook.ts': designSlopMain as ConcernMain,
@@ -375,6 +375,33 @@ export function buildNudgeLine(
375
375
  `${classification.reason}.</delegation-nudge>`
376
376
  );
377
377
  }
378
+ // Rung 4 (1.3): a contested-judgment verdict names the council's own entry
379
+ // point. The carrier NEVER runs it — `council_cli run` spends a metered or
380
+ // subscription seat, which is Hard-Floor reserved and is never inferred from
381
+ // a hook line.
382
+ if (rung === 4) {
383
+ return (
384
+ `<delegation-nudge>rung-4: council. This is contested judgment, not a ` +
385
+ `slice to dispatch — route it to the council yourself via ` +
386
+ "`./scripts-run src/scripts/council_cli run --input <file>` " +
387
+ "(check reachability first with `agent-config council:status`; the file " +
388
+ `path is the input, never an inline question). Not a spawn, and not run ` +
389
+ `for you — ${classification.reason}.</delegation-nudge>`
390
+ );
391
+ }
392
+ // Rung 3 (1.3): slices that must communicate DURING the run. The pointer
393
+ // names the host teams primitive; the fallback when the host has none is the
394
+ // same one-completion path rung 0.5 cites.
395
+ if (rung === 3) {
396
+ return (
397
+ `<delegation-nudge>rung-3: team. These slices must see each other's state ` +
398
+ `during the run, so a set of independent subagent spawns cannot express ` +
399
+ `it — use the host teams primitive, or fall back to ` +
400
+ "`./scripts-run src/scripts/ask_transport \"<question>\"` for a bounded " +
401
+ `sub-question. Not a spawn, and not run for you — ` +
402
+ `${classification.reason}.</delegation-nudge>`
403
+ );
404
+ }
378
405
  // Rung 1 (single bounded slice) carries no do-in-steps/do-in-parallel
379
406
  // mode of its own — `classification.mode` is `null` for that shape.
380
407
  const modeLabel = classification.mode ?? "single-slice";
@@ -437,8 +464,25 @@ export function classifyPrompt(
437
464
  // surfaces. Silence here also guarantees a question-shaped prompt can
438
465
  // never produce a spawn nudge ("the carrier stops nudging full spawns
439
466
  // for question-shaped slices").
467
+ // Rung 3/4: these used to be discarded by the same `verdict !== "subagent"`
468
+ // return as rung 0/0.5, so a RESOLVED council verdict produced no output on
469
+ // the only runtime carrier.
470
+ //
471
+ // What they emit is a POINTER, and every field here is chosen so it cannot
472
+ // read as a spawn authorisation: `delegable` stays false, the action stays
473
+ // `ask` (the existing token for "a verdict, never a speculative spawn"),
474
+ // the slice count is 0, and buildNudgeLine's rung-3/4 branch names an
475
+ // entry point rather than a dispatch.
476
+ if (ladder.verdict === "team" || ladder.verdict === "council") {
477
+ return {
478
+ classification: { delegable: false, action: "ask", mode: null, reason: ladder.reason },
479
+ sliceCount: 0,
480
+ tier: recommendSliceTier(downshift, separate_quota_pool),
481
+ rung: ladder.rung,
482
+ };
483
+ }
440
484
  if (ladder.verdict !== "subagent") {
441
- return null; // rung-0 script, rung-0.5 ask-transport, rung-3/4 team/council, or ∅ user-ask/in-session
485
+ return null; // rung-0 script, rung-0.5 ask-transport, or ∅ user-ask/in-session
442
486
  }
443
487
  const tier = recommendSliceTier(downshift, separate_quota_pool);
444
488
  // Rung 1 (single bounded slice) has no explicit slice count of its own —
@@ -0,0 +1,191 @@
1
+ #!/usr/bin/env tsx
2
+ /**
3
+ * PreToolUse guard: one question per structured-ask call.
4
+ *
5
+ * road-to-asked-not-parked 5.1. `ask-when-uncertain`'s Iron Law is one
6
+ * question per turn, and `user-interaction` § question pacing narrows what
7
+ * "one" means: one decision point, answerable with one reply. A host's native
8
+ * question picker makes it cheap to violate that — a payload can carry N
9
+ * questions in one call, and the user then answers a form instead of a
10
+ * question.
11
+ *
12
+ * DENY, NEVER TRUNCATE. Silently keeping the first question and dropping the
13
+ * rest would hide exactly the decisions the user was owed; the deny message
14
+ * names the count so the caller can split the ask instead of guessing what
15
+ * happened.
16
+ *
17
+ * WHAT IT SEES, honestly. `_lib/structured_ask.ts` carries no observed
18
+ * per-host tool, so this guard matches on a name SHAPE and is filtered by the
19
+ * manifest's per-concern `tools:` key to the same candidate names. On every
20
+ * host measured today it therefore fires on nothing — the concern exists so
21
+ * that the first host to ship a picker meets the rule already in force, not
22
+ * because a violation has been observed.
23
+ *
24
+ * ENFORCEMENT REACH, also honestly. `fail_closed: false` and the exit-1 deny
25
+ * are only a deny where the host both binds `pre_tool_use` AND honours the
26
+ * dispatcher's verdict. `hook-architecture-v1.md` § Which hosts carry
27
+ * pre_tool_use is the table; `agent-config hooks:status` answers it for the
28
+ * host actually running. This file claims no more than that.
29
+ *
30
+ * A payload whose shape is not recognised at all (`countStructuredAskQuestions`
31
+ * returns -1) is ALLOWED. A guard that blocks what it cannot parse would turn
32
+ * an unknown picker shape into a wedged session, and the failure it guards
33
+ * against — too many questions — is a shape defect, not a safety one.
34
+ *
35
+ * Exit codes (docs/contracts/hook-architecture-v1.md):
36
+ * 0 — allow
37
+ * 1 — block (the call carries more than one question)
38
+ */
39
+ import { fileURLToPath, pathToFileURL } from 'node:url';
40
+
41
+ import { countStructuredAskQuestions, isStructuredAskTool } from '../_lib/structured_ask.js';
42
+ import { readHookStdin } from './hook_stdin.js';
43
+
44
+ const _HERE = fileURLToPath(import.meta.url);
45
+
46
+ type JsonObject = Record<string, unknown>;
47
+
48
+ function _isObject(v: unknown): v is JsonObject {
49
+ return typeof v === 'object' && v !== null && !Array.isArray(v);
50
+ }
51
+
52
+ export interface AskCall {
53
+ readonly tool: string;
54
+ readonly questions: number;
55
+ }
56
+
57
+ /** Read (tool name, question count) off a PreToolUse envelope. */
58
+ export function extractAskCall(envelope: JsonObject): AskCall {
59
+ const payload = _isObject(envelope['payload']) ? envelope['payload'] : envelope;
60
+ const nameVal =
61
+ payload['tool_name'] ??
62
+ payload['toolName'] ??
63
+ payload['tool'] ??
64
+ envelope['tool_name'] ??
65
+ envelope['tool'];
66
+ const tool = typeof nameVal === 'string' ? nameVal : '';
67
+ const ti = _isObject(payload['tool_input'])
68
+ ? payload['tool_input']
69
+ : _isObject(envelope['tool_input'])
70
+ ? envelope['tool_input']
71
+ : null;
72
+ return { tool, questions: ti === null ? -1 : countStructuredAskQuestions(ti) };
73
+ }
74
+
75
+ /** The verdict, separated from I/O so the fixtures exercise the decision itself. */
76
+ export function verdict(call: AskCall): { block: boolean; reason: string } {
77
+ if (call.tool === '' || !isStructuredAskTool(call.tool)) {
78
+ return { block: false, reason: 'not a structured-ask call' };
79
+ }
80
+ if (call.questions < 0) {
81
+ return { block: false, reason: 'payload shape not recognised — allowed, never guessed' };
82
+ }
83
+ if (call.questions <= 1) {
84
+ return { block: false, reason: 'one question' };
85
+ }
86
+ return {
87
+ block: true,
88
+ reason:
89
+ `${call.tool} carries ${String(call.questions)} questions in one call. ` +
90
+ 'One decision per ask: put the first question, wait for the answer, then ' +
91
+ 'the next. The call is denied rather than truncated — dropping the extra ' +
92
+ 'questions would hide the decisions the user is owed.',
93
+ };
94
+ }
95
+
96
+ export function main(argv?: string[]): number {
97
+ const args = argv ?? process.argv.slice(2);
98
+ for (const a of args) {
99
+ if (a === '--self-test') {
100
+ return selfTest();
101
+ }
102
+ }
103
+ const raw = readHookStdin();
104
+ if (!raw.trim()) {
105
+ return 0;
106
+ }
107
+ let envelope: JsonObject;
108
+ try {
109
+ const parsed: unknown = JSON.parse(raw);
110
+ envelope = _isObject(parsed) ? parsed : {};
111
+ } catch {
112
+ return 0;
113
+ }
114
+ const v = verdict(extractAskCall(envelope));
115
+ if (v.block) {
116
+ process.stderr.write(`one-question-per-ask: BLOCKED — ${v.reason}\n`);
117
+ return 1;
118
+ }
119
+ return 0;
120
+ }
121
+
122
+ export function selfTest(): number {
123
+ const cases: Array<[string, JsonObject, boolean]> = [
124
+ [
125
+ 'two questions in one call is denied',
126
+ { tool_name: 'AskUserQuestion', tool_input: { questions: [{}, {}] } },
127
+ true,
128
+ ],
129
+ [
130
+ 'four questions is denied',
131
+ { tool_name: 'AskUserQuestion', tool_input: { questions: [{}, {}, {}, {}] } },
132
+ true,
133
+ ],
134
+ [
135
+ 'one question passes',
136
+ { tool_name: 'AskUserQuestion', tool_input: { questions: [{}] } },
137
+ false,
138
+ ],
139
+ [
140
+ 'a single-question field passes',
141
+ { tool_name: 'ask_user_question', tool_input: { question: 'which one?' } },
142
+ false,
143
+ ],
144
+ [
145
+ 'an empty ask passes — malformed, but not this guard\'s failure',
146
+ { tool_name: 'AskUserQuestion', tool_input: { questions: [] } },
147
+ false,
148
+ ],
149
+ [
150
+ 'an unrecognised payload shape passes rather than wedging the session',
151
+ { tool_name: 'AskUserQuestion', tool_input: { something: 'else' } },
152
+ false,
153
+ ],
154
+ ['an ordinary tool is never seen', { tool_name: 'Bash', tool_input: { command: 'ls' } }, false],
155
+ [
156
+ 'a Write with two questions in its body is not an ask call',
157
+ { tool_name: 'Write', tool_input: { questions: [{}, {}] } },
158
+ false,
159
+ ],
160
+ ['an empty envelope passes', {}, false],
161
+ ];
162
+ let failed = 0;
163
+ for (const [name, envelope, want] of cases) {
164
+ const got = verdict(extractAskCall(envelope)).block;
165
+ const ok = got === want;
166
+ process.stdout.write(
167
+ `${ok ? '✅' : '❌'} ${name} — block=${String(got)}` +
168
+ (ok ? '\n' : ` (wanted ${String(want)})\n`),
169
+ );
170
+ if (!ok) failed += 1;
171
+ }
172
+ const positives = cases.filter((c) => c[2]).length;
173
+ if (positives < 2) {
174
+ process.stderr.write(
175
+ '❌ one_question_per_ask --self-test: fewer than 2 deny cases — a guard never ' +
176
+ 'seen refuse has unknown sensitivity.\n',
177
+ );
178
+ return 1;
179
+ }
180
+ process.stdout.write(
181
+ `\none_question_per_ask --self-test: ${String(cases.length - failed)}/${String(cases.length)} ` +
182
+ `case(s) behaved (${String(positives)} deny, ${String(cases.length - positives)} allow)\n`,
183
+ );
184
+ return failed > 0 ? 1 : 0;
185
+ }
186
+
187
+ if (process.argv[1] !== undefined && import.meta.url === pathToFileURL(process.argv[1]).href) {
188
+ process.exit(main());
189
+ }
190
+
191
+ export { _HERE };
@@ -45,7 +45,7 @@ import { fileURLToPath, pathToFileURL } from 'node:url';
45
45
 
46
46
  import recycleThresholdConfig from '../../config/recycle-threshold-budget.json';
47
47
 
48
- import { RECYCLE_ENVELOPE_REL } from '../_lib/recycle_envelope_paths.js';
48
+ import { recycle_envelope_rel } from '../_lib/recycle_envelope_paths.js';
49
49
  import {
50
50
  emptyCounters,
51
51
  eolSessionKey,
@@ -180,8 +180,16 @@ export function readState(file: string): SessionEolState {
180
180
  * session's state — a wrong resume instead of an empty one. An envelope whose
181
181
  * `written_at` predates the advisory is not this session's.
182
182
  */
183
- export function envelopeExists(workspaceRoot: string, since: string | null = null): boolean {
184
- const target = path.join(workspaceRoot, RECYCLE_ENVELOPE_REL);
183
+ export function envelopeExists(
184
+ workspaceRoot: string,
185
+ since: string | null = null,
186
+ sessionId: string | null = null,
187
+ ): boolean {
188
+ // Phase 2.1: the record is keyed by session, so the counter-check must look
189
+ // at THIS session's path. Checking the shared name would read a peer's
190
+ // record as proof that this session wrote one — the same cross-session
191
+ // confusion the key exists to remove, re-created in the checker.
192
+ const target = path.join(workspaceRoot, recycle_envelope_rel(sessionId));
185
193
  let raw: string;
186
194
  try {
187
195
  raw = fs.readFileSync(target, 'utf-8');
@@ -212,10 +220,10 @@ export function envelopeExists(workspaceRoot: string, since: string | null = nul
212
220
  * the next action the advisory recommended is the one that destroys the
213
221
  * session.
214
222
  */
215
- export function buildMissingEnvelopeLine(workspaceRoot: string): string {
223
+ export function buildMissingEnvelopeLine(workspaceRoot: string, sessionId: string | null = null): string {
216
224
  return (
217
225
  `recycle advised earlier, but no envelope exists at ` +
218
- `${path.join(workspaceRoot, RECYCLE_ENVELOPE_REL)} — /clear now starts the successor ` +
226
+ `${path.join(workspaceRoot, recycle_envelope_rel(sessionId))} — /clear now starts the successor ` +
219
227
  `from nothing. Re-run \`agent-config session:recycle\` and check that it prints the ` +
220
228
  `absolute path it wrote before clearing.`
221
229
  );
@@ -334,11 +342,14 @@ export function main(): number {
334
342
  // `AGENT_RECYCLE_THRESHOLD_TOKENS=0` is documented as the emergency switch
335
343
  // for the whole advisory lane, and a lane that keeps one more warn after
336
344
  // being switched off is not off.
345
+ // Raw id, not `sessionKey`: the record path is built from the id the host
346
+ // exported (`safe_stem`), never from the hashed state-file key.
347
+ const rawSessionId = payloadSessionId(payload, envelope) || null;
337
348
  const shouldWarnMissing =
338
349
  threshold !== null &&
339
350
  state.advisory_fired_at !== null &&
340
351
  (state.missing_envelope_warned_at ?? null) === null &&
341
- !envelopeExists(workspaceRoot, state.advisory_fired_at);
352
+ !envelopeExists(workspaceRoot, state.advisory_fired_at, rawSessionId);
342
353
 
343
354
  const nextState: SessionEolState = {
344
355
  schema_version: 1,
@@ -415,7 +426,7 @@ export function main(): number {
415
426
  `${JSON.stringify({
416
427
  decision: 'warn',
417
428
  reason: 'session-eol: recycle advised, no envelope written',
418
- additional_context: buildMissingEnvelopeLine(workspaceRoot),
429
+ additional_context: buildMissingEnvelopeLine(workspaceRoot, rawSessionId),
419
430
  })}\n`,
420
431
  );
421
432
  return EXIT_WARN;
@@ -152,6 +152,58 @@ elif ! ./scripts-run src/scripts/check_branch_freshness --quiet; then
152
152
  exit 1
153
153
  fi
154
154
 
155
+ # BRANCH WORK COMMITTED — after base freshness, before everything else.
156
+ #
157
+ # Ordering is deliberate in BOTH directions. It runs AFTER base freshness
158
+ # because the remedy there (`task push-ready`) merges, and a merge changes the
159
+ # working tree this gate reads — checking first would answer against a tree the
160
+ # operator is about to replace. It runs BEFORE the remaining gates because they
161
+ # all answer against the working tree, and a tree carrying unfinished work
162
+ # makes their verdicts describe something that is not being pushed.
163
+ #
164
+ # Measured twice, and both placements were wrong for a different reason.
165
+ # Placing it FIRST reded tests/scripts/prepush_base_freshness.test.ts, which
166
+ # executes the whole hook and asserts the freshness block is reached. Placing
167
+ # it between the next block's comment header and that block's `echo` reded
168
+ # check_installed_hooks_fresh's advisory pin, whose extraction runs from that
169
+ # header to the following task-availability check and so swallowed this block's
170
+ # `exit 1`. A block goes BEFORE a neighbour's comment header, never between the
171
+ # header and its code.
172
+ #
173
+ # And this paragraph may NOT name that header literally: the pin locates it with
174
+ # a plain indexOf over the rendered hook, so a comment quoting the string
175
+ # becomes the first match and truncates the block to nothing. An anchor that is
176
+ # also content is not an anchor — spelled out here because the obvious edit to
177
+ # this comment is to put the string back in for clarity.
178
+ #
179
+ # The defect it exists for, measured 2026-09-07: a reconciled baseline was
180
+ # written into gate-violation-baselines.json AFTER `git add`, so
181
+ # `git commit --no-edit` captured the staged side, the edit stayed in the tree,
182
+ # and the push shipped a branch whose commits contradicted it. CI cannot see
183
+ # this class at all — it checks out the commit, not the tree the edit is in.
184
+ #
185
+ # It blocks only what it can attribute to THIS branch (staged paths, and dirty
186
+ # paths this branch's own commits touch). A gate script's report output and a
187
+ # parallel session's edit are named and waved through, which is what keeps this
188
+ # from becoming the blanket clean-tree rule that would train the operator to
189
+ # set the skip variable.
190
+ echo "🔍 Branch work committed — is any of this branch's own work still uncommitted?"
191
+ if [ "${AGENT_CONFIG_SKIP_PREPUSH_WORKTREE:-}" = "1" ]; then
192
+ echo "⏭️ skipped via AGENT_CONFIG_SKIP_PREPUSH_WORKTREE=1"
193
+ elif [ ! -x ./scripts-run ]; then
194
+ echo "⚠️ ./scripts-run not found — skipping the worktree check for this push."
195
+ elif ! ./scripts-run src/scripts/check_branch_work_committed --quiet; then
196
+ echo ""
197
+ echo " Push blocked — this branch's own work is not all committed, so the"
198
+ echo " pushed branch would carry commits its own tree contradicts."
199
+ echo ""
200
+ echo " Commit them, or 'git restore' whatever was not meant to land."
201
+ echo ""
202
+ echo " This hook refuses; it never commits for you. Bypass a genuine WIP"
203
+ echo " push with AGENT_CONFIG_SKIP_PREPUSH_WORKTREE=1."
204
+ exit 1
205
+ fi
206
+
155
207
  # INSTALLED-HOOK FRESHNESS — ADVISORY, and deliberately AFTER base freshness.
156
208
  #
157
209
  # What it answers: are the hooks in .git/hooks still what THIS checkout's
@@ -75,6 +75,7 @@ import { build_merge_entries } from './_lib/json_pointers.js';
75
75
  import { is_claude_builtin_name } from './_lib/claude_builtin_names.js';
76
76
  import * as installed_lock from './_lib/installed_lock.js';
77
77
  import * as mcp_bridge from './_lib/mcp_bridge.js';
78
+ import * as mcp_consent from './_lib/mcp_consent_residual.js';
78
79
  import * as scoped_projection from './_lib/scoped_projection.js';
79
80
  import * as surface_tiers from './_lib/surface_tiers.js';
80
81
  import * as global_deploy_inventory from './_lib/global_deploy_inventory.js';
@@ -5121,11 +5122,9 @@ function _main_project_install(
5121
5122
  ...ensure_augment_bridge(project_root, opts.force),
5122
5123
  ];
5123
5124
  if (_is_tool_enabled(tools, 'claude-code')) {
5124
- merged_keys_by_tool['claude-code'] = [
5125
- ...ensure_claude_bridge(project_root, opts.force),
5126
- ...ensure_mcp_bridge(project_root, opts.force),
5127
- ];
5125
+ merged_keys_by_tool['claude-code'] = ensure_claude_bridge(project_root, opts.force);
5128
5126
  }
5127
+ mcp_bridge.registerMcpHosts(merge_json_file, project_root, opts.force, package_root, tools, merged_keys_by_tool);
5129
5128
  if (_is_tool_enabled(tools, 'cursor')) {
5130
5129
  merged_keys_by_tool['cursor'] = ensure_cursor_bridge(project_root, opts.force);
5131
5130
  }
@@ -5226,6 +5225,7 @@ function _main_project_install(
5226
5225
  );
5227
5226
  process.stdout.write('\n');
5228
5227
  }
5228
+ mcp_consent.printResiduals(tools, state.QUIET);
5229
5229
  if (_is_tool_enabled(tools, 'claude-code')) {
5230
5230
  const team_hint = _team_setup_hint_line(project_root);
5231
5231
  if (team_hint !== null) {