@oneie/claude 0.7.0 → 0.9.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 (263) hide show
  1. package/agents/abm-strategist.md +89 -0
  2. package/agents/ads-meta.md +97 -0
  3. package/agents/analyst.md +173 -0
  4. package/agents/architect.md +280 -0
  5. package/agents/brand-guardian.md +88 -0
  6. package/agents/brand-strategist.md +92 -0
  7. package/agents/campaign-content.md +90 -0
  8. package/agents/campaign-email.md +88 -0
  9. package/agents/campaign-sms.md +87 -0
  10. package/agents/campaign-social.md +87 -0
  11. package/agents/cco.md +99 -0
  12. package/agents/ceo.md +106 -0
  13. package/agents/chairman.md +120 -0
  14. package/agents/cmo.md +101 -0
  15. package/agents/community-greeter.md +89 -0
  16. package/agents/community-moderator.md +92 -0
  17. package/agents/compliance.md +92 -0
  18. package/agents/copywriter.md +100 -0
  19. package/agents/creative-strategist.md +95 -0
  20. package/agents/cro.md +98 -0
  21. package/agents/cto.md +267 -0
  22. package/agents/customer-interviewer.md +93 -0
  23. package/agents/customer-researcher.md +89 -0
  24. package/agents/customer-success-manager.md +90 -0
  25. package/agents/customer-trainer.md +90 -0
  26. package/agents/cxo.md +100 -0
  27. package/agents/demand-creator.md +89 -0
  28. package/agents/demo-mover.md +83 -0
  29. package/agents/demo-specialist.md +89 -0
  30. package/agents/demo-thai-family-law.md +87 -0
  31. package/agents/designer.md +112 -0
  32. package/agents/discovery-caller.md +98 -0
  33. package/agents/doctor.md +139 -0
  34. package/agents/educate-coach.md +100 -0
  35. package/agents/elevate-tutor.md +83 -0
  36. package/agents/email-lifecycle-marketer.md +91 -0
  37. package/agents/engage-specialist.md +99 -0
  38. package/agents/events-coordinator.md +90 -0
  39. package/agents/foundation-builder.md +94 -0
  40. package/agents/funnel-architect.md +89 -0
  41. package/agents/gift-creator.md +100 -0
  42. package/agents/google-ads.md +103 -0
  43. package/agents/guide.md +292 -0
  44. package/agents/helpdesk-dispatcher.md +88 -0
  45. package/agents/hook-specialist.md +91 -0
  46. package/agents/identify-optimizer.md +101 -0
  47. package/agents/implementer.md +305 -0
  48. package/agents/incident-commander.md +120 -0
  49. package/agents/insights-lead.md +93 -0
  50. package/agents/journey-runner.md +113 -0
  51. package/agents/linkedin-ads.md +123 -0
  52. package/agents/live-sales-chat.md +90 -0
  53. package/agents/market-researcher.md +88 -0
  54. package/agents/media-buyer.md +96 -0
  55. package/agents/movers-customer-researcher.md +95 -0
  56. package/agents/movers-foundation-builder.md +96 -0
  57. package/agents/movers-market-researcher.md +97 -0
  58. package/agents/movers-pricing-strategist.md +171 -0
  59. package/agents/nurture-architect.md +99 -0
  60. package/agents/offer-architect.md +92 -0
  61. package/agents/onboarder.md +222 -0
  62. package/agents/onboarding-specialist.md +92 -0
  63. package/agents/operations-dashboard.md +98 -0
  64. package/agents/perf-engineer.md +348 -0
  65. package/agents/playbook-writer.md +71 -0
  66. package/agents/plg-strategist.md +91 -0
  67. package/agents/positioning-architect.md +88 -0
  68. package/agents/press-officer.md +89 -0
  69. package/agents/pricing-strategist.md +94 -0
  70. package/agents/privacy-officer.md +92 -0
  71. package/agents/referral-manager.md +91 -0
  72. package/agents/refine-analyst.md +102 -0
  73. package/agents/release-manager.md +261 -0
  74. package/agents/renewals-upsell-rep.md +90 -0
  75. package/agents/review-engineer.md +327 -0
  76. package/agents/rewards-steward.md +82 -0
  77. package/agents/sales-call-coach.md +94 -0
  78. package/agents/sales-closer.md +98 -0
  79. package/agents/security-auditor.md +313 -0
  80. package/agents/sell-closer.md +101 -0
  81. package/agents/share-amplifier.md +99 -0
  82. package/agents/social-media-manager.md +92 -0
  83. package/agents/storyteller.md +250 -0
  84. package/agents/strategist.md +83 -0
  85. package/agents/strategy-aligner.md +94 -0
  86. package/agents/support-agent.md +90 -0
  87. package/agents/tagger.md +245 -0
  88. package/agents/tech-writer.md +216 -0
  89. package/agents/test-engineer.md +243 -0
  90. package/agents/tiktok-ads.md +105 -0
  91. package/agents/tracking-engineer.md +92 -0
  92. package/agents/upsell-strategist.md +101 -0
  93. package/agents/voice.md +85 -0
  94. package/agents/w4-tools.md +153 -0
  95. package/agents/w4-verify.md +20 -138
  96. package/agents/workflow-optimiser.md +84 -0
  97. package/commands/close.md +814 -160
  98. package/commands/create.md +2 -2
  99. package/commands/deploy.md +554 -175
  100. package/commands/do.md +119 -109
  101. package/commands/fast.md +67 -0
  102. package/commands/improve.md +2 -2
  103. package/commands/one.md +418 -0
  104. package/commands/see.md +1 -1
  105. package/commands/sync.md +1 -1
  106. package/commands/tasks.md +222 -0
  107. package/commands/vespio.md +110 -0
  108. package/commands/vespio.remote.md +227 -0
  109. package/hooks/hooks.json +25 -79
  110. package/hooks/lib/governor-escape-match.sh +88 -0
  111. package/hooks/lib/hook.sh +4 -13
  112. package/hooks/lib/signal.sh +9 -2
  113. package/hooks/scripts/branch-pin.sh +6 -0
  114. package/hooks/scripts/config-protect.sh +6 -0
  115. package/hooks/scripts/do-outcome-gate.sh +19 -2
  116. package/hooks/scripts/git-add-guard.sh +43 -2
  117. package/hooks/scripts/governor-escape.sh +96 -0
  118. package/hooks/scripts/load-guard.sh +127 -0
  119. package/hooks/scripts/post-edit-check.sh +36 -29
  120. package/hooks/scripts/session-start.sh +34 -80
  121. package/hooks/scripts/task-complete-verify.sh +46 -40
  122. package/package.json +1 -1
  123. package/rules/documentation.md +9 -0
  124. package/scripts/ad-copy-lint.sh +656 -0
  125. package/scripts/agentverse-audit.sh +256 -0
  126. package/scripts/asi-walk.sh +435 -0
  127. package/scripts/astro-build-cached.sh +143 -0
  128. package/scripts/blocks-manifest-cached.sh +100 -0
  129. package/scripts/blocks-manifest.mjs +497 -0
  130. package/scripts/blocks-ratchet.sh +116 -0
  131. package/scripts/blocks-render-probe.mjs +529 -0
  132. package/scripts/blocks-usage.mjs +334 -0
  133. package/scripts/chat-context-check.sh +89 -0
  134. package/scripts/close-metrics.sh +558 -0
  135. package/scripts/close-owner.sh +268 -0
  136. package/scripts/db-sync-lock-check.sh +116 -0
  137. package/scripts/deploy-dev.sh +35 -0
  138. package/scripts/deploy-emit.sh +298 -0
  139. package/scripts/deploy-gate-check.sh +128 -0
  140. package/scripts/deploy-ready.sh +78 -0
  141. package/scripts/deploy-record.sh +605 -0
  142. package/scripts/deploy.sh +1273 -0
  143. package/scripts/do-auto.sh +598 -48
  144. package/scripts/do-brief.sh +113 -0
  145. package/scripts/do-close.sh +1137 -0
  146. package/scripts/do-commit.sh +75 -0
  147. package/scripts/do-consumer-sweep.sh +18 -1
  148. package/scripts/do-cycle-shape-check.sh +160 -0
  149. package/scripts/do-decide.sh +476 -0
  150. package/scripts/do-derive-check.sh +436 -0
  151. package/scripts/do-fleet.sh +106 -28
  152. package/scripts/do-folder.sh +10 -1
  153. package/scripts/do-next.sh +106 -0
  154. package/scripts/do-orchestrate.sh +17 -5
  155. package/scripts/do-plan-json.mjs +201 -0
  156. package/scripts/do-plan-json.sh +8 -0
  157. package/scripts/do-preflight.sh +117 -0
  158. package/scripts/do-project.sh +157 -0
  159. package/scripts/do-prove-selftest.sh +108 -0
  160. package/scripts/do-prove.sh +295 -23
  161. package/scripts/do-rank.py +31 -1
  162. package/scripts/do-recon-cache.sh +7 -1
  163. package/scripts/do-recon-pack.sh +196 -0
  164. package/scripts/do-reconcile.sh +121 -4
  165. package/scripts/do-signal.sh +280 -23
  166. package/scripts/do-smoke.sh +18 -1
  167. package/scripts/do-test-gate.sh +80 -0
  168. package/scripts/do-tick.sh +102 -0
  169. package/scripts/do-tier.sh +6 -0
  170. package/scripts/do-triage.sh +182 -0
  171. package/scripts/do-ui-gate.sh +1 -1
  172. package/scripts/do-w4-gates.sh +451 -0
  173. package/scripts/do-walk.sh +12 -1
  174. package/scripts/env-sync.sh +173 -0
  175. package/scripts/factory-brief-check.sh +330 -0
  176. package/scripts/factory-check.sh +68 -14
  177. package/scripts/factory-close-check.sh +257 -0
  178. package/scripts/factory-emit.sh +211 -0
  179. package/scripts/factory-executor-check.mjs +353 -0
  180. package/scripts/factory-peak.sh +301 -0
  181. package/scripts/factory-repo.sh +118 -3
  182. package/scripts/factory-review-check.mjs +61 -0
  183. package/scripts/factory-ship.sh +61 -0
  184. package/scripts/factory-tasks-check.sh +18 -1
  185. package/scripts/factory-turn.sh +326 -0
  186. package/scripts/factory-walk.sh +396 -0
  187. package/scripts/factory-width.sh +57 -0
  188. package/scripts/fade-toxic.sh +4 -3
  189. package/scripts/fixtures/factory-brief-real.md +44 -0
  190. package/scripts/fixtures/triage-dupe.md +5 -0
  191. package/scripts/fleet-manifest.mjs +108 -0
  192. package/scripts/fleet-status.sh +110 -0
  193. package/scripts/full-suite-paths-check.sh +144 -0
  194. package/scripts/gate-reaper-check.sh +98 -0
  195. package/scripts/gate-reaper.sh +125 -0
  196. package/scripts/gate-run.sh +73 -0
  197. package/scripts/gc-content-check.sh +140 -0
  198. package/scripts/gen-dev-config.py +20 -0
  199. package/scripts/govern-bound-check.sh +60 -0
  200. package/scripts/govern-claims-check.sh +233 -0
  201. package/scripts/govern-mem-check.sh +290 -0
  202. package/scripts/governor-doors-check.sh +362 -0
  203. package/scripts/governor-escape-check.sh +171 -0
  204. package/scripts/health.sh +413 -0
  205. package/scripts/id-inventory.mjs +418 -0
  206. package/scripts/land.sh +551 -0
  207. package/scripts/lib/gc-finished.sh +77 -0
  208. package/scripts/lib/govern.sh +361 -0
  209. package/scripts/lib/govern.ts +756 -0
  210. package/scripts/lighthouse-run.sh +187 -0
  211. package/scripts/livekit-live-check.sh +61 -0
  212. package/scripts/livekit-ratchet.sh +46 -0
  213. package/scripts/load-guard-check.sh +49 -0
  214. package/scripts/machine-check.sh +102 -0
  215. package/scripts/machine-watch.sh +177 -0
  216. package/scripts/one-agents.mjs +415 -0
  217. package/scripts/one-resume.sh +78 -0
  218. package/scripts/orphan-baseline.json +182 -0
  219. package/scripts/orphan-modules.mjs +179 -0
  220. package/scripts/pr-body.sh +335 -0
  221. package/scripts/preview-fd-check.sh +289 -0
  222. package/scripts/promise-manifest.mjs +24 -1
  223. package/scripts/release.sh +322 -0
  224. package/scripts/roles-check.sh +946 -0
  225. package/scripts/sdk-build-cached.sh +64 -0
  226. package/scripts/signal-watch.sh +241 -0
  227. package/scripts/skills-publish.sh +94 -0
  228. package/scripts/speed-cache-check.sh +173 -0
  229. package/scripts/speed-check.mjs +907 -0
  230. package/scripts/speed-parity-check.sh +648 -0
  231. package/scripts/speed-waterfall-check.sh +355 -0
  232. package/scripts/substrate-env-parity.mjs +156 -0
  233. package/scripts/tasks-claim-race.mjs +108 -0
  234. package/scripts/tasks-loop.sh +185 -0
  235. package/scripts/test-cached.sh +255 -0
  236. package/scripts/test-full.sh +87 -0
  237. package/scripts/test-honesty.mjs +137 -0
  238. package/scripts/test-lanes.sh +166 -0
  239. package/scripts/test-speed.sh +94 -0
  240. package/scripts/triage-shape-check.sh +149 -0
  241. package/scripts/tsc-cached.sh +179 -0
  242. package/scripts/typedb-flake-check.sh +197 -0
  243. package/scripts/urls-lint.sh +15 -0
  244. package/scripts/verify-fast.sh +445 -0
  245. package/scripts/vespio-sync.sh +149 -0
  246. package/scripts/wf-check.mjs +104 -1
  247. package/scripts/worktree-preview.sh +879 -0
  248. package/scripts/worktree-up.sh +208 -0
  249. package/skills/livekit-agents/SKILL.md +285 -0
  250. package/skills/livekit-agents/references/freshness-rules.md +168 -0
  251. package/skills/shadcn/SKILL.md +1 -1
  252. package/skills/signal/SKILL.md +0 -1
  253. package/skills/voice/SKILL.md +94 -6
  254. package/skills/voice/corpus-check.sh +87 -0
  255. package/hooks/scripts/compact-hint.sh +0 -35
  256. package/hooks/scripts/gate-guard.sh +0 -83
  257. package/hooks/scripts/read-tracker.sh +0 -26
  258. package/hooks/scripts/session-end-verify.sh +0 -51
  259. package/hooks/scripts/stop-reflect.sh +0 -140
  260. package/hooks/scripts/sync-priority-todo.sh +0 -57
  261. package/hooks/scripts/sync-todo-docs.sh +0 -46
  262. package/hooks/scripts/tool-signal.sh +0 -48
  263. package/scripts/do-tasks-bridge.py +0 -366
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: voice
3
- description: Write in Anthony O'Connell's voice. Use whenever prose will go out under Anthony's or ONE's name and must sound like him, not like a generic assistant — books, essays, whitepapers, manifestos, blog posts, landing-page and marketing copy, founder updates, social posts, newsletters, client emails, playbook chapters, README and doc prose, or any rewrite where the note is "this doesn't sound like me". Its first job is picking the register: book/essay (patient, observational, no visible author, never sells) or commercial (first person, receipts, product names, sells). Invoke AFTER `writer` (craft) and alongside `product-marketing.md` (product context). Triggers — "write this in my voice", "in Anthony's voice/tone", "make it sound like me", "this reads like AI", "too corporate", "sounds generic", "write the book/chapter/essay/whitepaper", "write the blog post/landing page", "rewrite this properly".
3
+ description: "Write in Anthony O'Connell's voice. Use whenever prose will go out under Anthony's or ONE's name and must sound like him, not like a generic assistant — books, essays, whitepapers, manifestos, blog posts, landing-page and marketing copy, founder updates, social posts, newsletters, client emails, playbook chapters, README and doc prose, or any rewrite where the note is \"this doesn't sound like me\". Its first job is picking the register: book/essay (patient, observational, no visible author, never sells) or commercial (first person, receipts, product names, sells). Invoke AFTER `writer` (craft) and alongside `product-marketing.md` (product context). Triggers — \"write this in my voice\", \"in Anthony's voice/tone\", \"make it sound like me\", \"this reads like AI\", \"too corporate\", \"sounds generic\", \"write the book/chapter/essay/whitepaper\", \"write the blog post/landing page\", \"rewrite this properly\"."
4
4
  ---
