@event4u/agent-config 1.14.0 → 1.16.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 (293) hide show
  1. package/.agent-src/commands/agent-handoff.md +1 -1
  2. package/.agent-src/commands/bug-fix.md +3 -3
  3. package/.agent-src/commands/bug-investigate.md +2 -2
  4. package/.agent-src/commands/chat-history-checkpoint.md +3 -3
  5. package/.agent-src/commands/chat-history-clear.md +2 -2
  6. package/.agent-src/commands/chat-history-resume.md +2 -2
  7. package/.agent-src/commands/chat-history.md +3 -3
  8. package/.agent-src/commands/check-current-md.md +44 -33
  9. package/.agent-src/commands/commit-in-chunks.md +43 -23
  10. package/.agent-src/commands/compress.md +34 -2
  11. package/.agent-src/commands/council-design.md +96 -0
  12. package/.agent-src/commands/council-optimize.md +115 -0
  13. package/.agent-src/commands/council-pr.md +123 -0
  14. package/.agent-src/commands/council.md +219 -0
  15. package/.agent-src/commands/create-pr.md +23 -0
  16. package/.agent-src/commands/do-and-judge.md +3 -3
  17. package/.agent-src/commands/do-in-steps.md +4 -4
  18. package/.agent-src/commands/e2e-heal.md +1 -1
  19. package/.agent-src/commands/e2e-plan.md +1 -1
  20. package/.agent-src/commands/feature-dev.md +8 -0
  21. package/.agent-src/commands/feature-explore.md +6 -1
  22. package/.agent-src/commands/feature-plan.md +33 -2
  23. package/.agent-src/commands/feature-refactor.md +5 -0
  24. package/.agent-src/commands/feature-roadmap.md +8 -3
  25. package/.agent-src/commands/feature.md +58 -0
  26. package/.agent-src/commands/fix-ci.md +5 -0
  27. package/.agent-src/commands/fix-portability.md +7 -2
  28. package/.agent-src/commands/fix-pr-bot-comments.md +5 -0
  29. package/.agent-src/commands/fix-pr-comments.md +5 -0
  30. package/.agent-src/commands/fix-pr-developer-comments.md +5 -0
  31. package/.agent-src/commands/fix-references.md +5 -0
  32. package/.agent-src/commands/fix-seeder.md +5 -0
  33. package/.agent-src/commands/fix.md +60 -0
  34. package/.agent-src/commands/jira-ticket.md +1 -1
  35. package/.agent-src/commands/judge.md +1 -1
  36. package/.agent-src/commands/memory-add.md +3 -3
  37. package/.agent-src/commands/memory-full.md +2 -2
  38. package/.agent-src/commands/memory-promote.md +2 -2
  39. package/.agent-src/commands/mode.md +5 -5
  40. package/.agent-src/commands/onboard.md +17 -8
  41. package/.agent-src/commands/optimize-agents.md +6 -1
  42. package/.agent-src/commands/optimize-augmentignore.md +14 -0
  43. package/.agent-src/commands/optimize-rtk-filters.md +5 -0
  44. package/.agent-src/commands/optimize-skills.md +6 -1
  45. package/.agent-src/commands/optimize.md +54 -0
  46. package/.agent-src/commands/propose-memory.md +2 -2
  47. package/.agent-src/commands/refine-ticket.md +9 -7
  48. package/.agent-src/commands/review-changes.md +61 -9
  49. package/.agent-src/commands/review-routing.md +1 -1
  50. package/.agent-src/commands/roadmap-create.md +42 -4
  51. package/.agent-src/commands/roadmap-execute.md +9 -7
  52. package/.agent-src/commands/set-cost-profile.md +11 -3
  53. package/.agent-src/commands/sync-agent-settings.md +11 -2
  54. package/.agent-src/commands/tests-create.md +1 -1
  55. package/.agent-src/commands/tests-execute.md +2 -3
  56. package/.agent-src/commands/upstream-contribute.md +1 -1
  57. package/.agent-src/contexts/authority/commit-mechanics.md +57 -0
  58. package/.agent-src/contexts/authority/destructive-mechanics.md +66 -0
  59. package/.agent-src/contexts/authority/scope-mechanics.md +87 -0
  60. package/.agent-src/contexts/execution/autonomy-detection.md +54 -0
  61. package/.agent-src/contexts/execution/autonomy-examples.md +90 -0
  62. package/.agent-src/contexts/execution/autonomy-mechanics.md +29 -0
  63. package/.agent-src/contexts/execution/verification-mechanics.md +80 -0
  64. package/.agent-src/personas/README.md +1 -1
  65. package/.agent-src/rules/agent-authority.md +24 -0
  66. package/.agent-src/rules/architecture.md +1 -1
  67. package/.agent-src/rules/artifact-drafting-protocol.md +1 -1
  68. package/.agent-src/rules/artifact-engagement-recording.md +2 -2
  69. package/.agent-src/rules/ask-when-uncertain.md +1 -1
  70. package/.agent-src/rules/augment-portability.md +56 -37
  71. package/.agent-src/rules/autonomous-execution.md +78 -114
  72. package/.agent-src/rules/capture-learnings.md +1 -1
  73. package/.agent-src/rules/chat-history-cadence.md +109 -0
  74. package/.agent-src/rules/chat-history-ownership.md +123 -0
  75. package/.agent-src/rules/chat-history-visibility.md +96 -0
  76. package/.agent-src/rules/cli-output-handling.md +1 -1
  77. package/.agent-src/rules/{command-suggestion.md → command-suggestion-policy.md} +10 -9
  78. package/.agent-src/rules/commit-conventions.md +1 -1
  79. package/.agent-src/rules/commit-policy.md +43 -61
  80. package/.agent-src/rules/context-hygiene.md +3 -3
  81. package/.agent-src/rules/direct-answers.md +2 -2
  82. package/.agent-src/rules/docs-sync.md +1 -1
  83. package/.agent-src/rules/e2e-testing.md +1 -1
  84. package/.agent-src/rules/guidelines.md +4 -4
  85. package/.agent-src/rules/improve-before-implement.md +2 -2
  86. package/.agent-src/rules/language-and-tone.md +41 -96
  87. package/.agent-src/rules/minimal-safe-diff.md +3 -3
  88. package/.agent-src/rules/model-recommendation.md +4 -4
  89. package/.agent-src/rules/no-cheap-questions.md +89 -0
  90. package/.agent-src/rules/non-destructive-by-default.md +25 -59
  91. package/.agent-src/rules/onboarding-gate.md +5 -5
  92. package/.agent-src/rules/review-routing-awareness.md +9 -9
  93. package/.agent-src/rules/roadmap-progress-sync.md +132 -80
  94. package/.agent-src/rules/role-mode-adherence.md +3 -3
  95. package/.agent-src/rules/scope-control.md +65 -46
  96. package/.agent-src/rules/security-sensitive-stop.md +2 -2
  97. package/.agent-src/rules/size-enforcement.md +3 -2
  98. package/.agent-src/rules/think-before-action.md +5 -5
  99. package/.agent-src/rules/token-efficiency.md +4 -4
  100. package/.agent-src/rules/{ui-audit-before-build.md → ui-audit-gate.md} +3 -3
  101. package/.agent-src/rules/user-interaction.md +31 -7
  102. package/.agent-src/rules/verify-before-complete.md +12 -67
  103. package/.agent-src/scripts/update_roadmap_progress.py +65 -8
  104. package/.agent-src/skills/ai-council/SKILL.md +333 -0
  105. package/.agent-src/skills/api-endpoint/SKILL.md +2 -2
  106. package/.agent-src/skills/blade-ui/SKILL.md +30 -11
  107. package/.agent-src/skills/blast-radius-analyzer/SKILL.md +1 -1
  108. package/.agent-src/skills/bug-analyzer/SKILL.md +1 -1
  109. package/.agent-src/skills/command-routing/SKILL.md +1 -1
  110. package/.agent-src/skills/command-writing/SKILL.md +16 -5
  111. package/.agent-src/skills/conventional-commits-writing/SKILL.md +1 -1
  112. package/.agent-src/skills/copilot-agents-optimization/SKILL.md +2 -2
  113. package/.agent-src/skills/developer-like-execution/SKILL.md +2 -2
  114. package/.agent-src/skills/existing-ui-audit/SKILL.md +24 -9
  115. package/.agent-src/skills/fe-design/SKILL.md +20 -15
  116. package/.agent-src/skills/file-editor/SKILL.md +9 -0
  117. package/.agent-src/skills/flux/SKILL.md +1 -1
  118. package/.agent-src/skills/git-workflow/SKILL.md +1 -1
  119. package/.agent-src/skills/guideline-writing/SKILL.md +11 -11
  120. package/.agent-src/skills/learning-to-rule-or-skill/SKILL.md +4 -4
  121. package/.agent-src/skills/livewire/SKILL.md +27 -8
  122. package/.agent-src/skills/override-management/SKILL.md +2 -2
  123. package/.agent-src/skills/php-coder/SKILL.md +1 -1
  124. package/.agent-src/skills/playwright-testing/SKILL.md +2 -2
  125. package/.agent-src/skills/readme-reviewer/SKILL.md +1 -1
  126. package/.agent-src/skills/readme-writing/SKILL.md +1 -1
  127. package/.agent-src/skills/readme-writing-package/SKILL.md +1 -1
  128. package/.agent-src/skills/receiving-code-review/SKILL.md +1 -1
  129. package/.agent-src/skills/refine-ticket/SKILL.md +30 -24
  130. package/.agent-src/skills/review-routing/SKILL.md +2 -2
  131. package/.agent-src/skills/roadmap-management/SKILL.md +22 -16
  132. package/.agent-src/skills/rule-writing/SKILL.md +1 -1
  133. package/.agent-src/skills/skill-reviewer/SKILL.md +1 -1
  134. package/.agent-src/skills/skill-writing/SKILL.md +6 -6
  135. package/.agent-src/skills/subagent-orchestration/SKILL.md +1 -0
  136. package/.agent-src/skills/systematic-debugging/SKILL.md +1 -1
  137. package/.agent-src/skills/upstream-contribute/SKILL.md +3 -3
  138. package/.agent-src/skills/validate-feature-fit/SKILL.md +2 -2
  139. package/.agent-src/skills/{verify-before-complete → verify-completion-evidence}/SKILL.md +2 -2
  140. package/.agent-src/templates/agent-settings.md +9 -9
  141. package/.agent-src/templates/contexts/auth-model.md +1 -1
  142. package/.agent-src/templates/roadmaps.md +9 -8
  143. package/.agent-src/templates/scripts/README.md +2 -2
  144. package/.agent-src/templates/scripts/memory_lookup.py +1 -1
  145. package/.agent-src/templates/scripts/telemetry/aggregator.py +16 -1
  146. package/.agent-src/templates/scripts/telemetry/engagement.py +59 -0
  147. package/.agent-src/templates/scripts/telemetry/report_renderer.py +28 -1
  148. package/.agent-src/templates/scripts/telemetry_record.py +14 -1
  149. package/.agent-src/templates/scripts/work_engine/__init__.py +2 -2
  150. package/.agent-src/templates/scripts/work_engine/cli.py +64 -461
  151. package/.agent-src/templates/scripts/work_engine/cli_args.py +116 -0
  152. package/.agent-src/templates/scripts/work_engine/delivery_state.py +3 -3
  153. package/.agent-src/templates/scripts/work_engine/directives/backend/__init__.py +1 -1
  154. package/.agent-src/templates/scripts/work_engine/directives/backend/implement.py +1 -1
  155. package/.agent-src/templates/scripts/work_engine/directives/backend/memory.py +1 -1
  156. package/.agent-src/templates/scripts/work_engine/directives/backend/plan.py +1 -1
  157. package/.agent-src/templates/scripts/work_engine/directives/backend/report.py +1 -1
  158. package/.agent-src/templates/scripts/work_engine/dispatcher.py +1 -1
  159. package/.agent-src/templates/scripts/work_engine/emitters.py +43 -0
  160. package/.agent-src/templates/scripts/work_engine/errors.py +19 -0
  161. package/.agent-src/templates/scripts/work_engine/hook_bootstrap.py +76 -0
  162. package/.agent-src/templates/scripts/work_engine/input_builders.py +163 -0
  163. package/.agent-src/templates/scripts/work_engine/migration/v0_to_v1.py +34 -2
  164. package/.agent-src/templates/scripts/work_engine/persona_policy.py +1 -1
  165. package/.agent-src/templates/scripts/work_engine/resolvers/prompt.py +1 -1
  166. package/.agent-src/templates/scripts/work_engine/state_io.py +202 -0
  167. package/.claude-plugin/marketplace.json +10 -2
  168. package/AGENTS.md +16 -12
  169. package/CHANGELOG.md +206 -9
  170. package/README.md +51 -52
  171. package/config/agent-settings.template.yml +58 -1
  172. package/config/gitignore-block.txt +3 -0
  173. package/docs/MIGRATION.md +122 -0
  174. package/docs/architecture.md +83 -34
  175. package/docs/catalog.md +331 -0
  176. package/docs/contracts/STABILITY.md +134 -0
  177. package/docs/contracts/adr-chat-history-split.md +132 -0
  178. package/docs/contracts/adr-command-suggestion.md +146 -0
  179. package/docs/contracts/adr-implement-ticket-runtime.md +122 -0
  180. package/docs/contracts/adr-product-ui-track.md +384 -0
  181. package/docs/contracts/adr-prompt-driven-execution.md +187 -0
  182. package/docs/contracts/agent-memory-contract.md +149 -0
  183. package/docs/contracts/artifact-engagement-flow.md +262 -0
  184. package/docs/contracts/command-clusters.md +126 -0
  185. package/docs/contracts/command-suggestion-flow.md +148 -0
  186. package/docs/contracts/implement-ticket-flow.md +628 -0
  187. package/docs/contracts/linear-ai-rules-inclusion.md +143 -0
  188. package/docs/contracts/linear-ai-three-layers.md +131 -0
  189. package/docs/contracts/load-context-schema.md +186 -0
  190. package/docs/contracts/rule-interactions.md +107 -0
  191. package/docs/contracts/rule-interactions.yml +238 -0
  192. package/docs/contracts/rule-priority-hierarchy.md +87 -0
  193. package/docs/contracts/ui-stack-extension.md +236 -0
  194. package/docs/contracts/ui-track-flow.md +338 -0
  195. package/docs/customization.md +14 -0
  196. package/docs/end-to-end-walkthroughs.md +165 -0
  197. package/docs/getting-started.md +27 -9
  198. package/docs/github-topics.md +12 -3
  199. package/docs/guidelines/agent-infra/language-and-tone-examples.md +79 -0
  200. package/{.agent-src → docs}/guidelines/docs/readme-size-and-splitting.md +26 -25
  201. package/docs/guidelines/php/git.md +164 -0
  202. package/docs/installation.md +42 -6
  203. package/docs/migrations/commands-1.15.0.md +112 -0
  204. package/docs/showcase.md +9 -4
  205. package/docs/skills-catalog.md +14 -8
  206. package/docs/ui-track-mental-model.md +121 -0
  207. package/llms.txt +13 -7
  208. package/package.json +1 -1
  209. package/scripts/agent-config +23 -0
  210. package/scripts/ai_council/__init__.py +39 -0
  211. package/scripts/ai_council/_default_prices.py +41 -0
  212. package/scripts/ai_council/_one_off_rebalancing_audit.py +149 -0
  213. package/scripts/ai_council/_one_off_roundtrip.py +106 -0
  214. package/scripts/ai_council/budget_guard.py +172 -0
  215. package/scripts/ai_council/bundler.py +261 -0
  216. package/scripts/ai_council/clients.py +381 -0
  217. package/scripts/ai_council/modes.py +127 -0
  218. package/scripts/ai_council/orchestrator.py +350 -0
  219. package/scripts/ai_council/pricing.py +213 -0
  220. package/scripts/ai_council/project_context.py +159 -0
  221. package/scripts/ai_council/prompts.py +232 -0
  222. package/scripts/ai_council/session.py +144 -0
  223. package/scripts/build_linear_digest.py +4 -4
  224. package/scripts/check_always_budget.py +126 -0
  225. package/scripts/check_augmentignore.py +69 -0
  226. package/scripts/check_command_count_messaging.py +120 -0
  227. package/scripts/check_portability.py +57 -0
  228. package/scripts/check_public_catalog_links.py +122 -0
  229. package/scripts/check_public_links.py +185 -0
  230. package/scripts/check_references.py +5 -1
  231. package/scripts/check_roadmap_trackable.py +111 -0
  232. package/scripts/command_suggester/cooldown.py +1 -1
  233. package/scripts/generate_index.py +266 -0
  234. package/scripts/install_anthropic_key.sh +5 -0
  235. package/scripts/install_openai_key.sh +106 -0
  236. package/scripts/lint_load_context.py +163 -0
  237. package/scripts/lint_no_new_atomic_commands.py +179 -0
  238. package/scripts/lint_rule_interactions.py +149 -0
  239. package/scripts/memory_lookup.py +1 -1
  240. package/scripts/release.py +297 -64
  241. package/scripts/schemas/command.schema.json +20 -0
  242. package/scripts/schemas/rule.schema.json +10 -0
  243. package/scripts/skill_linter.py +26 -4
  244. package/scripts/sync_agent_settings.py +1 -1
  245. package/scripts/update_counts.py +19 -4
  246. package/scripts/update_prices.py +124 -0
  247. package/.agent-src/guidelines/php/git.md +0 -96
  248. package/.agent-src/rules/chat-history.md +0 -200
  249. /package/.agent-src/rules/{slash-commands.md → slash-command-routing-policy.md} +0 -0
  250. /package/{.agent-src → docs}/guidelines/agent-infra/agent-interaction-and-decision-quality.md +0 -0
  251. /package/{.agent-src → docs}/guidelines/agent-infra/break-glass-usage.md +0 -0
  252. /package/{.agent-src → docs}/guidelines/agent-infra/developer-judgment.md +0 -0
  253. /package/{.agent-src → docs}/guidelines/agent-infra/engineering-memory-data-format.md +0 -0
  254. /package/{.agent-src → docs}/guidelines/agent-infra/layered-settings.md +0 -0
  255. /package/{.agent-src → docs}/guidelines/agent-infra/memory-access.md +0 -0
  256. /package/{.agent-src → docs}/guidelines/agent-infra/naming.md +0 -0
  257. /package/{.agent-src → docs}/guidelines/agent-infra/output-patterns.md +0 -0
  258. /package/{.agent-src → docs}/guidelines/agent-infra/review-routing-data-format.md +0 -0
  259. /package/{.agent-src → docs}/guidelines/agent-infra/role-contracts.md +0 -0
  260. /package/{.agent-src → docs}/guidelines/agent-infra/role-mode-router.md +0 -0
  261. /package/{.agent-src → docs}/guidelines/agent-infra/runtime-layer.md +0 -0
  262. /package/{.agent-src → docs}/guidelines/agent-infra/self-improvement-pipeline.md +0 -0
  263. /package/{.agent-src → docs}/guidelines/agent-infra/size-and-scope.md +0 -0
  264. /package/{.agent-src → docs}/guidelines/agent-infra/tool-integration.md +0 -0
  265. /package/{.agent-src → docs}/guidelines/e2e/playwright.md +0 -0
  266. /package/{.agent-src → docs}/guidelines/php/api-design.md +0 -0
  267. /package/{.agent-src → docs}/guidelines/php/artisan-commands.md +0 -0
  268. /package/{.agent-src → docs}/guidelines/php/blade-ui.md +0 -0
  269. /package/{.agent-src → docs}/guidelines/php/controllers.md +0 -0
  270. /package/{.agent-src → docs}/guidelines/php/database.md +0 -0
  271. /package/{.agent-src → docs}/guidelines/php/eloquent.md +0 -0
  272. /package/{.agent-src → docs}/guidelines/php/flux.md +0 -0
  273. /package/{.agent-src → docs}/guidelines/php/general.md +0 -0
  274. /package/{.agent-src → docs}/guidelines/php/jobs.md +0 -0
  275. /package/{.agent-src → docs}/guidelines/php/livewire.md +0 -0
  276. /package/{.agent-src → docs}/guidelines/php/logging.md +0 -0
  277. /package/{.agent-src → docs}/guidelines/php/naming.md +0 -0
  278. /package/{.agent-src → docs}/guidelines/php/patterns/dependency-injection.md +0 -0
  279. /package/{.agent-src → docs}/guidelines/php/patterns/dtos.md +0 -0
  280. /package/{.agent-src → docs}/guidelines/php/patterns/events.md +0 -0
  281. /package/{.agent-src → docs}/guidelines/php/patterns/factory.md +0 -0
  282. /package/{.agent-src → docs}/guidelines/php/patterns/pipelines.md +0 -0
  283. /package/{.agent-src → docs}/guidelines/php/patterns/policies.md +0 -0
  284. /package/{.agent-src → docs}/guidelines/php/patterns/repositories.md +0 -0
  285. /package/{.agent-src → docs}/guidelines/php/patterns/service-layer.md +0 -0
  286. /package/{.agent-src → docs}/guidelines/php/patterns/strategy.md +0 -0
  287. /package/{.agent-src → docs}/guidelines/php/patterns.md +0 -0
  288. /package/{.agent-src → docs}/guidelines/php/performance.md +0 -0
  289. /package/{.agent-src → docs}/guidelines/php/resources.md +0 -0
  290. /package/{.agent-src → docs}/guidelines/php/security.md +0 -0
  291. /package/{.agent-src → docs}/guidelines/php/sql.md +0 -0
  292. /package/{.agent-src → docs}/guidelines/php/validations.md +0 -0
  293. /package/{.agent-src → docs}/guidelines/php/websocket.md +0 -0
