@event4u/agent-config 1.15.0 → 1.17.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 (354) hide show
  1. package/.agent-src/commands/{agents-audit.md → agents/audit.md} +4 -3
  2. package/.agent-src/commands/{agents-cleanup.md → agents/cleanup.md} +12 -6
  3. package/.agent-src/commands/{agents-prepare.md → agents/prepare.md} +4 -3
  4. package/.agent-src/commands/agents.md +46 -0
  5. package/.agent-src/commands/bug-fix.md +1 -1
  6. package/.agent-src/commands/bug-investigate.md +2 -2
  7. package/.agent-src/commands/{chat-history-checkpoint.md → chat-history/checkpoint.md} +5 -5
  8. package/.agent-src/commands/{chat-history-clear.md → chat-history/clear.md} +5 -5
  9. package/.agent-src/commands/{chat-history-resume.md → chat-history/resume.md} +4 -4
  10. package/.agent-src/commands/chat-history/show.md +107 -0
  11. package/.agent-src/commands/chat-history.md +33 -89
  12. package/.agent-src/commands/check-current-md.md +1 -1
  13. package/.agent-src/commands/{commit-in-chunks.md → commit/in-chunks.md} +15 -13
  14. package/.agent-src/commands/commit.md +22 -2
  15. package/.agent-src/commands/{context-create.md → context/create.md} +4 -3
  16. package/.agent-src/commands/{context-refactor.md → context/refactor.md} +4 -3
  17. package/.agent-src/commands/context.md +44 -0
  18. package/.agent-src/commands/{copilot-agents-init.md → copilot-agents/init.md} +4 -3
  19. package/.agent-src/commands/{copilot-agents-optimize.md → copilot-agents/optimize.md} +4 -3
  20. package/.agent-src/commands/copilot-agents.md +44 -0
  21. package/.agent-src/commands/council/default.md +221 -0
  22. package/.agent-src/commands/council/design.md +97 -0
  23. package/.agent-src/commands/council/optimize.md +116 -0
  24. package/.agent-src/commands/council/pr.md +124 -0
  25. package/.agent-src/commands/council.md +54 -0
  26. package/.agent-src/commands/{create-pr-description.md → create-pr/description-only.md} +4 -2
  27. package/.agent-src/commands/create-pr.md +49 -5
  28. package/.agent-src/commands/e2e-heal.md +1 -1
  29. package/.agent-src/commands/e2e-plan.md +1 -1
  30. package/.agent-src/commands/{feature-dev.md → feature/dev.md} +6 -3
  31. package/.agent-src/commands/{feature-explore.md → feature/explore.md} +5 -4
  32. package/.agent-src/commands/{feature-plan.md → feature/plan.md} +32 -5
  33. package/.agent-src/commands/{feature-refactor.md → feature/refactor.md} +4 -3
  34. package/.agent-src/commands/{feature-roadmap.md → feature/roadmap.md} +7 -6
  35. package/.agent-src/commands/feature.md +52 -0
  36. package/.agent-src/commands/{fix-ci.md → fix/ci.md} +4 -3
  37. package/.agent-src/commands/{fix-portability.md → fix/portability.md} +4 -3
  38. package/.agent-src/commands/{fix-pr-bot-comments.md → fix/pr-bots.md} +4 -3
  39. package/.agent-src/commands/{fix-pr-developer-comments.md → fix/pr-developers.md} +4 -3
  40. package/.agent-src/commands/{fix-pr-comments.md → fix/pr.md} +7 -6
  41. package/.agent-src/commands/{fix-references.md → fix/refs.md} +4 -3
  42. package/.agent-src/commands/{fix-seeder.md → fix/seeder.md} +4 -3
  43. package/.agent-src/commands/fix.md +54 -0
  44. package/.agent-src/commands/jira-ticket.md +1 -1
  45. package/.agent-src/commands/{do-and-judge.md → judge/on-diff.md} +7 -6
  46. package/.agent-src/commands/judge/solo.md +90 -0
  47. package/.agent-src/commands/{do-in-steps.md → judge/steps.md} +8 -7
  48. package/.agent-src/commands/judge.md +35 -70
  49. package/.agent-src/commands/{memory-add.md → memory/add.md} +7 -6
  50. package/.agent-src/commands/{memory-full.md → memory/load.md} +6 -5
  51. package/.agent-src/commands/{memory-promote.md → memory/promote.md} +6 -5
  52. package/.agent-src/commands/{propose-memory.md → memory/propose.md} +6 -5
  53. package/.agent-src/commands/memory.md +48 -0
  54. package/.agent-src/commands/mode.md +5 -5
  55. package/.agent-src/commands/{module-create.md → module/create.md} +4 -3
  56. package/.agent-src/commands/{module-explore.md → module/explore.md} +4 -3
  57. package/.agent-src/commands/module.md +44 -0
  58. package/.agent-src/commands/onboard.md +3 -3
  59. package/.agent-src/commands/{optimize-agents.md → optimize/agents.md} +5 -4
  60. package/.agent-src/commands/{optimize-augmentignore.md → optimize/augmentignore.md} +4 -4
  61. package/.agent-src/commands/{optimize-rtk-filters.md → optimize/rtk.md} +4 -3
  62. package/.agent-src/commands/{optimize-skills.md → optimize/skills.md} +5 -4
  63. package/.agent-src/commands/optimize.md +48 -0
  64. package/.agent-src/commands/{override-create.md → override/create.md} +4 -3
  65. package/.agent-src/commands/{override-manage.md → override/manage.md} +4 -3
  66. package/.agent-src/commands/override.md +44 -0
  67. package/.agent-src/commands/review-changes.md +26 -1
  68. package/.agent-src/commands/review-routing.md +1 -1
  69. package/.agent-src/commands/{roadmap-create.md → roadmap/create.md} +33 -5
  70. package/.agent-src/commands/{roadmap-execute.md → roadmap/execute.md} +4 -3
  71. package/.agent-src/commands/roadmap.md +44 -0
  72. package/.agent-src/commands/set-cost-profile.md +3 -3
  73. package/.agent-src/commands/sync-agent-settings.md +2 -2
  74. package/.agent-src/commands/{tests-create.md → tests/create.md} +5 -4
  75. package/.agent-src/commands/{tests-execute.md → tests/execute.md} +4 -3
  76. package/.agent-src/commands/tests.md +44 -0
  77. package/.agent-src/commands/upstream-contribute.md +1 -1
  78. package/.agent-src/contexts/authority/commit-mechanics.md +57 -0
  79. package/.agent-src/contexts/authority/destructive-mechanics.md +66 -0
  80. package/.agent-src/contexts/authority/scope-mechanics.md +87 -0
  81. package/.agent-src/contexts/communication/rules-auto/artifact-engagement-recording-mechanics.md +72 -0
  82. package/.agent-src/contexts/communication/rules-auto/augment-portability-mechanics.md +79 -0
  83. package/.agent-src/contexts/communication/rules-auto/augment-source-of-truth-mechanics.md +98 -0
  84. package/.agent-src/contexts/communication/rules-auto/cli-output-handling-mechanics.md +87 -0
  85. package/.agent-src/contexts/communication/rules-auto/command-suggestion-policy-mechanics.md +62 -0
  86. package/.agent-src/contexts/communication/rules-auto/docs-sync-mechanics.md +78 -0
  87. package/.agent-src/contexts/communication/rules-auto/package-ci-checks-mechanics.md +85 -0
  88. package/.agent-src/contexts/communication/rules-auto/review-routing-awareness-mechanics.md +65 -0
  89. package/.agent-src/contexts/communication/rules-auto/roadmap-progress-sync-mechanics.md +78 -0
  90. package/.agent-src/contexts/communication/rules-auto/skill-quality-mechanics.md +62 -0
  91. package/.agent-src/contexts/communication/rules-auto/slash-command-routing-policy-mechanics.md +55 -0
  92. package/.agent-src/contexts/communication/rules-auto/ui-audit-gate-mechanics.md +53 -0
  93. package/.agent-src/contexts/communication/rules-auto/user-interaction-mechanics.md +77 -0
  94. package/.agent-src/contexts/execution/autonomy-detection.md +54 -0
  95. package/.agent-src/contexts/execution/autonomy-examples.md +90 -0
  96. package/.agent-src/contexts/execution/autonomy-mechanics.md +29 -0
  97. package/.agent-src/contexts/execution/verification-mechanics.md +80 -0
  98. package/.agent-src/contexts/judges/no-consolidate-rationale.md +102 -0
  99. package/.agent-src/contexts/judges/persona-voice-rubric.md +140 -0
  100. package/.agent-src/personas/README.md +1 -1
  101. package/.agent-src/rules/agent-authority.md +24 -0
  102. package/.agent-src/rules/architecture.md +1 -1
  103. package/.agent-src/rules/artifact-drafting-protocol.md +1 -1
  104. package/.agent-src/rules/artifact-engagement-recording.md +14 -70
  105. package/.agent-src/rules/ask-when-uncertain.md +28 -43
  106. package/.agent-src/rules/augment-portability.md +15 -61
  107. package/.agent-src/rules/augment-source-of-truth.md +27 -93
  108. package/.agent-src/rules/autonomous-execution.md +78 -114
  109. package/.agent-src/rules/capture-learnings.md +1 -1
  110. package/.agent-src/rules/chat-history-cadence.md +3 -3
  111. package/.agent-src/rules/chat-history-ownership.md +3 -3
  112. package/.agent-src/rules/chat-history-visibility.md +3 -3
  113. package/.agent-src/rules/cli-output-handling.md +10 -76
  114. package/.agent-src/rules/command-suggestion-policy.md +93 -0
  115. package/.agent-src/rules/commit-conventions.md +17 -14
  116. package/.agent-src/rules/commit-policy.md +14 -42
  117. package/.agent-src/rules/context-hygiene.md +3 -3
  118. package/.agent-src/rules/direct-answers.md +34 -49
  119. package/.agent-src/rules/docker-commands.md +5 -5
  120. package/.agent-src/rules/docs-sync.md +16 -70
  121. package/.agent-src/rules/e2e-testing.md +1 -1
  122. package/.agent-src/rules/guidelines.md +4 -4
  123. package/.agent-src/rules/improve-before-implement.md +2 -2
  124. package/.agent-src/rules/language-and-tone.md +50 -133
  125. package/.agent-src/rules/minimal-safe-diff.md +3 -3
  126. package/.agent-src/rules/missing-tool-handling.md +28 -22
  127. package/.agent-src/rules/model-recommendation.md +4 -4
  128. package/.agent-src/rules/no-cheap-questions.md +82 -0
  129. package/.agent-src/rules/no-roadmap-references.md +73 -0
  130. package/.agent-src/rules/non-destructive-by-default.md +15 -49
  131. package/.agent-src/rules/onboarding-gate.md +5 -5
  132. package/.agent-src/rules/package-ci-checks.md +21 -61
  133. package/.agent-src/rules/preservation-guard.md +64 -29
  134. package/.agent-src/rules/review-routing-awareness.md +26 -45
  135. package/.agent-src/rules/roadmap-progress-sync.md +28 -96
  136. package/.agent-src/rules/role-mode-adherence.md +2 -2
  137. package/.agent-src/rules/scope-control.md +65 -46
  138. package/.agent-src/rules/security-sensitive-stop.md +9 -9
  139. package/.agent-src/rules/size-enforcement.md +1 -1
  140. package/.agent-src/rules/skill-quality.md +16 -48
  141. package/.agent-src/rules/{slash-commands.md → slash-command-routing-policy.md} +7 -4
  142. package/.agent-src/rules/think-before-action.md +55 -45
  143. package/.agent-src/rules/token-efficiency.md +4 -4
  144. package/.agent-src/rules/tool-safety.md +19 -16
  145. package/.agent-src/rules/{ui-audit-before-build.md → ui-audit-gate.md} +27 -41
  146. package/.agent-src/rules/user-interaction.md +16 -71
  147. package/.agent-src/rules/verify-before-complete.md +12 -67
  148. package/.agent-src/scripts/update_roadmap_progress.py +9 -4
  149. package/.agent-src/skills/ai-council/SKILL.md +335 -0
  150. package/.agent-src/skills/api-endpoint/SKILL.md +2 -2
  151. package/.agent-src/skills/api-testing/SKILL.md +1 -1
  152. package/.agent-src/skills/blade-ui/SKILL.md +1 -1
  153. package/.agent-src/skills/blast-radius-analyzer/SKILL.md +1 -1
  154. package/.agent-src/skills/bug-analyzer/SKILL.md +1 -1
  155. package/.agent-src/skills/check-refs/SKILL.md +59 -40
  156. package/.agent-src/skills/command-routing/SKILL.md +1 -1
  157. package/.agent-src/skills/command-writing/SKILL.md +1 -1
  158. package/.agent-src/skills/conventional-commits-writing/SKILL.md +86 -28
  159. package/.agent-src/skills/copilot-agents-optimization/SKILL.md +7 -7
  160. package/.agent-src/skills/developer-like-execution/SKILL.md +6 -6
  161. package/.agent-src/skills/finishing-a-development-branch/SKILL.md +101 -65
  162. package/.agent-src/skills/flux/SKILL.md +31 -11
  163. package/.agent-src/skills/git-workflow/SKILL.md +1 -1
  164. package/.agent-src/skills/github-ci/SKILL.md +2 -2
  165. package/.agent-src/skills/guideline-writing/SKILL.md +11 -11
  166. package/.agent-src/skills/judge-code-quality/SKILL.md +7 -8
  167. package/.agent-src/skills/judge-security-auditor/SKILL.md +4 -5
  168. package/.agent-src/skills/judge-test-coverage/SKILL.md +3 -4
  169. package/.agent-src/skills/learning-to-rule-or-skill/SKILL.md +4 -4
  170. package/.agent-src/skills/lint-skills/SKILL.md +57 -39
  171. package/.agent-src/skills/livewire/SKILL.md +1 -1
  172. package/.agent-src/skills/md-language-check/SKILL.md +61 -39
  173. package/.agent-src/skills/override-management/SKILL.md +7 -7
  174. package/.agent-src/skills/php-coder/SKILL.md +1 -1
  175. package/.agent-src/skills/playwright-testing/SKILL.md +2 -2
  176. package/.agent-src/skills/quality-tools/SKILL.md +2 -2
  177. package/.agent-src/skills/react-shadcn-ui/SKILL.md +116 -43
  178. package/.agent-src/skills/readme-reviewer/SKILL.md +31 -30
  179. package/.agent-src/skills/readme-writing/SKILL.md +79 -54
  180. package/.agent-src/skills/readme-writing-package/SKILL.md +51 -48
  181. package/.agent-src/skills/receiving-code-review/SKILL.md +53 -48
  182. package/.agent-src/skills/refine-prompt/SKILL.md +0 -1
  183. package/.agent-src/skills/requesting-code-review/SKILL.md +35 -30
  184. package/.agent-src/skills/review-routing/SKILL.md +2 -2
  185. package/.agent-src/skills/rule-writing/SKILL.md +1 -1
  186. package/.agent-src/skills/security/SKILL.md +7 -2
  187. package/.agent-src/skills/security-audit/SKILL.md +7 -3
  188. package/.agent-src/skills/skill-reviewer/SKILL.md +1 -1
  189. package/.agent-src/skills/skill-writing/SKILL.md +3 -3
  190. package/.agent-src/skills/subagent-orchestration/SKILL.md +1 -0
  191. package/.agent-src/skills/systematic-debugging/SKILL.md +69 -61
  192. package/.agent-src/skills/test-driven-development/SKILL.md +59 -57
  193. package/.agent-src/skills/test-performance/SKILL.md +0 -1
  194. package/.agent-src/skills/traefik/SKILL.md +4 -4
  195. package/.agent-src/skills/upstream-contribute/SKILL.md +1 -1
  196. package/.agent-src/skills/validate-feature-fit/SKILL.md +2 -2
  197. package/.agent-src/skills/{verify-before-complete → verify-completion-evidence}/SKILL.md +30 -28
  198. package/.agent-src/templates/agent-settings.md +8 -8
  199. package/.agent-src/templates/contexts/auth-model.md +1 -1
  200. package/.agent-src/templates/scripts/README.md +2 -2
  201. package/.agent-src/templates/scripts/telemetry/aggregator.py +16 -1
  202. package/.agent-src/templates/scripts/telemetry/engagement.py +59 -0
  203. package/.agent-src/templates/scripts/telemetry/report_renderer.py +28 -1
  204. package/.agent-src/templates/scripts/telemetry_record.py +14 -1
  205. package/.claude-plugin/marketplace.json +31 -12
  206. package/AGENTS.md +11 -9
  207. package/CHANGELOG.md +213 -2
  208. package/README.md +43 -44
  209. package/config/agent-settings.template.yml +58 -1
  210. package/config/gitignore-block.txt +3 -0
  211. package/docs/architecture.md +5 -7
  212. package/docs/catalog.md +359 -0
  213. package/docs/contracts/STABILITY.md +46 -1
  214. package/docs/contracts/adr-chat-history-split.md +1 -3
  215. package/docs/contracts/adr-command-suggestion.md +3 -5
  216. package/docs/contracts/adr-implement-ticket-runtime.md +1 -2
  217. package/docs/contracts/adr-product-ui-track.md +5 -8
  218. package/docs/contracts/adr-prompt-driven-execution.md +3 -4
  219. package/docs/contracts/agent-memory-contract.md +8 -13
  220. package/docs/contracts/artifact-engagement-flow.md +7 -10
  221. package/docs/contracts/command-clusters.md +56 -46
  222. package/docs/contracts/command-suggestion-flow.md +4 -6
  223. package/docs/contracts/context-paths.md +99 -0
  224. package/docs/contracts/file-ownership-matrix.json +6722 -0
  225. package/docs/contracts/file-ownership-matrix.md +134 -0
  226. package/docs/contracts/implement-ticket-flow.md +8 -11
  227. package/docs/contracts/linear-ai-rules-inclusion.md +1 -2
  228. package/docs/contracts/linear-ai-three-layers.md +0 -2
  229. package/docs/contracts/load-context-budget-model.md +178 -0
  230. package/docs/contracts/load-context-schema.md +184 -0
  231. package/docs/contracts/rule-interactions.md +0 -1
  232. package/docs/contracts/rule-interactions.yml +96 -0
  233. package/docs/contracts/rule-priority-hierarchy.md +87 -0
  234. package/docs/contracts/ui-track-flow.md +8 -18
  235. package/docs/customization.md +16 -0
  236. package/docs/end-to-end-walkthroughs.md +165 -0
  237. package/docs/getting-started.md +29 -10
  238. package/docs/github-topics.md +12 -3
  239. package/docs/guidelines/agent-infra/asking-and-brevity-examples.md +100 -0
  240. package/docs/guidelines/agent-infra/language-and-tone-examples.md +79 -0
  241. package/{.agent-src → docs}/guidelines/docs/readme-size-and-splitting.md +26 -25
  242. package/docs/guidelines/php/git.md +164 -0
  243. package/docs/migrations/commands-1.15.0.md +1 -1
  244. package/docs/showcase.md +9 -4
  245. package/docs/skills-catalog.md +14 -8
  246. package/docs/ui-track-mental-model.md +2 -2
  247. package/llms.txt +13 -7
  248. package/package.json +1 -1
  249. package/scripts/_one_off_phase4_dispatch_latency.py +108 -0
  250. package/scripts/_one_off_phase6_trigger_jaccard.py +92 -0
  251. package/scripts/_phase2_shim_helper.py +109 -0
  252. package/scripts/agent-config +33 -0
  253. package/scripts/ai_council/__init__.py +39 -0
  254. package/scripts/ai_council/_default_prices.py +41 -0
  255. package/scripts/ai_council/_one_off_2a4_acceptance.py +208 -0
  256. package/scripts/ai_council/_one_off_context_layer_v1_estimate.py +67 -0
  257. package/scripts/ai_council/_one_off_context_layer_v1_review.py +292 -0
  258. package/scripts/ai_council/_one_off_followups_review.py +259 -0
  259. package/scripts/ai_council/_one_off_nondestructive_inline_audit.py +209 -0
  260. package/scripts/ai_council/_one_off_phase_2a_budget_rebalance.py +257 -0
  261. package/scripts/ai_council/_one_off_phase_2a_post_revert.py +197 -0
  262. package/scripts/ai_council/_one_off_rebalancing_audit.py +149 -0
  263. package/scripts/ai_council/_one_off_roundtrip.py +106 -0
  264. package/scripts/ai_council/_one_off_rule_hardening_v1.py +251 -0
  265. package/scripts/ai_council/_one_off_structural_open_questions.py +232 -0
  266. package/scripts/ai_council/_one_off_structural_optimization.py +144 -0
  267. package/scripts/ai_council/_one_off_structural_v3_gaps.py +252 -0
  268. package/scripts/ai_council/_one_off_structural_v3_review.py +240 -0
  269. package/scripts/ai_council/budget_guard.py +172 -0
  270. package/scripts/ai_council/bundler.py +261 -0
  271. package/scripts/ai_council/clients.py +381 -0
  272. package/scripts/ai_council/modes.py +127 -0
  273. package/scripts/ai_council/orchestrator.py +350 -0
  274. package/scripts/ai_council/pricing.py +213 -0
  275. package/scripts/ai_council/project_context.py +159 -0
  276. package/scripts/ai_council/prompts.py +232 -0
  277. package/scripts/ai_council/session.py +144 -0
  278. package/scripts/check_always_budget.py +444 -0
  279. package/scripts/check_augmentignore.py +69 -0
  280. package/scripts/check_cluster_patterns.py +159 -0
  281. package/scripts/check_command_count_messaging.py +127 -0
  282. package/scripts/check_context_paths.py +201 -0
  283. package/scripts/check_no_roadmap_refs.py +155 -0
  284. package/scripts/check_phase_coupling.py +148 -0
  285. package/scripts/check_portability.py +57 -0
  286. package/scripts/check_public_catalog_links.py +122 -0
  287. package/scripts/check_references.py +33 -3
  288. package/scripts/check_roadmap_trackable.py +111 -0
  289. package/scripts/check_safety_floor_untouched.py +125 -0
  290. package/scripts/command_suggester/cooldown.py +1 -1
  291. package/scripts/command_suggester/loader.py +4 -1
  292. package/scripts/compress.py +59 -13
  293. package/scripts/generate_index.py +270 -0
  294. package/scripts/generate_ownership_matrix.py +323 -0
  295. package/scripts/hooks/augment-roadmap-progress.sh +57 -0
  296. package/scripts/install.py +49 -28
  297. package/scripts/install_anthropic_key.sh +5 -0
  298. package/scripts/install_openai_key.sh +106 -0
  299. package/scripts/lint_load_context.py +163 -0
  300. package/scripts/lint_no_new_atomic_commands.py +12 -11
  301. package/scripts/requirements-evals.txt +1 -0
  302. package/scripts/roadmap_progress_hook.py +159 -0
  303. package/scripts/schemas/command.schema.json +22 -1
  304. package/scripts/schemas/rule.schema.json +10 -0
  305. package/scripts/skill_linter.py +13 -4
  306. package/scripts/sync_agent_settings.py +26 -3
  307. package/scripts/update_counts.py +16 -4
  308. package/scripts/update_prices.py +124 -0
  309. package/.agent-src/guidelines/php/git.md +0 -96
  310. package/.agent-src/rules/command-suggestion.md +0 -134
  311. /package/{.agent-src → docs}/guidelines/agent-infra/agent-interaction-and-decision-quality.md +0 -0
  312. /package/{.agent-src → docs}/guidelines/agent-infra/break-glass-usage.md +0 -0
  313. /package/{.agent-src → docs}/guidelines/agent-infra/developer-judgment.md +0 -0
  314. /package/{.agent-src → docs}/guidelines/agent-infra/engineering-memory-data-format.md +0 -0
  315. /package/{.agent-src → docs}/guidelines/agent-infra/layered-settings.md +0 -0
  316. /package/{.agent-src → docs}/guidelines/agent-infra/memory-access.md +0 -0
  317. /package/{.agent-src → docs}/guidelines/agent-infra/naming.md +0 -0
  318. /package/{.agent-src → docs}/guidelines/agent-infra/output-patterns.md +0 -0
  319. /package/{.agent-src → docs}/guidelines/agent-infra/review-routing-data-format.md +0 -0
  320. /package/{.agent-src → docs}/guidelines/agent-infra/role-contracts.md +0 -0
  321. /package/{.agent-src → docs}/guidelines/agent-infra/role-mode-router.md +0 -0
  322. /package/{.agent-src → docs}/guidelines/agent-infra/runtime-layer.md +0 -0
  323. /package/{.agent-src → docs}/guidelines/agent-infra/self-improvement-pipeline.md +0 -0
  324. /package/{.agent-src → docs}/guidelines/agent-infra/size-and-scope.md +0 -0
  325. /package/{.agent-src → docs}/guidelines/agent-infra/tool-integration.md +0 -0
  326. /package/{.agent-src → docs}/guidelines/e2e/playwright.md +0 -0
  327. /package/{.agent-src → docs}/guidelines/php/api-design.md +0 -0
  328. /package/{.agent-src → docs}/guidelines/php/artisan-commands.md +0 -0
  329. /package/{.agent-src → docs}/guidelines/php/blade-ui.md +0 -0
  330. /package/{.agent-src → docs}/guidelines/php/controllers.md +0 -0
  331. /package/{.agent-src → docs}/guidelines/php/database.md +0 -0
  332. /package/{.agent-src → docs}/guidelines/php/eloquent.md +0 -0
  333. /package/{.agent-src → docs}/guidelines/php/flux.md +0 -0
  334. /package/{.agent-src → docs}/guidelines/php/general.md +0 -0
  335. /package/{.agent-src → docs}/guidelines/php/jobs.md +0 -0
  336. /package/{.agent-src → docs}/guidelines/php/livewire.md +0 -0
  337. /package/{.agent-src → docs}/guidelines/php/logging.md +0 -0
  338. /package/{.agent-src → docs}/guidelines/php/naming.md +0 -0
  339. /package/{.agent-src → docs}/guidelines/php/patterns/dependency-injection.md +0 -0
  340. /package/{.agent-src → docs}/guidelines/php/patterns/dtos.md +0 -0
  341. /package/{.agent-src → docs}/guidelines/php/patterns/events.md +0 -0
  342. /package/{.agent-src → docs}/guidelines/php/patterns/factory.md +0 -0
  343. /package/{.agent-src → docs}/guidelines/php/patterns/pipelines.md +0 -0
  344. /package/{.agent-src → docs}/guidelines/php/patterns/policies.md +0 -0
  345. /package/{.agent-src → docs}/guidelines/php/patterns/repositories.md +0 -0
  346. /package/{.agent-src → docs}/guidelines/php/patterns/service-layer.md +0 -0
  347. /package/{.agent-src → docs}/guidelines/php/patterns/strategy.md +0 -0
  348. /package/{.agent-src → docs}/guidelines/php/patterns.md +0 -0
  349. /package/{.agent-src → docs}/guidelines/php/performance.md +0 -0
  350. /package/{.agent-src → docs}/guidelines/php/resources.md +0 -0
  351. /package/{.agent-src → docs}/guidelines/php/security.md +0 -0
  352. /package/{.agent-src → docs}/guidelines/php/sql.md +0 -0
  353. /package/{.agent-src → docs}/guidelines/php/validations.md +0 -0
  354. /package/{.agent-src → docs}/guidelines/php/websocket.md +0 -0
