@event4u/agent-config 1.16.0 → 1.18.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 (224) 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/{chat-history-checkpoint.md → chat-history/checkpoint.md} +4 -4
  6. package/.agent-src/commands/{chat-history-clear.md → chat-history/clear.md} +4 -4
  7. package/.agent-src/commands/{chat-history-resume.md → chat-history/resume.md} +4 -4
  8. package/.agent-src/commands/chat-history/show.md +107 -0
  9. package/.agent-src/commands/chat-history.md +33 -89
  10. package/.agent-src/commands/{commit-in-chunks.md → commit/in-chunks.md} +15 -13
  11. package/.agent-src/commands/commit.md +22 -2
  12. package/.agent-src/commands/{context-create.md → context/create.md} +4 -3
  13. package/.agent-src/commands/{context-refactor.md → context/refactor.md} +4 -3
  14. package/.agent-src/commands/context.md +44 -0
  15. package/.agent-src/commands/{copilot-agents-init.md → copilot-agents/init.md} +4 -3
  16. package/.agent-src/commands/{copilot-agents-optimize.md → copilot-agents/optimize.md} +4 -3
  17. package/.agent-src/commands/copilot-agents.md +44 -0
  18. package/.agent-src/commands/council/default.md +221 -0
  19. package/.agent-src/commands/{council-design.md → council/design.md} +6 -5
  20. package/.agent-src/commands/{council-optimize.md → council/optimize.md} +7 -6
  21. package/.agent-src/commands/{council-pr.md → council/pr.md} +6 -5
  22. package/.agent-src/commands/council.md +47 -212
  23. package/.agent-src/commands/{create-pr-description.md → create-pr/description-only.md} +4 -2
  24. package/.agent-src/commands/create-pr.md +26 -5
  25. package/.agent-src/commands/{feature-dev.md → feature/dev.md} +5 -10
  26. package/.agent-src/commands/{feature-explore.md → feature/explore.md} +4 -8
  27. package/.agent-src/commands/{feature-plan.md → feature/plan.md} +4 -8
  28. package/.agent-src/commands/{feature-refactor.md → feature/refactor.md} +4 -8
  29. package/.agent-src/commands/{feature-roadmap.md → feature/roadmap.md} +6 -10
  30. package/.agent-src/commands/feature.md +6 -12
  31. package/.agent-src/commands/{fix-ci.md → fix/ci.md} +4 -8
  32. package/.agent-src/commands/{fix-portability.md → fix/portability.md} +4 -8
  33. package/.agent-src/commands/{fix-pr-bot-comments.md → fix/pr-bots.md} +4 -8
  34. package/.agent-src/commands/{fix-pr-developer-comments.md → fix/pr-developers.md} +4 -8
  35. package/.agent-src/commands/{fix-pr-comments.md → fix/pr.md} +7 -11
  36. package/.agent-src/commands/{fix-references.md → fix/refs.md} +4 -8
  37. package/.agent-src/commands/{fix-seeder.md → fix/seeder.md} +4 -8
  38. package/.agent-src/commands/fix.md +7 -13
  39. package/.agent-src/commands/{do-and-judge.md → judge/on-diff.md} +4 -3
  40. package/.agent-src/commands/judge/solo.md +90 -0
  41. package/.agent-src/commands/{do-in-steps.md → judge/steps.md} +4 -3
  42. package/.agent-src/commands/judge.md +35 -70
  43. package/.agent-src/commands/{memory-add.md → memory/add.md} +4 -3
  44. package/.agent-src/commands/{memory-full.md → memory/load.md} +4 -3
  45. package/.agent-src/commands/{memory-promote.md → memory/promote.md} +4 -3
  46. package/.agent-src/commands/{propose-memory.md → memory/propose.md} +4 -3
  47. package/.agent-src/commands/memory.md +48 -0
  48. package/.agent-src/commands/{module-create.md → module/create.md} +4 -3
  49. package/.agent-src/commands/{module-explore.md → module/explore.md} +4 -3
  50. package/.agent-src/commands/module.md +44 -0
  51. package/.agent-src/commands/{optimize-agents.md → optimize/agents.md} +4 -8
  52. package/.agent-src/commands/{optimize-augmentignore.md → optimize/augmentignore.md} +4 -9
  53. package/.agent-src/commands/{optimize-rtk-filters.md → optimize/rtk.md} +4 -8
  54. package/.agent-src/commands/{optimize-skills.md → optimize/skills.md} +4 -8
  55. package/.agent-src/commands/optimize.md +4 -10
  56. package/.agent-src/commands/{override-create.md → override/create.md} +4 -3
  57. package/.agent-src/commands/{override-manage.md → override/manage.md} +4 -3
  58. package/.agent-src/commands/override.md +44 -0
  59. package/.agent-src/commands/{roadmap-create.md → roadmap/create.md} +4 -3
  60. package/.agent-src/commands/{roadmap-execute.md → roadmap/execute.md} +4 -3
  61. package/.agent-src/commands/roadmap.md +44 -0
  62. package/.agent-src/commands/{tests-create.md → tests/create.md} +4 -3
  63. package/.agent-src/commands/{tests-execute.md → tests/execute.md} +4 -3
  64. package/.agent-src/commands/tests.md +44 -0
  65. package/.agent-src/contexts/communication/rules-auto/artifact-engagement-recording-mechanics.md +72 -0
  66. package/.agent-src/contexts/communication/rules-auto/augment-portability-mechanics.md +79 -0
  67. package/.agent-src/contexts/communication/rules-auto/augment-source-of-truth-mechanics.md +98 -0
  68. package/.agent-src/contexts/communication/rules-auto/cli-output-handling-mechanics.md +87 -0
  69. package/.agent-src/contexts/communication/rules-auto/command-suggestion-policy-mechanics.md +62 -0
  70. package/.agent-src/contexts/communication/rules-auto/docs-sync-mechanics.md +78 -0
  71. package/.agent-src/contexts/communication/rules-auto/package-ci-checks-mechanics.md +85 -0
  72. package/.agent-src/contexts/communication/rules-auto/review-routing-awareness-mechanics.md +65 -0
  73. package/.agent-src/contexts/communication/rules-auto/roadmap-progress-sync-mechanics.md +78 -0
  74. package/.agent-src/contexts/communication/rules-auto/skill-quality-mechanics.md +62 -0
  75. package/.agent-src/contexts/communication/rules-auto/slash-command-routing-policy-mechanics.md +55 -0
  76. package/.agent-src/contexts/communication/rules-auto/ui-audit-gate-mechanics.md +53 -0
  77. package/.agent-src/contexts/communication/rules-auto/user-interaction-mechanics.md +77 -0
  78. package/.agent-src/contexts/judges/no-consolidate-rationale.md +102 -0
  79. package/.agent-src/contexts/judges/persona-voice-rubric.md +140 -0
  80. package/.agent-src/rules/artifact-engagement-recording.md +13 -69
  81. package/.agent-src/rules/ask-when-uncertain.md +27 -42
  82. package/.agent-src/rules/augment-portability.md +15 -61
  83. package/.agent-src/rules/augment-source-of-truth.md +27 -93
  84. package/.agent-src/rules/cli-output-handling.md +10 -76
  85. package/.agent-src/rules/command-suggestion-policy.md +18 -59
  86. package/.agent-src/rules/commit-conventions.md +17 -14
  87. package/.agent-src/rules/context-hygiene.md +6 -0
  88. package/.agent-src/rules/direct-answers.md +35 -59
  89. package/.agent-src/rules/docker-commands.md +5 -5
  90. package/.agent-src/rules/docs-sync.md +15 -69
  91. package/.agent-src/rules/language-and-tone.md +48 -72
  92. package/.agent-src/rules/missing-tool-handling.md +28 -22
  93. package/.agent-src/rules/no-cheap-questions.md +39 -53
  94. package/.agent-src/rules/no-roadmap-references.md +73 -0
  95. package/.agent-src/rules/onboarding-gate.md +7 -0
  96. package/.agent-src/rules/package-ci-checks.md +21 -61
  97. package/.agent-src/rules/preservation-guard.md +64 -29
  98. package/.agent-src/rules/review-routing-awareness.md +24 -43
  99. package/.agent-src/rules/roadmap-progress-sync.md +31 -65
  100. package/.agent-src/rules/rule-type-governance.md +28 -0
  101. package/.agent-src/rules/security-sensitive-stop.md +8 -8
  102. package/.agent-src/rules/skill-quality.md +16 -48
  103. package/.agent-src/rules/slash-command-routing-policy.md +7 -4
  104. package/.agent-src/rules/think-before-action.md +52 -42
  105. package/.agent-src/rules/tool-safety.md +19 -16
  106. package/.agent-src/rules/ui-audit-gate.md +24 -38
  107. package/.agent-src/rules/user-interaction.md +13 -68
  108. package/.agent-src/skills/ai-council/SKILL.md +2 -0
  109. package/.agent-src/skills/api-testing/SKILL.md +1 -1
  110. package/.agent-src/skills/check-refs/SKILL.md +59 -40
  111. package/.agent-src/skills/conventional-commits-writing/SKILL.md +86 -28
  112. package/.agent-src/skills/copilot-agents-optimization/SKILL.md +5 -5
  113. package/.agent-src/skills/developer-like-execution/SKILL.md +4 -4
  114. package/.agent-src/skills/finishing-a-development-branch/SKILL.md +101 -65
  115. package/.agent-src/skills/flux/SKILL.md +30 -10
  116. package/.agent-src/skills/github-ci/SKILL.md +2 -2
  117. package/.agent-src/skills/judge-code-quality/SKILL.md +7 -8
  118. package/.agent-src/skills/judge-security-auditor/SKILL.md +4 -5
  119. package/.agent-src/skills/judge-test-coverage/SKILL.md +3 -4
  120. package/.agent-src/skills/lint-skills/SKILL.md +57 -39
  121. package/.agent-src/skills/md-language-check/SKILL.md +61 -39
  122. package/.agent-src/skills/override-management/SKILL.md +5 -5
  123. package/.agent-src/skills/quality-tools/SKILL.md +2 -2
  124. package/.agent-src/skills/react-shadcn-ui/SKILL.md +116 -43
  125. package/.agent-src/skills/readme-reviewer/SKILL.md +30 -29
  126. package/.agent-src/skills/readme-writing/SKILL.md +78 -53
  127. package/.agent-src/skills/readme-writing-package/SKILL.md +50 -47
  128. package/.agent-src/skills/receiving-code-review/SKILL.md +52 -47
  129. package/.agent-src/skills/refine-prompt/SKILL.md +0 -1
  130. package/.agent-src/skills/requesting-code-review/SKILL.md +35 -30
  131. package/.agent-src/skills/security/SKILL.md +7 -2
  132. package/.agent-src/skills/security-audit/SKILL.md +7 -3
  133. package/.agent-src/skills/systematic-debugging/SKILL.md +68 -60
  134. package/.agent-src/skills/test-driven-development/SKILL.md +59 -57
  135. package/.agent-src/skills/test-performance/SKILL.md +0 -1
  136. package/.agent-src/skills/traefik/SKILL.md +4 -4
  137. package/.agent-src/skills/verify-completion-evidence/SKILL.md +28 -26
  138. package/.agent-src/templates/roadmaps.md +4 -0
  139. package/.claude-plugin/marketplace.json +22 -11
  140. package/AGENTS.md +2 -2
  141. package/CHANGELOG.md +125 -1
  142. package/README.md +18 -17
  143. package/docs/architecture.md +4 -6
  144. package/docs/catalog.md +67 -39
  145. package/docs/contracts/STABILITY.md +13 -7
  146. package/docs/contracts/adr-chat-history-split.md +1 -3
  147. package/docs/contracts/adr-command-suggestion.md +0 -2
  148. package/docs/contracts/adr-implement-ticket-runtime.md +1 -2
  149. package/docs/contracts/adr-product-ui-track.md +3 -6
  150. package/docs/contracts/adr-prompt-driven-execution.md +3 -4
  151. package/docs/contracts/agent-memory-contract.md +6 -11
  152. package/docs/contracts/artifact-engagement-flow.md +6 -9
  153. package/docs/contracts/command-clusters.md +56 -46
  154. package/docs/contracts/command-suggestion-flow.md +1 -3
  155. package/docs/contracts/context-paths.md +99 -0
  156. package/docs/contracts/file-ownership-matrix.json +6722 -0
  157. package/docs/contracts/file-ownership-matrix.md +134 -0
  158. package/docs/contracts/implement-ticket-flow.md +6 -9
  159. package/docs/contracts/linear-ai-rules-inclusion.md +0 -1
  160. package/docs/contracts/linear-ai-three-layers.md +0 -2
  161. package/docs/contracts/load-context-budget-model.md +258 -0
  162. package/docs/contracts/load-context-schema.md +21 -3
  163. package/docs/contracts/roadmap-complexity-standard.md +137 -0
  164. package/docs/contracts/rule-interactions.md +0 -1
  165. package/docs/contracts/rule-priority-hierarchy.md +1 -1
  166. package/docs/contracts/ui-track-flow.md +7 -17
  167. package/docs/customization.md +2 -0
  168. package/docs/getting-started.md +5 -4
  169. package/docs/guidelines/agent-infra/ask-when-uncertain-demos.md +134 -0
  170. package/docs/guidelines/agent-infra/asking-and-brevity-examples.md +100 -0
  171. package/docs/guidelines/agent-infra/direct-answers-demos.md +145 -0
  172. package/docs/guidelines/agent-infra/verify-before-complete-demos.md +128 -0
  173. package/package.json +1 -1
  174. package/scripts/_phase2_shim_helper.py +109 -0
  175. package/scripts/agent-config +30 -0
  176. package/scripts/ai_council/one_off_archive/2026-05/README.md +45 -0
  177. package/scripts/ai_council/one_off_archive/2026-05/_one_off_2a4_acceptance.py +208 -0
  178. package/scripts/ai_council/one_off_archive/2026-05/_one_off_budget_v2_audit.py +206 -0
  179. package/scripts/ai_council/one_off_archive/2026-05/_one_off_context_layer_v1_estimate.py +67 -0
  180. package/scripts/ai_council/one_off_archive/2026-05/_one_off_context_layer_v1_review.py +292 -0
  181. package/scripts/ai_council/one_off_archive/2026-05/_one_off_followups_review.py +259 -0
  182. package/scripts/ai_council/one_off_archive/2026-05/_one_off_nondestructive_inline_audit.py +209 -0
  183. package/scripts/ai_council/one_off_archive/2026-05/_one_off_phase4_dispatch_latency.py +108 -0
  184. package/scripts/ai_council/one_off_archive/2026-05/_one_off_phase6_trigger_jaccard.py +92 -0
  185. package/scripts/ai_council/one_off_archive/2026-05/_one_off_phase_2a_budget_rebalance.py +257 -0
  186. package/scripts/ai_council/one_off_archive/2026-05/_one_off_phase_2a_post_revert.py +197 -0
  187. package/scripts/ai_council/one_off_archive/2026-05/_one_off_rule_hardening_v1.py +251 -0
  188. package/scripts/ai_council/one_off_archive/2026-05/_one_off_structural_open_questions.py +232 -0
  189. package/scripts/ai_council/one_off_archive/2026-05/_one_off_structural_optimization.py +144 -0
  190. package/scripts/ai_council/one_off_archive/2026-05/_one_off_structural_v3_gaps.py +252 -0
  191. package/scripts/ai_council/one_off_archive/2026-05/_one_off_structural_v3_review.py +240 -0
  192. package/scripts/build_rule_trigger_matrix.py +360 -0
  193. package/scripts/check_always_budget.py +402 -45
  194. package/scripts/check_cluster_patterns.py +159 -0
  195. package/scripts/check_command_count_messaging.py +14 -7
  196. package/scripts/check_context_paths.py +201 -0
  197. package/scripts/check_no_roadmap_refs.py +155 -0
  198. package/scripts/check_one_off_location.py +81 -0
  199. package/scripts/check_phase_coupling.py +148 -0
  200. package/scripts/check_portability.py +2 -0
  201. package/scripts/check_references.py +35 -2
  202. package/scripts/check_safety_floor_untouched.py +125 -0
  203. package/scripts/command_suggester/loader.py +4 -1
  204. package/scripts/compress.py +64 -15
  205. package/scripts/context_hygiene_hook.py +173 -0
  206. package/scripts/generate_index.py +6 -2
  207. package/scripts/generate_ownership_matrix.py +323 -0
  208. package/scripts/hooks/augment-context-hygiene.sh +55 -0
  209. package/scripts/hooks/augment-onboarding-gate.sh +55 -0
  210. package/scripts/hooks/augment-roadmap-progress.sh +57 -0
  211. package/scripts/install.py +105 -45
  212. package/scripts/lint_examples.py +98 -0
  213. package/scripts/lint_no_new_atomic_commands.py +12 -11
  214. package/scripts/lint_roadmap_complexity.py +127 -0
  215. package/scripts/onboarding_gate_hook.py +137 -0
  216. package/scripts/requirements-evals.txt +1 -0
  217. package/scripts/roadmap_progress_hook.py +159 -0
  218. package/scripts/schemas/command.schema.json +4 -3
  219. package/scripts/schemas/rule.schema.json +5 -0
  220. package/scripts/skill_linter.py +1 -0
  221. package/scripts/sync_agent_settings.py +25 -2
  222. package/scripts/update_counts.py +7 -0
  223. /package/scripts/ai_council/{_one_off_rebalancing_audit.py → one_off_archive/2026-05/_one_off_rebalancing_audit.py} +0 -0
  224. /package/scripts/ai_council/{_one_off_roundtrip.py → one_off_archive/2026-05/_one_off_roundtrip.py} +0 -0
