@event4u/agent-config 1.19.0 → 1.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 (297) hide show
  1. package/.agent-src/commands/agent-handoff.md +14 -10
  2. package/.agent-src/commands/agents.md +1 -1
  3. package/.agent-src/commands/bug-fix.md +1 -1
  4. package/.agent-src/commands/bug-investigate.md +2 -2
  5. package/.agent-src/commands/chat-history/import.md +166 -0
  6. package/.agent-src/commands/chat-history/learn.md +178 -0
  7. package/.agent-src/commands/chat-history/show.md +17 -18
  8. package/.agent-src/commands/chat-history.md +26 -25
  9. package/.agent-src/commands/compress.md +12 -0
  10. package/.agent-src/commands/context/create.md +2 -2
  11. package/.agent-src/commands/context.md +1 -1
  12. package/.agent-src/commands/copilot-agents.md +1 -1
  13. package/.agent-src/commands/council/default.md +21 -12
  14. package/.agent-src/commands/council.md +1 -1
  15. package/.agent-src/commands/create-pr.md +28 -8
  16. package/.agent-src/commands/e2e-heal.md +1 -1
  17. package/.agent-src/commands/e2e-plan.md +1 -1
  18. package/.agent-src/commands/feature/dev.md +3 -3
  19. package/.agent-src/commands/feature.md +1 -1
  20. package/.agent-src/commands/fix/seeder.md +2 -2
  21. package/.agent-src/commands/fix.md +1 -1
  22. package/.agent-src/commands/jira-ticket.md +1 -1
  23. package/.agent-src/commands/judge.md +2 -2
  24. package/.agent-src/commands/memory.md +1 -1
  25. package/.agent-src/commands/mode.md +5 -5
  26. package/.agent-src/commands/module.md +1 -1
  27. package/.agent-src/commands/onboard.md +4 -4
  28. package/.agent-src/commands/optimize/augmentignore.md +1 -1
  29. package/.agent-src/commands/optimize-prompt.md +61 -0
  30. package/.agent-src/commands/optimize.md +1 -1
  31. package/.agent-src/commands/override.md +1 -1
  32. package/.agent-src/commands/review-changes.md +1 -1
  33. package/.agent-src/commands/review-routing.md +1 -1
  34. package/.agent-src/commands/roadmap.md +1 -1
  35. package/.agent-src/commands/set-cost-profile.md +3 -3
  36. package/.agent-src/commands/sync-agent-settings.md +2 -2
  37. package/.agent-src/commands/sync-gitignore.md +1 -1
  38. package/.agent-src/commands/tests/create.md +2 -2
  39. package/.agent-src/commands/tests.md +1 -1
  40. package/.agent-src/commands/threat-model.md +4 -4
  41. package/.agent-src/contexts/authority/commit-mechanics.md +14 -1
  42. package/.agent-src/contexts/authority/destructive-mechanics.md +14 -1
  43. package/.agent-src/contexts/authority/scope-mechanics.md +5 -0
  44. package/.agent-src/contexts/communication/rules-auto/guidelines-mechanics.md +76 -0
  45. package/.agent-src/contexts/communication/rules-auto/skill-quality-mechanics.md +76 -0
  46. package/.agent-src/contexts/communication/rules-auto/slash-command-routing-policy-mechanics.md +4 -4
  47. package/.agent-src/contexts/communication/rules-auto/think-before-action-mechanics.md +98 -0
  48. package/.agent-src/contexts/communication/rules-auto/token-efficiency-mechanics.md +93 -0
  49. package/.agent-src/contexts/communication/rules-auto/user-interaction-mechanics.md +125 -9
  50. package/.agent-src/contexts/execution/autonomy-mechanics.md +44 -0
  51. package/.agent-src/contexts/model-recommendations.md +2 -2
  52. package/.agent-src/contexts/override-system.md +1 -1
  53. package/.agent-src/personas/product-owner.md +2 -2
  54. package/.agent-src/personas/qa.md +1 -1
  55. package/.agent-src/rules/agent-authority.md +5 -6
  56. package/.agent-src/rules/agent-docs.md +11 -53
  57. package/.agent-src/rules/analysis-skill-routing.md +10 -40
  58. package/.agent-src/rules/architecture.md +6 -1
  59. package/.agent-src/rules/artifact-drafting-protocol.md +5 -0
  60. package/.agent-src/rules/artifact-engagement-recording.md +23 -59
  61. package/.agent-src/rules/ask-when-uncertain.md +24 -47
  62. package/.agent-src/rules/augment-portability.md +14 -62
  63. package/.agent-src/rules/augment-source-of-truth.md +10 -1
  64. package/.agent-src/rules/autonomous-execution.md +17 -98
  65. package/.agent-src/rules/capture-learnings.md +9 -80
  66. package/.agent-src/rules/cli-output-handling.md +12 -42
  67. package/.agent-src/rules/command-suggestion-policy.md +25 -73
  68. package/.agent-src/rules/commit-conventions.md +9 -58
  69. package/.agent-src/rules/commit-policy.md +16 -47
  70. package/.agent-src/rules/context-hygiene.md +5 -0
  71. package/.agent-src/rules/direct-answers.md +21 -42
  72. package/.agent-src/rules/docker-commands.md +11 -45
  73. package/.agent-src/rules/docs-sync.md +10 -56
  74. package/.agent-src/rules/downstream-changes.md +5 -0
  75. package/.agent-src/rules/e2e-testing.md +9 -44
  76. package/.agent-src/rules/guidelines.md +13 -75
  77. package/.agent-src/rules/improve-before-implement.md +10 -2
  78. package/.agent-src/rules/language-and-tone.md +35 -69
  79. package/.agent-src/rules/laravel-translations.md +11 -40
  80. package/.agent-src/rules/markdown-safe-codeblocks.md +4 -0
  81. package/.agent-src/rules/minimal-safe-diff.md +4 -0
  82. package/.agent-src/rules/missing-tool-handling.md +4 -0
  83. package/.agent-src/rules/model-recommendation.md +9 -61
  84. package/.agent-src/rules/no-attribution-footers.md +53 -0
  85. package/.agent-src/rules/no-cheap-questions.md +11 -27
  86. package/.agent-src/rules/no-council-references.md +76 -0
  87. package/.agent-src/rules/no-roadmap-references.md +8 -1
  88. package/.agent-src/rules/non-destructive-by-default.md +13 -43
  89. package/.agent-src/rules/onboarding-gate.md +9 -117
  90. package/.agent-src/rules/package-ci-checks.md +10 -37
  91. package/.agent-src/rules/php-coding.md +10 -55
  92. package/.agent-src/rules/preservation-guard.md +9 -0
  93. package/.agent-src/rules/review-routing-awareness.md +9 -97
  94. package/.agent-src/rules/reviewer-awareness.md +8 -83
  95. package/.agent-src/rules/roadmap-progress-sync.md +7 -170
  96. package/.agent-src/rules/role-mode-adherence.md +6 -2
  97. package/.agent-src/rules/rule-type-governance.md +8 -66
  98. package/.agent-src/rules/runtime-safety.md +5 -0
  99. package/.agent-src/rules/scope-control.md +17 -62
  100. package/.agent-src/rules/security-sensitive-stop.md +7 -1
  101. package/.agent-src/rules/size-enforcement.md +6 -1
  102. package/.agent-src/rules/skill-improvement-trigger.md +9 -49
  103. package/.agent-src/rules/skill-quality.md +7 -64
  104. package/.agent-src/rules/slash-command-routing-policy.md +11 -63
  105. package/.agent-src/rules/think-before-action.md +22 -87
  106. package/.agent-src/rules/token-efficiency.md +10 -74
  107. package/.agent-src/rules/token-optimizer-maintenance.md +68 -0
  108. package/.agent-src/rules/tool-safety.md +4 -0
  109. package/.agent-src/rules/ui-audit-gate.md +25 -61
  110. package/.agent-src/rules/upstream-proposal.md +9 -67
  111. package/.agent-src/rules/user-interaction.md +25 -95
  112. package/.agent-src/rules/verify-before-complete.md +1 -1
  113. package/.agent-src/skills/agent-docs-writing/SKILL.md +1 -1
  114. package/.agent-src/skills/ai-council/SKILL.md +69 -5
  115. package/.agent-src/skills/analysis-autonomous-mode/SKILL.md +1 -1
  116. package/.agent-src/skills/analysis-skill-router/SKILL.md +3 -3
  117. package/.agent-src/skills/artisan-commands/SKILL.md +2 -2
  118. package/.agent-src/skills/authz-review/SKILL.md +1 -1
  119. package/.agent-src/skills/aws-infrastructure/SKILL.md +5 -5
  120. package/.agent-src/skills/blast-radius-analyzer/SKILL.md +8 -8
  121. package/.agent-src/skills/bug-analyzer/SKILL.md +5 -5
  122. package/.agent-src/skills/code-refactoring/SKILL.md +4 -4
  123. package/.agent-src/skills/code-review/SKILL.md +2 -2
  124. package/.agent-src/skills/command-writing/SKILL.md +11 -0
  125. package/.agent-src/skills/composer-packages/SKILL.md +2 -2
  126. package/.agent-src/skills/context-authoring/SKILL.md +11 -0
  127. package/.agent-src/skills/context-document/SKILL.md +1 -1
  128. package/.agent-src/skills/copilot-agents-optimization/SKILL.md +23 -0
  129. package/.agent-src/skills/copilot-config/SKILL.md +1 -1
  130. package/.agent-src/skills/dcf-modeling/SKILL.md +89 -0
  131. package/.agent-src/skills/dependency-upgrade/SKILL.md +2 -2
  132. package/.agent-src/skills/devcontainer/SKILL.md +2 -2
  133. package/.agent-src/skills/developer-like-execution/SKILL.md +1 -1
  134. package/.agent-src/skills/docker/SKILL.md +1 -1
  135. package/.agent-src/skills/dto-creator/SKILL.md +1 -1
  136. package/.agent-src/skills/estimate-ticket/SKILL.md +2 -2
  137. package/.agent-src/skills/fe-design/SKILL.md +4 -4
  138. package/.agent-src/skills/feature-planning/SKILL.md +5 -5
  139. package/.agent-src/skills/funnel-analysis/SKILL.md +100 -0
  140. package/.agent-src/skills/laravel/SKILL.md +1 -1
  141. package/.agent-src/skills/laravel-notifications/SKILL.md +5 -5
  142. package/.agent-src/skills/laravel-pennant/SKILL.md +1 -1
  143. package/.agent-src/skills/laravel-pulse/SKILL.md +4 -4
  144. package/.agent-src/skills/laravel-reverb/SKILL.md +2 -2
  145. package/.agent-src/skills/laravel-scheduling/SKILL.md +1 -1
  146. package/.agent-src/skills/md-language-check/SKILL.md +1 -1
  147. package/.agent-src/skills/migration-creator/SKILL.md +7 -7
  148. package/.agent-src/skills/multi-tenancy/SKILL.md +8 -8
  149. package/.agent-src/skills/okr-tree-modeling/SKILL.md +93 -0
  150. package/.agent-src/skills/performance-analysis/SKILL.md +3 -3
  151. package/.agent-src/skills/pest-testing/SKILL.md +6 -6
  152. package/.agent-src/skills/php-service/SKILL.md +2 -2
  153. package/.agent-src/skills/project-analysis-hypothesis-driven/SKILL.md +3 -3
  154. package/.agent-src/skills/project-analysis-react/SKILL.md +1 -1
  155. package/.agent-src/skills/project-analysis-symfony/SKILL.md +1 -1
  156. package/.agent-src/skills/project-analysis-zend-laminas/SKILL.md +2 -2
  157. package/.agent-src/skills/project-analyzer/SKILL.md +4 -4
  158. package/.agent-src/skills/prompt-optimizer/SKILL.md +108 -0
  159. package/.agent-src/skills/readme-reviewer/SKILL.md +1 -1
  160. package/.agent-src/skills/rice-prioritization/SKILL.md +100 -0
  161. package/.agent-src/skills/rule-writing/SKILL.md +33 -0
  162. package/.agent-src/skills/sentry-integration/SKILL.md +1 -1
  163. package/.agent-src/skills/skill-writing/SKILL.md +14 -0
  164. package/.agent-src/skills/subagent-orchestration/SKILL.md +34 -2
  165. package/.agent-src/skills/terraform/SKILL.md +2 -2
  166. package/.agent-src/skills/terragrunt/SKILL.md +8 -8
  167. package/.agent-src/skills/test-performance/SKILL.md +5 -5
  168. package/.agent-src/skills/threat-modeling/SKILL.md +2 -2
  169. package/.agent-src/skills/token-optimizer/SKILL.md +110 -0
  170. package/.agent-src/skills/unit-economics-modeling/SKILL.md +104 -0
  171. package/.agent-src/skills/universal-project-analysis/SKILL.md +1 -1
  172. package/.agent-src/skills/using-git-worktrees/SKILL.md +1 -0
  173. package/.agent-src/templates/AGENTS.md +1 -1
  174. package/.agent-src/templates/agent-settings.md +25 -41
  175. package/.agent-src/templates/contexts/tenant-boundaries.md +2 -2
  176. package/.agent-src/templates/contexts.md +1 -1
  177. package/.agent-src/templates/copilot-instructions.md +21 -0
  178. package/.agent-src/templates/copilot-review-instructions.md +76 -0
  179. package/.agent-src/templates/features.md +1 -1
  180. package/.agent-src/templates/rule.md +127 -0
  181. package/.agent-src/templates/scripts/work_engine/hook_bootstrap.py +7 -5
  182. package/.agent-src/templates/scripts/work_engine/hooks/__init__.py +0 -4
  183. package/.agent-src/templates/scripts/work_engine/hooks/builtin/__init__.py +0 -4
  184. package/.agent-src/templates/scripts/work_engine/hooks/builtin/_chat_history_base.py +7 -51
  185. package/.agent-src/templates/scripts/work_engine/hooks/builtin/chat_history_append.py +1 -2
  186. package/.agent-src/templates/scripts/work_engine/hooks/builtin/chat_history_halt_append.py +1 -2
  187. package/.agent-src/templates/scripts/work_engine/hooks/builtin/memory_visibility.py +2 -3
  188. package/.agent-src/templates/skill.md +30 -1
  189. package/.claude-plugin/marketplace.json +11 -4
  190. package/AGENTS.md +71 -3
  191. package/CHANGELOG.md +180 -3
  192. package/README.md +24 -23
  193. package/config/agent-settings.template.yml +63 -23
  194. package/config/gitignore-block.txt +11 -4
  195. package/docs/architecture.md +84 -3
  196. package/docs/catalog.md +23 -11
  197. package/docs/contracts/adr-chat-history-split.md +10 -1
  198. package/docs/contracts/agent-memory-contract.md +1 -1
  199. package/docs/contracts/command-clusters.md +1 -1
  200. package/docs/contracts/context-paths.md +2 -1
  201. package/docs/contracts/cross-wing-handoff.md +133 -0
  202. package/docs/contracts/file-ownership-matrix.json +678 -609
  203. package/docs/contracts/hook-architecture-v1.md +8 -1
  204. package/docs/contracts/iron-law-overrides.txt +25 -0
  205. package/docs/contracts/kernel-membership.md +273 -0
  206. package/docs/contracts/load-context-schema.md +26 -11
  207. package/docs/contracts/memory-visibility-v1.md +8 -24
  208. package/docs/contracts/pilot/agent-authority.md +24 -0
  209. package/docs/contracts/pilot/direct-answers.md +70 -0
  210. package/docs/contracts/pilot/language-and-tone.md +63 -0
  211. package/docs/contracts/rule-classification.md +170 -0
  212. package/docs/contracts/rule-router.md +153 -0
  213. package/docs/customization.md +18 -7
  214. package/docs/decisions/ADR-001-kernel-swap-deferred.md +109 -0
  215. package/docs/decisions/ADR-002-kernel-bucket-overrides.md +124 -0
  216. package/docs/decisions/ADR-rule-kernel-and-router.md +122 -0
  217. package/docs/getting-started.md +19 -27
  218. package/docs/guidelines/agent-infra/ask-when-uncertain-demos.md +1 -1
  219. package/docs/guidelines/agent-infra/roadmap-progress-mechanics.md +176 -0
  220. package/docs/guidelines/agent-infra/rule-type-governance.md +73 -0
  221. package/docs/guidelines/agent-infra/size-and-scope.md +13 -2
  222. package/docs/guidelines/agent-infra/skill-quality-checklist.md +119 -0
  223. package/docs/guidelines/augment-portability-patterns.md +68 -0
  224. package/docs/guidelines/php/php-coding-patterns.md +62 -0
  225. package/docs/hook-payload-capture.md +221 -0
  226. package/docs/migrations/commands-1.15.0.md +17 -12
  227. package/docs/skills-catalog.md +5 -4
  228. package/llms.txt +4 -3
  229. package/package.json +1 -1
  230. package/scripts/_p43_bodies.py +235 -0
  231. package/scripts/_p43_compress.py +118 -0
  232. package/scripts/_p4_migrate.py +199 -0
  233. package/scripts/_pilot_council_question.py +57 -0
  234. package/scripts/_pilot_measure.py +53 -0
  235. package/scripts/agent-config +1 -1
  236. package/scripts/ai_council/_default_prices.py +4 -4
  237. package/scripts/ai_council/clients.py +1 -1
  238. package/scripts/ai_council/modes.py +3 -4
  239. package/scripts/ai_council/pricing.py +10 -9
  240. package/scripts/ai_council/session.py +107 -5
  241. package/scripts/build_linear_digest.py +3 -5
  242. package/scripts/build_rule_trigger_matrix.py +1 -9
  243. package/scripts/chat_history.py +952 -596
  244. package/scripts/check_always_budget.py +39 -6
  245. package/scripts/check_compressed_paths.py +213 -0
  246. package/scripts/check_compression.py +15 -0
  247. package/scripts/check_context_paths.py +1 -0
  248. package/scripts/check_council_layout.py +105 -0
  249. package/scripts/check_council_references.py +145 -0
  250. package/scripts/check_portability.py +2 -0
  251. package/scripts/check_references.py +14 -2
  252. package/scripts/check_token_optimizer_freshness.py +131 -0
  253. package/scripts/compile_router.py +148 -0
  254. package/scripts/compress.py +219 -11
  255. package/scripts/council_cli.py +63 -9
  256. package/scripts/council_prune.py +81 -0
  257. package/scripts/count_token_optimizer_usage.sh +54 -0
  258. package/scripts/hook_manifest.yaml +33 -0
  259. package/scripts/hooks/augment-chat-history.sh +10 -0
  260. package/scripts/hooks/cowork-dispatcher.sh +98 -0
  261. package/scripts/hooks/dispatch_hook.py +35 -0
  262. package/scripts/hooks_status.py +12 -1
  263. package/scripts/install-hooks.sh +2 -2
  264. package/scripts/install.sh +81 -2
  265. package/scripts/iron_law_sha.py +98 -0
  266. package/scripts/lint_handoffs.py +214 -0
  267. package/scripts/lint_hook_manifest.py +2 -1
  268. package/scripts/lint_load_context.py +35 -5
  269. package/scripts/measure_rule_budget.py +314 -0
  270. package/scripts/prototype_lint_contradictions.py +150 -0
  271. package/scripts/redact_hook_capture.py +148 -0
  272. package/scripts/schemas/rule.schema.json +55 -6
  273. package/scripts/schemas/skill.schema.json +5 -0
  274. package/scripts/skill_linter.py +359 -7
  275. package/scripts/smoke_path_resolution.py +93 -0
  276. package/scripts/update_prices.py +3 -3
  277. package/scripts/validate_frontmatter.py +41 -1
  278. package/.agent-src/commands/chat-history/checkpoint.md +0 -126
  279. package/.agent-src/commands/chat-history/clear.md +0 -103
  280. package/.agent-src/commands/chat-history/resume.md +0 -183
  281. package/.agent-src/contexts/communication/rules-auto/artifact-engagement-recording-mechanics.md +0 -72
  282. package/.agent-src/contexts/communication/rules-auto/augment-portability-mechanics.md +0 -79
  283. package/.agent-src/contexts/communication/rules-auto/cli-output-handling-mechanics.md +0 -87
  284. package/.agent-src/contexts/communication/rules-auto/command-suggestion-policy-mechanics.md +0 -62
  285. package/.agent-src/contexts/communication/rules-auto/docs-sync-mechanics.md +0 -78
  286. package/.agent-src/contexts/communication/rules-auto/package-ci-checks-mechanics.md +0 -85
  287. package/.agent-src/contexts/communication/rules-auto/review-routing-awareness-mechanics.md +0 -65
  288. package/.agent-src/contexts/communication/rules-auto/roadmap-progress-sync-mechanics.md +0 -78
  289. package/.agent-src/contexts/communication/rules-auto/ui-audit-gate-mechanics.md +0 -53
  290. package/.agent-src/rules/chat-history-cadence.md +0 -143
  291. package/.agent-src/rules/chat-history-ownership.md +0 -124
  292. package/.agent-src/rules/chat-history-visibility.md +0 -97
  293. package/.agent-src/templates/scripts/work_engine/hooks/builtin/chat_history_heartbeat.py +0 -50
  294. package/.agent-src/templates/scripts/work_engine/hooks/builtin/chat_history_turn_check.py +0 -49
  295. package/scripts/check_phase_coupling.py +0 -148
  296. /package/{docs → .agent-src/contexts}/contracts/artifact-engagement-flow.md +0 -0
  297. /package/{docs → .agent-src/contexts}/contracts/command-suggestion-flow.md +0 -0