5
5
 
6
6
  # voice — Anthony O'Connell's register
@@ -33,7 +33,7 @@ Everything else — observe don't assert, specific numbers or none, short senten
33
33
 
34
34
  ## Step 2 — the sources, in order of authority
35
35
 
36
- 1. **`text/voice-and-tone.md`** — the specification. **Authored by Anthony.** Vendored from `apps/ants/docs/book/files/01-voice-and-tone.md`; edit the original, re-vendor here. Demonstrated across 96,540 words in `apps/ants/docs/book/manuscript/`. **Senior to everything else. Where anything disagrees with it, it wins.**
36
+ 1. **`text/voice-and-tone.md`** — the specification. **Authored by Anthony.** Vendored from `apps/ants/docs/book/files/01-voice-and-tone.md`; edit the original, re-vendor here. Demonstrated across `apps/ants/docs/book/manuscript/` — 96,540 words of directory, 93,032 of them the 25 chapters the section below measures. **Senior to everything else. Where anything disagrees with it, it wins.**
37
37
  2. **`text/writing-style-guide.md`** — derived. Splits universal from book-only, and documents the commercial register the spec doesn't cover.
38
38
  3. **`.claude/product-marketing.md`** — product context: offer, audience, thesis, the measured-numbers table. Commercial only.