@@ -20,10 +20,13 @@ Pipeline:
20
20
  push the tag (this triggers publish-npm.yml).
21
21
  9. GitHub Release — `gh release create X.Y.Z --notes <changelog>`.
22
22
 
23
- Idempotency is intentionally limited: this script mutates git state, so
24
- re-running after a partial failure needs a clean tree. Each step prints
25
- what it's about to do before doing it, so a crash leaves a recoverable
26
- trail.
23
+ Idempotency: pass `--resume` to recover from a partial failure. Each
24
+ step then probes existing state (branch, commit, PR, tag, GitHub
25
+ Release) and skips work that is already done, instead of erroring out.
26
+ Without `--resume` the pipeline still mutates git/network state, so
27
+ re-running on a dirty tree needs `--resume` (or a manual cleanup).
28
+ Each step prints what it's about to do before doing it, so a crash
29
+ leaves a recoverable trail.
27
30
 
28
31
  Stdlib-only (Python 3.10+). No third-party runtime dependencies.
29
32
  """
@@ -183,6 +186,61 @@ def have(bin: str) -> bool:
183
186
  )
184
187
 
185
188
 
189
+ # ─── resume-mode state probes ────────────────────────────────────────────────
190
+
191
+
192
+ def _branch_exists_local(branch: str) -> bool:
193
+ r = run(
194
+ "git", "rev-parse", "--verify", "--quiet", f"refs/heads/{branch}",
195
+ check=False, capture=True,
196
+ )
197
+ return r.returncode == 0
198
+
199
+
200
+ def _branch_exists_remote(branch: str) -> bool:
201
+ r = run(
202
+ "git", "ls-remote", "--exit-code", "--heads", REMOTE, branch,
203
+ check=False, capture=True,
204
+ )
205
+ return r.returncode == 0
206
+
207
+
208
+ def _tag_exists_local(tag: str) -> bool:
209
+ return tag in git("tag", "-l", tag, capture=True).splitlines()
210
+
211
+
212
+ def _tag_exists_remote(tag: str) -> bool:
213
+ r = run(
214
+ "git", "ls-remote", "--exit-code", "--tags", REMOTE, tag,
215
+ check=False, capture=True,
216
+ )
217
+ return r.returncode == 0
218
+
219
+
220
+ def _pr_for_branch(branch: str) -> dict | None:
221
+ """Most recent PR (any state) with `release/X.Y.Z` as head, or None."""
222
+ r = run(
223
+ "gh", "pr", "list",
224
+ "--head", branch,
225
+ "--state", "all",
226
+ "--json", "number,state,url",
227
+ "--limit", "1",
228
+ check=False, capture=True,
229
+ )
230
+ if r.returncode != 0:
231
+ return None
232
+ try:
233
+ items = json.loads(r.stdout or "[]")
234
+ except json.JSONDecodeError:
235
+ return None
236
+ return items[0] if items else None
237
+
238
+
239
+ def _release_exists(tag: str) -> bool:
240
+ r = run("gh", "release", "view", tag, check=False, capture=True)
241
+ return r.returncode == 0
242
+
243
+
186
244
  # ─── version math ─────────────────────────────────────────────────────────────
187
245
 
188
246
 
@@ -353,8 +411,21 @@ def set_marketplace_version(path: Path, version: str) -> None:
353
411
  # ─── preflight ────────────────────────────────────────────────────────────────
354
412
 
355
413
 
356
- def preflight(target: str) -> None:
357
- """Fail fast on conditions that would break the release mid-flight."""
414
+ def preflight(target: str, *, resume: bool = False) -> None:
415
+ """Fail fast on conditions that would break the release mid-flight.
416
+
417
+ In ``--resume`` mode two invariants are relaxed:
418
+
419
+ * The starting branch may be ``release/{target}`` in addition to
420
+ ``main`` — both are valid resume positions (mid-pipeline crash
421
+ after step 1 leaves you on the release branch).
422
+ * The target-tag-exists check is dropped — execute() probes for
423
+ existing tags/releases and skips them.
424
+
425
+ Tree cleanliness, gh auth, and ``main`` in-sync with origin are
426
+ still enforced, so resuming has the same starting posture as a
427
+ fresh run; only step-level outcomes differ.
428
+ """
358
429
  for b in ("git", "gh"):
359
430
  if not have(b):
360
431
  die(f"{b!r} not found on PATH")
@@ -368,7 +439,14 @@ def preflight(target: str) -> None:
368
439
  die("gh is not authenticated; run `gh auth login` first")
369
440
 
370
441
  branch = git("rev-parse", "--abbrev-ref", "HEAD", capture=True)
371
- if branch != MAIN_BRANCH:
442
+ release_branch = f"release/{target}"
443
+ allowed = {MAIN_BRANCH, release_branch} if resume else {MAIN_BRANCH}
444
+ if branch not in allowed:
445
+ if resume:
446
+ die(
447
+ f"resume must run from {MAIN_BRANCH!r} or {release_branch!r}, "
448
+ f"currently on {branch!r}"
449
+ )
372
450
  die(f"release must run from {MAIN_BRANCH!r}, currently on {branch!r}")
373
451
 
374
452
  porcelain = git("status", "--porcelain", capture=True)
@@ -380,17 +458,24 @@ def preflight(target: str) -> None:
380
458
  # about to create a new tag anyway — local drift (e.g. from renamed
381
459
  # release-please tags) should not block the fetch.
382
460
  run("git", "fetch", REMOTE, "--tags", "--prune", "--force", capture=True)
383
- local = git("rev-parse", "HEAD", capture=True)
384
- remote = git("rev-parse", f"{REMOTE}/{MAIN_BRANCH}", capture=True)
385
- if local != remote:
386
- die(
387
- f"local {MAIN_BRANCH} is not in sync with {REMOTE}/{MAIN_BRANCH}; "
388
- "pull or push first"
389
- )
390
461
 
391
- tags = git("tag", "-l", target, capture=True).splitlines()
392
- if target in tags:
393
- die(f"tag {target!r} already exists; nothing to release")
462
+ # The local-in-sync-with-origin check only applies to main; if we're
463
+ # already on the release branch in resume mode, the relevant invariant
464
+ # is "main hasn't moved beyond what release/X.Y.Z branched off", which
465
+ # `git pull --ff-only` enforces in step 8 anyway.
466
+ if branch == MAIN_BRANCH:
467
+ local = git("rev-parse", "HEAD", capture=True)
468
+ remote = git("rev-parse", f"{REMOTE}/{MAIN_BRANCH}", capture=True)
469
+ if local != remote:
470
+ die(
471
+ f"local {MAIN_BRANCH} is not in sync with "
472
+ f"{REMOTE}/{MAIN_BRANCH}; pull or push first"
473
+ )
474
+
475
+ if not resume:
476
+ tags = git("tag", "-l", target, capture=True).splitlines()
477
+ if target in tags:
478
+ die(f"tag {target!r} already exists; nothing to release")
394
479
 
395
480
 
396
481
  # ─── plan ─────────────────────────────────────────────────────────────────────
@@ -436,7 +521,13 @@ def _step(n: int, total: int, msg: str) -> None:
436
521
  print(f"[{n}/{total}] {msg}")
437
522
 
438
523
 
439
- def execute(plan: Plan, *, wait_for_checks: bool, dry_run: bool) -> None:
524
+ def execute(
525
+ plan: Plan,
526
+ *,
527
+ wait_for_checks: bool,
528
+ dry_run: bool,
529
+ resume: bool = False,
530
+ ) -> None:
440
531
  branch = f"release/{plan.target}"
441
532
  total = 9
442
533
 
@@ -444,57 +535,129 @@ def execute(plan: Plan, *, wait_for_checks: bool, dry_run: bool) -> None:
444
535
  print("(dry-run) no git/gh mutations will be performed.")
445
536
  return
446
537
 
447
- _step(1, total, f"Create branch {branch}")
448
- run("git", "checkout", "-b", branch)
449
-
450
- _step(2, total, "Bump package.json + marketplace.json, prepend CHANGELOG")
451
- set_package_version(PACKAGE_JSON, plan.target)
452
- set_marketplace_version(MARKETPLACE_JSON, plan.target)
453
- prepend_changelog(CHANGELOG, plan.changelog_entry)
454
-
455
- _step(3, total, f"Commit `release: {plan.target}`")
456
- run("git", "add", str(PACKAGE_JSON), str(MARKETPLACE_JSON), str(CHANGELOG))
457
- run("git", "commit", "-m", f"release: {plan.target}")
458
-
459
- _step(4, total, f"Push {branch} to {REMOTE}")
460
- run("git", "push", "-u", REMOTE, branch)
538
+ # Probe the world once at the top so each step skip-decision is cheap.
539
+ pr_info = _pr_for_branch(branch) if resume else None
540
+ pr_state = (pr_info or {}).get("state")
541
+ pr_merged = pr_state == "MERGED"
542
+
543
+ # ─── 1. branch ──────────────────────────────────────────────────────────
544
+ if pr_merged:
545
+ _step(1, total, f"PR for {branch} already merged — staying on {MAIN_BRANCH}")
546
+ if git("rev-parse", "--abbrev-ref", "HEAD", capture=True) != MAIN_BRANCH:
547
+ run("git", "checkout", MAIN_BRANCH)
548
+ run("git", "pull", "--ff-only", REMOTE, MAIN_BRANCH)
549
+ elif resume and _branch_exists_local(branch):
550
+ _step(1, total, f"Branch {branch} exists locally — checkout")
551
+ run("git", "checkout", branch)
552
+ elif resume and _branch_exists_remote(branch):
553
+ _step(1, total, f"Branch {branch} exists on {REMOTE} — fetch + checkout")
554
+ run("git", "fetch", REMOTE, branch)
555
+ run("git", "checkout", "-b", branch, f"{REMOTE}/{branch}")
556
+ else:
557
+ _step(1, total, f"Create branch {branch}")
558
+ run("git", "checkout", "-b", branch)
461
559
 
462
- _step(5, total, "Open pull request")
463
- pr_body = (
464
- f"Release {plan.target}.\n\n"
465
- f"{plan.changelog_body}\n\n"
466
- "Created by `scripts/release.py`."
467
- )
468
- run(
469
- "gh", "pr", "create",
470
- "--base", MAIN_BRANCH,
471
- "--head", branch,
472
- "--title", f"release: {plan.target}",
473
- "--body", pr_body,
474
- )
560
+ # ─── 2. file mutations ──────────────────────────────────────────────────
561
+ if pr_merged:
562
+ _step(2, total, "PR already merged — skip file bumps")
563
+ else:
564
+ current_pkg = json.loads(PACKAGE_JSON.read_text(encoding="utf-8")).get("version")
565
+ if resume and current_pkg == plan.target:
566
+ _step(2, total, f"Files already at {plan.target} — skip bump")
567
+ else:
568
+ _step(2, total, "Bump package.json + marketplace.json, prepend CHANGELOG")
569
+ set_package_version(PACKAGE_JSON, plan.target)
570
+ set_marketplace_version(MARKETPLACE_JSON, plan.target)
571
+ prepend_changelog(CHANGELOG, plan.changelog_entry)
572
+
573
+ # ─── 3. commit ──────────────────────────────────────────────────────────
574
+ if pr_merged:
575
+ _step(3, total, "PR already merged — skip commit")
576
+ else:
577
+ last_msg = git("log", "-1", "--format=%s", capture=True)
578
+ porcelain = git("status", "--porcelain", capture=True)
579
+ if resume and last_msg == f"release: {plan.target}" and not porcelain:
580
+ _step(3, total, f"Last commit already `release: {plan.target}` and tree clean — skip")
581
+ else:
582
+ _step(3, total, f"Commit `release: {plan.target}`")
583
+ run("git", "add", str(PACKAGE_JSON), str(MARKETPLACE_JSON), str(CHANGELOG))
584
+ run("git", "commit", "-m", f"release: {plan.target}")
585
+
586
+ # ─── 4. push ────────────────────────────────────────────────────────────
587
+ if pr_merged:
588
+ _step(4, total, "PR already merged — skip push")
589
+ else:
590
+ # `git push -u` is naturally idempotent — it prints "Everything
591
+ # up-to-date" when remote already matches. No probe needed.
592
+ _step(4, total, f"Push {branch} to {REMOTE}")
593
+ run("git", "push", "-u", REMOTE, branch)
594
+
595
+ # ─── 5. PR ──────────────────────────────────────────────────────────────
596
+ if pr_merged:
597
+ _step(5, total, f"PR #{pr_info.get('number')} already merged — skip")
598
+ elif resume and pr_state == "OPEN":
599
+ _step(5, total, f"PR already open: {pr_info.get('url')}")
600
+ else:
601
+ _step(5, total, "Open pull request")
602
+ pr_body = (
603
+ f"Release {plan.target}.\n\n"
604
+ f"{plan.changelog_body}\n\n"
605
+ "Created by `scripts/release.py`."
606
+ )
607
+ run(
608
+ "gh", "pr", "create",
609
+ "--base", MAIN_BRANCH,
610
+ "--head", branch,
611
+ "--title", f"release: {plan.target}",
612
+ "--body", pr_body,
613
+ )
475
614
 
476
- if wait_for_checks:
615
+ # ─── 6. wait for checks ─────────────────────────────────────────────────
616
+ if pr_merged:
617
+ _step(6, total, "PR already merged — skip checks wait")
618
+ elif wait_for_checks:
477
619
  _step(6, total, "Wait for PR checks")
478
620
  watch_pr_checks()
479
621
  else:
480
622
  _step(6, total, "Skip waiting for checks (--no-wait)")
481
623
 
482
- _step(7, total, "Merge pull request (merge commit) and delete branch")
483
- run("gh", "pr", "merge", "--merge", "--delete-branch")
484
-
485
- _step(8, total, f"Fast-forward {MAIN_BRANCH}, tag merge commit, push tag")
486
- run("git", "checkout", MAIN_BRANCH)
624
+ # ─── 7. merge ───────────────────────────────────────────────────────────
625
+ if pr_merged:
626
+ _step(7, total, f"PR #{pr_info.get('number')} already merged — skip")
627
+ else:
628
+ _step(7, total, "Merge pull request (merge commit) and delete branch")
629
+ run("gh", "pr", "merge", "--merge", "--delete-branch")
630
+
631
+ # ─── 8. tag main + push tag ─────────────────────────────────────────────
632
+ # Always idempotent — even outside resume mode this prevents a mid-flight
633
+ # crash on step 9 from leaving a half-tagged release that subsequent
634
+ # `task release` invocations can't recover from without `--resume`.
635
+ if git("rev-parse", "--abbrev-ref", "HEAD", capture=True) != MAIN_BRANCH:
636
+ run("git", "checkout", MAIN_BRANCH)
487
637
  run("git", "pull", "--ff-only", REMOTE, MAIN_BRANCH)
488
- run("git", "tag", plan.target)
489
- run("git", "push", REMOTE, plan.target)
490
-
491
- _step(9, total, "Create GitHub Release (triggers publish-npm on the tag)")
492
- notes = plan.changelog_body or f"Release {plan.target}"
493
- run(
494
- "gh", "release", "create", plan.target,
495
- "--title", plan.target,
496
- "--notes", notes,
497
- )
638
+
639
+ if _tag_exists_local(plan.target):
640
+ if _tag_exists_remote(plan.target):
641
+ _step(8, total, f"Tag {plan.target} already on {REMOTE} skip")
642
+ else:
643
+ _step(8, total, f"Tag {plan.target} exists locally — push only")
644
+ run("git", "push", REMOTE, plan.target)
645
+ else:
646
+ _step(8, total, f"Tag merge commit and push {plan.target}")
647
+ run("git", "tag", plan.target)
648
+ run("git", "push", REMOTE, plan.target)
649
+
650
+ # ─── 9. GitHub Release ──────────────────────────────────────────────────
651
+ if _release_exists(plan.target):
652
+ _step(9, total, f"GitHub Release {plan.target} already exists — skip")
653
+ else:
654
+ _step(9, total, "Create GitHub Release (triggers publish-npm on the tag)")
655
+ notes = plan.changelog_body or f"Release {plan.target}"
656
+ run(
657
+ "gh", "release", "create", plan.target,
658
+ "--title", plan.target,
659
+ "--notes", notes,
660
+ )
498
661
 
499
662
  print()
500
663
  print(f"✅ Released {plan.target}")
@@ -535,6 +698,15 @@ def _parse_args(argv: list[str]) -> argparse.Namespace:
535
698
  "--no-wait", action="store_true",
536
699
  help="Merge immediately without waiting for PR checks to pass.",
537
700
  )
701
+ p.add_argument(
702
+ "--resume", action="store_true",
703
+ help=(
704
+ "Recover from a partial run. Each step probes existing state "
705
+ "(branch, commit, PR, tag, GitHub Release) and skips work that "
706
+ "is already done. Use this when an earlier `task release` "
707
+ "crashed mid-pipeline."
708
+ ),
709
+ )
538
710
  return p.parse_args(argv)
539
711
 
540
712
 
@@ -545,6 +717,49 @@ def resolve_bump(override: str | None, commits: list[Commit]) -> str:
545
717
  return infer_bump(commits)
546
718
 
547
719
 
720
+ _RELEASE_BRANCH_RE = re.compile(r"^release/(\d+\.\d+\.\d+)$")
721
+
722
+
723
+ def _detect_in_flight_target() -> str | None:
724
+ """Find the in-flight release target from existing release branches.
725
+
726
+ Resume mode needs to know which `release/X.Y.Z` is being recovered,
727
+ not what the next bump would be. The release branch name is the
728
+ canonical anchor: it was committed by step 1 of an earlier run and
729
+ is the only state guaranteed to survive a partial pipeline.
730
+
731
+ Local branches win over remote, current-branch wins over both — if
732
+ you ran `git checkout release/1.15.0`, that's the target. Returns
733
+ None if no release branch exists; caller falls back to the regular
734
+ bump-inference path.
735
+ """
736
+ head = git("rev-parse", "--abbrev-ref", "HEAD", capture=True)
737
+ m = _RELEASE_BRANCH_RE.match(head)
738
+ if m:
739
+ return m.group(1)
740
+
741
+ local_raw = git("for-each-ref", "--format=%(refname:short)", "refs/heads/release/", capture=True)
742
+ candidates = [
743
+ m.group(1)
744
+ for line in local_raw.splitlines()
745
+ if (m := _RELEASE_BRANCH_RE.match(line.strip()))
746
+ ]
747
+ remote_raw = git(
748
+ "for-each-ref", "--format=%(refname:short)",
749
+ f"refs/remotes/{REMOTE}/release/", capture=True,
750
+ )
751
+ for line in remote_raw.splitlines():
752
+ bare = line.strip().removeprefix(f"{REMOTE}/")
753
+ if (m := _RELEASE_BRANCH_RE.match(bare)):
754
+ candidates.append(m.group(1))
755
+
756
+ if not candidates:
757
+ return None
758
+ # Sort semver-aware so 1.10.0 > 1.9.0 (lexicographic would lose).
759
+ candidates.sort(key=parse_version)
760
+ return candidates[-1]
761
+
762
+
548
763
  def main(argv: list[str] | None = None) -> int:
549
764
  args = _parse_args(list(sys.argv[1:] if argv is None else argv))
550
765
 
@@ -554,11 +769,22 @@ def main(argv: list[str] | None = None) -> int:
554
769
  prev = latest_tag()
555
770
  commits = commits_since(prev)
556
771
  bump = resolve_bump(args.bump_override, commits)
557
- target = args.explicit or bump_version(current, bump)
772
+
773
+ # Resume mode: prefer an existing `release/X.Y.Z` over computed bump,
774
+ # so we don't accidentally start a 1.16.0 release while 1.15.0 is
775
+ # still in flight. Explicit --version still wins.
776
+ in_flight = _detect_in_flight_target() if args.resume else None
777
+ if args.explicit:
778
+ target = args.explicit
779
+ elif in_flight:
780
+ target = in_flight
781
+ print(f"(resume) detected in-flight release branch release/{in_flight}")
782
+ else:
783
+ target = bump_version(current, bump)
558
784
  parse_version(target)
559
785
 
560
786
  if not args.dry_run:
561
- preflight(target)
787
+ preflight(target, resume=args.resume)
562
788
 
563
789
  today = _date.today().isoformat()
564
790
  full, body = render_changelog_entry(target, prev, commits, today)
@@ -572,6 +798,8 @@ def main(argv: list[str] | None = None) -> int:
572
798
  changelog_entry=full,
573
799
  )
574
800
  print_preview(plan)
801
+ if args.resume:
802
+ print("(resume) probing existing state — completed steps will be skipped.")
575
803
 
576
804
  if args.dry_run:
577
805
  return 0
@@ -580,7 +808,12 @@ def main(argv: list[str] | None = None) -> int:
580
808
  print("aborted.")
581
809
  return 1
582
810
 
583
- execute(plan, wait_for_checks=not args.no_wait, dry_run=False)
811
+ execute(
812
+ plan,
813
+ wait_for_checks=not args.no_wait,
814
+ dry_run=False,
815
+ resume=args.resume,
816
+ )
584
817
  return 0
585
818
 
586
819
 
@@ -28,6 +28,26 @@
28
28
  "pattern": "^[a-z][a-z0-9-]*$"
29
29
  }
30
30
  },
31
+ "cluster": {
32
+ "type": "string",
33
+ "pattern": "^[a-z][a-z0-9-]*$",
34
+ "description": "Locked verb cluster this command belongs to. See docs/contracts/command-clusters.md."
35
+ },
36
+ "sub": {
37
+ "type": "string",
38
+ "pattern": "^[a-z][a-z0-9-]*$",
39
+ "description": "Sub-command identifier within the cluster (e.g. `ci` for `/fix ci`)."
40
+ },
41
+ "superseded_by": {
42
+ "type": "string",
43
+ "pattern": "^[a-z][a-z0-9-]*( [a-z][a-z0-9-]*)?$",
44
+ "description": "Set on deprecation shims. Format: '<cluster> <sub>' (e.g. 'fix ci'). See docs/contracts/command-clusters.md § Deprecation shim contract."
45
+ },
46
+ "deprecated_in": {
47
+ "type": "string",
48
+ "pattern": "^[0-9]+\\.[0-9]+\\.[0-9]+$",
49
+ "description": "Semver release in which this command became a shim (e.g. '1.15.0')."
50
+ },
31
51
  "suggestion": {
32
52
  "type": "object",
33
53
  "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
  }
@@ -136,9 +136,7 @@ def read_text(path: Path) -> str:
136
136
  # --- Role-contract anchor cache (see road-to-role-modes Phase 1) ---
137
137
  # Populated lazily so the linter stays fast when the guideline is absent.
138
138
  _ROLE_CONTRACT_CANDIDATES = (
139
- Path(".agent-src.uncompressed/guidelines/agent-infra/role-contracts.md"),
140
- Path(".agent-src/guidelines/agent-infra/role-contracts.md"),
141
- Path(".augment/guidelines/agent-infra/role-contracts.md"),
139
+ Path("docs/guidelines/agent-infra/role-contracts.md"),
142
140
  )
143
141
  _ROLE_CONTRACT_SLUGS_CACHE: Optional[set[str]] = None
144
142
 
@@ -373,7 +371,8 @@ def lint_skill(path: Path, text: str) -> LintResult:
373
371
 
374
372
  if description:
375
373
  if len(description) > 200:
376
- issues.append(Issue("warning", "description_too_long", "Description is longer than 200 characters"))
374
+ issues.append(Issue("error", "description_too_long",
375
+ f"Description is {len(description)} chars (hard cap: 200) — see road-to-governance-cleanup F6"))
377
376
  for pattern in TRIGGER_WARNING_PATTERNS:
378
377
  if re.search(pattern, description, re.IGNORECASE):
379
378
  issues.append(Issue("warning", "weak_trigger", f"Description looks too generic: {description}"))
@@ -716,6 +715,12 @@ def lint_rule(path: Path, text: str) -> LintResult:
716
715
  if not description:
717
716
  issues.append(Issue("error", "auto_missing_description", "Auto rules require a 'description' field for matching"))
718
717
 
718
+ # description length cap (F6 — 200-char hard cap, see road-to-governance-cleanup)
719
+ rule_description = extract_description(text)
720
+ if rule_description and len(rule_description) > 200:
721
+ issues.append(Issue("error", "description_too_long",
722
+ f"Description is {len(rule_description)} chars (hard cap: 200) — see road-to-governance-cleanup F6"))
723
+
719
724
  # always-rules that look like auto candidates (rule-type-governance check)
720
725
  if rule_type == "always":
721
726
  description = extract_description(text) or ""
@@ -863,10 +868,27 @@ def lint_command(path: Path, text: str) -> LintResult:
863
868
  description = extract_description(text)
864
869
  if not description:
865
870
  issues.append(Issue("warning", "missing_description", "Frontmatter description is missing"))
871
+ elif len(description) > 200:
872
+ issues.append(Issue("error", "description_too_long",
873
+ f"Description is {len(description)} chars (hard cap: 200) — see road-to-governance-cleanup F6"))
866
874
 
867
875
  # suggestion block (road-to-context-aware-command-suggestion Phase 2)
868
876
  issues.extend(_lint_command_suggestion_block(text))
869
877
 
878
+ # deprecation-shim warning line (P0.8b — command-clusters contract)
879
+ if "superseded_by:" in frontmatter:
880
+ shim_warning = re.search(
881
+ r"⚠️\s+/[a-z][a-z0-9-]*\s+is deprecated;\s+use\s+/[a-z][a-z0-9 -]+\s+instead",
882
+ text,
883
+ )
884
+ if not shim_warning:
885
+ issues.append(Issue(
886
+ "error", "shim_missing_warning",
887
+ "Deprecation shim must contain a one-line warning matching "
888
+ "'⚠️ /<old-name> is deprecated; use /<cluster> <sub> instead.'"
889
+ " (see docs/contracts/command-clusters.md § Deprecation shim contract)"
890
+ ))
891
+
870
892
  # --- Structure checks ---
871
893
  if not H1_PATTERN.search(text):
872
894
  issues.append(Issue("error", "missing_h1", "Command is missing an H1 heading (# Title)"))
@@ -2,7 +2,7 @@
2
2
  """Sync `.agent-settings.yml` against the template + profile.