@@ -0,0 +1,109 @@
1
+ #!/usr/bin/env python3
2
+ """One-shot helper: add `superseded_by:` + `deprecated_in:` + warning
3
+ banner to Phase 2 atomic-command shims.
4
+
5
+ Idempotent — if a file already has `superseded_by:` set, it is skipped.
6
+ """
7
+ from __future__ import annotations
8
+ import sys
9
+ from pathlib import Path
10
+
11
+ # (file-stem, "<cluster> <sub>") — "<cluster> --flag" for flag-based
12
+ PHASE2_SHIMS: list[tuple[str, str]] = [
13
+ # chat-history cluster
14
+ ("chat-history-resume", "chat-history resume"),
15
+ ("chat-history-clear", "chat-history clear"),
16
+ ("chat-history-checkpoint", "chat-history checkpoint"),
17
+ # agents cluster
18
+ ("agents-audit", "agents audit"),
19
+ ("agents-cleanup", "agents cleanup"),
20
+ ("agents-prepare", "agents prepare"),
21
+ # memory cluster
22
+ ("memory-add", "memory add"),
23
+ ("memory-full", "memory load"),
24
+ ("memory-promote", "memory promote"),
25
+ ("propose-memory", "memory propose"),
26
+ # roadmap cluster
27
+ ("roadmap-create", "roadmap create"),
28
+ ("roadmap-execute", "roadmap execute"),
29
+ # module cluster
30
+ ("module-create", "module create"),
31
+ ("module-explore", "module explore"),
32
+ # tests cluster
33
+ ("tests-create", "tests create"),
34
+ ("tests-execute", "tests execute"),
35
+ # context cluster
36
+ ("context-create", "context create"),
37
+ ("context-refactor", "context refactor"),
38
+ # override cluster
39
+ ("override-create", "override create"),
40
+ ("override-manage", "override manage"),
41
+ # copilot-agents cluster
42
+ ("copilot-agents-init", "copilot-agents init"),
43
+ ("copilot-agents-optimize", "copilot-agents optimize"),
44
+ # judge cluster (do-and-judge / do-in-steps now sub-commands)
45
+ ("do-and-judge", "judge on-diff"),
46
+ ("do-in-steps", "judge steps"),
47
+ # commit / create-pr — flag-based clusters
48
+ ("commit-in-chunks", "commit --in-chunks"),
49
+ ("create-pr-description", "create-pr --description-only"),
50
+ ]
51
+
52
+ DEPRECATED_IN = "1.17.0"
53
+ COMMANDS_DIR = Path(".agent-src.uncompressed/commands")
54
+
55
+
56
+ def patch_file(stem: str, target: str) -> str:
57
+ path = COMMANDS_DIR / f"{stem}.md"
58
+ if not path.exists():
59
+ return f"SKIP {stem}: not found"
60
+ text = path.read_text(encoding="utf-8")
61
+ if "superseded_by:" in text.split("---", 2)[1] if text.startswith("---") else False:
62
+ return f"SKIP {stem}: already shimmed"
63
+
64
+ if not text.startswith("---\n"):
65
+ return f"SKIP {stem}: no frontmatter"
66
+ end = text.find("\n---\n", 4)
67
+ if end == -1:
68
+ return f"SKIP {stem}: malformed frontmatter"
69
+ fm_block = text[4:end]
70
+ body = text[end + len("\n---\n"):]
71
+
72
+ if "superseded_by:" in fm_block:
73
+ return f"SKIP {stem}: already shimmed"
74
+
75
+ new_fm_lines = fm_block.rstrip("\n").splitlines()
76
+ new_fm_lines.append(f"superseded_by: {target}")
77
+ new_fm_lines.append(f'deprecated_in: "{DEPRECATED_IN}"')
78
+ new_fm = "\n".join(new_fm_lines)
79
+
80
+ is_flag = target.startswith(("commit ", "create-pr "))
81
+ if is_flag:
82
+ cluster_invocation = f"/{target}"
83
+ else:
84
+ cluster_invocation = f"/{target}"
85
+ banner = (
86
+ f"> ⚠️ /{stem} is deprecated; use {cluster_invocation} instead.\n"
87
+ f"> This shim is retained for one release cycle "
88
+ f"({DEPRECATED_IN} → next minor) and forwards to the same "
89
+ f"instructions below. See "
90
+ f"[`docs/contracts/command-clusters.md`]"
91
+ f"(../../docs/contracts/command-clusters.md).\n\n"
92
+ )
93
+
94
+ new_text = f"---\n{new_fm}\n---\n\n{banner}{body.lstrip(chr(10))}"
95
+ path.write_text(new_text, encoding="utf-8")
96
+ return f"OK {stem} → {target}"
97
+
98
+
99
+ def main() -> int:
100
+ results = []
101
+ for stem, target in PHASE2_SHIMS:
102
+ results.append(patch_file(stem, target))
103
+ for r in results:
104
+ print(r)
105
+ return 0
106
+
107
+
108
+ if __name__ == "__main__":
109
+ sys.exit(main())
@@ -70,6 +70,12 @@ Commands:
70
70
  Usage: chat-history:hook --platform <claude|augment|cursor|cline|windsurf|gemini>