39
39
 
@@ -51,22 +51,110 @@ If it performs urgency, expertise, contrarianism, or aspiration — rewrite it.
51
51
 
52
52
  ---
53
53
 
54
+ ## What the corpus actually does — measured
55
+
56
+ `text/voice-and-tone.md` says what the voice must never do. The 25 chapters of
57
+ *100 Million Years Ahead* show what it does. Measured 2026-09-09 over
58
+ `apps/ants/docs/book/manuscript/*.md` — 93,032 words, 6,163 sentences, 1,441
59
+ paragraphs. Re-measure any time with `bash .claude/skills/voice/corpus-check.sh --corpus`.
60
+
61
+ | Signature | Measured | What it means for a draft |
62
+ |---|---|---|
63
+ | **"I"** | **0** in 93,032 words | Absolute, not a preference. One occurrence is a defect. |
64
+ | **Contractions** (`n't`) | **5** in the whole book | Effectively never. Write *does not*, *is not*, *will not*. The spec never states this; the corpus is unanimous. |
65
+ | **`###` headings inside a chapter** | **0**, across all 25 | Confirmed absolute. |
66
+ | **Horizontal rules** (`---`) | **median 5 per chapter**, up to 10 | The derived guide's "once or twice" is **wrong**. The scene break is a primary structural tool, not a rarity. |
67
+ | **One-sentence paragraphs** | **371 of 1,441 — 25.7%** | One paragraph in four is a single sentence. That is the rhythm, not an occasional flourish. |
68
+ | **Sentence length** | median **12** words · mean 15.1 · p10 **4** · p90 30 · max 82 | Wide range on purpose; 22.2% of sentences are 6 words or fewer. A draft of uniform 20-word sentences is not this voice. |
69
+ | **Final sentence of a chapter** | median **10** words; three chapters end in 3 | Land short. *"The soil will."* · *"In the substrate."* · *"The architecture, running."* |
70
+ | **"the reader"** vs **"you"** | 134 vs 113 — and **50 of the 113 sit in the epilogue alone** | The standing device is third-person *"the reader."* Direct *you* is held back and spent at the end, where the book turns to face the reader. |
71
+ | **Digits** | 5.8 per 10k words | Numbers are rare and therefore load-bearing. A number earns its place or is cut. |
72
+ | **Hedges** | *on the order of* ×12 · *roughly* ×23 · *approximately* ×3 | Precise when the evidence is sharp, *on the order of* when it is not. Never a fake decimal. |
73
+ | **Em dashes** | 89.6 per 10k | Book register uses them freely. The "3 or fewer" rule is **commercial only** — do not carry it across. |
74
+ | **Question marks** | 5.3 per 10k — 49 in the whole book | A rhetorical question is a rationed move. Two chapters end on one. |
75
+
76
+ ---
77
+
78
+ ## The three sentence shapes
79
+
80
+ These are the shapes the corpus reaches for. They are not decoration. They are how an
81
+ observation gets made without being asserted.
82
+
83
+ **1. The negative-definition fragment.** A statement, then a fragment that names the
84
+ obvious alternative and refuses it. The most characteristic sentence in the book.
85
+
86
+ > *"This is the thing to look at. Not the ant."*
87
+ > *"This is where the colony's memory lives. Not in any ant."*
88
+ > *"The colony regulates the queen. Not the other way around."*
89
+ > *"That eighth one ran in fifteen years what the desert ran in a hundred million. Not because it was better designed."*
90
+
91
+ The fragment is deliberate. It does the work an em dash and a subordinate clause would
92
+ do, and it lands harder because it stops.
93
+
94
+ **2. "It is not X. It is Y."** Two flat copulas. The first clears the ground, the second
95
+ puts the thing down. No connective, no *rather*, no *instead*.
96
+
97
+ > *"It is not chemistry. It is not soil."*
98
+ > *"It is not a stored recipe retrieved on cue. It is constructed for the case in front of it."*
99
+ > *"It was not built as a substrate for collective intelligence. It was built to record grain shipments and tax debts."*
100
+
101
+ **3. The copula-forward declarative.** *It is* appears 683 times — 73.5 per 10k. The
102
+ voice states what a thing is and then stops, rather than explaining that it is about to
103
+ state it. This is what "confidence without assertion" looks like structurally.
104
+
105
+ **And one shape to avoid:** the interpretive paragraph after a clear observation. The
106
+ corpus makes the observation and leaves a blank line. The reader is given room to feel
107
+ the implication before the next paragraph arrives.
108
+
109
+ ---
110
+
111
+ ## Openings and closings
112
+
113
+ **Every one of the 25 chapters opens on a concrete particular.** Never on an argument,
114
+ never on a thesis, never on a summary of what the chapter will do.
115
+
116
+ They open on: a temperature on dirt · a nine-month-old on a kitchen floor · dawn in the
117
+ Chihuahuan Desert · a corridor a centimetre wide · a freshly emerged ant · a stretch of
118
+ high desert near Rodeo · *"She is the largest animal in the nest, and she is doing the
119
+ least."* · a man opening a coffee shop · a person selling four hundred shares · Vienna,
120
+ 1847 · a scrape on a knee · one and a half kilograms of tissue · the year 1300 · 2008 ·
121
+ *"The desert is still there."*
122
+
123
+ Three reliable opening moves: **a place and a temperature**; **a date, a person, an
124
+ action**; **a flat short sentence holding a contradiction** ("largest… doing the least").
125
+ Pick one and begin. Do not announce.
126
+
127
+ **The closings are short, and they return.** Median 10 words. The dominant move is a
128
+ recontextualised return to the chapter's own opening image — chapter 22 opens *"The
129
+ desert is still there"* and closes *"The architecture, running."* Two chapters close on a
130
+ question. Several close on a fragment that lands on one noun and nothing else.
131
+
132
+ Never close on a summary. Never close on an implication the reader can draw alone.
133
+
134
+ ---
54
135
  ## Book-register checklist