@@ -464,44 +464,65 @@ def ensure_augment_bridge(project_root: Path, force: bool) -> None:
464
464
  # .augment/settings.json is plugin enablement, not hooks.
465
465
  AUGMENT_USER_DIR = Path.home() / ".augment"
466
466
  AUGMENT_USER_HOOKS_DIR = AUGMENT_USER_DIR / "hooks"
467
- AUGMENT_TRAMPOLINE_NAME = "augment-chat-history.sh"
468
- AUGMENT_HOOK_EVENTS = ("SessionStart", "SessionEnd", "Stop", "PostToolUse")
467
+ AUGMENT_CHAT_HISTORY_TRAMPOLINE = "augment-chat-history.sh"
468
+ AUGMENT_ROADMAP_PROGRESS_TRAMPOLINE = "augment-roadmap-progress.sh"
469
+ # (trampoline name, list of events it should fire on). Each trampoline
470
+ # is a self-contained workspace router; mapping them per-event keeps the
471
+ # wiring explicit and lets a future hook bind to a different surface
472
+ # without touching the chat-history one.
473
+ AUGMENT_HOOK_BINDINGS = (
474
+ (AUGMENT_CHAT_HISTORY_TRAMPOLINE,
475
+ ("SessionStart", "SessionEnd", "Stop", "PostToolUse")),
476
+ (AUGMENT_ROADMAP_PROGRESS_TRAMPOLINE,
477
+ ("PostToolUse",)),
478
+ )
479
+
480
+
481
+ def _deploy_augment_trampoline(package_root: Path, name: str, force: bool) -> Path | None:
482
+ src = package_root / "scripts" / "hooks" / name
483
+ if not src.exists():
484
+ skip(f"augment trampoline missing in package: {src}")
485
+ return None
486
+ AUGMENT_USER_HOOKS_DIR.mkdir(parents=True, exist_ok=True)
487
+ dst = AUGMENT_USER_HOOKS_DIR / name
488
+ src_text = src.read_text(encoding="utf-8")
489
+ if dst.exists() and dst.read_text(encoding="utf-8") == src_text and not force:
490
+ skip(f"~/.augment/hooks/{name} already up to date")
491
+ else:
492
+ dst.write_text(src_text, encoding="utf-8")
493
+ dst.chmod(0o755)
494
+ success(f"~/.augment/hooks/{name} installed")
495
+ return dst
469
496
 