71
71
  chat-history:checkpoint Append a phase-boundary entry to .agent-chat-history
72
72
  (CHECKPOINT fallback for platforms without native hooks)
73
+ roadmap-progress:hook PostToolUse hook entry point (read JSON from stdin)
74
+ Regenerates roadmaps-progress.md when a tool wrote under agents/roadmaps/
75
+ onboarding-gate:hook Hook entry point (drains stdin)
76
+ Writes .augment/state/onboarding-gate.json from .agent-settings.yml
77
+ context-hygiene:hook PostToolUse hook entry point (read JSON from stdin)
78
+ Maintains .augment/state/context-hygiene.json (turn count, loop, freshness)
73
79
  telemetry:record Append one artefact-engagement event (default-off)
74
80
  telemetry:status Print artefact-engagement telemetry status (read-only)
75
81
  telemetry:report Aggregate the engagement log into a quartile report
@@ -316,6 +322,27 @@ cmd_chat_history_hook() {
316
322
  exec python3 "$script" hook-dispatch "$@"
317
323
  }
318
324
 
325
+ cmd_roadmap_progress_hook() {
326
+ require_python3
327
+ local script
328
+ script="$(resolve_script "scripts/roadmap_progress_hook.py")" || return 1
329
+ exec python3 "$script" "$@"
330
+ }
331
+
332
+ cmd_onboarding_gate_hook() {
333
+ require_python3
334
+ local script
335
+ script="$(resolve_script "scripts/onboarding_gate_hook.py")" || return 1
336
+ exec python3 "$script" "$@"
337
+ }
338
+
339
+ cmd_context_hygiene_hook() {
340
+ require_python3
341
+ local script
342
+ script="$(resolve_script "scripts/context_hygiene_hook.py")" || return 1
343
+ exec python3 "$script" "$@"
344
+ }
345
+
319
346
  cmd_chat_history_checkpoint() {
320
347
  require_python3
321
348
  local script
@@ -436,6 +463,9 @@ main() {
436
463
  refine-ticket:detect) cmd_refine_ticket_detect "$@" ;;
437
464
  chat-history:hook) cmd_chat_history_hook "$@" ;;