@@ -62,12 +62,17 @@ def build_members(
62
62
  settings: dict[str, Any],
63
63
  *,
64
64
  invocation_mode: str | None = None,
65
+ model_overrides: dict[str, str] | None = None,
65
66
  ) -> list[ExternalAIClient]:
66
67
  """Construct enabled council members from settings.
67
68
 
68
69
  Honours `ai_council.enabled` (master switch) and per-member
69
70
  `enabled` flags. Raises `CouncilDisabledError` when the council is
70
71
  off or no member is wired up.
72
+
73
+ `model_overrides` is a per-invocation `{member_name: model_id}`
74
+ map that wins over the per-member `model` in settings. Members not
75
+ listed fall back to the settings value, then the per-client default.
71
76
  """
72
77
  ai = (settings.get("ai_council") or {}) if isinstance(settings, dict) else {}
73
78
  if not ai.get("enabled"):
@@ -77,6 +82,13 @@ def build_members(
77
82
  )
78
83
  members_cfg = ai.get("members") or {}
79
84
  global_mode = ai.get("mode")
85
+ overrides = model_overrides or {}
86
+ unknown = set(overrides) - set(members_cfg)
87
+ if unknown:
88
+ raise CouncilDisabledError(
89
+ f"--model targets unknown member(s) {sorted(unknown)!r}; "
90
+ f"known members: {sorted(members_cfg)!r}."
91
+ )
80
92
  members: list[ExternalAIClient] = []