470
497
 
471
498
  def ensure_augment_user_hooks(package_root: Path, force: bool) -> None:
472
- """Deploy the Augment lifecycle-hook trampoline at user scope.
499
+ """Deploy the Augment lifecycle-hook trampolines at user scope.
473
500
 
474
501
  Augment hook scripts must use the .sh extension and be referenced by
475
502
  absolute path; user scope is the only surface that fires for both the
476
503
  CLI and the IDE plugins. This installs once per developer (not per
477
- project) — the trampoline reads workspace_roots from the event payload
478
- and dispatches into whichever project is active at hook-fire time.
504
+ project) — each trampoline reads workspace_roots from the event
505
+ payload and dispatches into whichever project is active at hook-fire
506
+ time.
507
+
508
+ Two trampolines are deployed:
509
+ - augment-chat-history.sh → SessionStart/SessionEnd/Stop/PostToolUse
510
+ - augment-roadmap-progress.sh → PostToolUse (path-filtered to
511
+ agents/roadmaps/ — see scripts/roadmap_progress_hook.py)
479
512
  """
480
- src = package_root / "scripts" / "hooks" / AUGMENT_TRAMPOLINE_NAME
481
- if not src.exists():
482
- skip(f"augment trampoline missing in package: {src}")
483
- return
484
-
485
- AUGMENT_USER_HOOKS_DIR.mkdir(parents=True, exist_ok=True)
486
- dst = AUGMENT_USER_HOOKS_DIR / AUGMENT_TRAMPOLINE_NAME
513
+ per_event: dict[str, list] = {}
514
+ for name, events in AUGMENT_HOOK_BINDINGS:
515
+ dst = _deploy_augment_trampoline(package_root, name, force)
516
+ if dst is None:
517
+ continue
518
+ entry = {"hooks": [{"type": "command", "command": str(dst)}]}
519
+ for event in events:
520
+ per_event.setdefault(event, []).append(entry)
487
521
 
488
- src_text = src.read_text(encoding="utf-8")
489
- if dst.exists() and dst.read_text(encoding="utf-8") == src_text and not force:
490
- skip(f"~/.augment/hooks/{AUGMENT_TRAMPOLINE_NAME} already up to date")
491
- else:
492
- dst.write_text(src_text, encoding="utf-8")
493
- dst.chmod(0o755)
494
- success(f"~/.augment/hooks/{AUGMENT_TRAMPOLINE_NAME} installed")
522
+ if not per_event:
523
+ return
495
524
 
496
- hook_entry = {
497
- "hooks": [
498
- {
499
- "type": "command",
500
- "command": str(dst),
501
- },
502
- ],
503
- }
504
- settings_patch: dict = {"hooks": {event: [hook_entry] for event in AUGMENT_HOOK_EVENTS}}
525
+ settings_patch: dict = {"hooks": per_event}
505
526
  merge_json_file(
506
527
  AUGMENT_USER_DIR / "settings.json",
507
528
  settings_patch,
@@ -99,3 +99,8 @@ echo "✅ Key installed: ${TARGET_FILE} (mode 0600)."
99
99
  echo " Verify: ls -la ${TARGET_FILE}"
100
100
  echo " Rotate: rerun this script (you'll be prompted to overwrite)."
101
101
  echo " Remove: rm ${TARGET_FILE}"
102
+ echo
103
+ echo "ℹ️ Key install ≠ enable. To use this provider in /council:"
104
+ echo " set ai_council.enabled: true and ai_council.members.anthropic.enabled: true"
105
+ echo " in .agent-settings.yml. Council is a 'full' cost_profile feature; under"
106
+ echo " 'minimal' / 'balanced' the runtime hooks stay inactive."
@@ -0,0 +1,106 @@
1
+ #!/usr/bin/env bash
2
+ # Interactive OpenAI-API-key installer for scripts/ai_council/clients.py.
3
+ #
4
+ # Reads the key with `read -s` so it never echoes to the terminal and
5
+ # never lands in shell history or scrollback. Writes atomically to
6
+ # ~/.config/agent-config/openai.key with mode 0600.
7
+ #
8
+ # Contract — companion to scripts/ai_council/clients.py:
9
+ # - File path: $HOME/.config/agent-config/openai.key
10
+ # - File mode: 0600 (owner read/write only)
11
+ # - Key format: must start with `sk-`
12
+ # - No --force, no --yes, no env-var bypass. Piped stdin is rejected.
13
+ #
14
+ # The runner re-checks all of the above at every live invocation and
15
+ # refuses to run if the file drifts from this contract.
16
+
17
+ set -euo pipefail
18
+
19
+ TARGET_DIR="${HOME}/.config/agent-config"
20
+ TARGET_FILE="${TARGET_DIR}/openai.key"
21
+
22
+ # ── controlling-terminal requirement ─────────────────────────────────────
23
+ # We read from /dev/tty directly (fd 3), not from stdin. This is the
24
+ # stricter and more portable contract:
25
+ # - works under `task`, `script`, `sudo`, anything that reattaches stdin
26
+ # - forces every character to come from the user's real keyboard, so a
27
+ # pipe or redirected file cannot smuggle the key into the process
28
+ # - exits cleanly if there is no controlling terminal at all (e.g. CI,
29
+ # cron, agent automation)
30
+ if ! exec 3</dev/tty 2>/dev/null; then
31
+ echo "❌ install_openai_key.sh requires a controlling terminal." >&2
32
+ echo " /dev/tty not available — refusing to run under automation." >&2
33
+ exit 2
34
+ fi
35
+
36
+ # ── overwrite confirmation ───────────────────────────────────────────────
37
+ if [[ -e "${TARGET_FILE}" ]]; then
38
+ echo "⚠️ ${TARGET_FILE} already exists."
39
+ printf "Overwrite? [type 'yes' to replace, anything else aborts]: "
40
+ read -r -u 3 answer
41
+ if [[ "${answer}" != "yes" ]]; then
42
+ echo "Aborted. Existing key untouched."
43
+ exit 0
44
+ fi
45
+ fi
46
+
47
+ # ── read key (no echo, no history) ───────────────────────────────────────
48
+ echo "Paste your OpenAI API key (input is hidden, no echo)."
49
+ echo "The key should start with 'sk-'."
50
+ printf "Key: "
51
+ # -s = silent (no echo), read from fd 3 = /dev/tty, not stdin.
52
+ read -r -s -u 3 API_KEY
53
+ echo
54
+
55
+ if [[ -z "${API_KEY}" ]]; then
56
+ echo "❌ Empty input — no file written." >&2
57
+ exit 2
58
+ fi
59
+
60
+ if [[ "${API_KEY}" != sk-* ]]; then
61
+ echo "❌ Input does not look like an OpenAI key (missing 'sk-' prefix)." >&2
62
+ echo " No file written." >&2
63
+ exit 2
64
+ fi
65
+
66
+ # ── create config dir with 0700, atomic write with 0600 ──────────────────
67
+ mkdir -p "${TARGET_DIR}"
68
+ chmod 0700 "${TARGET_DIR}"
69
+
70
+ TMP_FILE="$(mktemp "${TARGET_DIR}/.openai.key.XXXXXX")"
71
+ cleanup() { rm -f "${TMP_FILE}"; }
72
+ trap cleanup EXIT
73
+
74
+ # chmod the tmpfile BEFORE writing the key, so there is no window where
75
+ # the key sits on disk with group/other-readable permissions.
76
+ chmod 0600 "${TMP_FILE}"
77
+ printf '%s\n' "${API_KEY}" > "${TMP_FILE}"
78
+ mv "${TMP_FILE}" "${TARGET_FILE}"
79
+ trap - EXIT
80
+
81
+ # Clear the variable and the `mv` positional argument — defence in depth
82
+ # against a crash handler that dumps the process environment.
83
+ API_KEY=""
84
+
85
+ # ── verify mode post-write (portable stat: BSD on macOS, GNU on Linux) ───
86
+ if ACTUAL_MODE=$(stat -f '%Lp' "${TARGET_FILE}" 2>/dev/null); then
87
+ : # macOS / BSD
88
+ else
89
+ ACTUAL_MODE=$(stat -c '%a' "${TARGET_FILE}")
90
+ fi
91
+
92
+ if [[ "${ACTUAL_MODE}" != "600" ]]; then
93
+ echo "❌ Permissions verification failed: ${TARGET_FILE} has mode ${ACTUAL_MODE}, expected 600." >&2
94
+ echo " Delete and reinstall: rm ${TARGET_FILE} && $0" >&2
95
+ exit 3
96
+ fi
97
+
98
+ echo "✅ Key installed: ${TARGET_FILE} (mode 0600)."
99
+ echo " Verify: ls -la ${TARGET_FILE}"
100
+ echo " Rotate: rerun this script (you'll be prompted to overwrite)."
101
+ echo " Remove: rm ${TARGET_FILE}"
102
+ echo
103
+ echo "ℹ️ Key install ≠ enable. To use this provider in /council:"
104
+ echo " set ai_council.enabled: true and ai_council.members.openai.enabled: true"
105
+ echo " in .agent-settings.yml. Council is a 'full' cost_profile feature; under"
106
+ echo " 'minimal' / 'balanced' the runtime hooks stay inactive."
@@ -0,0 +1,163 @@
1
+ #!/usr/bin/env python3
2
+ """Lint the `load_context:` / `load_context_eager:` frontmatter schema.
3
+
4
+ Validates per docs/contracts/load-context-schema.md:
5
+ - Paths exist and are .md
6
+ - Allowed roots only (.agent-src*/contexts/, agents/contexts/)
7
+ - No public→project-local leak (warn)
8
+ - No circular refs across lazy + eager edges
9
+ - Combined char-budget for eager edges (rule + eager targets ≤ cap)
10
+
11
+ Exits non-zero on error; warnings are reported but do not fail.
12
+ Used in CI via `task lint-load-context`.
13
+ """
14
+ from __future__ import annotations
15
+
16
+ import sys
17
+ from pathlib import Path
18
+ from typing import Iterable
19
+
20
+ import yaml
21
+
22
+ ROOT = Path(__file__).resolve().parent.parent
23
+
24
+ SCAN_DIRS = [
25
+ ROOT / ".agent-src.uncompressed" / "rules",
26
+ ROOT / ".agent-src.uncompressed" / "contexts",
27
+ ROOT / "agents" / "contexts",
28
+ ]
29
+
30
+ ALLOWED_PREFIXES = (
31
+ ".agent-src.uncompressed/contexts/",
32
+ ".agent-src/contexts/",
33
+ "agents/contexts/",
34
+ )
35
+
36
+ PUBLIC_RULE_PREFIX = ".agent-src.uncompressed/rules/"
37
+ PROJECT_LOCAL_PREFIX = "agents/contexts/"
38
+
39
+ HARD_FLOOR_RULES = {"non-destructive-by-default", "security-sensitive-stop"}
40
+
41
+ CAP_ALWAYS = 2_500
42
+ CAP_AUTO = 4_000
43
+ CAP_SAFETY = 5_000
44
+
45
+
46
+ def parse_frontmatter(path: Path) -> dict:
47
+ text = path.read_text(encoding="utf-8")
48
+ if not text.startswith("---\n"):
49
+ return {}
50
+ end = text.find("\n---\n", 4)
51
+ if end == -1:
52
+ return {}
53
+ try:
54
+ data = yaml.safe_load(text[4:end])
55
+ except yaml.YAMLError:
56
+ return {}
57
+ return data if isinstance(data, dict) else {}
58
+
59
+
60
+ def collect_files() -> Iterable[Path]:
61
+ for d in SCAN_DIRS:
62
+ if d.exists():
63
+ yield from d.rglob("*.md")
64
+
65
+
66
+ def rel(p: Path) -> str:
67
+ return p.relative_to(ROOT).as_posix()
68
+
69
+
70
+ def cap_for(rule_path: Path, fm: dict) -> int:
71
+ if rule_path.stem in HARD_FLOOR_RULES:
72
+ return CAP_SAFETY
73
+ rtype = (fm.get("type") or "").strip('"').strip("'")
74
+ if rtype == "always":
75
+ return CAP_ALWAYS
76
+ if rtype == "auto":
77
+ return CAP_AUTO
78
+ return CAP_AUTO # default for non-rule contexts cited in eager (won't trigger)
79
+
80
+
81
+ def find_cycles(graph: dict[str, list[str]]) -> list[list[str]]:
82
+ cycles: list[list[str]] = []
83
+ visiting: set[str] = set()
84
+ visited: set[str] = set()
85
+ stack: list[str] = []
86
+
87
+ def dfs(node: str) -> None:
88
+ if node in visiting:
89
+ i = stack.index(node)
90
+ cycles.append(stack[i:] + [node])
91
+ return
92
+ if node in visited:
93
+ return
94
+ visiting.add(node)
95
+ stack.append(node)
96
+ for nxt in graph.get(node, []):
97
+ dfs(nxt)
98
+ stack.pop()
99
+ visiting.discard(node)
100
+ visited.add(node)
101
+
102
+ for n in graph:
103
+ dfs(n)
104
+ return cycles
105
+
106
+
107
+ def main() -> int:
108
+ errors: list[str] = []
109
+ warnings: list[str] = []
110
+ graph: dict[str, list[str]] = {}
111
+
112
+ for f in collect_files():
113
+ fm = parse_frontmatter(f)
114
+ lazy = fm.get("load_context") or []
115
+ eager = fm.get("load_context_eager") or []
116
+ if not (lazy or eager):
117
+ continue
118
+ if not isinstance(lazy, list) or not isinstance(eager, list):
119
+ errors.append(f"{rel(f)}: load_context* must be a list")
120
+ continue
121
+
122
+ edges = list(lazy) + list(eager)
123
+ graph[rel(f)] = edges
124
+
125
+ for entry in edges:
126
+ if not isinstance(entry, str) or not entry.endswith(".md"):
127
+ errors.append(f"{rel(f)}: entry not str ending in .md → {entry!r}")
128
+ continue
129
+ if not entry.startswith(ALLOWED_PREFIXES):
130
+ errors.append(f"{rel(f)}: disallowed root → {entry}")
131
+ continue
132
+ target = ROOT / entry
133
+ if not target.exists():
134
+ errors.append(f"{rel(f)}: target missing → {entry}")
135
+ continue
136
+ if rel(f).startswith(PUBLIC_RULE_PREFIX) and entry.startswith(PROJECT_LOCAL_PREFIX):
137
+ warnings.append(f"{rel(f)}: public rule references project-local context → {entry}")
138
+
139
+ if eager:
140
+ cap = cap_for(f, fm)
141
+ total = len(f.read_text(encoding="utf-8"))
142
+ for entry in eager:
143
+ tgt = ROOT / entry
144
+ if tgt.exists():
145
+ total += len(tgt.read_text(encoding="utf-8"))
146
+ if total > cap:
147
+ errors.append(f"{rel(f)}: eager-load combined chars {total} > cap {cap}")
148
+
149
+ for cycle in find_cycles(graph):
150
+ errors.append("circular load_context: " + " → ".join(cycle))
151
+
152
+ for w in warnings:
153
+ print(f"⚠️ {w}")
154
+ for e in errors:
155
+ print(f"❌ {e}")
156
+ if errors:
157
+ return 1
158
+ print(f"✅ load_context schema clean ({len(graph)} declarer(s))")
159
+ return 0
160
+
161
+
162
+ if __name__ == "__main__":
163
+ sys.exit(main())
@@ -43,24 +43,24 @@ class Violation:
43
43
 
44
44
 
45
45
  def load_locked_clusters() -> set[str]:
46
- """Parse the Phase 1 cluster table from the locked contract."""
46
+ """Parse the locked cluster table from the contract."""
47
47
  text = (ROOT / CLUSTER_CONTRACT).read_text(encoding="utf-8")
48
- # Locate the Phase 1 table; cluster names sit in backticks in column 1.
49
- in_phase_1 = False
48
+ # Locate the locked-clusters table; cluster names sit in backticks in column 1.
49
+ in_table = False
50
50
  clusters: set[str] = set()
51
51
  for line in text.splitlines():
52
- if line.startswith("## Phase 1 clusters"):
53
- in_phase_1 = True
52
+ if line.startswith("## Locked clusters"):
53
+ in_table = True
54
54
  continue
55
- if in_phase_1 and line.startswith("## "):
55
+ if in_table and line.startswith("## "):
56
56
  break
57
- if in_phase_1:
57
+ if in_table:
58
58
  m = re.match(r"\|\s*`([a-z][a-z0-9-]*)`\s*\|", line)
59
59
  if m:
60
60
  clusters.add(m.group(1))
61
61
  if not clusters:
62
62
  print(
63
- f"❌ Could not parse Phase 1 cluster table from {CLUSTER_CONTRACT}",
63
+ f"❌ Could not parse locked-clusters table from {CLUSTER_CONTRACT}",
64
64
  file=sys.stderr,
65
65
  )
66
66
  sys.exit(3)
@@ -83,7 +83,7 @@ def added_command_files(baseline: str) -> list[Path]:
83
83
  file=sys.stderr)
84
84
  sys.exit(3)
85
85
  files = [Path(p) for p in result.stdout.splitlines()
86
- if p.endswith(".md") and p != ""]
86
+ if p.endswith(".md") and p != "" and Path(p).name != "AGENTS.md"]
87
87
  # Also include untracked (newly added, uncommitted) files.
88
88
  try:
89
89
  wt = subprocess.run(
@@ -97,7 +97,7 @@ def added_command_files(baseline: str) -> list[Path]:
97
97
  if status.strip() not in ("A", "??", "AM"):
98
98
  continue
99
99
  path = line[3:].strip().split(" -> ")[-1]
100
- if path.endswith(".md"):
100
+ if path.endswith(".md") and Path(path).name != "AGENTS.md":
101
101
  p = Path(path)
102
102
  if p not in files:
103
103
  files.append(p)
@@ -107,7 +107,8 @@ def added_command_files(baseline: str) -> list[Path]:
107
107
 
108
108
 
109
109
  def all_command_files() -> list[Path]:
110
- return sorted((ROOT / COMMANDS_DIR).glob("*.md"))
110
+ return sorted(p for p in (ROOT / COMMANDS_DIR).rglob("*.md")
111
+ if p.name != "AGENTS.md")
111
112
 
112
113
 
113
114
  def parse_frontmatter(path: Path) -> dict[str, str]:
@@ -5,3 +5,4 @@
5
5
  # be upgraded, bump the version here and rerun the setup script.
6
6
 
7
7
  anthropic==0.96.0
8
+ openai==1.109.1
@@ -0,0 +1,159 @@
1
+ #!/usr/bin/env python3
2
+ """Platform-agnostic PostToolUse hook for the `roadmap-progress-sync` rule.
3
+
4
+ Reads a JSON event from stdin (Augment / Claude / Cursor / Cline /
5
+ Windsurf / Gemini PostToolUse-shaped envelopes), decides whether the
6
+ tool call wrote to a roadmap file under `agents/roadmaps/`, and — when
7
+ it did — re-runs `update_roadmap_progress.py` so the dashboard stays
8
+ in sync without depending on agent self-discipline.
9
+
10
+ Exit code is **always 0**. Hooks must never block the agent loop; the
11
+ worst-case is a no-op when stdin is malformed or the regenerator is
12
+ missing.
13
+
14
+ Output discipline:
15
+ - stdout: nothing (Augment would surface stdout to the user)
16
+ - stderr: one short line in --verbose mode, otherwise silent
17
+
18
+ CLI:
19
+ python3 scripts/roadmap_progress_hook.py [--platform NAME] [--verbose]
20
+
21
+ The `--platform` flag is informational only — the filter logic reads
22
+ the same field names across platforms (tool_name, tool_input.path,
23
+ file_changes[].path).
24
+ """
25
+ from __future__ import annotations
26
+
27
+ import argparse
28
+ import json
29
+ import subprocess
30
+ import sys
31
+ from pathlib import Path
32
+
33
+ # Tools whose successful execution can write to a roadmap file. We keep
34
+ # the list explicit so an unknown tool name (e.g. a new MCP tool that
35
+ # happens to mention a roadmap path in its input) does not trigger a
36
+ # spurious regeneration.
37
+ WRITE_TOOLS = frozenset({
38
+ "str-replace-editor",
39
+ "save-file",
40
+ "remove-files",
41
+ # Claude Code / Cursor naming variants — kept for cross-platform
42
+ # parity if this hook is ever wired beyond Augment.
43
+ "Edit",
44
+ "Write",
45
+ "MultiEdit",
46
+ })
47
+
48
+ ROADMAP_PREFIX = "agents/roadmaps/"
49
+ # Paths under these subtrees are tracked but not part of the open list
50
+ # the dashboard summarises — regenerating on every archived edit would
51
+ # be wasteful. The check still fires on the parent dir itself.
52
+ ROADMAP_EXCLUDED_PARTS = frozenset({"archive", "skipped"})
53
+ DASHBOARD_PATH = "agents/roadmaps-progress.md"
54
+
55
+
56
+ def _candidate_paths(payload: dict) -> list[str]:
57
+ """Pull every plausible file path out of a PostToolUse payload."""
58
+ out: list[str] = []
59
+ fc = payload.get("file_changes")
60
+ if isinstance(fc, list):
61
+ for entry in fc:
62
+ if isinstance(entry, dict):
63
+ p = entry.get("path")
64
+ if isinstance(p, str) and p:
65
+ out.append(p)
66
+ ti = payload.get("tool_input")
67
+ if isinstance(ti, dict):
68
+ for key in ("path", "file_path", "target_file"):
69
+ v = ti.get(key)
70
+ if isinstance(v, str) and v:
71
+ out.append(v)
72
+ return out
73
+
74
+
75
+ def _is_roadmap_touch(path: str) -> bool:
76
+ """Return True if `path` is a roadmap file we should react to."""
77
+ norm = path.lstrip("./").replace("\\", "/")
78
+ if not norm.startswith(ROADMAP_PREFIX):
79
+ return False
80
+ if norm == DASHBOARD_PATH:
81
+ # Defensive — the dashboard sits at agents/roadmaps-progress.md,
82
+ # NOT inside agents/roadmaps/. The prefix check above already
83
+ # excludes it, but keep this explicit so a future relocation
84
+ # cannot turn the hook into an infinite loop.
85
+ return False
86
+ rest = norm[len(ROADMAP_PREFIX):]
87
+ parts = rest.split("/")
88
+ if len(parts) >= 2 and parts[0] in ROADMAP_EXCLUDED_PARTS:
89
+ return False
90
+ if not norm.endswith(".md"):
91
+ return False
92
+ return True
93
+
94
+
95
+ def _resolve_regenerator(consumer_root: Path) -> Path | None:
96
+ """Find the regenerator script — package-shipped or installed copy."""
97
+ for candidate in (
98
+ consumer_root / ".augment" / "scripts" / "update_roadmap_progress.py",
99
+ consumer_root / ".agent-src" / "scripts" / "update_roadmap_progress.py",
100
+ consumer_root / ".agent-src.uncompressed" / "scripts" / "update_roadmap_progress.py",
101
+ ):
102
+ if candidate.is_file():
103
+ return candidate
104
+ return None
105
+
106
+
107
+ def run(stdin_text: str, *, consumer_root: Path, verbose: bool = False) -> int:
108
+ payload: dict = {}
109
+ if stdin_text.strip():
110
+ try:
111
+ decoded = json.loads(stdin_text)
112
+ if isinstance(decoded, dict):
113
+ payload = decoded
114
+ except json.JSONDecodeError:
115
+ return 0 # malformed stdin → silent no-op, never block
116
+
117
+ tool = payload.get("tool_name") or payload.get("toolName") or payload.get("tool")
118
+ if not isinstance(tool, str) or tool not in WRITE_TOOLS:
119
+ return 0
120
+
121
+ paths = _candidate_paths(payload)
122
+ if not any(_is_roadmap_touch(p) for p in paths):
123
+ return 0
124
+
125
+ script = _resolve_regenerator(consumer_root)
126
+ if script is None:
127
+ if verbose:
128
+ print("roadmap-progress-hook: regenerator not found, skipping",
129
+ file=sys.stderr)
130
+ return 0
131
+
132
+ try:
133
+ subprocess.run(
134
+ [sys.executable, str(script)],
135
+ cwd=consumer_root, check=False,
136
+ stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL,
137
+ timeout=30,
138
+ )
139
+ except (OSError, subprocess.SubprocessError):
140
+ pass # never propagate regenerator failures into the agent loop
141
+
142
+ if verbose:
143
+ print(f"roadmap-progress-hook: regenerated for tool={tool}",
144
+ file=sys.stderr)
145
+ return 0
146
+
147
+
148
+ def main(argv: list[str] | None = None) -> int:
149
+ parser = argparse.ArgumentParser(description=__doc__)
150
+ parser.add_argument("--platform", default="generic",
151
+ help="informational platform tag (augment/claude/...)")
152
+ parser.add_argument("--verbose", action="store_true",
153
+ help="emit one stderr line per invocation")
154
+ args = parser.parse_args(argv)
155
+ return run(sys.stdin.read(), consumer_root=Path.cwd(), verbose=args.verbose)
156
+
157
+
158
+ if __name__ == "__main__": # pragma: no cover
159
+ sys.exit(main())
@@ -9,7 +9,8 @@
9
9
  "properties": {
10
10
  "name": {
11
11
  "type": "string",
12
- "pattern": "^[a-z][a-z0-9-]*$"
12
+ "pattern": "^[a-z][a-z0-9-]*(:[a-z][a-z0-9-]*)?$",
13
+ "$comment": "Top-level commands use the bare slug (`commit`). Nested cluster commands under `commands/<cluster>/<sub>.md` use the colon form (`council:default`) to mirror Claude Code's `/cluster:sub` rendering. Directory slug for `.claude/skills/` is the hyphenated form (`council-default`), generated by compress.py."
13
14
  },
14
15
  "description": {
15
16
  "type": "string",
@@ -28,6 +29,26 @@
28
29
  "pattern": "^[a-z][a-z0-9-]*$"
29
30
  }
30
31
  },
32
+ "cluster": {
33
+ "type": "string",
34
+ "pattern": "^[a-z][a-z0-9-]*$",
35
+ "description": "Locked verb cluster this command belongs to. See docs/contracts/command-clusters.md."
36
+ },
37
+ "sub": {
38
+ "type": "string",
39
+ "pattern": "^[a-z][a-z0-9-]*$",
40
+ "description": "Sub-command identifier within the cluster (e.g. `ci` for `/fix ci`)."
41
+ },
42
+ "superseded_by": {
43
+ "type": "string",
44
+ "pattern": "^[a-z][a-z0-9-]*( (--[a-z][a-z0-9-]*|[a-z][a-z0-9-]*))?$",
45
+ "description": "Set on deprecation shims. Format: '<cluster> <sub>' (e.g. 'fix ci') or '<cluster> --<flag>' for flag-clusters (e.g. 'commit --in-chunks'). See docs/contracts/command-clusters.md § Deprecation shim contract."
46
+ },
47
+ "deprecated_in": {
48
+ "type": "string",
49
+ "pattern": "^[0-9]+\\.[0-9]+\\.[0-9]+$",
50
+ "description": "Semver release in which this command became a shim (e.g. '1.15.0')."
51
+ },
31
52
  "suggestion": {
32
53
  "type": "object",
33
54
  "additionalProperties": false,
@@ -23,6 +23,16 @@
23
23
  "alwaysApply": {
24
24
  "type": "boolean",
25
25
  "description": "Optional sidecar for Cursor/Cline; by convention true when type=always, false when type=auto."
26
+ },
27
+ "load_context": {
28
+ "type": "array",
29
+ "items": {"type": "string", "pattern": "\\.md$"},
30
+ "description": "Lazy on-demand context references. Path rules and budget caps enforced by scripts/lint_load_context.py. Contract: docs/contracts/load-context-schema.md."
31
+ },
32
+ "load_context_eager": {
33
+ "type": "array",
34
+ "items": {"type": "string", "pattern": "\\.md$"},
35
+ "description": "Eager auto-loaded context references. Counts against the per-rule char budget; enforced by scripts/lint_load_context.py."
26
36
  }
27
37
  }
28
38
  }