55
136
 
56
137
  - [ ] **Opens on a scene** — a place, a person, a moment, a number. Never on an argument.
57
138
  - [ ] **No "I", no editorial "we", no visible author.** The camera is there; the camera is not the subject.
58
139
  - [ ] **Observes; does not assert.** "The intelligence was not in any of the ants," not "intelligence is a property of substrates."
59
140
  - [ ] **Sells nothing.** Names no company, product, or technology. Quotes no code.
60
- - [ ] **No subheadings.** A horizontal rule may mark a shift in scene or scale, once or twice.
61
- - [ ] **Specific numbers, or honest hedging** (*on the order of*, *approximately*). Never false specificity.
141
+ - [ ] **No contractions.** *does not*, not *doesn't*. Five in 92,894 words of corpus.
142
+ - [ ] **No `###` subheadings** zero across 25 chapters. But **use the horizontal rule**: median 5 scene breaks per chapter, up to 10.
143
+ - [ ] **"The reader", not "you"** — 134 to 116, and 50 of the *you*s are in the epilogue. Direct address is saved for the end.
144
+ - [ ] **One paragraph in four is a single sentence** (25.7% measured). Vary sentence length hard: median 12 words, but 22.2% are ≤6.
145
+ - [ ] **Specific numbers, or honest hedging** (*on the order of*, *roughly*). Never false specificity. Digits appear only 5.8 times per 10k words — each one is load-bearing.
62
146
  - [ ] **Never defines a technical term** — makes its meaning land through use.
63
- - [ ] **Closes on a short concrete sentence** the reader carries, often a recontextualised return to the opening.
147
+ - [ ] **Opens on a concrete particular** a place and a temperature, a date and a person and an action, or a short flat sentence holding a contradiction. Never on the thesis.
148
+ - [ ] **Closes short** — median 10 words — often a recontextualised return to the opening image. Never a summary.
149
+ - [ ] **Reaches for the three shapes** — the negative-definition fragment, "It is not X. It is Y.", the copula-forward declarative.
150
+ - [ ] **Leaves the observation alone.** No interpretive paragraph after a clear one.
64
151
  - [ ] **Passes both the "your mum" and the "Demis Hassabis" test.**
65
152
  - [ ] **The emotion is recognition, not awe.** No "this changes everything."
153
+ - [ ] **Run `bash .claude/skills/voice/corpus-check.sh <draft.md>`** — it counts the mechanical half against the corpus and cannot judge the rest.
66
154
 
67
155
  ## Commercial-register checklist
68
156
 
69
- - [ ] **Em dashes: 3 or fewer.** Count them.
157
+ - [ ] **Em dashes: 3 or fewer.** Count them. (Book register is the opposite — 89.6 per 10k. Do not carry this rule across.)
70
158
  - [ ] **Every quality adjective replaced by a number** — or the claim cut, or the gap stated.
71
159
  - [ ] **No fabricated proof.** Every metric, quote, logo, benchmark, file path real or marked unproven.
72
160
  - [ ] **Speed claims carry a measured number** from `product-marketing.md`'s table.