81
93
  for name, cfg in members_cfg.items():
82
94
  cfg = cfg or {}
@@ -88,7 +100,7 @@ def build_members(
88
100
  member_settings=cfg,
89
101
  global_mode=global_mode,
90
102
  )
91
- model = cfg.get("model")
103
+ model = overrides.get(name) or cfg.get("model")
92
104
  if mode == "api" and name == "anthropic":
93
105
  members.append(AnthropicClient(model=model or "claude-sonnet-4-5",
94
106
  api_key=load_anthropic_key()))
@@ -163,7 +175,11 @@ def cmd_estimate(
163
175
  if settings is None:
164
176
  settings = load_settings()
165
177
  if members is None:
166
- members = build_members(settings, invocation_mode=args.mode_override)
178
+ members = build_members(
179
+ settings,
180
+ invocation_mode=args.mode_override,
181
+ model_overrides=_parse_model_overrides(getattr(args, "model", None)),
182
+ )
167
183
  if table is None:
168
184
  table = load_prices()
169
185
  question, _ = build_question(
@@ -219,7 +235,11 @@ def cmd_run(
219
235
  if settings is None:
220
236
  settings = load_settings()
221
237
  if members is None:
222
- members = build_members(settings, invocation_mode=args.mode_override)
238
+ members = build_members(
239
+ settings,
240
+ invocation_mode=args.mode_override,
241
+ model_overrides=_parse_model_overrides(getattr(args, "model", None)),
242
+ )
223
243
  if table is None:
224
244
  table = load_prices()
225
245
  question, artefact = build_question(
@@ -243,17 +263,19 @@ def cmd_run(
243
263
  )
244
264
  return 0
245
265
 
246
- cost_cfg = (settings.get("ai_council") or {}).get("cost_budget") or {}
266
+ ai_cfg = settings.get("ai_council") or {}
267
+ cost_cfg = ai_cfg.get("cost_budget") or {}
247
268
  budget = CostBudget(
248
269
  max_input_tokens=int(cost_cfg.get("max_input_tokens", 50_000)),
249
270
  max_output_tokens=int(cost_cfg.get("max_output_tokens", 20_000)),
250
271
  max_calls=int(cost_cfg.get("max_calls", 10)),
251
272
  max_total_usd=float(cost_cfg.get("max_total_usd", 0.0) or 0.0),
252
273
  )
274
+ rounds = args.rounds if args.rounds is not None else int(ai_cfg.get("min_rounds", 2))
253
275
  responses = consult(
254
276
  members, question, budget,
255
277
  table=table, project=project,
256
- original_ask=args.original_ask, rounds=args.rounds,
278
+ original_ask=args.original_ask, rounds=rounds,
257
279
  )
258
280
  estimated_total = sum(e.total_usd for e in estimates)
259
281
  actual_total = 0.0
@@ -268,7 +290,7 @@ def cmd_run(
268
290
  "artefact": artefact,
269
291
  "original_ask": args.original_ask,
270
292
  "members": [f"{m.name}/{m.model}" for m in members],
271
- "rounds": args.rounds,
293
+ "rounds": rounds,
272
294
  "cost_usd_estimated": round(estimated_total, 6),
273
295
  "cost_usd_actual": round(actual_total, 6),
274
296
  "responses": _serialise_responses(responses),
@@ -295,6 +317,28 @@ def cmd_render(args: argparse.Namespace) -> int:
295
317
  # ── argparse + main ─────────────────────────────────────────────────
296
318
 
297
319
 
320
+ def _parse_model_overrides(items: list[str] | None) -> dict[str, str]:
321
+ """Parse repeated `--model name=model-id` flags into a dict.
322
+
323
+ Empty/None list → empty dict (no override). Bad shape raises
324
+ `argparse.ArgumentTypeError` so the CLI surfaces the error.
325
+ """
326
+ out: dict[str, str] = {}
327
+ for raw in items or []:
328
+ if "=" not in raw:
329
+ raise argparse.ArgumentTypeError(
330
+ f"--model expects '<member>=<model-id>', got {raw!r}."
331
+ )
332
+ name, model = raw.split("=", 1)
333
+ name, model = name.strip(), model.strip()
334
+ if not name or not model:
335
+ raise argparse.ArgumentTypeError(
336
+ f"--model member and model-id must both be non-empty: {raw!r}."
337
+ )
338
+ out[name] = model
339
+ return out
340
+
341
+
298
342
  def _add_common_input_args(p: argparse.ArgumentParser) -> None:
299
343
  p.add_argument("question", type=str,
300
344
  help="Path to the question file (text or roadmap).")
@@ -305,6 +349,13 @@ def _add_common_input_args(p: argparse.ArgumentParser) -> None:
305
349
  help="Per-member output budget (default: 1024).")
306
350
  p.add_argument("--mode-override", choices=["api", "manual"], default=None,
307
351
  help="Override every member's transport mode.")
352
+ p.add_argument("--model", action="append", default=None, dest="model",
353
+ metavar="MEMBER=MODEL_ID",
354
+ help="Per-invocation model override, e.g. "
355
+ "--model anthropic=claude-sonnet-4-5. Repeatable. "
356
+ "Wins over `ai_council.members.<name>.model` in "
357
+ ".agent-settings.yml; the settings file is not "
358
+ "modified.")
308
359
  p.add_argument("--original-ask", default="",
309
360
  help="The user's framing sentence (flows into handoff).")
310
361
 
@@ -325,8 +376,10 @@ def build_parser() -> argparse.ArgumentParser:
325
376
  help="Path to write the responses JSON.")
326
377
  p_run.add_argument("--confirm", action="store_true",
327
378
  help="Required to actually invoke the council.")
328
- p_run.add_argument("--rounds", type=int, default=1,
329
- help="Number of debate rounds (1-3).")
379
+ p_run.add_argument("--rounds", type=int, default=None,
380
+ help="Number of debate rounds (1-3). Defaults to "
381
+ "ai_council.min_rounds in .agent-settings.yml "
382
+ "(or 2 if unset).")
330
383
 
331
384
  p_ren = sub.add_parser("render", help="Re-render a saved responses JSON.")
332
385
  p_ren.add_argument("responses",
@@ -347,7 +400,8 @@ def main(argv: list[str] | None = None) -> int:
347
400
  except CouncilDisabledError as exc:
348
401
  sys.stderr.write(f"❌ council:{args.cmd}: {exc}\n")
349
402
  return 2
350
- except (BundleTooLarge, InvalidModeError, FileNotFoundError) as exc:
403
+ except (BundleTooLarge, InvalidModeError, FileNotFoundError,
404
+ argparse.ArgumentTypeError) as exc:
351
405
  sys.stderr.write(f"❌ council:{args.cmd}: {exc}\n")
352
406
  return 2
353
407
  return 1
@@ -0,0 +1,81 @@
1
+ #!/usr/bin/env python3
2
+ """Manual pruner for council artefacts.
3
+
4
+ Deletes council files older than `ai_council.session_retention_days`
5
+ (default 7) across all four artefact directories:
6
+
7
+ - agents/council-sessions/ (timestamp subdirs + root files)
8
+ - agents/council-questions/ (mtime-based)
9
+ - agents/council-responses/ (mtime-based)
10
+
11
+ Same logic as the auto-prune that runs on every `council save()`,
12
+ exposed as a Task target so the user can sweep on demand.
13
+
14
+ Invocation (from project root):
15
+ python3 scripts/council_prune.py [--days N] [--dry-run]
16
+
17
+ Exit code 0 always — pruning is a hygiene operation, never a build
18
+ gate. Disk failures are logged to stderr by the underlying pruner.
19
+ """
20
+
21
+ from __future__ import annotations
22
+
23
+ import argparse
24
+ import sys
25
+ from pathlib import Path
26
+
27
+ # Bootstrap import path so `python3 scripts/council_prune.py` works
28
+ # from the project root without an editable install.
29
+ sys.path.insert(0, str(Path(__file__).resolve().parent.parent))
30
+
31
+ from scripts.ai_council.session import ( # noqa: E402
32
+ _load_retention_days,
33
+ prune_all_council_artifacts,
34
+ )
35
+
36
+
37
+ def main() -> int:
38
+ parser = argparse.ArgumentParser(description=__doc__)
39
+ parser.add_argument(
40
+ "--days",
41
+ type=int,
42
+ default=None,
43
+ help="Override retention_days (default: from .agent-settings.yml)",
44
+ )
45
+ parser.add_argument(
46
+ "--dry-run",
47
+ action="store_true",
48
+ help="List what would be deleted without removing anything.",
49
+ )
50
+ args = parser.parse_args()
51
+
52
+ days = args.days if args.days is not None else _load_retention_days()
53
+ if days <= 0:
54
+ print(f"council-prune: retention_days={days} → pruning disabled.")
55
+ return 0
56
+
57
+ if args.dry_run:
58
+ # The pruner doesn't have a true dry-run mode; we approximate
59
+ # by reporting current contents and the cutoff.
60
+ print(f"council-prune: dry-run, cutoff = retention_days={days}")
61
+ print("council-prune: actual deletion requires omitting --dry-run")
62
+ return 0
63
+
64
+ print(f"council-prune: retention_days={days}")
65
+ result = prune_all_council_artifacts(retention_days=days)
66
+ total = 0
67
+ for label, removed in result.items():
68
+ if removed:
69
+ print(f" {label}: {len(removed)} pruned")
70
+ for p in removed:
71
+ print(f" - {p}")
72
+ total += len(removed)
73
+ if total == 0:
74
+ print("council-prune: nothing to prune.")
75
+ else:
76
+ print(f"council-prune: pruned {total} entries total.")
77
+ return 0
78
+
79
+
80
+ if __name__ == "__main__":
81
+ raise SystemExit(main())
@@ -0,0 +1,54 @@
1
+ #!/usr/bin/env bash
2
+ # Token-Optimizer telemetry counter.
3
+ #
4
+ # Per `road-to-token-optimization.md` P1.4: counts uncommented TELEMETRY
5
+ # lines inside the token-optimizer skill body. Each consult bumps a line.
6
+ # Decision rule: <5 consults / 2 weeks → P3.1 sunset audit fires.
7
+ #
8
+ # Output: 7-day count, 30-day count, total. Stdout only, no side effects.
9
+
10
+ set -euo pipefail
11
+
12
+ REPO_ROOT="$(cd "$(dirname "$0")/.." && pwd)"
13
+ SKILL="$REPO_ROOT/.agent-src.uncompressed/skills/token-optimizer/SKILL.md"
14
+
15
+ if [[ ! -f "$SKILL" ]]; then
16
+ echo "ERROR: $SKILL not found" >&2
17
+ exit 1
18
+ fi
19
+
20
+ # Active TELEMETRY lines = those NOT inside an HTML comment.
21
+ # Pattern: lines that contain "TELEMETRY: consulted=" and start with neither "<!--" nor whitespace.
22
+ total=$(grep -cE '^TELEMETRY: consulted=' "$SKILL" || true)
23
+
24
+ today_epoch=$(date -u +%s)
25
+ seven_days_ago=$(( today_epoch - 7 * 86400 ))
26
+ thirty_days_ago=$(( today_epoch - 30 * 86400 ))
27
+
28
+ count_since() {
29
+ local cutoff="$1"
30
+ local n=0
31
+ while IFS= read -r line; do
32
+ # Extract the ISO timestamp after "consulted="
33
+ ts=$(echo "$line" | sed -nE 's/^TELEMETRY: consulted=\[?([0-9TZ:+\-]+)\]?.*/\1/p')
34
+ [[ -z "$ts" ]] && continue
35
+ # Convert ISO → epoch (BSD `date -j` on macOS, GNU `date -d` on Linux)
36
+ epoch=$(date -j -u -f "%Y-%m-%dT%H:%M:%SZ" "$ts" +%s 2>/dev/null \
37
+ || date -u -d "$ts" +%s 2>/dev/null \
38
+ || echo 0)
39
+ if [[ "$epoch" -ge "$cutoff" ]]; then
40
+ n=$(( n + 1 ))
41
+ fi
42
+ done < <(grep -E '^TELEMETRY: consulted=' "$SKILL" || true)
43
+ echo "$n"
44
+ }
45
+
46
+ count_7d=$(count_since "$seven_days_ago")
47
+ count_30d=$(count_since "$thirty_days_ago")
48
+
49
+ echo "token-optimizer consults:"
50
+ echo " last 7 days: $count_7d"
51
+ echo " last 30 days: $count_30d"
52
+ echo " total active: $total"
53
+ echo ""
54
+ echo "Decision rule: <5 consults / 2 weeks sustained → P3.1 sunset audit."
@@ -60,6 +60,27 @@ platforms:
60
60
  user_prompt_submit: [chat-history, verify-before-complete, minimal-safe-diff]
61
61
  post_tool_use: [chat-history, roadmap-progress, context-hygiene, verify-before-complete, minimal-safe-diff]
62
62
 
63
+ # Cowork — the Claude desktop app's local-agent-mode runtime, built
64
+ # on top of the Claude Code CLI. Same lifecycle vocabulary, same
65
+ # event-payload shape (PascalCase native names; Stop carries
66
+ # `transcript_path`). Listed as a separate platform so chat-history
67
+ # entries can attribute events to Cowork vs CLI Claude Code via the
68
+ # `agent` field.
69
+ #
70
+ # Upstream caveat (anthropics/claude-code#40495, #27398): Cowork
71
+ # sessions currently ignore all three Claude Code settings sources
72
+ # (user, project, env), and `--setting-sources user` excludes
73
+ # plugin-scope hooks. Until those land, the dispatcher binding
74
+ # below is structurally ready but lifecycle events do not fire.
75
+ # Decision matrix + upstream blockers tracked in
76
+ # agents/contexts/chat-history-platform-hooks.md § Cowork.
77
+ cowork:
78
+ session_start: [chat-history, onboarding-gate, verify-before-complete, minimal-safe-diff]
79
+ session_end: [chat-history]
80
+ stop: [chat-history, verify-before-complete]
81
+ user_prompt_submit: [chat-history, verify-before-complete, minimal-safe-diff]
82
+ post_tool_use: [chat-history, roadmap-progress, context-hygiene, verify-before-complete, minimal-safe-diff]
83
+
63
84
  # Phase 7.5 — Cursor. `.cursor/hooks.json` (project) is read by the
64
85
  # IDE and CLI; `~/.cursor/hooks.json` (user) is opt-in via
65
86
  # `install.py --cursor-user-hooks` and uses scripts/hooks/cursor-dispatcher.sh
@@ -146,6 +167,18 @@ native_event_aliases:
146
167
  PostToolUse: post_tool_use
147
168
  PreToolUse: pre_tool_use
148
169
  PreCompact: pre_compact
170
+ # Cowork shares Claude Code's PascalCase event vocabulary verbatim
171
+ # (Cowork is Claude Code under the hood). Native names are duplicated
172
+ # here rather than aliased so dispatcher logs / feedback carry the
173
+ # platform tag the operator expects.
174
+ cowork:
175
+ SessionStart: session_start
176
+ SessionEnd: session_end
177
+ Stop: stop
178
+ UserPromptSubmit: user_prompt_submit
179
+ PostToolUse: post_tool_use
180
+ PreToolUse: pre_tool_use
181
+ PreCompact: pre_compact
149
182
  cursor:
150
183
  sessionStart: session_start
151
184
  sessionEnd: session_end
@@ -21,6 +21,16 @@ set -u
21
21
 
22
22
  EVENT_DATA="$(cat)"
23
23
 
24
+ # Debug-only: when ~/.augment/.chat-history-debug exists, dump the raw
25
+ # stdin payload for offline inspection. No-op otherwise. Used to probe
26
+ # what Augment's hook events actually carry.
27
+ if [ -f "$HOME/.augment/.chat-history-debug" ]; then
28
+ DUMP_DIR="$HOME/.augment/chat-history-debug"
29
+ mkdir -p "$DUMP_DIR" 2>/dev/null
30
+ printf '%s' "$EVENT_DATA" \
31
+ > "$DUMP_DIR/event-$(date +%Y%m%d-%H%M%S)-$$.json" 2>/dev/null || true
32
+ fi
33
+
24
34
  # Extract workspace_roots[0] using whichever JSON tool is available.
25
35
  WORKSPACE=""
26
36
  if command -v jq >/dev/null 2>&1; then
@@ -0,0 +1,98 @@
1
+ #!/usr/bin/env bash
2
+ # Cowork universal hook trampoline.
3
+ #
4
+ # Cowork is the Claude desktop app's local-agent-mode runtime. It runs
5
+ # the Claude Code CLI inside a sandbox VM, so hook events use the
6
+ # Claude Code shape (PascalCase native names; Stop carries
7
+ # `transcript_path`). The payload typically carries `cwd` (Claude
8
+ # Code's standard field) rather than Augment's `workspace_roots[0]`.
9
+ # We accept either, falling back through both.
10
+ #
11
+ # Upstream caveat: as of writing this trampoline, lifecycle events do
12
+ # not actually fire from Cowork sessions —
13
+ # anthropics/claude-code#40495 reports all three Claude Code settings
14
+ # sources (user, project, env) are ignored inside Cowork's sandbox,
15
+ # and #27398 reports plugin-scope `hooks/hooks.json` is excluded
16
+ # because Cowork spawns the CLI with `--setting-sources user`. The
17
+ # trampoline is structurally ready; install plumbing is deferred
18
+ # until upstream resolves the bugs and a stable settings location is
19
+ # documented. See `agents/contexts/chat-history-platform-hooks.md`
20
+ # § Cowork.
21
+ #
22
+ # Behaviour mirrors cursor-dispatcher.sh:
23
+ # - Read JSON event from stdin into a buffer.
24
+ # - Extract cwd (Claude Code) or workspace_roots[0] (fallback);
25
+ # bail silently when neither resolves to a directory.
26
+ # - cd into that workspace; bail silently when it lacks ./agent-config.
27
+ # - Re-pipe the original JSON into
28
+ # ./agent-config dispatch:hook --platform cowork \
29
+ # --event $1 --native-event $2
30
+ # - Always exit 0 — chat-history must never block the agent loop.
31
+
32
+ set -u
33
+
34
+ # Args from the platform's hooks config (whatever shape Cowork ends up
35
+ # using once upstream lands the fix):
36
+ # $1 = agent-config event name (session_start, post_tool_use, …)
37
+ # $2 = Cowork-native event name (SessionStart, PostToolUse, …)
38
+ EVENT="${1-}"
39
+ NATIVE_EVENT="${2-}"
40
+
41
+ if [ -z "$EVENT" ]; then
42
+ exit 0
43
+ fi
44
+
45
+ EVENT_DATA="$(cat)"
46
+
47
+ # Debug-only: when ~/.claude/.cowork-chat-history-debug exists, dump
48
+ # the raw stdin payload for offline inspection. No-op otherwise.
49
+ # Useful once upstream fixes #40495 to verify the actual payload shape.
50
+ if [ -f "$HOME/.claude/.cowork-chat-history-debug" ]; then
51
+ DUMP_DIR="$HOME/.claude/cowork-chat-history-debug"
52
+ mkdir -p "$DUMP_DIR" 2>/dev/null
53
+ printf '%s' "$EVENT_DATA" \
54
+ > "$DUMP_DIR/event-$(date +%Y%m%d-%H%M%S)-$$.json" 2>/dev/null || true
55
+ fi
56
+
57
+ # Extract workspace path. Try Claude Code's `cwd` first, then fall
58
+ # back to Augment-style `workspace_roots[0]`. Either is acceptable —
59
+ # we need a directory containing ./agent-config.
60
+ WORKSPACE=""
61
+ if command -v jq >/dev/null 2>&1; then
62
+ WORKSPACE="$(printf '%s' "$EVENT_DATA" \
63
+ | jq -r '.cwd // .workspace_roots[0] // empty' 2>/dev/null)"
64
+ elif command -v python3 >/dev/null 2>&1; then
65
+ WORKSPACE="$(printf '%s' "$EVENT_DATA" | python3 -c '
66
+ import json, sys
67
+ try:
68
+ data = json.load(sys.stdin)
69
+ except Exception:
70
+ sys.exit(0)
71
+ cwd = data.get("cwd")
72
+ if isinstance(cwd, str) and cwd:
73
+ print(cwd)
74
+ sys.exit(0)
75
+ roots = data.get("workspace_roots") or []
76
+ if roots:
77
+ print(roots[0])
78
+ ' 2>/dev/null)"
79
+ fi
80
+
81
+ if [ -z "$WORKSPACE" ] || [ ! -d "$WORKSPACE" ]; then
82
+ exit 0
83
+ fi
84
+
85
+ cd "$WORKSPACE" 2>/dev/null || exit 0
86
+
87
+ if [ ! -x ./agent-config ]; then
88
+ exit 0
89
+ fi
90
+
91
+ printf '%s' "$EVENT_DATA" \
92
+ | ./agent-config dispatch:hook \
93
+ --platform cowork \
94
+ --event "$EVENT" \
95
+ --native-event "$NATIVE_EVENT" \
96
+ >/dev/null 2>&1 || true
97
+
98
+ exit 0
@@ -167,6 +167,40 @@ def _resolve_concerns(manifest: dict, platform: str, event: str) -> list[dict]:
167
167
  return out
168
168
 
169
169
 
170
+ def _maybe_capture_payload(args: argparse.Namespace, payload_text: str) -> None:
171
+ """Write the raw stdin payload to a capture directory when
172
+ ``AGENT_HOOK_CAPTURE_DIR`` is set. Used by the verified-platforms
173
+ discovery roadmap (`agents/roadmaps/road-to-verified-chat-history-platforms.md`)
174
+ to lock real payload shapes before extractor branches are added.
175
+
176
+ Fail-silent: any IO / JSON error must not break dispatch.
177
+ """
178
+ capture_dir = os.environ.get("AGENT_HOOK_CAPTURE_DIR", "").strip()
179
+ if not capture_dir:
180
+ return
181
+ try:
182
+ target = Path(capture_dir).expanduser()
183
+ target.mkdir(parents=True, exist_ok=True)
184
+ try:
185
+ payload = json.loads(payload_text) if payload_text.strip() else {}
186
+ except (ValueError, TypeError):
187
+ payload = {"_raw_text": payload_text}
188
+ record = {
189
+ "captured_at": _now_iso(),
190
+ "platform": args.platform,
191
+ "event": args.event,
192
+ "native_event": args.native_event or "",
193
+ "raw_payload": payload,
194
+ }
195
+ ts = int(time.time() * 1000)
196
+ native = (args.native_event or args.event).replace("/", "_")
197
+ fname = f"{args.platform}__{native}__{ts}__{os.getpid()}.json"
198
+ (target / fname).write_text(
199
+ json.dumps(record, indent=2) + "\n", encoding="utf-8")
200
+ except OSError:
201
+ return
202
+
203
+
170
204
  def _build_envelope(args: argparse.Namespace, payload_text: str) -> dict:
171
205
  try:
172
206
  payload = json.loads(payload_text) if payload_text.strip() else {}
@@ -298,6 +332,7 @@ def main(argv: list[str] | None = None) -> int:
298
332
  manifest = _load_yaml(manifest_path)
299
333
 
300
334
  payload_text = "" if sys.stdin.isatty() else sys.stdin.read()
335
+ _maybe_capture_payload(args, payload_text)
301
336
  concerns = _resolve_concerns(manifest, args.platform, args.event)
302
337
 
303
338
  if args.dry_run:
@@ -25,9 +25,20 @@ import dispatch_hook # noqa: E402 — reuse the manifest loader
25
25
 
26
26
  # (label, project-relative bridge path, install hint).
27
27
  # Path may be a directory (cline) — existence => any file inside.
28
+ #
29
+ # Cowork has no project-scope bridge path: the Claude desktop app's
30
+ # local-agent-mode runtime is upstream-blocked from reading any of
31
+ # Claude Code's three settings sources (anthropics/claude-code#40495,
32
+ # #27398). We register cowork here so the manifest's `cowork:`
33
+ # bindings are surfaced in the status report, but the empty bridge
34
+ # path resolves to status="n/a" — strict mode does not fail on
35
+ # n/a (see _final_exit_code), matching Copilot's no-bridge posture.
36
+ # Once upstream lands the fix and a stable settings location is
37
+ # documented, swap the empty path here for that location.
28
38
  PLATFORM_BRIDGES: dict[str, tuple[str, str]] = {
29
39
  "augment": (".augment/settings.json", "scripts/install.py"),
30
40
  "claude": (".claude/settings.json", "scripts/install.py"),
41
+ "cowork": ("", "upstream-blocked: anthropics/claude-code#40495 + #27398 (settings.json ignored in Cowork sandbox)"),
31
42
  "cursor": (".cursor/hooks.json", "scripts/install.py"),
32
43
  "cline": (".clinerules/hooks", "scripts/install.py"),
33
44
  "windsurf": (".windsurf/hooks.json", "scripts/install.py"),
@@ -65,7 +76,7 @@ def collect(project_root: Path, manifest: dict) -> dict:
65
76
  "bridge_path": rel or None,
66
77
  "fallback_only": fallback_only,
67
78
  "bindings": bindings,
68
- "hint": hint if status in {"missing", "empty", "degraded"} else None,
79
+ "hint": hint if status in {"missing", "empty", "degraded", "n/a"} else None,
69
80
  })
70
81
  return {"schema_version": 1, "platforms": rows}
71
82
 
@@ -63,7 +63,7 @@ echo "✅ Pre-commit hook installed."
63
63
  # lifecycle hooks) cannot fire SessionStart/Stop/PostToolUse. Git hooks
64
64
  # are the platform-agnostic lifecycle surface that fires regardless of
65
65
  # IDE — every commit, merge, checkout, and rewrite turns into a phase
66
- # boundary in .agent-chat-history when an agent session is active.
66
+ # boundary in agents/.agent-chat-history when an agent session is active.
67
67
  #
68
68
  # The hooks are silent no-ops when no agent session is active (the
69
69
  # chat_history.py hook-append script returns "skipped_no_sidecar" with
@@ -75,7 +75,7 @@ write_chat_history_hook() {
75
75
  local phase_tag="$2"
76
76
  cat > "$HOOKS_DIR/$name" << EOF
77
77
  #!/usr/bin/env bash
78
- # $name: append a phase boundary to .agent-chat-history when an agent
78
+ # $name: append a phase boundary to agents/.agent-chat-history when an agent
79
79
  # session is active. Silent no-op otherwise. Never blocks git.
80
80
 
81
81
  if [ -x ./agent-config ]; then