438
465
  chat-history:checkpoint) cmd_chat_history_checkpoint "$@" ;;
466
+ roadmap-progress:hook) cmd_roadmap_progress_hook "$@" ;;
467
+ onboarding-gate:hook) cmd_onboarding_gate_hook "$@" ;;
468
+ context-hygiene:hook) cmd_context_hygiene_hook "$@" ;;
439
469
  telemetry:record) cmd_telemetry_record "$@" ;;
440
470
  telemetry:status) cmd_telemetry_status "$@" ;;
441
471
  telemetry:report) cmd_telemetry_report "$@" ;;
@@ -0,0 +1,45 @@
1
+ # One-off archive — 2026-05
2
+
3
+ > Archived per **Phase 0a.2** of `agents/roadmaps/road-to-rule-hardening.md`.
4
+ > Each script here was a single-purpose AI-council probe or measurement
5
+ > tied to a specific phase of `road-to-structural-optimization.md` (now
6
+ > archived) or `road-to-rule-hardening.md`. The session output lives
7
+ > under `agents/council-sessions/` (durable evidence) and the linter
8
+ > `scripts/check_one_off_location.py` enforces that no new
9
+ > `_one_off_*.py` lands outside this folder.
10
+
11
+ ## Lifecycle rule (uniform — Phase 0.2 of context-layer-maturity)
12
+
13
+ > A one-off is **archived**, never deleted. The session manifest under
14
+ > `agents/council-sessions/` is the audit trail; the script itself is
15
+ > kept here so a future contributor can re-read intent, re-run a probe
16
+ > on a future branch, or extract a reusable helper.
17
+
18
+ ## Inventory
19
+
20
+ | Script | Roadmap / Phase | Council session id |
21
+ |---|---|---|
22
+ | `_one_off_2a4_acceptance.py` | structural-optimization 2A.4 | various 2A sessions |
23
+ | `_one_off_context_layer_v1_estimate.py` | context-layer-maturity v1 cost estimate | `2026-05-03T17-56-21Z` |
24
+ | `_one_off_context_layer_v1_review.py` | context-layer-maturity v1 review | `2026-05-03T17-56-21Z` |
25
+ | `_one_off_followups_review.py` | road-to-1-16-followups review | session under `agents/council-sessions/` |
26
+ | `_one_off_nondestructive_inline_audit.py` | non-destructive-by-default audit | session under `agents/council-sessions/` |
27
+ | `_one_off_phase4_dispatch_latency.py` | structural-optimization 4.3.1 cluster latency benchmark | local benchmark, no council |
28
+ | `_one_off_phase6_trigger_jaccard.py` | structural-optimization Phase 6 trigger overlap | local measurement |
29
+ | `_one_off_phase_2a_budget_rebalance.py` | structural-optimization 2A budget rebalance | `2026-05-03T*` |
30
+ | `_one_off_phase_2a_post_revert.py` | structural-optimization 2A post-revert | `2026-05-03T*` |
31
+ | `_one_off_rebalancing_audit.py` | rebalancing roadmap audit | session under `agents/council-sessions/` |
32
+ | `_one_off_roundtrip.py` | council client roundtrip smoke test | local smoke test |
33
+ | `_one_off_rule_hardening_v1.py` | rule-hardening v1 review | `2026-05-03T19-16-25Z` |
34
+ | `_one_off_structural_open_questions.py` | structural-optimization open questions | session under `agents/council-sessions/` |
35
+ | `_one_off_structural_optimization.py` | structural-optimization initial review | session under `agents/council-sessions/` |
36
+ | `_one_off_structural_v3_gaps.py` | structural-optimization v3 gap audit | session under `agents/council-sessions/` |
37
+ | `_one_off_structural_v3_review.py` | structural-optimization v3 review | session under `agents/council-sessions/` |
38
+
39
+ ## Re-running an archived script
40
+
41
+ Imports may have shifted (e.g. `scripts.ai_council.*`). If a probe
42
+ needs to be re-run against a current branch, copy it back to its
43
+ original location, fix imports, run, then move the working copy
44
+ back here. Do **not** edit in place — keep the archive immutable
45
+ beyond cosmetic README updates.
@@ -0,0 +1,208 @@
1
+ """Council acceptance review of Phase 0.4 2A.4 worked example.
2
+
3
+ Purpose: Phase 0.4.3 of road-to-structural-optimization.md requires a
4
+ council acceptance pass on the 2A.4 obligation-keyword-diff contract
5
+ before Phase 2A may begin. The artefact lives at
6
+ `agents/roadmaps/structural-optimization-2A4-example.md` plus two
7
+ sandbox files. Status will move from `draft` to `locked` only on
8
+ ACCEPT or ACCEPT_WITH_REVISIONS where revisions are minor.
9
+
10
+ Invocation:
11
+ .venv/bin/python -m scripts.ai_council._one_off_2a4_acceptance
12
+ """
13
+ from __future__ import annotations
14
+
15
+ import sys
16
+ from pathlib import Path
17
+
18
+ from scripts.ai_council.bundler import bundle_files
19
+ from scripts.ai_council.clients import (
20
+ AnthropicClient,
21
+ OpenAIClient,
22
+ load_anthropic_key,
23
+ load_openai_key,
24
+ )
25
+ from scripts.ai_council.orchestrator import (
26
+ CostBudget,
27
+ CouncilQuestion,
28
+ consult,
29
+ estimate,
30
+ )
31
+ from scripts.ai_council.pricing import estimate_cost, load_prices
32
+ from scripts.ai_council.project_context import detect_project_context
33
+ from scripts.ai_council.session import SessionManifest, save as save_session
34
+
35
+ REPO_ROOT = Path(__file__).resolve().parents[2]
36
+ ARTEFACTS = [
37
+ REPO_ROOT / "agents/roadmaps/structural-optimization-2A4-example.md",
38
+ REPO_ROOT / "agents/roadmaps/examples/2A4-direct-answers/direct-answers.slim.md",
39
+ REPO_ROOT / "agents/roadmaps/examples/2A4-direct-answers/direct-answers-mechanics.md",
40
+ ]
41
+
42
+ ORIGINAL_ASK = (
43
+ "Phase 0.4 of road-to-structural-optimization v3.1 dry-runs the "
44
+ "2A.4 obligation-keyword-diff contract on `direct-answers.md` to "
45
+ "lock the contract before Phase 2A begins. The artefact and two "
46
+ "sandbox files (slim rule + extracted mechanics) are presented. "
47
+ "Council task: ACCEPT / ACCEPT_WITH_REVISIONS / REJECT the "
48
+ "contract for use across the remaining 8 always-rules in Phase 2A."
49
+ )
50
+
51
+ REVIEW_PROMPT = """\
52
+ # Council Acceptance Review — 2A.4 Worked Example
53
+
54
+ ## Context
55
+
56
+ The host agent ran Phase 0.4 of `road-to-structural-optimization` v3.1: \
57
+ took one always-rule (`direct-answers.md`, smallest of the top-3), split \
58
+ it into a slim RULE+LOGIC half and a MECHANICS context, then applied \
59
+ the 2A.4 obligation-keyword diff contract. The artefact is the report \
60
+ of that dry-run; the two sandbox files are the actual produced split.
61
+
62
+ You are not asked to re-litigate the v3.1 roadmap or the choice of \
63
+ `direct-answers.md` — both were settled in earlier rounds. Verdict \
64
+ solely concerns whether the **contract** (keyword × counts × \
65
+ accept-rationale table, plus its tie-break rules) is now ready to be \
66
+ applied to the remaining 8 always-rules in Phase 2A.
67
+
68
+ ## Output Contract (STRICT)
69
+
70
+ Produce exactly these blocks in order. Be decisive — total response \
71
+ budget <= 1200 words.
72
+
73
+ ```
74
+ ### Contract correctness
75
+
76
+ **Verdict:** <ACCEPT | ACCEPT_WITH_REVISIONS | REJECT>
77
+ **Keyword extraction completeness:** <COMPLETE | PARTIAL — list missing>
78
+ **Tie-break rules sufficient:** <YES | NO — name the gap>
79
+ **Required revisions (numbered, 1-3 max, only on ACCEPT_WITH_REVISIONS):**
80
+ 1. <one sentence — smallest change>
81
+ 2. <...>
82
+ 3. <...>
83
+ ```
84
+
85
+ ```
86
+ ### Sandbox split quality
87
+
88
+ **Slim file preserves all RULE+LOGIC obligations:** <YES | NO — list lost>
89
+ **Mechanics file holds only mechanics+examples:** <YES | NO — list misplaced>
90
+ **Round-trip: rule_slim + load_context(mechanics) == original behaviour:**
91
+ <YES | NO — name the divergence>
92
+ ```
93
+
94
+ ```
95
+ ### Generalisability to remaining 8 rules
96
+
97
+ **Contract scales without per-rule tuning:** <YES | NO — name failure mode>
98
+ **Single biggest risk on the next rule (likely `non-destructive-by-default`):**
99
+ <one sentence>
100
+ ```
101
+
102
+ ```
103
+ ### Final verdict
104
+
105
+ **Lockable as-is for Phase 2A?** <YES | NO>
106
+ **If NO, single blocking change required:** <one sentence>
107
+ ```
108
+
109
+ Verdict definitions:
110
+ - **ACCEPT** — contract ships unchanged; status moves to locked.
111
+ - **ACCEPT_WITH_REVISIONS** — locks after the 1-3 listed revisions land.
112
+ - **REJECT** — contract is structurally wrong; describe the fault.
113
+
114
+ The three artefacts follow this prompt verbatim.
115
+ """
116
+
117
+
118
+ def main() -> int:
119
+ anthropic = AnthropicClient(api_key=load_anthropic_key(), model="claude-sonnet-4-5")
120
+ openai = OpenAIClient(api_key=load_openai_key(), model="gpt-4o")
121
+ members = [anthropic, openai]
122
+
123
+ context = bundle_files(ARTEFACTS)
124
+ project = detect_project_context(REPO_ROOT)
125
+ table = load_prices()
126
+
127
+ user_prompt = REVIEW_PROMPT + "\n\n---\n\n" + context.text
128
+
129
+ question = CouncilQuestion(
130
+ mode="files",
131
+ user_prompt=user_prompt,
132
+ max_tokens=3072,
133
+ )
134
+
135
+ estimates = estimate(
136
+ question, members, table, project=project, original_ask=ORIGINAL_ASK,
137
+ )
138
+ print("=== ESTIMATE (single round, max tokens) ===")
139
+ total_est = 0.0
140
+ for c, e in zip(members, estimates):
141
+ print(f" {c.name}/{c.model}: ~{e.input_tokens} in + {e.output_tokens} out = ${e.total_usd:.4f}")
142
+ total_est += e.total_usd
143
+ print(f" TOTAL per round (max): ${total_est:.4f}")
144
+ print()
145
+
146
+ budget = CostBudget(
147
+ max_input_tokens=200_000,
148
+ max_output_tokens=80_000,
149
+ max_calls=20,
150
+ max_total_usd=2.50,
151
+ )
152
+
153
+ rounds_collected: list[list] = []
154
+
155
+ def _on_round_complete(round_idx: int, round_responses) -> None:
156
+ rounds_collected.append(list(round_responses))
157
+ print(f"=== ROUND {round_idx + 1} COMPLETE ===")
158
+ for r in round_responses:
159
+ if r.error:
160
+ print(f" [error] {r.provider}/{r.model}: {r.error}")
161
+ continue
162
+ actual = estimate_cost(r.provider, r.model, r.input_tokens, r.output_tokens, table)
163
+ print(f" [done] {r.provider}/{r.model}: {r.input_tokens} in / "
164
+ f"{r.output_tokens} out · {r.latency_ms} ms · ${actual.total_usd:.4f}")
165
+ print()
166
+
167
+ print("=== CONSULT (1 round, 2A.4 acceptance review) ===")
168
+ consult(
169
+ members, question, budget,
170
+ rounds=1,
171
+ on_round_complete=_on_round_complete,
172
+ table=table, project=project, original_ask=ORIGINAL_ASK,
173
+ )
174
+
175
+ if not rounds_collected:
176
+ print("[error] no rounds completed", file=sys.stderr)
177
+ return 1
178
+
179
+ actual_total = 0.0
180
+ for round_responses in rounds_collected:
181
+ for r in round_responses:
182
+ if r.error:
183
+ continue
184
+ actual = estimate_cost(r.provider, r.model, r.input_tokens, r.output_tokens, table)
185
+ actual_total += actual.total_usd
186
+ print(f"=== TOTAL ACTUAL: ${actual_total:.4f} ===")
187
+
188
+ final_round = rounds_collected[-1]
189
+ if not [r for r in final_round if not r.error]:
190
+ return 1
191
+
192
+ manifest = SessionManifest(
193
+ mode="files",
194
+ artefact="agents/roadmaps/structural-optimization-2A4-example.md",
195
+ original_ask=ORIGINAL_ASK,
196
+ members=[f"{r.provider}/{r.model}" for r in final_round],
197
+ rounds=len(rounds_collected),
198
+ cost_usd_estimated=total_est,
199
+ cost_usd_actual=actual_total,
200
+ extra={"purpose": "Council acceptance review of Phase 0.4 2A.4 worked example"},
201
+ )
202
+ session_dir = save_session(manifest=manifest, responses=rounds_collected)
203
+ print(f"[saved] {session_dir.relative_to(REPO_ROOT)}/")
204
+ return 1 if any(r.error for round_r in rounds_collected for r in round_r) else 0
205
+
206
+
207
+ if __name__ == "__main__":
208
+ raise SystemExit(main())
@@ -0,0 +1,206 @@
1
+ """Council audit of Budget-v2 result (Phase 4.5 of road-to-context-layer-maturity).
2
+
3
+ Phase 4 of road-to-context-layer-maturity selected two 4d-trim paths
4
+ (`direct-answers`, `no-cheap-questions`) from a fixed option set
5
+ documented in agents/contexts/budget-v2-matrix.md and shipped them.
6
+ Exit-gate actuals (run 2026-05-04): total 44,928 / 49,000 chars
7
+ (91.7 %, 4,072 chars headroom) — ≥ 4,000 headroom goal hit. Top-3
8
+ sum unchanged. Safety-floor rules untouched.
9
+
10
+ Phase 4.5 requires a council audit before archival: confirm the
11
+ trim choices were sound, no semantic drift introduced, no better
12
+ path missed inside the Phase 4 inputs gate.
13
+
14
+ Invocation:
15
+ .venv/bin/python -m scripts.ai_council.one_off_archive.2026-05._one_off_budget_v2_audit
16
+ """
17
+ from __future__ import annotations
18
+
19
+ import sys
20
+ from pathlib import Path
21
+
22
+ from scripts.ai_council.bundler import bundle_files
23
+ from scripts.ai_council.clients import (
24
+ AnthropicClient,
25
+ OpenAIClient,
26
+ load_anthropic_key,
27
+ load_openai_key,
28
+ )
29
+ from scripts.ai_council.orchestrator import (
30
+ CostBudget,
31
+ CouncilQuestion,
32
+ consult,
33
+ estimate,
34
+ )
35
+ from scripts.ai_council.pricing import estimate_cost, load_prices
36
+ from scripts.ai_council.project_context import detect_project_context
37
+ from scripts.ai_council.session import SessionManifest, save as save_session
38
+
39
+ REPO_ROOT = Path(__file__).resolve().parents[4]
40
+ ARTEFACTS = [
41
+ REPO_ROOT / "docs/contracts/load-context-budget-model.md",
42
+ REPO_ROOT / "agents/contexts/budget-v2-matrix.md",
43
+ REPO_ROOT / ".agent-src.uncompressed/rules/direct-answers.md",
44
+ REPO_ROOT / ".agent-src.uncompressed/rules/no-cheap-questions.md",
45
+ ]
46
+
47
+ ORIGINAL_ASK = (
48
+ "Phase 4 of road-to-context-layer-maturity trimmed two always-rules "
49
+ "(direct-answers, no-cheap-questions) under the locked Model (b) "
50
+ "literal budget contract, hitting the ≥ 4,000-chars headroom goal "
51
+ "(actual: 4,072). Council task: audit the trim choices for "
52
+ "soundness and semantic drift before roadmap archival."
53
+ )
54
+
55
+ REVIEW_PROMPT = """\
56
+ # Council Audit — Budget-v2 Trim Result (Phase 4.5)
57
+
58
+ ## Context
59
+
60
+ Phase 4 selected two 4d-trim paths from a fixed option set documented
61
+ in `budget-v2-matrix.md`. The matrix evaluated 4a (demote→auto), 4b
62
+ (merge), 4c (shared-context, locked at 3a Model (b) literal — no-op),
63
+ and 4d (compress prose) for every touchable always-rule. Safety-floor
64
+ rules (scope-control, non-destructive-by-default, commit-policy,
65
+ agent-authority) were untouchable. Outcome-untested rules were
66
+ restricted to 4d only per the Phase 4.0 inputs gate.
67
+
68
+ ## Selected paths and result
69
+
70
+ - **4d on `direct-answers`** — emoji-scope subsection trimmed,
71
+ failure-mode collapsed to pointer. Δ ext: 4,098 → 3,987 (−111).
72
+ - **4d on `no-cheap-questions`** — "What counts as cheap" subsection
73
+ collapsed to pointer at `asking-and-brevity-examples.md`. Δ ext:
74
+ 4,257 → 3,933 (−324).
75
+
76
+ Combined: −435 chars · headroom 3,637 → 4,072 (+435) · top-3 sum
77
+ unchanged · safety-floor rules untouched.
78
+
79
+ ## Audit questions (please address each)
80
+
81
+ 1. **Trim soundness** — do the surviving Iron Laws in both rules still
82
+ carry the rule's purpose, or did the prose trim sacrifice precision?
83
+ Cite the specific subsection if you find drift.
84
+
85
+ 2. **Path selection** — was 4d the right choice for these two rules
86
+ given the matrix? Or should one of the deferred paths (4a, 4b)
87
+ have been picked despite the matrix verdict?
88
+
89
+ 3. **Missed leverage** — inside the Phase 4 inputs gate (4d only on
90
+ outcome-untested rules; safety-floor untouchable), is there a
91
+ higher-leverage 4d target the matrix missed?
92
+
93
+ 4. **Headroom durability** — 4,072 chars is +72 over the 4,000 goal.
94
+ Is this margin stable against expected near-term rule edits, or
95
+ should Phase 5 be tightened to defend it?
96
+
97
+ ## Output Contract (STRICT)
98
+
99
+ ```
100
+ ### Verdict
101
+ **Trim choices sound:** <YES — archive · NO — escalate>
102
+ **One-sentence rationale:** <≤ 30 words>
103
+ ```
104
+
105
+ ```
106
+ ### Per-question findings (1–4 above)
107
+ 1. <≤ 2 sentences>
108
+ 2. <≤ 2 sentences>
109
+ 3. <≤ 2 sentences>
110
+ 4. <≤ 2 sentences>
111
+ ```
112
+
113
+ ```
114
+ ### Risk note
115
+ **Single biggest residual risk:** <one sentence>
116
+ **Mitigation (if any):** <one sentence or NONE>
117
+ ```
118
+
119
+ Be decisive — total response ≤ 800 words. Artefacts follow verbatim.
120
+ """
121
+
122
+
123
+ def main() -> int:
124
+ anthropic = AnthropicClient(api_key=load_anthropic_key(), model="claude-sonnet-4-5")
125
+ openai = OpenAIClient(api_key=load_openai_key(), model="gpt-4o")
126
+ members = [anthropic, openai]
127
+
128
+ context = bundle_files(ARTEFACTS)
129
+ project = detect_project_context(REPO_ROOT)
130
+ table = load_prices()
131
+
132
+ user_prompt = REVIEW_PROMPT + "\n\n---\n\n" + context.text
133
+
134
+ question = CouncilQuestion(mode="files", user_prompt=user_prompt, max_tokens=2048)
135
+
136
+ estimates = estimate(question, members, table, project=project, original_ask=ORIGINAL_ASK)
137
+ print("=== ESTIMATE (single round) ===")
138
+ total_est = 0.0
139
+ for c, e in zip(members, estimates):
140
+ print(f" {c.name}/{c.model}: ~{e.input_tokens} in + {e.output_tokens} out = ${e.total_usd:.4f}")
141
+ total_est += e.total_usd
142
+ print(f" TOTAL per round (max): ${total_est:.4f}\n")
143
+
144
+ budget = CostBudget(
145
+ max_input_tokens=200_000,
146
+ max_output_tokens=80_000,
147
+ max_calls=20,
148
+ max_total_usd=2.50,
149
+ )
150
+
151
+ rounds_collected: list[list] = []
152
+
153
+ def _on_round_complete(round_idx: int, round_responses) -> None:
154
+ rounds_collected.append(list(round_responses))
155
+ print(f"=== ROUND {round_idx + 1} COMPLETE ===")
156
+ for r in round_responses:
157
+ if r.error:
158
+ print(f" [error] {r.provider}/{r.model}: {r.error}")
159
+ continue
160
+ actual = estimate_cost(r.provider, r.model, r.input_tokens, r.output_tokens, table)
161
+ print(f" [done] {r.provider}/{r.model}: {r.input_tokens} in / "
162
+ f"{r.output_tokens} out · {r.latency_ms} ms · ${actual.total_usd:.4f}")
163
+ print()
164
+
165
+ print("=== CONSULT (1 round, Phase 4.5 Budget-v2 audit) ===")
166
+ consult(
167
+ members, question, budget,
168
+ rounds=1,
169
+ on_round_complete=_on_round_complete,
170
+ table=table, project=project, original_ask=ORIGINAL_ASK,
171
+ )
172
+
173
+ if not rounds_collected:
174
+ print("[error] no rounds completed", file=sys.stderr)
175
+ return 1
176
+
177
+ actual_total = 0.0
178
+ for round_responses in rounds_collected:
179
+ for r in round_responses:
180
+ if r.error:
181
+ continue
182
+ actual = estimate_cost(r.provider, r.model, r.input_tokens, r.output_tokens, table)
183
+ actual_total += actual.total_usd
184
+ print(f"=== TOTAL ACTUAL: ${actual_total:.4f} ===")
185
+
186
+ final_round = rounds_collected[-1]
187
+ if not [r for r in final_round if not r.error]:
188
+ return 1
189
+
190
+ manifest = SessionManifest(
191
+ mode="files",
192
+ artefact="agents/roadmaps/road-to-context-layer-maturity.md",
193
+ original_ask=ORIGINAL_ASK,
194
+ members=[f"{r.provider}/{r.model}" for r in final_round],
195
+ rounds=len(rounds_collected),
196
+ cost_usd_estimated=total_est,
197
+ cost_usd_actual=actual_total,
198
+ extra={"purpose": "Phase 4.5 Budget-v2 trim-result audit"},
199
+ )
200
+ session_dir = save_session(manifest=manifest, responses=rounds_collected)
201
+ print(f"[saved] {session_dir.relative_to(REPO_ROOT)}/")
202
+ return 1 if any(r.error for round_r in rounds_collected for r in round_r) else 0
203
+
204
+
205
+ if __name__ == "__main__":
206
+ raise SystemExit(main())
@@ -0,0 +1,67 @@
1
+ """One-shot estimator for the v1 council review (no consult call).
2
+
3
+ Sibling of `_one_off_context_layer_v1_review.py`. Prints bundle size and
4
+ per-model token / cost projection so the user can confirm spend before
5
+ the actual consult fires.
6
+ """
7
+ from __future__ import annotations
8
+
9
+ from pathlib import Path
10
+
11
+ from scripts.ai_council._one_off_context_layer_v1_review import (
12
+ ORIGINAL_ASK,
13
+ REVIEW_PROMPT_HEADER,
14
+ ROADMAP_PATH,
15
+ _diff_stat,
16
+ _pr_body,
17
+ )
18
+ from scripts.ai_council.bundler import bundle_prompt
19
+ from scripts.ai_council.clients import (
20
+ AnthropicClient,
21
+ OpenAIClient,
22
+ load_anthropic_key,
23
+ load_openai_key,
24
+ )
25
+ from scripts.ai_council.orchestrator import CouncilQuestion, estimate
26
+ from scripts.ai_council.pricing import load_prices
27
+ from scripts.ai_council.project_context import detect_project_context
28
+
29
+ REPO_ROOT = Path(__file__).resolve().parents[2]
30
+
31
+
32
+ def main() -> int:
33
+ roadmap_text = ROADMAP_PATH.read_text(encoding="utf-8")
34
+ parts = [
35
+ REVIEW_PROMPT_HEADER,
36
+ "## PR #36 — diff --stat\n\n```\n" + _diff_stat() + "\n```",
37
+ "## PR #36 — body\n\n" + _pr_body(),
38
+ "## Roadmap v1\n\n" + roadmap_text,
39
+ ]
40
+ bundle_text = "\n\n---\n\n".join(parts)
41
+ print(f"Bundle bytes: {len(bundle_text.encode('utf-8'))}")
42
+
43
+ ctx = bundle_prompt(bundle_text)
44
+ project = detect_project_context(REPO_ROOT)
45
+ table = load_prices()
46
+
47
+ anthropic = AnthropicClient(api_key=load_anthropic_key(), model="claude-sonnet-4-5")
48
+ openai = OpenAIClient(api_key=load_openai_key(), model="gpt-4o")
49
+ members = [anthropic, openai]
50
+
51
+ question = CouncilQuestion(mode="prompt", user_prompt=ctx.text, max_tokens=4096)
52
+ estimates = estimate(
53
+ question, members, table, project=project, original_ask=ORIGINAL_ASK,
54
+ )
55
+ total = 0.0
56
+ for c, e in zip(members, estimates):
57
+ print(
58
+ f" {c.name}/{c.model}: ~{e.input_tokens} in + "
59
+ f"{e.output_tokens} out = ${e.total_usd:.4f}"
60
+ )
61
+ total += e.total_usd
62
+ print(f" TOTAL (max, single round): ${total:.4f}")
63
+ return 0
64
+
65
+
66
+ if __name__ == "__main__":
67
+ raise SystemExit(main())