@@ -0,0 +1,87 @@
1
+ #!/usr/bin/env bash
2
+ # corpus-check.sh — measure book-register prose against the corpus that defines it.
3
+ #
4
+ # bash .claude/skills/voice/corpus-check.sh --corpus re-derive the SKILL.md table
5
+ # bash .claude/skills/voice/corpus-check.sh <draft.md> ... check a draft
6
+ # bash .claude/skills/voice/corpus-check.sh --self-test prove the checker goes RED
7
+ #
8
+ # It counts the MECHANICAL half of the voice only: the things a machine can see.
9
+ # It cannot tell whether a sentence observes or asserts, and it never claims to.
10
+ # A green run is a draft that has not broken a countable rule. It is not a good draft.
11
+ #
12
+ # manifest: monorepo-only (the corpus lives in the sibling repo apps/ants)
13
+ set -o pipefail
14
+
15
+ CORPUS="${VOICE_CORPUS:-/Users/toc/Server/apps/ants/docs/book/manuscript}"
16
+
17
+ measure() { # measure <label> <file...>
18
+ python3 - "$@" <<'PY'
19
+ import re,sys,statistics
20
+ label=sys.argv[1]; files=sys.argv[2:]
21
+ txt=[]
22
+ for f in files:
23
+ try: t=open(f, encoding="utf-8").read()
24
+ except OSError as e: print(f" cannot read {f}: {e}"); continue
25
+ txt.append(t)
26
+ raw="\n".join(txt)
27
+ raw=re.sub(r'\A---\n.*?\n---\n','',raw,flags=re.S) # YAML frontmatter is metadata, not prose
28
+ body="\n".join(l for l in raw.split("\n") if not l.startswith("#"))
29
+ words=len(body.split())
30
+ if not words: print(" EMPTY — nothing to measure"); sys.exit(2)
31
+ sents=[s.strip() for s in re.split(r'(?<=[.!?])\s+',body) if len(s.strip())>1]
32
+ wl=[len(s.split()) for s in sents]
33
+ paras=[p.strip() for p in body.split("\n\n") if p.strip() and p.strip()!="---"]
34
+ psent=[len(re.split(r'(?<=[.!?])\s+',p)) for p in paras]
35
+ per10k=lambda n: 10000*n/words
36
+ CONTRACTION=r"n[\u2019']t\b"
37
+ c=lambda pat: len(re.findall(pat,body))
38
+ craw=lambda pat: len(re.findall(pat,raw)) # headings live only in raw
39
+ one=sum(1 for x in psent if x==1)
40
+ short=sum(1 for x in wl if x<=6)
41
+ last=re.split(r'(?<=[.!?])\s+',paras[-1].replace("\n"," "))[-1] if paras else ""
42
+ print(f" {label}: {words} words · {len(sents)} sentences · {len(paras)} paragraphs")
43
+ print(f" I {c(r'(?<![A-Za-z])I[ ,.]'):6d} target 0")
44
+ print(f" contractions n\'t {c(CONTRACTION):6d} target ~0 (corpus 0.5/10k)")
45
+ print(f" ### headings {craw(r'(?m)^#{3,}'):6d} target 0")
46
+ sb=[len(re.findall(r'(?m)^---\s*$',t)) for t in txt]
47
+ print(f" --- scene breaks {sum(sb):6d} median {statistics.median(sb) if sb else 0:.0f}/file corpus median 5")
48
+ print(f" 1-sentence paras {one:6d} {100*one/len(paras):5.1f}% corpus 25.7%")
49
+ print(f" sentences <=6 words {short:6d} {100*short/len(sents):5.1f}% corpus 22.4%")
50
+ print(f" sentence median {statistics.median(wl):6.0f} words corpus 12 (mean {statistics.mean(wl):.1f}, corpus 15.1)")
51
+ print(f" 'the reader' {c(r'(?i)\bthe reader\b'):6d}")
52
+ print(f" 'you' {c(r'(?i)\byou\b'):6d} corpus favours 'the reader'")
53
+ print(f" digits per10k {per10k(c(r'\b\d')):6.1f} corpus 5.8")
54
+ print(f" em dash per10k {per10k(c(chr(8212))):6.1f} corpus 89.8")
55
+ print(f" final sentence {len(last.split()):6d} words corpus median 10")
56
+ if last: print(f" > {last[:100]}")
57
+ PY
58
+ }
59
+
60
+ case "${1:-}" in
61
+ --corpus)
62
+ if [ ! -d "$CORPUS" ]; then
63
+ echo "corpus not found: $CORPUS"
64
+ echo "It lives in the sibling repo apps/ants and does not ship. Set VOICE_CORPUS to point at it."
65
+ exit 4 # unavailable — NOT a pass
66
+ fi
67
+ measure "corpus" "$CORPUS"/[0-9][0-9]-*.md ;;
68
+
69
+ --self-test)
70
+ d=$(mktemp -d); trap 'rm -rf "$d"' EXIT
71
+ printf '### A heading\n\nI think this is fine. It doesn'"'"'t matter.\n\nYou will see that you agree, you really will.\n' > "$d/bad.md"
72
+ out=$(measure "red-proof" "$d/bad.md")
73
+ echo "$out"
74
+ fail=0
75
+ echo "$out" | grep -qE '^ +I +[1-9]' || { echo "RED PROOF FAILED: 'I' not counted"; fail=1; }
76
+ echo "$out" | grep -qE "contractions n't +[1-9]" || { echo "RED PROOF FAILED: contraction not counted"; fail=1; }
77
+ echo "$out" | grep -qE '### headings +[1-9]' || { echo "RED PROOF FAILED: heading not counted"; fail=1; }
78
+ [ $fail -eq 0 ] && echo "SELF-TEST ok — the checker sees all three violations" || exit 1 ;;
79
+
80
+ ""|-h|--help)
81
+ sed -n '2,14p' "$0" | sed 's/^# \{0,1\}//' ;;
82
+
83
+ *)
84
+ measure "draft" "$@"
85
+ echo
86
+ echo " Counted, not judged. The uncountable half is the checklist in SKILL.md." ;;
87
+ esac
@@ -1,35 +0,0 @@
1
- #!/usr/bin/env bash
2
- # COMPACT-HINT — PreToolUse: suggest /compact when context is large.
3
- #
4
- # Non-blocking — writes one line to stderr, fires at most once per session.
5
- # Threshold: 400KB transcript (~80-120k tokens depending on content density).
6
- #
7
- # Disable: ECC_DISABLED_HOOKS=hook:compact-hint
8
-
9
- # shellcheck source=lib/hook.sh
10
- source "$CLAUDE_PROJECT_DIR/.claude/hooks/lib/hook.sh"
11
- is_hook_disabled "hook:compact-hint" && exit 0
12
-
13
- PAYLOAD="${1:-}"
14
- [[ -z "$PAYLOAD" ]] && exit 0
15
-
16
- # Locate the transcript — from hook JSON or env var (Claude Code sets both)
17
- TRANSCRIPT=$(printf '%s' "$PAYLOAD" | jq -r '.transcript_path // .transcriptPath // empty' 2>/dev/null)
18
- [[ -z "$TRANSCRIPT" ]] && TRANSCRIPT="${CLAUDE_TRANSCRIPT_PATH:-}"
19
- [[ -z "$TRANSCRIPT" || ! -f "$TRANSCRIPT" ]] && exit 0
20
-
21
- SIZE=$(wc -c < "$TRANSCRIPT" 2>/dev/null | tr -d ' ')
22
- [[ -z "$SIZE" || "$SIZE" -lt 400000 ]] && exit 0
23
-
24
- # Fire at most once per session
25
- SESSION_KEY=$(hook_session_key "$PAYLOAD")
26
- FLAG="/tmp/oneie-compact-hint-${SESSION_KEY}"
27
- [[ -f "$FLAG" ]] && exit 0
28
- touch "$FLAG"
29
-
30
- SIZE_KB=$(( SIZE / 1024 ))
31
- echo "" >&2
32
- echo "⚡ Context is ~${SIZE_KB}KB — run /compact before the next big edit to keep responses fast and cheap." >&2
33
- echo "" >&2
34
-
35
- exit 0
@@ -1,83 +0,0 @@
1
- #!/usr/bin/env bash
2
- # GATE-GUARD — PreToolUse(Edit|Write|MultiEdit): require Read before edit.
3
- #
4
- # Blocks the first attempt to Edit/Write an existing file that hasn't been
5
- # Read in this session. Forces "understand before you change."
6
- #
7
- # Rules:
8
- # - New files (Write creating a file that doesn't exist yet) → always allowed
9
- # - Settings files (.claude/settings*.json) → always allowed
10
- # - Subagent calls → allowed (parent session's reads cover the session)
11
- # - File already in this session's read registry → allowed
12
- # - Existing file NOT yet read → BLOCK with instructions
13
- #
14
- # Disable for the session: ECC_GATEGUARD=off
15
- # Disable one-off: ECC_DISABLED_HOOKS=hook:gate-guard
16
- # Skip globally in CI: add hook:gate-guard to ECC_DISABLED_HOOKS in env
17
-
18
- # shellcheck source=lib/hook.sh
19
- source "$CLAUDE_PROJECT_DIR/.claude/hooks/lib/hook.sh"
20
- is_hook_disabled "hook:gate-guard" && exit 0
21
-
22
- PAYLOAD="${1:-}"
23
- [[ -z "$PAYLOAD" ]] && exit 0
24
-
25
- TOOL=$(printf '%s' "$PAYLOAD" | jq -r '.tool_name // empty' 2>/dev/null)
26
- case "$TOOL" in Edit|Write|MultiEdit) ;; *) exit 0 ;; esac
27
-
28
- # Subagents: parent session already passed the gate for these files
29
- SUBAGENT=$(printf '%s' "$PAYLOAD" | jq -r '.parent_tool_use_id // .parentToolUseId // empty' 2>/dev/null)
30
- [[ -n "$SUBAGENT" ]] && exit 0
31
-
32
- SESSION_KEY=$(hook_session_key "$PAYLOAD")
33
- READS_FILE="/tmp/oneie-gate-reads-${SESSION_KEY}"
34
-
35
- _deny() {
36
- # Claude Code PreToolUse block format
37
- printf '%s' "$(jq -nc --arg msg "$1" \
38
- '{"hookSpecificOutput":{"hookEventName":"PreToolUse","permissionDecision":"deny","permissionDecisionReason":$msg}}')"
39
- exit 0
40
- }
41
-
42
- _is_settings() {
43
- [[ "$1" =~ \.claude/settings[^/]*\.json$ ]]
44
- }
45
-
46
- _was_read() {
47
- local fp="$1"
48
- [[ -f "$READS_FILE" ]] && grep -qF "$fp" "$READS_FILE" 2>/dev/null
49
- }
50
-
51
- _block_msg() {
52
- local fp="$1" verb="$2"
53
- printf '[Gate-Guard] Read %s before you %s it.\n\nUse the Read tool on this file first to prove you understand it, then retry.\n\nTo disable for this session: set ECC_GATEGUARD=off\nTo disable permanently: add hook:gate-guard to ECC_DISABLED_HOOKS in your environment.' \
54
- "$fp" "$verb"
55
- }
56
-
57
- check() {
58
- local fp="$1" tool="$2"
59
- [[ -z "$fp" ]] && return 0
60
- _is_settings "$fp" && return 0
61
- # New file being created — no prior read needed
62
- [[ "$tool" == "Write" && ! -f "$fp" ]] && return 0
63
- # Previously read this session — allowed
64
- _was_read "$fp" && return 0
65
- # Existing file not read → block
66
- [[ -f "$fp" ]] && { _deny "$(_block_msg "$fp" "$(printf '%s' "$tool" | tr '[:upper:]' '[:lower:]')")"; }
67
- return 0
68
- }
69
-
70
- case "$TOOL" in
71
- Edit|Write)
72
- FILE=$(printf '%s' "$PAYLOAD" | jq -r '.tool_input.file_path // empty' 2>/dev/null)
73
- check "$FILE" "$TOOL"
74
- ;;
75
- MultiEdit)
76
- while IFS= read -r fp; do
77
- [[ -z "$fp" ]] && continue
78
- check "$fp" "Edit"
79
- done < <(printf '%s' "$PAYLOAD" | jq -r '.tool_input.edits[].file_path // empty' 2>/dev/null)
80
- ;;
81
- esac
82
-
83
- exit 0
@@ -1,26 +0,0 @@
1
- #!/usr/bin/env bash
2
- # READ-TRACKER — PostToolUse(Read): record file_path as read this session.
3
- #
4
- # Feeds gate-guard.sh: once a file appears in the reads registry,
5
- # Edit/Write on that file is allowed. Disable both with ECC_GATEGUARD=off
6
- # or ECC_DISABLED_HOOKS=hook:gate-guard.
7
- #
8
- # Non-blocking, always exits 0. Failure to write the registry is silent
9
- # (gate-guard falls back to allow on missing registry).
10
-
11
- # shellcheck source=lib/hook.sh
12
- source "$CLAUDE_PROJECT_DIR/.claude/hooks/lib/hook.sh"
13
- is_hook_disabled "hook:gate-guard" && exit 0
14
-
15
- PAYLOAD="${1:-}"
16
- [[ -z "$PAYLOAD" ]] && exit 0
17
-
18
- FILE=$(printf '%s' "$PAYLOAD" | jq -r '.tool_input.file_path // empty' 2>/dev/null)
19
- [[ -z "$FILE" ]] && exit 0
20
-
21
- SESSION_KEY=$(hook_session_key "$PAYLOAD")
22
- READS_FILE="/tmp/oneie-gate-reads-${SESSION_KEY}"
23
-
24
- # Append absolute path — idempotent (duplicates are fine, grep is fast)
25
- echo "$FILE" >> "$READS_FILE" 2>/dev/null || true
26
- exit 0
@@ -1,51 +0,0 @@
1
- #!/bin/bash
2
- # SESSION-END VERIFY — Report regressions introduced during session
3
- #
4
- # Runs on Stop (session end). Non-blocking — just reports.
5
- # Lets human see what might have broken without blocking the session.
6
- # Emits hook:session-end:{ok,warn} signal per Rule 1 (see .claude/skills/signal.md).
7
-
8
- # shellcheck source=lib/signal.sh
9
- source "$CLAUDE_PROJECT_DIR/.claude/hooks/lib/signal.sh"
10
-
11
- cd "$CLAUDE_PROJECT_DIR" || exit 0
12
-
13
- echo ""
14
- echo "┌─────────────────────────────────────────────────────────────┐"
15
- echo "│ SESSION-END VERIFICATION │"
16
- echo "└─────────────────────────────────────────────────────────────┘"
17
- echo ""
18
-
19
- # Run only biome (fast, ~0.3s). Skip tsc/vitest to avoid blocking session exit.
20
- RESULT=$(bun biome check . 2>&1)
21
- EXIT=$?
22
-
23
- if [ $EXIT -eq 0 ]; then
24
- echo "✓ All checks passed. Baseline is green."
25
- echo ""
26
- emit_signal "hook:session-end:ok" 1 "biome=clean"
27
- exit 0
28
- fi
29
-
30
- # Extract test counts
31
- PASSED=$(echo "$RESULT" | grep -o '[0-9]* pass' | head -1 | awk '{print $1}')
32
- FAILED=$(echo "$RESULT" | grep -o '[0-9]* fail' | head -1 | awk '{print $1}')
33
- ERRORS=$(echo "$RESULT" | grep -c "error TS" || echo "0")
34
-
35
- echo "⚠ Issues detected:"
36
- if [ -n "$FAILED" ] && [ "$FAILED" -gt 0 ]; then
37
- echo " · Tests: $FAILED failed (was passing before?)"
38
- fi
39
- if [ "$ERRORS" -gt 0 ]; then
40
- echo " · TypeScript: $ERRORS type errors"
41
- fi
42
-
43
- echo ""
44
- echo "Next session should start with: bun run verify"
45
- echo ""
46
-
47
- # Mild warn — baseline dirty but session continuing
48
- emit_signal "hook:session-end:warn" -0.5 "failed=${FAILED:-0} errors=${ERRORS:-0}"
49
-
50
- # Non-blocking — always exit 0
51
- exit 0
@@ -1,140 +0,0 @@
1
- #!/usr/bin/env bash
2
- # STOP-REFLECT — capture session learnings while context is fresh.
3
- #
4
- # Runs on Stop alongside session-end-verify. Non-blocking.
5
- # Scans the session's git delta for signals of new conventions and appends
6
- # proposals to .claude/improvements.queue.md for batch review.
7
- #
8
- # Heuristics (intentionally conservative — false positives = noise):
9
- # 1. CLAUDE.md / rules / skills changed → record the change as a candidate
10
- # convention for upstream propagation.
11
- # 2. Code touched but no doc touched in same family → flag for doc-drift.
12
- # 3. New file created under .claude/skills/ or .claude/rules/ → flag as new
13
- # primitive (likely deserves a one-line README mention).
14
- #
15
- # Per Rule 1 (closed loop) — emits hook:stop-reflect:{ok,warn} with counts.
16
- # shellcheck source=lib/signal.sh
17
- source "$CLAUDE_PROJECT_DIR/.claude/hooks/lib/signal.sh"
18
-
19
- cd "$CLAUDE_PROJECT_DIR" || exit 0
20
-
21
- QUEUE="$CLAUDE_PROJECT_DIR/.claude/improvements.queue.md"
22
- mkdir -p "$(dirname "$QUEUE")"
23
-
24
- # What changed this session? Use unstaged + staged + untracked.
25
- CHANGED=$(git status --porcelain 2>/dev/null | awk '{print $2}')
26
- [ -z "$CHANGED" ] && { emit_signal "hook:stop-reflect:ok" 1 "changed=0"; exit 0; }
27
-
28
- # Header for this session's block (idempotent — appends if file exists)
29
- TS=$(date -u +%Y-%m-%dT%H:%M:%SZ)
30
- PROPOSALS=0
31
-
32
- # Buffer proposals; only write if non-empty
33
- BUF=""
34
-
35
- # add_if_new — dedup guard: skip proposal if an equivalent entry already
36
- # appears in the queue (or earlier in this session's buffer).
37
- #
38
- # Key = category + primary identifier only (the backtick-quoted file/path).
39
- # This means "doc-drift `foo.md` not updated despite 6 files" and
40
- # "doc-drift `foo.md` not updated despite 7 files" collapse to the same key,
41
- # preventing the queue from ballooning on each Stop.
42
- add_if_new() {
43
- local msg="$1" key
44
- # Extract: **category** `identifier` — everything after the second backtick is noise.
45
- key=$(printf '%s' "$msg" | grep -oE '\*\*[a-z-]+\*\*[^`]*`[^`]+`' | head -1)
46
- # Fallback: use full message with numbers normalised (for entries without backtick paths).
47
- [ -z "$key" ] && key=$(printf '%s' "$msg" | sed -E 's/[0-9]+/N/g')
48
- { cat "$QUEUE" 2>/dev/null; printf '%b' "$BUF"; } \
49
- | grep -qF -- "$key" && return 0
50
- BUF+="$msg\n"
51
- PROPOSALS=$((PROPOSALS + 1))
52
- }
53
-
54
- # (1) Convention-bearing files
55
- CONVENTION_HITS=$(echo "$CHANGED" | grep -E '(CLAUDE\.md$|\.claude/rules/|\.claude/skills/|\.claude/agents/)' || true)
56
- if [ -n "$CONVENTION_HITS" ]; then
57
- while IFS= read -r f; do
58
- add_if_new "- **convention** \`$f\` — review: did this change introduce a rule the broader team should know? If yes, surface it in root \`CLAUDE.md\` or the relevant skill."
59
- done <<< "$CONVENTION_HITS"
60
- fi
61
-
62
- # (2) New primitives (untracked files in .claude/)
63
- NEW_PRIMITIVES=$(echo "$CHANGED" | grep -E '^\.claude/(skills|rules|agents|hooks)/[^/]+\.(md|sh)$' | while read -r f; do
64
- git ls-files --error-unmatch "$f" >/dev/null 2>&1 || echo "$f"
65
- done)
66
- if [ -n "$NEW_PRIMITIVES" ]; then
67
- while IFS= read -r f; do
68
- add_if_new "- **new primitive** \`$f\` — add a one-line entry to the index (\`.claude/CLAUDE.md\` or root README skills table)."
69
- done <<< "$NEW_PRIMITIVES"
70
- fi
71
-
72
- # (3) Doc drift — code touched in a family but no doc touched
73
- # Family map: agents/src ↔ agents/CLAUDE.md, packages/sdk/src ↔ packages/sdk/CLAUDE.md,
74
- # one.ie/web/src ↔ one.ie/web/CLAUDE.md
75
- check_drift() {
76
- local code_glob="$1"; local doc_file="$2"
77
- local code_changed
78
- code_changed=$(echo "$CHANGED" | grep -E "$code_glob" || true)
79
- if [ -n "$code_changed" ] && ! echo "$CHANGED" | grep -qF "$doc_file"; then
80
- local count
81
- count=$(echo "$code_changed" | wc -l | awk '{print $1}')
82
- if [ "$count" -ge 3 ]; then
83
- add_if_new "- **doc-drift** \`$doc_file\` not updated despite $count file changes under \`$code_glob\`. Review."
84
- fi
85
- fi
86
- }
87
- check_drift '^agents/src/' 'agents/CLAUDE.md'
88
- check_drift '^packages/sdk/src/' 'packages/sdk/CLAUDE.md'
89
- check_drift '^one\.ie/web/src/' 'one.ie/web/CLAUDE.md'
90
- check_drift '^api/src/' 'api/CLAUDE.md'
91
-
92
- # (4) Completed /do cycle → suggest /skill-create to crystallise the pattern.
93
- # Heuristic: learnings.md was touched AND W3 edited >=3 non-plan/non-text files.
94
- if echo "$CHANGED" | grep -qF 'text/learnings.md'; then
95
- CYCLE_FILES=$(echo "$CHANGED" | grep -vE '^text/|^text/|^\.claude/' | wc -l | awk '{print $1}')
96
- if [ "$CYCLE_FILES" -ge 3 ]; then
97
- # Extract the cycle slug from the last learnings entry
98
- CYCLE_SLUG=$(grep -oE 'cycle [0-9]+|· [a-z][a-z0-9-]+' text/learnings.md 2>/dev/null | tail -1 | sed 's/^· //')
99
- add_if_new "- **skill-create** cycle closed with ${CYCLE_FILES} file(s) changed — run \`/skill-create ${CYCLE_SLUG}\` to crystallise the pattern as a reusable skill."
100
- fi
101
- fi
102
-
103
- # (5) Promise runtime — a touched todo whose promise (text/<slug>.md) declares a
104
- # world: manifest. One-line nudge to presence-check the declared runtime.
105
- TODO_TOUCHED=$(echo "$CHANGED" | grep -E '^text/[^/]+-todo\.md$' || true)
106
- if [ -n "$TODO_TOUCHED" ]; then
107
- while IFS= read -r f; do
108
- [ -z "$f" ] && continue
109
- slug=$(basename "$f"); slug="${slug%-todo.md}"
110
- promise="text/${slug}.md"
111
- [ -f "$promise" ] || continue
112
- # world: block inside YAML frontmatter only (body prose may mention "world:")
113
- if awk 'BEGIN{fm=0} /^---[[:space:]]*$/{fm++; if(fm==2) exit; next} fm==1 && /^world:/{found=1; exit} END{exit !found}' "$promise"; then
114
- add_if_new "- **promise-world** \`$promise\` — todo touched this session; presence-check its world: entries (agents/skills/workflow) for gaps."
115
- fi
116
- done <<< "$TODO_TOUCHED"
117
- fi
118
-
119
- # Only write the file if we found something worth reviewing.
120
- # Append under ## Actionable (no new timestamped section — avoids dated noise).
121
- if [ "$PROPOSALS" -gt 0 ]; then
122
- {
123
- printf "%b" "$BUF"
124
- } >> "$QUEUE"
125
-
126
- echo ""
127
- echo "┌─────────────────────────────────────────────────────────────┐"
128
- echo "│ STOP-REFLECT: $PROPOSALS proposal(s) queued │"
129
- echo "│ Review: .claude/improvements.queue.md │"
130
- echo "└─────────────────────────────────────────────────────────────┘"
131
-
132
- emit_signal "hook:stop-reflect:warn" 0.5 "proposals=$PROPOSALS"
133
- emit_world "session:stop" "fyi" "session,stop" "session stopped — $PROPOSALS proposal(s) queued" "proposals=$PROPOSALS"
134
- else
135
- CHANGED_N="$(echo "$CHANGED" | wc -l | awk '{print $1}')"
136
- emit_signal "hook:stop-reflect:ok" 1 "changed=$CHANGED_N proposals=0"
137
- emit_world "session:stop" "fyi" "session,stop" "session stopped — $CHANGED_N file(s) changed" "changed=$CHANGED_N"
138
- fi
139
-
140
- exit 0
@@ -1,57 +0,0 @@
1
- #!/usr/bin/env bash
2
- # SYNC-PRIORITY-TODO — Keep todo.md at the project root in sync with the priority queue.
3
- #
4
- # Fires on:
5
- # PostToolUse Write/Edit — when any *-todo.md or text/learnings.md changes
6
- # Stop — always at session end
7
- # SessionStart — always at session start
8
- #
9
- # Rewrites /todo.md with the current ranked queue from do-rank.py.
10
- # Non-blocking, best-effort — always exits 0.
11
-
12
- # shellcheck source=lib/signal.sh
13
- HOOK_DIR="$(cd "$(dirname "$0")" && pwd)"
14
- source "$HOOK_DIR/lib/signal.sh" 2>/dev/null || true
15
-
16
- cd "$CLAUDE_PROJECT_DIR" || exit 0
17
-
18
- # When fired from PostToolUse, only regenerate if a todo or learnings file changed.
19
- # Stop/SessionStart pass no $1 argument → always regenerate.
20
- if [ -n "$1" ]; then
21
- FILE=$(printf '%s' "$1" | python3 -c "import sys,json; d=json.load(sys.stdin); print(d.get('tool_input',{}).get('file_path','') or d.get('tool_input',{}).get('path',''))" 2>/dev/null)
22
- case "$FILE" in
23
- *-todo.md|*/text/learnings.md) ;;
24
- *) exit 0 ;;
25
- esac
26
- fi
27
-
28
- # Hook-driven run: this fires on every session open and every plan edit, so the ranker's
29
- # tasks:everywhere board read gets a short budget and degrades to file-only rather than
30
- # blocking the session on an ~11s receiver. An explicit `/do next` waits for the real answer.
31
- export DO_RANK_HOOK=1
32
-
33
- # Close → weight: reconcile path strength from learnings.md closes (idempotent) before
34
- # we rank, so a cycle close moves the next pick autonomously. See text/loop-plan.md.
35
- python3 "$CLAUDE_PROJECT_DIR/.claude/scripts/do-rank.py" --sync-closes >/dev/null 2>&1 || true
36
-
37
- QUEUE_OUT=$(python3 "$CLAUDE_PROJECT_DIR/.claude/scripts/do-rank.py" 2>/dev/null)
38
- if [ -z "$QUEUE_OUT" ]; then
39
- emit_signal "hook:priority-todo:dissolved" -0.5 "ranker=no-output"
40
- exit 0
41
- fi
42
-
43
- TS=$(date '+%Y-%m-%d %H:%M')
44
-
45
- cat > "$CLAUDE_PROJECT_DIR/todo.md" << EOF
46
- # Priority queue — $TS
47
-
48
- \`\`\`
49
- $QUEUE_OUT
50
- \`\`\`
51
-
52
- > Auto-generated by \`do-rank.py\` on every session start/end and every plan edit.
53
- > Run \`/do next\` to see this live, or \`/do audit\` for kill-switch states.
54
- EOF
55
-
56
- emit_signal "hook:priority-todo:ok" 1 "ts=$TS"
57
- exit 0