3
3
 
4
4
  Applies the section-aware merge rules documented in
5
- `.agent-src.uncompressed/guidelines/agent-infra/layered-settings.md`:
5
+ `docs/guidelines/agent-infra/layered-settings.md`:
6
6
 
7
7
  - Template section order always wins — reorder keys to match.
8
8
  - Existing user scalar values are preserved verbatim (as parsed).
@@ -28,8 +28,9 @@ def count(kind: str) -> int:
28
28
  if kind == "skills":
29
29
  return sum(1 for _ in (SRC / "skills").rglob("SKILL.md"))
30
30
  if kind == "guidelines":
31
- # guidelines are grouped by topic subdirectory
32
- return sum(1 for _ in (SRC / "guidelines").rglob("*.md"))
31
+ # Guidelines live under docs/guidelines/{topic}/ they are reference
32
+ # material, not packaged artefacts. Recursive walk to count every .md.
33
+ return sum(1 for _ in (REPO_ROOT / "docs" / "guidelines").rglob("*.md"))
33
34
  if kind == "personas":
34
35
  # personas live as flat .md files, README excluded
35
36
  pdir = SRC / "personas"
@@ -47,12 +48,16 @@ TARGETS: list[tuple[str, list[tuple[str, str]]]] = [
47
48
  [
48
49
  (r"(Browse all )(\d+)( commands\])", "commands"),
49
50
  (r"(package \(rules \+ )(\d+)( skills)", "skills"),
50
- (r"(skills \+ )(\d+)( native commands)", "commands"),
51
51
  # Hero line: **NNN Skills** · **NNN Rules** · **NNN Commands** · **NNN Guidelines**
52
52
  (r"(<strong>)(\d+)( Skills</strong>)", "skills"),
53
53
  (r"(<strong>)(\d+)( Rules</strong>)", "rules"),
54
- (r"(<strong>)(\d+)( Commands</strong>)", "commands"),
55
54
  (r"(<strong>)(\d+)( Guidelines</strong>)", "guidelines"),
55
+ # NOTE: hero `<strong>N Commands</strong>` and tools-blurb
56
+ # `skills + N native commands` are owned by
57
+ # `check_command_count_messaging.py` (Phase-1.2 of
58
+ # road-to-pr-34-followups). Those surfaces advertise the
59
+ # **active** command count (total − deprecation shims), not
60
+ # the raw file count this script computes.
56
61
  ],
57
62
  ),
58
63
  (
@@ -72,6 +77,16 @@ TARGETS: list[tuple[str, list[tuple[str, str]]]] = [
72
77
  (r"(Browse all )(\d+)( commands\])", "commands"),
73
78
  ],
74
79
  ),
80
+ (
81
+ "docs/architecture.md",
82
+ [
83
+ # "What's inside" table: | **Skills** | NNN | … |
84
+ (r"(\| \*\*Skills\*\* \| )(\d+)( \|)", "skills"),
85
+ (r"(\| \*\*Rules\*\* \| )(\d+)( \|)", "rules"),
86
+ (r"(\| \*\*Commands\*\* \| )(\d+)( \|)", "commands"),
87
+ (r"(\| \*\*Guidelines\*\* \| )(\d+)( \|)", "guidelines"),
88
+ ],
89
+ ),
75
90
  # Note: ``agents/roadmaps/road-to-stronger-skills.md`` was previously
76
91
  # tracked here with a living ``baseline N as of`` pattern. The roadmap
77
92
  # was moved to ``skipped/`` on 2026-04-23 (Q35 superseded), so its