geneseed 2.0.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 (337) hide show
  1. package/CHANGELOG.md +938 -0
  2. package/DESIGN.md +1423 -0
  3. package/LICENSE +21 -0
  4. package/QUICKSTART.md +48 -0
  5. package/README.md +336 -0
  6. package/SETUP.md +1027 -0
  7. package/SHIPPED.md +70 -0
  8. package/adapters/bob/README.md +100 -0
  9. package/adapters/claude-code/README.md +101 -0
  10. package/adapters/claude-code/settings.json +47 -0
  11. package/adapters/claude-code/skills/geneseed/SKILL.md +72 -0
  12. package/adapters/copilot/README.md +76 -0
  13. package/adapters/opencode/GLOBAL-HARNESS-SPEC.md +434 -0
  14. package/adapters/opencode/HOW-OPENCODE-LOADS.md +158 -0
  15. package/adapters/opencode/README.md +582 -0
  16. package/adapters/opencode/agents/orchestrator.md +25 -0
  17. package/adapters/opencode/opencode.json +44 -0
  18. package/adapters/opencode/plugins/geneseed-activity.js +430 -0
  19. package/adapters/opencode/plugins/geneseed-context.js +876 -0
  20. package/adapters/opencode/plugins/geneseed-guard.js +290 -0
  21. package/adapters/opencode/plugins/geneseed-learn.js +396 -0
  22. package/adapters/opencode/plugins/geneseed-notify.js +142 -0
  23. package/adapters/opencode/plugins/geneseed-ponytail.js +148 -0
  24. package/adapters/opencode/plugins/geneseed-workflow.js +183 -0
  25. package/adapters/opencode/workflows/_runtime.js +277 -0
  26. package/adapters/opencode/workflows/council.js +64 -0
  27. package/adapters/opencode/workflows/dispatch.js +89 -0
  28. package/adapters/opencode/workflows/research-plan-implement.js +43 -0
  29. package/adapters/opencode/workflows/review.js +57 -0
  30. package/bin/geneseed-cli.mjs +412 -0
  31. package/bin/geneseed-hook.mjs +129 -0
  32. package/bin/geneseed.mjs +1086 -0
  33. package/docs/declined.md +149 -0
  34. package/docs/limits.md +270 -0
  35. package/docs/opencode-plugin-setup.md +64 -0
  36. package/docs/token-footprint.md +68 -0
  37. package/docs/web/_groups.json +45 -0
  38. package/docs/web/about.md +6 -0
  39. package/docs/web/adapters-claude-code.md +8 -0
  40. package/docs/web/adapters-opencode-loads.md +8 -0
  41. package/docs/web/adapters-opencode-spec.md +8 -0
  42. package/docs/web/adapters-opencode.md +8 -0
  43. package/docs/web/agents.md +8 -0
  44. package/docs/web/authoring.md +11 -0
  45. package/docs/web/autostart.md +9 -0
  46. package/docs/web/claude-hooks.md +36 -0
  47. package/docs/web/cli.md +6 -0
  48. package/docs/web/collaboration.md +27 -0
  49. package/docs/web/configure-wiki.md +9 -0
  50. package/docs/web/design.md +7 -0
  51. package/docs/web/env-knobs.md +9 -0
  52. package/docs/web/exclusions.md +26 -0
  53. package/docs/web/first-session.md +28 -0
  54. package/docs/web/footprint.md +31 -0
  55. package/docs/web/foreman-mode.md +33 -0
  56. package/docs/web/glossary.md +6 -0
  57. package/docs/web/harnesses.md +28 -0
  58. package/docs/web/headless.md +9 -0
  59. package/docs/web/ingest-docs.md +9 -0
  60. package/docs/web/install-paths.md +9 -0
  61. package/docs/web/install-quick.md +35 -0
  62. package/docs/web/lsp-overview.md +37 -0
  63. package/docs/web/mcp-claude-code.md +10 -0
  64. package/docs/web/mcp-filesystem.md +9 -0
  65. package/docs/web/mcp-gitlab.md +9 -0
  66. package/docs/web/mcp-markitdown.md +9 -0
  67. package/docs/web/mcp-overview.md +34 -0
  68. package/docs/web/mcp-trouble.md +9 -0
  69. package/docs/web/mcp-verify.md +9 -0
  70. package/docs/web/memory.md +7 -0
  71. package/docs/web/migrate.md +39 -0
  72. package/docs/web/model.md +20 -0
  73. package/docs/web/notebook.md +7 -0
  74. package/docs/web/pipelines.md +24 -0
  75. package/docs/web/plugin-activity.md +23 -0
  76. package/docs/web/plugin-context.md +26 -0
  77. package/docs/web/plugin-guard.md +24 -0
  78. package/docs/web/plugin-learn.md +27 -0
  79. package/docs/web/plugin-notify.md +24 -0
  80. package/docs/web/plugin-ponytail.md +23 -0
  81. package/docs/web/plugin-setup.md +7 -0
  82. package/docs/web/plugin-workflow.md +24 -0
  83. package/docs/web/plugins.md +17 -0
  84. package/docs/web/project-context.md +9 -0
  85. package/docs/web/rules.md +8 -0
  86. package/docs/web/run-anywhere.md +9 -0
  87. package/docs/web/self-improve.md +8 -0
  88. package/docs/web/setup-choices.md +39 -0
  89. package/docs/web/skills.md +8 -0
  90. package/docs/web/themes-author.md +8 -0
  91. package/docs/web/themes.md +9 -0
  92. package/docs/web/token-footprint.md +7 -0
  93. package/docs/web/trouble.md +38 -0
  94. package/docs/web/upgrade.md +9 -0
  95. package/docs/web/verify.md +30 -0
  96. package/docs/web/wiki.md +7 -0
  97. package/docs/web/worktree.md +10 -0
  98. package/docs/web-ui.md +144 -0
  99. package/docs/wiki.md +43 -0
  100. package/geneseed +39 -0
  101. package/geneseed.cmd +34 -0
  102. package/harness.config.json +6 -0
  103. package/js/anim.mjs +326 -0
  104. package/js/catalog.mjs +112 -0
  105. package/js/checkout.mjs +88 -0
  106. package/js/cli-table.json +1034 -0
  107. package/js/cli.mjs +498 -0
  108. package/js/diff.mjs +384 -0
  109. package/js/doctor.mjs +1364 -0
  110. package/js/emit.mjs +1373 -0
  111. package/js/excludes.mjs +271 -0
  112. package/js/generate.mjs +379 -0
  113. package/js/hooks.mjs +1026 -0
  114. package/js/hosts.mjs +253 -0
  115. package/js/installs.mjs +378 -0
  116. package/js/inventory.mjs +175 -0
  117. package/js/lib/fs.mjs +913 -0
  118. package/js/lib/proc.mjs +28 -0
  119. package/js/lib/udiff.mjs +275 -0
  120. package/js/link.mjs +286 -0
  121. package/js/mcp.mjs +335 -0
  122. package/js/memory.mjs +108 -0
  123. package/js/menu.mjs +118 -0
  124. package/js/migrate.mjs +251 -0
  125. package/js/native.mjs +426 -0
  126. package/js/opencode.mjs +325 -0
  127. package/js/registry.mjs +110 -0
  128. package/js/render.mjs +282 -0
  129. package/js/settings.mjs +924 -0
  130. package/js/setup.mjs +492 -0
  131. package/js/status.mjs +281 -0
  132. package/js/themes.mjs +195 -0
  133. package/js/tui.mjs +444 -0
  134. package/js/uninstall.mjs +1137 -0
  135. package/js/update.mjs +910 -0
  136. package/js/web/actions.mjs +868 -0
  137. package/js/web/activity.mjs +284 -0
  138. package/js/web/api.mjs +873 -0
  139. package/js/web/docs.mjs +531 -0
  140. package/js/web/graph.mjs +0 -0
  141. package/js/web/jobs.mjs +480 -0
  142. package/js/web/server.mjs +1135 -0
  143. package/package.json +54 -0
  144. package/registry.json +474 -0
  145. package/src/AGENT.md.tmpl +390 -0
  146. package/src/agents/_template.md +76 -0
  147. package/src/agents/advocate.md +36 -0
  148. package/src/agents/architect.md +55 -0
  149. package/src/agents/developer.md +66 -0
  150. package/src/agents/docs.md +54 -0
  151. package/src/agents/empiricist.md +39 -0
  152. package/src/agents/explorer.md +54 -0
  153. package/src/agents/framer.md +36 -0
  154. package/src/agents/historian.md +51 -0
  155. package/src/agents/operator.md +37 -0
  156. package/src/agents/pragmatist.md +37 -0
  157. package/src/agents/reviewer.md +52 -0
  158. package/src/agents/security.md +57 -0
  159. package/src/agents/skeptic.md +48 -0
  160. package/src/agents/steward.md +36 -0
  161. package/src/agents/tester.md +54 -0
  162. package/src/agents/user-advocate.md +36 -0
  163. package/src/agents/visionary.md +36 -0
  164. package/src/laws/universal.md +387 -0
  165. package/src/memory/README.md +109 -0
  166. package/src/memory/gitignore +6 -0
  167. package/src/modes/README.md +26 -0
  168. package/src/modes/direct.md +2 -0
  169. package/src/modes/foreman.md +19 -0
  170. package/src/notebook/README.md +39 -0
  171. package/src/notebook/gitignore +7 -0
  172. package/src/postures/README.md +31 -0
  173. package/src/postures/artisan.md +14 -0
  174. package/src/postures/assistant.md +12 -0
  175. package/src/postures/expert.md +11 -0
  176. package/src/postures/mentor.md +11 -0
  177. package/src/postures/peer.md +12 -0
  178. package/src/skills/_template.md +47 -0
  179. package/src/skills/brainstorm.md +28 -0
  180. package/src/skills/clarify.md +28 -0
  181. package/src/skills/codebase-design.md +44 -0
  182. package/src/skills/commit.md +48 -0
  183. package/src/skills/council.md +34 -0
  184. package/src/skills/crash-course.md +28 -0
  185. package/src/skills/daydream/.claude-plugin/plugin.json +9 -0
  186. package/src/skills/daydream/SKILL.md +74 -0
  187. package/src/skills/daydream/VENDOR.md +25 -0
  188. package/src/skills/daydream/critic-prompt.md +38 -0
  189. package/src/skills/daydream/instructions.md +422 -0
  190. package/src/skills/daydream/synthesizer-prompt.md +41 -0
  191. package/src/skills/debug.md +37 -0
  192. package/src/skills/decode.md +28 -0
  193. package/src/skills/develop.md +29 -0
  194. package/src/skills/document-project.md +79 -0
  195. package/src/skills/domain-modeling.md +38 -0
  196. package/src/skills/drill.md +28 -0
  197. package/src/skills/feynman.md +26 -0
  198. package/src/skills/forge-mcp.md +48 -0
  199. package/src/skills/fresh-eyes.md +29 -0
  200. package/src/skills/frontend-design.md +58 -0
  201. package/src/skills/gap-detector.md +27 -0
  202. package/src/skills/geneseed-code-review.md +33 -0
  203. package/src/skills/geneseed.md +29 -0
  204. package/src/skills/git-archaeology.md +47 -0
  205. package/src/skills/git-rescue.md +68 -0
  206. package/src/skills/handoff.md +29 -0
  207. package/src/skills/herdr.md +164 -0
  208. package/src/skills/ingest.md +49 -0
  209. package/src/skills/learning-path.md +26 -0
  210. package/src/skills/migrate.md +45 -0
  211. package/src/skills/opencode-theme.md +52 -0
  212. package/src/skills/parallel-agents.md +28 -0
  213. package/src/skills/pipeline.md +52 -0
  214. package/src/skills/plan.md +45 -0
  215. package/src/skills/ponytail.md +29 -0
  216. package/src/skills/profile.md +58 -0
  217. package/src/skills/prose.md +42 -0
  218. package/src/skills/prototype.md +44 -0
  219. package/src/skills/react-view-transitions/AGENTS.md +955 -0
  220. package/src/skills/react-view-transitions/README.md +42 -0
  221. package/src/skills/react-view-transitions/SKILL.md +320 -0
  222. package/src/skills/react-view-transitions/VENDOR.md +16 -0
  223. package/src/skills/react-view-transitions/metadata.json +12 -0
  224. package/src/skills/react-view-transitions/references/css-recipes.md +242 -0
  225. package/src/skills/react-view-transitions/references/implementation.md +182 -0
  226. package/src/skills/react-view-transitions/references/nextjs.md +176 -0
  227. package/src/skills/react-view-transitions/references/patterns.md +262 -0
  228. package/src/skills/refactor.md +32 -0
  229. package/src/skills/release.md +43 -0
  230. package/src/skills/repo-map.md +36 -0
  231. package/src/skills/research.md +42 -0
  232. package/src/skills/review-response.md +36 -0
  233. package/src/skills/roast-me.md +28 -0
  234. package/src/skills/rule.md +100 -0
  235. package/src/skills/ship.md +49 -0
  236. package/src/skills/tdd.md +31 -0
  237. package/src/skills/tickets.md +44 -0
  238. package/src/skills/token-report/SKILL.md +76 -0
  239. package/src/skills/token-report/VENDOR.md +23 -0
  240. package/src/skills/token-report/scripts/token_report.mjs +1301 -0
  241. package/src/skills/wayfinder.md +49 -0
  242. package/src/skills/wiki.md +68 -0
  243. package/src/skills/workflow.md +38 -0
  244. package/themes/README.md +69 -0
  245. package/themes/_TEMPLATE.json +147 -0
  246. package/themes/biker.json +147 -0
  247. package/themes/commentator.json +147 -0
  248. package/themes/cyberpunk.json +147 -0
  249. package/themes/gamer.json +147 -0
  250. package/themes/imperial.json +147 -0
  251. package/themes/joker.json +147 -0
  252. package/themes/marvin.json +147 -0
  253. package/themes/mean.json +147 -0
  254. package/themes/military.json +147 -0
  255. package/themes/neutral.json +147 -0
  256. package/themes/opencode/README.md +58 -0
  257. package/themes/opencode/catppuccin.json +27 -0
  258. package/themes/opencode/dracula.json +27 -0
  259. package/themes/opencode/everforest.json +27 -0
  260. package/themes/opencode/gruvbox.json +27 -0
  261. package/themes/opencode/kanagawa.json +27 -0
  262. package/themes/opencode/neon.json +27 -0
  263. package/themes/opencode/nord.json +27 -0
  264. package/themes/opencode/rosepine.json +27 -0
  265. package/themes/opencode/tokyonight.json +27 -0
  266. package/themes/pirate.json +147 -0
  267. package/themes/sports.json +147 -0
  268. package/themes/verstappen.json +147 -0
  269. package/themes/wizard.json +147 -0
  270. package/web/dist/assets/About-DX1-VTBP.js +1 -0
  271. package/web/dist/assets/Activity-Dp9NaXOn.js +1 -0
  272. package/web/dist/assets/ActivityDetail-HpOBtrXS.js +1 -0
  273. package/web/dist/assets/Diff-Ct4G3Se8.js +5 -0
  274. package/web/dist/assets/Doctor-DGjkZFuA.js +1 -0
  275. package/web/dist/assets/Graph-b8o-S6kv.js +1 -0
  276. package/web/dist/assets/Harnesses-gr3-aHBF.js +1 -0
  277. package/web/dist/assets/Laws-DTwF5tTC.js +1 -0
  278. package/web/dist/assets/Library-BEZscyaQ.js +1 -0
  279. package/web/dist/assets/Markdown-k_LSLBGq.js +1 -0
  280. package/web/dist/assets/Profile-DydukTxP.js +1 -0
  281. package/web/dist/assets/Rules-CIRG4Ldt.js +1 -0
  282. package/web/dist/assets/Skills-Buoi1IBr.js +1 -0
  283. package/web/dist/assets/StatusBadge-CE_AJttl.js +1 -0
  284. package/web/dist/assets/Themes-CI4o3gJC.js +2 -0
  285. package/web/dist/assets/activity-BCW7e6Cy.js +1 -0
  286. package/web/dist/assets/audiowide-latin-400-normal-6GFCX7ni.woff2 +0 -0
  287. package/web/dist/assets/geist-mono-latin-400-normal-DKaoCDn5.woff2 +0 -0
  288. package/web/dist/assets/geist-mono-latin-500-normal-C3sF8Y1B.woff2 +0 -0
  289. package/web/dist/assets/geist-mono-latin-600-normal-BHzjB6_C.woff2 +0 -0
  290. package/web/dist/assets/hanken-grotesk-latin-400-italic-Bserb8X5.woff2 +0 -0
  291. package/web/dist/assets/hanken-grotesk-latin-400-normal-BG6hkEXj.woff2 +0 -0
  292. package/web/dist/assets/hanken-grotesk-latin-500-italic-BGfwwhek.woff2 +0 -0
  293. package/web/dist/assets/hanken-grotesk-latin-500-normal-DrDcrrxK.woff2 +0 -0
  294. package/web/dist/assets/hanken-grotesk-latin-600-normal-CIXX6EOa.woff2 +0 -0
  295. package/web/dist/assets/hanken-grotesk-latin-700-normal-CeQ8H3UY.woff2 +0 -0
  296. package/web/dist/assets/ibm-plex-mono-latin-400-normal-DMJ8VG8y.woff2 +0 -0
  297. package/web/dist/assets/ibm-plex-mono-latin-500-normal-DSY6xOcd.woff2 +0 -0
  298. package/web/dist/assets/ibm-plex-mono-latin-600-normal-BgSNZQsw.woff2 +0 -0
  299. package/web/dist/assets/ibm-plex-serif-latin-400-normal-BIGslYFI.woff2 +0 -0
  300. package/web/dist/assets/ibm-plex-serif-latin-500-normal-REKAfBVG.woff2 +0 -0
  301. package/web/dist/assets/ibm-plex-serif-latin-600-normal-DAxitmSu.woff2 +0 -0
  302. package/web/dist/assets/index-B1PIx7RM.js +1 -0
  303. package/web/dist/assets/index-BnTQUSUz.js +12 -0
  304. package/web/dist/assets/index-Ck2iCdaC.js +2 -0
  305. package/web/dist/assets/index-DUCsDv7z.css +1 -0
  306. package/web/dist/assets/inter-latin-400-normal-C38fXH4l.woff2 +0 -0
  307. package/web/dist/assets/inter-latin-500-normal-Cerq10X2.woff2 +0 -0
  308. package/web/dist/assets/inter-latin-600-normal-LgqL8muc.woff2 +0 -0
  309. package/web/dist/assets/inter-latin-700-normal-Yt3aPRUw.woff2 +0 -0
  310. package/web/dist/assets/jetbrains-mono-latin-400-normal-V6pRDFza.woff2 +0 -0
  311. package/web/dist/assets/jetbrains-mono-latin-500-normal-BWZEU5yA.woff2 +0 -0
  312. package/web/dist/assets/jetbrains-mono-latin-600-normal-C8RAYTDA.woff2 +0 -0
  313. package/web/dist/assets/marked.esm-JKvyS0Pp.js +46 -0
  314. package/web/dist/assets/oswald-latin-400-normal-BAFo8sP8.woff2 +0 -0
  315. package/web/dist/assets/oswald-latin-500-normal-B-eyT0Dw.woff2 +0 -0
  316. package/web/dist/assets/oswald-latin-600-normal-plFmSr5g.woff2 +0 -0
  317. package/web/dist/assets/oswald-latin-700-normal-vy6hmKSr.woff2 +0 -0
  318. package/web/dist/assets/poppins-latin-400-normal-cpxAROuN.woff2 +0 -0
  319. package/web/dist/assets/poppins-latin-500-normal-C8OXljZJ.woff2 +0 -0
  320. package/web/dist/assets/poppins-latin-600-normal-zEkxB9Mr.woff2 +0 -0
  321. package/web/dist/assets/poppins-latin-700-normal-Qrb0O0WB.woff2 +0 -0
  322. package/web/dist/assets/react-DOpiTn5v.js +32 -0
  323. package/web/dist/assets/roman-DkYN0LX9.js +1 -0
  324. package/web/dist/assets/space-grotesk-latin-400-normal-CJ-V5oYT.woff2 +0 -0
  325. package/web/dist/assets/space-grotesk-latin-500-normal-lFbtlQH6.woff2 +0 -0
  326. package/web/dist/assets/space-grotesk-latin-600-normal-DjKNqYRj.woff2 +0 -0
  327. package/web/dist/assets/space-grotesk-latin-700-normal-RjhwGPKo.woff2 +0 -0
  328. package/web/dist/assets/space-mono-latin-400-italic-YylcN9Ay.woff2 +0 -0
  329. package/web/dist/assets/space-mono-latin-400-normal-Rg4St2Dn.woff2 +0 -0
  330. package/web/dist/assets/space-mono-latin-700-italic-vNvENeTh.woff2 +0 -0
  331. package/web/dist/assets/space-mono-latin-700-normal-mWgeinG7.woff2 +0 -0
  332. package/web/dist/icon-maskable.svg +10 -0
  333. package/web/dist/icon.svg +8 -0
  334. package/web/dist/index.html +21 -0
  335. package/web/dist/manifest.webmanifest +14 -0
  336. package/web/dist/sw.js +40 -0
  337. package/web/src/pages/Laws.jsx +230 -0
package/CHANGELOG.md ADDED
@@ -0,0 +1,938 @@
1
+ # Changelog
2
+
3
+ All notable changes to Geneseed are recorded here. The format follows
4
+ [Keep a Changelog](https://keepachangelog.com/); versions are the human-readable
5
+ labels in `harness.config.json`. The canonical identity of an *installed* harness
6
+ is the source fingerprint in `.geneseed-version` (see `geneseed version`), not this
7
+ label. For the capability ↔ spec map, see [SHIPPED.md](SHIPPED.md).
8
+
9
+ ## [Unreleased]
10
+
11
+ ### Added
12
+ - **`npx geneseed setup` is now the way in, and the README says exactly where that stops
13
+ being true.** The install docs assume npm first: one command, no clone, no Python, on
14
+ macOS, Linux and Windows alike. **All 25 commands** run from Node, along with all
15
+ four hooks, every web-console endpoint and both generators, producing byte-identical
16
+ output. Three things still need Python and each is now named in the README and the Setup
17
+ guide rather than discovered: the full-screen browse panel that `tui` and `menu` open on a
18
+ terminal is still Python — from Node both refuse the panel by name and print the command
19
+ list, while off a terminal the two runtimes print the same bytes, and `geneseed home` opens
20
+ the web console exactly as it does under Python; the self-update commands (`upgrade`, `update`, `sync-self`, `bootstrap`) are for
21
+ a git checkout and now point an npm install at `npm install -g geneseed@latest` instead of
22
+ telling it to re-clone; and **every bundle carries one Python script**, the `token-report`
23
+ skill's own, which runs when the agent invokes that skill and at no other time. In the web
24
+ console, the "browse…" folder picker needs an OS-native dialog and reports itself
25
+ unavailable on the Node server — the path field beside it stays editable.
26
+ A publishing workflow ships with it, using npm's trusted publishing (OIDC): no long-lived
27
+ token in the repository, manual trigger only, and it explains the one step that has to be
28
+ done by hand on the npm side. Nothing has been published.
29
+ - **`geneseed migrate` moves an existing install to the npm shape, in one pass.** If you
30
+ installed by cloning the repository, your hooks run through a small machine-wide shim that
31
+ hands every call to your checkout's Python; installing from npm changes where that code
32
+ lives. `migrate` surveys every install you already have, re-emits each one **in its own
33
+ theme, emit, footprint, posture and mode** — nothing is defaulted, so it can never quietly
34
+ change what you chose — and re-points the shim. `--dry-run` prints the plan and writes
35
+ nothing. Run it once; a second run says so and does nothing.
36
+ **It is all-or-nothing**: every settings file it will touch is copied first, and if any
37
+ install fails to rebuild, everything is put back. You are never left half on one shape and
38
+ half on the other. **It refuses rather than guesses**: an install whose marker names
39
+ something unrecognised stops the whole run with the offending path named, because
40
+ re-emitting an install as something its owner never chose is worse than stopping.
41
+ **And it does not touch what it did not write** — your own hooks, third-party hooks, and
42
+ the login autostart entry you created by hand are reported, never rewritten. See the new
43
+ *Migrate an existing install to npx* page in the docs. Your old clone keeps working for a
44
+ full release; there is no cliff.
45
+ - **Geneseed is an npm package now — as a file on disk, not yet as something you can
46
+ install.** The repository carries a `package.json` with three commands (`geneseed`,
47
+ `geneseed-hook`, `geneseed-build`), a minimum Node version of 22.3.0, and an explicit list
48
+ of what a release would contain. Packing it and installing the result works today: all
49
+ three commands run, and `geneseed-build` renders a full bundle from the installed copy.
50
+ Two problems had to be fixed first, both found by installing it rather than by reading it:
51
+ npm rewrote the two `.gitignore` files that guard the agent's `memory/` and `notebook/`
52
+ directories, which would have let an agent's private notes be committed into your
53
+ repository, and the notebook's charter page went missing from the bundle. Both are fixed at
54
+ the source — those two files are stored without their leading dot and the renderer puts it
55
+ back — so nothing an install produces differs from what a git clone produces, byte for byte.
56
+ Nothing has been published yet.
57
+ - **The web console's CLI reference page works without Python, and the harness's command
58
+ surface now has exactly one description.** The Docs page that lists every command and every
59
+ flag used to be readable only from Python, because it walked the harness's own argument
60
+ parser — 24 commands, 43 arguments. That metadata is now generated into a tracked
61
+ `cli.json` that both runtimes read, so the page works on either, and `geneseed doctor`
62
+ reports it as a problem — on either runtime — when the file and the parser part company.
63
+ The page itself is unchanged. What changed is that there is no longer a second,
64
+ hand-maintained copy of the command list that could quietly disagree with the commands you
65
+ actually have.
66
+ - **`geneseed bootstrap`, `geneseed sync-self` and `geneseed update` have Node twins, and the
67
+ web console's Update button works without Python.** Nineteen of the harness's 24 commands
68
+ now run from `node bin/geneseed-cli.mjs` as well as from `python rituals/harness.py`. The
69
+ About page in the web console works there too — it reads your install's own git origin, so
70
+ the links on it point at the repository your updates actually come from.
71
+ - **A real fix in `geneseed bootstrap`: it now runs the setup wizard again.** `bootstrap`
72
+ updates everything and then hands off to `setup` — and that handoff was pointed at an
73
+ internal module instead of the harness, so it did nothing at all and exited 0. `./geneseed`
74
+ with no arguments takes that path. If bootstrap has been "succeeding" without ever showing
75
+ you the wizard, this is why.
76
+
77
+ ### Removed
78
+ - **`upgrade.sh` and `sync-self.sh` are gone.** Each was a few lines of bash that found a
79
+ Python interpreter and then ran `rituals/harness.py upgrade` (or `sync-self`) — the same
80
+ command every launcher already runs, on every OS, and one that native Windows could never
81
+ reach through a `.sh` file at all. Use `./geneseed upgrade` (or `.\geneseed.cmd upgrade`,
82
+ `.\geneseed.ps1 upgrade`, `python rituals/harness.py upgrade`, or the web console's Update
83
+ button) — all of which is what they did. Nothing else changes: the launchers' self-repair
84
+ path for a factory too old to know the subcommand never went through either script and is
85
+ untouched.
86
+
87
+ - **`geneseed upgrade` has a Node twin — the one command a "no Python needed" install could
88
+ not do without Python.** Seventeen of the harness's 24 commands now run from
89
+ `node bin/geneseed-cli.mjs` as well as from `python rituals/harness.py`, and this is the
90
+ one that mattered most: an install that shelled out to Python to update ITSELF would have
91
+ had Python as a hard requirement of the only command you must always be able to run.
92
+ Everything about the update is unchanged — it still fast-forwards your own checkout's
93
+ origin and never pushes, still refuses to touch a dirty tree, a detached HEAD or a branch
94
+ with no upstream, still validates the pulled source with `doctor` before trusting it and
95
+ **rolls the checkout back to the previous commit if that validation fails**, and still
96
+ rebuilds the bundle plus every registered install afterwards. Local edits you made to a
97
+ deployed harness are still exported to an improvements file first, so a rebuild cannot
98
+ quietly overwrite them.
99
+ **One real fix rides with it, on Windows.** The `[rebuild-all]` lines an upgrade printed
100
+ while refreshing your other installs were being discarded — including the FAILED rows the
101
+ error message tells you to look for. They now appear, in the terminal and in
102
+ `~/.geneseed-install.log` both.
103
+ - **The port's nineteenth piece: `geneseed setup` has a Node twin — and it is the first one
104
+ that ASKS YOU QUESTIONS.** Fifteen of the harness's 24 commands now run from
105
+ `node bin/geneseed-cli.mjs` as well as from `python rituals/harness.py`. The wizard behaves
106
+ the same: the same five questions, the same menus, each one pre-selecting what you already
107
+ have installed rather than a stock default, the same plan printed before anything is
108
+ written, and the same "nothing is written until you confirm". It still refuses outright
109
+ when there is no terminal to ask on, and still offers a health check at the end.
110
+ **One thing you can see is different, on macOS and Linux only.** The Python version tries a
111
+ full-screen version of the wizard first and falls back to plain prompts when it cannot; the
112
+ Node one goes straight to the prompts. On Windows that is what the Python has always done
113
+ too. The full-screen console is a later piece of the port and will bring its own wizard
114
+ with it.
115
+ **What is genuinely better: the pre-selected answers.** The install detector had been
116
+ reporting only the theme and install mode of what it found; the wizard also asks about
117
+ posture, mode and footprint, so those three questions had been quietly offering the
118
+ configured default instead of what is actually deployed. All five now come from the
119
+ install.
120
+ **And the checking had to grow a new shape.** A wizard cannot be tested by running the
121
+ command — it refuses without a terminal, which is exactly what a test gives it. So the two
122
+ implementations are now driven by a *file of answers* fed to them as if typed, and their
123
+ entire output compared character for character: every prompt, every menu line, every
124
+ default marker, the plan, and the choices they came back with. That immediately caught a
125
+ real bug in the new code — an answer containing a non-ASCII character (an accent, a
126
+ non-Latin digit) was being mangled before anything read it.
127
+ - **The port's eighteenth piece: `geneseed uninstall` has a Node twin — and it is the first
128
+ one that DELETES.** Fourteen of the harness's 24 commands now run from
129
+ `node bin/geneseed-cli.mjs` as well as from `python rituals/harness.py`. Nothing about what
130
+ `uninstall` does has changed: it still removes only what the install's manifest claims,
131
+ still leaves your own files where they are, still never deletes `memory/` or `notebook/`
132
+ (`--archive-memory` moves them aside to a timestamped sibling), and still refuses to
133
+ proceed without `--yes` when it cannot ask.
134
+ **What changed is how it is checked.** Every earlier verb was proved by comparing what the
135
+ two implementations *wrote*. A removal needs the opposite question, and two implementations
136
+ that had both stopped deleting would have agreed perfectly in every test forever. So the
137
+ test harness grew two things: a record of every *directory* in the sandbox — an empty
138
+ leftover folder was invisible to all 219 previous cases, and cleaning up after itself is
139
+ half of what this command is for — and a way to state that a file or folder must be
140
+ **gone**. Thirty-five new cases, each of which also seeds a file the manifest does *not*
141
+ own and insists it survives: the difference between "removed the install" and "removed the
142
+ directory" is not a comment, it is a control.
143
+ **Two things the checking found, both in the existing Python.** When a file you own keeps
144
+ one of Geneseed's directories alive, the uninstall reports INCOMPLETE and tells you the
145
+ install marker was kept so you can retry — but for a *global* install the marker is already
146
+ gone by then, so the retry reports no install at all. And any unclaimed file under
147
+ `agents/` or `skills/` triggers that report even when everything Geneseed owned was removed
148
+ cleanly. Both are recorded as behaviour both implementations must share, not quietly fixed
149
+ on one side; the fix belongs to a change that can be reviewed on its own.
150
+ - **The port's seventeenth piece: `geneseed doctor` has a Node twin.** Thirteen of the
151
+ harness's 24 commands now run from `node bin/geneseed-cli.mjs` as well as from
152
+ `python rituals/harness.py`: the one that validates the build — unresolved tokens, dead
153
+ links, links that escape the bundle, theme-key parity, colour palettes, the authoring gates
154
+ on every spec, the credential sweep, the vendored-skill pins, the count mirrors in the
155
+ README and the web pages, the hook shim, and whether a committed bundle still matches a
156
+ fresh render of the source.
157
+ **Checking it was harder than porting it, and that is the news.** `doctor` prints
158
+ `[doctor] ok` when all fifteen of its checks find nothing, so two versions that had both
159
+ stopped checking would agree perfectly. Ten of the fifteen read the checkout itself, which
160
+ no sandboxed test could write to. So each test now gets its own copy of the checkout, breaks
161
+ exactly one thing in it, and runs both versions from that copy — 30 checks, one planted
162
+ fault at a time.
163
+
164
+ - **The port's sixteenth piece: `geneseed diff` and `geneseed rebuild-all` have Node twins.**
165
+ Twelve of the harness's 24 commands now run from `node bin/geneseed-cli.mjs` as well as from
166
+ `python rituals/harness.py`: the drift report that shows what your deployed harness has that
167
+ a fresh render of the source does not (and exports it as a file you can hand to an agent to
168
+ back-port), and the sweep that re-emits every active install in place. 21 new side-by-side
169
+ checks compare everything either one can be observed doing — for `rebuild-all` that includes
170
+ every file of every rebuilt install.
171
+ **Your diffs are the same diffs.** Python's `difflib` makes specific choices about how to
172
+ line two files up, so the Node side reproduces it rather than using a different diff that
173
+ would also be correct and would not match. 176 generated cases check that, including files
174
+ long enough to trigger the heuristic Python applies only past 200 lines.
175
+ **Both commands preserve what an install already is.** A rebuild re-emits each install in
176
+ its own theme, host, footprint, posture and mode, read back off the install itself; `diff`
177
+ renders its "expected" copy the same way, so themed wording and a lean footprint are not
178
+ reported as your local edits.
179
+
180
+ ### Fixed
181
+ - **`rebuild-all`'s progress lines came out in the wrong order when its output was redirected
182
+ to a file or a log** — every `[rebuild-all] <install>` line appeared *after* the build it
183
+ introduced, so each one named the wrong install. Only visible outside a terminal, which is
184
+ where the web UI's "build all" job log lives. Same helper, and the same shape, as the
185
+ swallowed-output fix in the previous release.
186
+ - **The Node builder's console output now ends its lines the way the Python one does on
187
+ Windows.** Nothing you could see on screen, and a difference if you piped it into anything
188
+ that counts bytes.
189
+
190
+ - **The port's fifteenth piece: `geneseed build`, `geneseed prompt` and `geneseed theme`
191
+ have Node twins.** Ten of the harness's 24 commands now run from
192
+ `node bin/geneseed-cli.mjs` as well as from `python rituals/harness.py`: rendering the
193
+ bundle, writing the self-contained install prompt, and creating a custom OpenCode colour
194
+ theme. 23 new side-by-side checks compare everything either one can be observed doing —
195
+ for `build` that includes the whole rendered tree, file for file.
196
+ **`build` does not start a second program.** The Python version runs the builder as a
197
+ separate process; the Node one calls it directly, because it is already part of the same
198
+ program. Nothing about the bundle you get changes.
199
+ **Three commands deliberately did not move.** `sync-self` is an alias for `update`, which
200
+ the self-update work replaces outright rather than translating. `link` and `unlink` put
201
+ `geneseed` on your PATH, and that is exactly what installing from npm will do for you — so
202
+ they belong with the packaging work, not here. They keep working as they always have.
203
+
204
+ - **The port's fourteenth piece: `geneseed status` and `geneseed version` have Node twins.**
205
+ The install dashboard — theme, install mode, how many agents/skills/laws you have, where
206
+ your memory store is and how many facts are in it, and whether the installed build matches
207
+ the source — and the fingerprint comparison behind it now run from
208
+ `node bin/geneseed-cli.mjs` as well as from `python rituals/harness.py`. The panel is
209
+ compared line for line, in colour and in plain ASCII, against the Python one.
210
+ **Colour still works on a real terminal**, and that took a different kind of test to
211
+ prove. Every side-by-side check captures output through a pipe, and a pipe is never a
212
+ terminal, so the coloured panel is invisible to all of them — a version that quietly
213
+ dropped every escape code would have looked perfect. The panel renderer is called directly
214
+ instead, on both sides, over a list of made-up dashboards, which also covers three other
215
+ things no ordinary check can reach.
216
+ **A real bug came out of it, in something already shipped.** The Node hook had its own
217
+ private copy of a path helper, under a different name from the shared one, and the two had
218
+ drifted: an exclusion entry written by hand with a `..` in it would make the Node hook go
219
+ quiet for a repository the Python one still watches. There is now one copy, and a check
220
+ for exactly that entry.
221
+ - **The port's thirteenth piece, and the first command that is not a hook: `geneseed exclude`
222
+ has a Node twin.** `exclude add`, `exclude remove` and `exclude list` — the sovereign-repo
223
+ exclusions, the folders where your global install goes quiet — now run from
224
+ `node bin/geneseed-cli.mjs` as well as from `python rituals/harness.py`. Both maintain the
225
+ same `excludes.json` in every global install, both wire the same per-host suppression into
226
+ the excluded folder, and 22 side-by-side checks compare everything either one can be
227
+ observed doing.
228
+ **Why a new command file rather than an existing one.** The hook launcher is deliberately
229
+ tiny — it runs on *every* tool call — and the builder is under a rule that it may not start
230
+ other programs, which is half of what proves it is a real second implementation. Neither
231
+ was the right home for an ordinary CLI command, so there is now a third: the hook launcher,
232
+ the builder, and this. Nothing you have installed changes.
233
+ **Nothing about your existing exclusions changes**, and the Python command is still there —
234
+ the web UI's exclusions page calls straight into it, so both stay until that page moves too.
235
+ - **The port's twelfth piece: an install built with `node bin/geneseed.mjs` no longer needs
236
+ Python at all.** The hooks it wires now launch the Node twin, so building and running a
237
+ Claude or Bob install is Python-free end to end. Building one used to stop with an error
238
+ if no Python could be found; there is nothing left to find, so that error is gone.
239
+ **One thing worth knowing if you have several installs on one machine.** The small
240
+ launcher your hooks go through (`~/.geneseed/bin/geneseed-hook`, or `.cmd` on Windows) is
241
+ *shared* — one file for the whole machine, not one per install. It always was, and while
242
+ both commands wrote the same thing into it that made no difference. It does now: whichever
243
+ command you ran **last** decides what every install's hooks launch. Both answer the four
244
+ hook commands identically, and a check enforces that they keep doing so, so in practice
245
+ you should see nothing — but if you mix `python build.py` and `node bin/geneseed.mjs`,
246
+ that is the rule.
247
+ Also fixed on the way: on Windows the Node hooks ended their lines differently from the
248
+ Python ones. No host was affected — they all read JSON or plain text — but it was a real
249
+ difference in the one place the side-by-side checks structurally could not see, so it is
250
+ fixed and now checked in raw bytes.
251
+ - **The port's eleventh piece, and the first that is not the builder: the four hooks your
252
+ install runs every session have a Node twin.** `context` (the one that injects your repo's
253
+ docs at session start), `git-gate` and `rule-gate` (the two that make the host ask before a
254
+ commit or a memory write), and `learn` (the one that distils a session into memory) all now
255
+ run from `node bin/geneseed-hook.mjs` as well as from `python rituals/harness.py`.
256
+ **At the time, nothing about your installs changed.** Wiring the new twin in was kept a
257
+ separate step, deliberately — an install's hooks are the part that fails *silently* when it
258
+ is wrong, so it moved once and with the evidence in hand. That step is the entry above.
259
+ What is in hand: 103 side-by-side checks covering both, comparing everything either one can
260
+ be observed doing — what it prints, what it warns, the exit code it returns, and every file
261
+ it writes. Discovery with and without a `context.json`, globs, `extend`, the
262
+ project-bypasses-global stand-down, sovereign-repo exclusions, malformed payloads, memory
263
+ dedup, transcripts, per-agent lessons and `--consolidate`.
264
+ - **Fixed on the way: a distilled memory containing an accent or an em dash could be
265
+ corrupted as it was stored.** `learn` read the model CLI's reply using the console's legacy
266
+ code page on Windows rather than UTF-8, and the mangled text was then written into your
267
+ memory store — so the damage outlived the run. It now reads UTF-8 on both paths.
268
+ - **Changed: a `context.json` with a syntax error now names the file and tells you to fix it,
269
+ instead of quoting the JSON parser's own message.** The old message came straight from
270
+ Python's decoder, and no second implementation can reproduce it — the two engines disagree
271
+ about both the wording and where the error is. An unreadable (as opposed to invalid) file is
272
+ now reported separately, which it never was.
273
+ - **The port's tenth piece: every install mode now works from `node bin/geneseed.mjs`,
274
+ including the four that install hooks.** `claude`, `claude-global`, `bob` and `bob-global`
275
+ were the last four on Python, and they were last because of one honest problem: a hook is
276
+ a small script that launches the Python harness, so whatever writes one has to name a
277
+ Python interpreter on your machine — and the Node command has no way to inherit the answer
278
+ the Python command simply knows about itself.
279
+ **At the time it found one, and refused to build if it could not** — superseded by the
280
+ twelfth piece above, where the hooks stopped being Python and there was no longer anything
281
+ to find. It looked at `$PYTHON` first (the
282
+ same variable the `geneseed` launchers honour), then for `py`, `python` and `python3` on
283
+ your `PATH`, and stopped with a clear message having written nothing if none was there.
284
+ That refusal was the point rather than a limitation: hooks that name a missing interpreter
285
+ do not fail loudly, they simply never fire, and an install that looks finished with six
286
+ dead hooks is worse than a build that stopped and told you.
287
+ On Windows it deliberately stepped past the Microsoft Store's `python.exe` placeholder, the
288
+ one that opens the Store instead of running anything.
289
+ Everything else is unchanged and verified: same files, same console output, same exit
290
+ codes as `python build.py`, across every theme, both footprints, all five postures and
291
+ both modes — and now with nothing narrowed out of that comparison. The emitted hooks are
292
+ checked to actually run, not merely to exist.
293
+ Still no `package.json` and no published package; that remains a later phase. What exists
294
+ today is a runnable script in the checkout.
295
+ - **The port's ninth piece, and the first one you can run without Python: `node
296
+ bin/geneseed.mjs` builds the bundle.** Everything before this rendered *inside* a build
297
+ that Python started; this is a second front door. `node bin/geneseed.mjs --theme imperial`
298
+ produces the same bundle, the same console output and the same exit code as `python
299
+ build.py --theme imperial` — verified byte-for-byte over every theme, both footprints, all
300
+ five postures and both modes.
301
+ **Five modes worked this way when this entry was written** — the plain bundle (`--emit
302
+ files`), both OpenCode installs (`opencode`, `opencode-global`) and both Copilot ones
303
+ (`copilot`, `copilot-global`) — including the parts that only happen on your *second*
304
+ build: the Node driver reads the previous manifest, removes what the layer no longer owns,
305
+ and rewrites the manifest exactly as Python does. `$OPENCODE_CONFIG_DIR` and
306
+ `$COPILOT_CONFIG_DIR` relocate the global targets on the Node side too, so keeping your
307
+ harness in a git-tracked folder works unchanged. (The remaining four followed — see the
308
+ entry above.) Nothing about the Python command changes at any point: it is still the one
309
+ the wizard, the web console, doctor and upgrade all use.
310
+ Two flags are deliberately *not* coming to the Node side. `--sync-themes` edits this
311
+ repository's own theme files — maintainer tooling, not something an installed copy should
312
+ carry — and `--validate-only` needs the Python doctor to do its second half. Both say so
313
+ and point you at `python build.py`.
314
+ There is no `package.json` and no published package yet; that is a later phase. What
315
+ exists today is a runnable script in the checkout.
316
+ - **The port's eighth piece: `--emit opencode-global` renders through Node too, and now
317
+ *every* emit does — counted this time, not claimed.** It was the one mode still on
318
+ Python, which the entry below corrects the record about; it now takes the same path as
319
+ the other eight, so the same promise applies: same files, same console output, same exit
320
+ code, and no Node means nothing changes at all.
321
+ What is worth knowing is what it took to say "every" honestly. The test that counts the
322
+ modes refuses one that crosses with no comparison behind it — and this mode had never
323
+ been compared between the two runtimes at all, only against itself. So it arrived with
324
+ six new cases: a plain install and the rebuild over it; the lean footprint's standalone
325
+ laws file; the opt-in primary agent and slash commands; an old harness to carry a memory
326
+ store over from; a config dir you already keep your own agents, wiki and exclude list in,
327
+ with the stores then edited between the two builds — the only way a byte comparison can
328
+ tell "kept your memory" from "re-seeded it"; and an `opencode.jsonc` you have commented.
329
+ One thing that reads like a detail and is not: `--out` is **not** where this emit writes.
330
+ It renders into your OpenCode config dir and takes `--out` only as an old bundle to carry
331
+ a memory or notebook store over from. Every earlier test left those two the same
332
+ directory, so nothing could tell them apart.
333
+ - **The port's seventh piece: the code that edits *your* config files is now the code that
334
+ runs when you build with Node.** The twin added last time was proven and unused; it is
335
+ wired in now, so a build merges your `settings.json` / `settings.local.json` hooks, the
336
+ managed block in your `CLAUDE.md`, and your `opencode.json` in the same Node process that
337
+ renders. As with the six pieces before it, you should not be able to tell: same files,
338
+ same console output, same exit code, and no Node means nothing changes at all.
339
+ Two things stay on the Python side, and both are deliberate. The **check that runs after
340
+ every build** — the one that re-reads your settings file and warns if the hooks did not
341
+ actually land — now verifies Node's work from the other implementation, on every build,
342
+ which is a stronger guarantee than either half could give alone. And the **hook shim**
343
+ still pointed at Python and `harness.py` at that stage, because the hooks themselves were
344
+ still Python — so nothing already deployed changed. (It points at Node as of the twelfth
345
+ piece above.) That last one used to be invisible to every test — the shim is deliberately
346
+ excluded from the byte comparison so a version-to-version run is not drowned in noise —
347
+ so the boundary test now compares it directly.
348
+ Newly watched, because nothing reached them before: a `settings.local.json` you have
349
+ added comments to (left untouched, and it says so), an `opencode.jsonc` likewise, and an
350
+ install that has accumulated more than one recorded exclude — where the *order* they are
351
+ recorded in is part of the file and one entry was never enough to notice.
352
+ - **A count in these notes and in DESIGN.md was wrong for two releases: `--emit
353
+ opencode-global` never rendered through Node.** "Every emit now renders through Node" was
354
+ eight of the nine. That mode still runs the Python, exactly as it always has, so nothing
355
+ about it has changed or broken — but the sentence claiming otherwise has, and there is now
356
+ a test that counts the modes instead of trusting the prose.
357
+ - **The port's sixth piece: the layer that edits *your* config files now has a Node twin
358
+ too — proven, not yet wired in.** Nothing about your builds changes with this; the new
359
+ code is not called yet. What changes is that the merging into `settings.json`, the
360
+ `opencode.json` wiring, the managed block in `CLAUDE.md` and the hook shim are now
361
+ compared byte for byte between the two runtimes, across states no ordinary build ever
362
+ reaches: a settings file carrying your own hooks beside Geneseed's, one with comments in
363
+ it (which the harness refuses to rewrite, and says so), one that is not valid JSON, and
364
+ an older install whose hooks were wired into a different file and have to be unwired
365
+ there. These are the paths `deactivate`, `remerge`, `reactivate`, `uninstall` and
366
+ `exclude` run on a real machine, and nothing had ever compared them.
367
+ - **The rebuild's clean-up of files it no longer produces is now actually tested.** The
368
+ build removes what a previous build owned and this one does not — a dropped skill, a
369
+ footprint switch, a theme change. The acceptance harness re-emitted the *same*
370
+ configuration twice, so there was never anything to remove and the clean-up ran empty
371
+ every time. It now builds one configuration, builds a different one on top, and checks
372
+ the result matches a fresh build of the second — which catches both a clean-up that
373
+ leaves stale files behind and one that deletes files the new build still needs.
374
+ - **The port's fifth piece: eight of the nine emits now render through Node when you have
375
+ it — Claude, Bob and Copilot included, per-repo and global.** Before this, only `build`
376
+ and `--emit opencode` did; six more moved here. (This entry originally said "every emit"
377
+ and "the other six"; it was seven that remained, and `--emit opencode-global` is the one
378
+ still on Python. Corrected in the seventh piece above.) As with the last four
379
+ pieces, the whole point is that you cannot tell: same files, same console output, same
380
+ exit code. No Node, or `GENESEED_NO_JS=1`, and nothing changes at all.
381
+ What is worth knowing is what the new tests now watch, because these emits touch files
382
+ you co-own and files you own outright. Your `settings.json` / `settings.local.json` hook
383
+ merge and the managed block inside `CLAUDE.md` / `AGENTS.md` are compared byte for byte
384
+ between the two runtimes for the first time, and so are the cases that only happen on a
385
+ real machine: an install migrating a `memory/` or `notebook/` store in from an older
386
+ bundle, a project `.claude/` where you already put your own agent or `.gitignore`, and
387
+ every seeded-once file — `excludes.json`, `user-rules.md`, `PROFILE.md`, `wiki.jsonc`,
388
+ your memory index — **edited between two builds**, which is the only way a comparison can
389
+ prove a rebuild left them alone instead of rewriting them with the same bytes.
390
+ - **The port's fourth piece, and the first one you actually run: if you have Node
391
+ installed, `geneseed build` and `--emit opencode` now render through it.** This is the
392
+ first change in the port that touches your machine, and the point is that you should not
393
+ be able to tell — the bundle is byte-for-byte what Python produced, down to the progress
394
+ lines. No Node, or `GENESEED_NO_JS=1`, and the Python path runs exactly as before; there
395
+ is nothing to install and nothing to configure either way.
396
+ The new gate is what makes that claim checkable: it builds the same target twice, once
397
+ each way, and compares the files, both output streams and the exit code — including
398
+ cases a normal build never produces, like a second build over an existing one, a
399
+ hand-edited `.geneseed-srcdirs.json` pointing outside the bundle, and files you edited
400
+ between two builds that the harness promises never to overwrite. The build-comparison
401
+ harness now checks the console output too, which nothing had ever compared.
402
+ - **The port's third piece: the OpenCode extras — colour themes, the opt-in primary agent
403
+ and slash commands, the plugin and workflow copies, and the `agent-overrides.json`
404
+ stub.** Still nothing changes about running Geneseed; Python remains what builds your
405
+ harness. The point again is what the new test reaches. Two of these layers only exist
406
+ when `GENESEED_PRIMARY` or `GENESEED_COMMANDS` is set, so a normal build never writes
407
+ them and no build-and-compare test ever had — they are now checked in both languages
408
+ with the flags on and off, along with the "your overrides predate an upgrade" notice in
409
+ each of its four states.
410
+ - **The port's second piece: the layer that writes your host-native agents and skills now
411
+ exists in JavaScript too, with a test that covers the cases a normal build never
412
+ reaches.** Nothing about running Geneseed changes yet — Python still builds your harness.
413
+ What is new is the gate. Until now every acceptance test emitted into an empty folder with
414
+ an empty `agent-overrides.json`, so three behaviours had never been checked in either
415
+ language: what happens when you *have* overrides, what happens when a file already exists
416
+ that Geneseed did not write (it is left alone, and you are told), and what the three host
417
+ dialects do differently. `tests/test_native_layer_parity.py` runs all of them in both
418
+ languages and compares the files, the ownership record and the warnings.
419
+ - **A bug this found before anyone hit it:** an `agent-overrides.json` setting
420
+ `"temperature": 1.0` would have emitted `temperature: 1.0` from Python and
421
+ `temperature: 1` from JavaScript, because JavaScript has one number type where Python has
422
+ two. No build-and-compare test could have caught it — the build always writes an *empty*
423
+ overrides file, so no such test has ever had an override to render. Fixed, and pinned by a
424
+ test that compares number formatting directly.
425
+ - **The generator's render core now exists in JavaScript as well as Python, and a test
426
+ proves the two produce identical bytes.** Nothing about running Geneseed changes yet —
427
+ Python is still what builds your harness — but this is the first piece of the runtime to
428
+ be ported, and it lands with the gate that will keep the rest honest:
429
+ `tests/test_render_parity.py` renders every theme in both languages, on every footprint,
430
+ catalogue, posture and mode axis, writes both trees to disk and compares them byte for
431
+ byte. Writing to disk rather than comparing strings is deliberate: on Windows, Python's
432
+ text writer silently turns every `\n` into `\r\n` and Node's does not, so a port that
433
+ skipped that detail would differ in every single file while looking correct in a diff
434
+ viewer.
435
+ - **Every emit now runs its stages in one fixed order** — render everything Geneseed owns,
436
+ then reconcile the files you co-own (`settings.json`, `opencode.json`, the CLAUDE.md
437
+ block), then prune, then record the manifest, then verify. Three emits used to interleave
438
+ those stages differently. Output is unchanged, byte for byte, on all 259 theme × host ×
439
+ footprint combinations; what changes is that there is now a single seam between "files
440
+ Geneseed writes wholesale" and "files you co-own", which is what lets the render half
441
+ move to another language without the merge logic following it.
442
+ - **Emitted hooks now go through a stable shim, so moving the checkout no longer kills
443
+ every install at once.** Until now each of the four Claude/Bob hook commands embedded
444
+ two machine-absolute paths — this machine's Python interpreter and this clone's
445
+ `rituals/harness.py` — directly in your `settings.json`. Relocating or replacing the
446
+ checkout therefore broke the gates in every deployed install simultaneously, and the
447
+ only repair was re-emitting every config. The emit now writes one small shim at
448
+ `~/.geneseed/bin/geneseed-hook` (`geneseed-hook.cmd` on Windows, relocatable with
449
+ `GENESEED_HOME`) and points every hook at that single stable path; the shim holds the
450
+ two volatile paths instead. Re-pointing every install at a new checkout is now one
451
+ file write. The shim is refreshed on every emit — that refresh is what replaces the
452
+ accidental self-heal the old form had, since a config that no longer names the
453
+ checkout can no longer detect that the checkout moved — and a new `doctor` gate reads
454
+ it back and reports a shim that points at nothing. The shim is deliberately silent:
455
+ `git-gate` and `rule-gate` return success on every path and signal their verdict as
456
+ JSON on **stdout**, so a single stray byte would turn a blocking gate into a silently
457
+ permissive one. Existing installs migrate on their next build — the manifest-driven
458
+ prune replaces the old hook groups exactly, and the orphan scan now recognises both
459
+ the legacy and the shim shape so a stranded hook still surfaces.
460
+ - **The `rule` skill becomes the front door to both durable stores, behind a Law VI
461
+ gate**: nothing reaches `user-rules.md` or `memory/` on the agent's own initiative
462
+ any more. The skill now opens on a fork it must put to the user — *a standing rule,
463
+ or a fact to remember?* — because the agent silently arbitrating that was the actual
464
+ defect: a passing preference got legislated as a permanent rule, or a real rule was
465
+ filed away as a forgettable note. The memory branch asks for the binding `force`
466
+ (constraint · choice · conviction · tempered) and shows the exact file, frontmatter
467
+ included, before writing. The rule branch pressure-tests instead of drafting: the
468
+ user restates the rule as they would to a colleague on day one and gets interrupted
469
+ on jargon they cannot unpack, a missing step, or a simplification that makes the rule
470
+ false (the feynman skill's mechanic, borrowed — not delegated to); then a **mandatory
471
+ counter-example**, where the agent builds the case the rule would harm and the user
472
+ must either accept it or narrow the rule. A rule that cannot survive its own worst
473
+ case was never generic, only never contradicted. The asymmetry in cost between the
474
+ two branches is deliberate — cheap to remember, expensive to legislate, or the rule
475
+ set inflates. Enforced at the tool boundary, not just in prose: a new
476
+ `harness.py rule-gate` PreToolUse hook makes Claude Code and Bob **ask** before any
477
+ write to `user-rules.md` or a memory file, and `geneseed-guard.js` speed-bumps the
478
+ first such write on OpenCode (its `tool.execute.before` has no ask tier — a re-issued
479
+ write goes through, so nothing is ever trapped). Copilot has no hook mechanism and is
480
+ held by the Law and the preamble alone.
481
+ - **`token-report` folder skill — session token usage breakdown on every host**: a
482
+ first-party folder skill (the first non-vendored entry in `VENDORED_SKILL_DIRS`,
483
+ which the folder mechanism carries because it bundles an executable script) that
484
+ renders the session's token usage as markdown tables: exact recorded totals
485
+ (output, fresh input, cache reads/writes; main thread vs subagents), context
486
+ window occupancy (session-start harness baseline, current/peak vs limit), an
487
+ estimated per-category attribution of what filled the context (user messages,
488
+ replies, thinking, per-tool calls/results, injected skill content), and the
489
+ heaviest single items. `scripts/token_report.py` auto-detects the host by most
490
+ recent session activity: exact usage on Claude Code, IBM Bob (`$BOB_CONFIG_DIR`
491
+ honoured) and OpenCode; best-effort harvesting on GitHub Copilot, whose
492
+ session-state schema is undocumented. OpenCode reads the v1.2+ SQLite store
493
+ (`opencode.db`: `session`/`message`/`part` tables, JSON `data` columns,
494
+ step-finish fallback when a message record carries no tokens, child sessions
495
+ attributed as subagent usage) and falls back to the pre-1.2 `storage/` JSON
496
+ files when no DB exists. Carrier ceiling (full) raised 49_000 → 51_000 for
497
+ the new AGENT.md folder-skill entry.
498
+ - **GitHub Copilot host — `--emit copilot` / `--emit copilot-global`**: the fourth
499
+ first-class host, riding the Claude-shaped emit engine. Per-repo: root `AGENTS.md`
500
+ (auto-loaded by the Copilot CLI, coding agent, and VS Code agent mode) + a layer in
501
+ the shared `.github/` dir — `agents/<name>.agent.md` in Copilot's custom-agent
502
+ dialect (`tools:` allowlist for read-only agents, sibling links rewritten to the
503
+ `.agent.md` extension) and byte-identical `skills/` (Copilot Agent Skills).
504
+ Personal: `~/.copilot` (`$COPILOT_CONFIG_DIR` relocates) with the preamble as a
505
+ managed block in `copilot-instructions.md`, which the CLI auto-loads — no Bob-style
506
+ rules-folder workaround needed. Copilot has no settings.json or hook mechanism, so
507
+ the settings/hooks/excludes stage is skipped entirely (memory rides the preamble's
508
+ instructions); with no exclude mechanism either, the global emit warns when project
509
+ installs exist (both preambles stack). Writing into `.github/` is safe by
510
+ construction: the ownership manifest + claim-on-create never touch user files.
511
+ Full lifecycle parity — setup wizard/TUI rows, web console deploy option +
512
+ Harnesses rows, MCP wiring (`~/.copilot/mcp-config.json`, `mcpServers` with the
513
+ CLI's required `type`/`tools` keys, global-only), doctor per-repo emit validation,
514
+ rebuild-all, diff/restore, deactivate/reactivate/uninstall, footprint dial, and
515
+ theme detection via the `copilot-instructions.md` sigil fallback.
516
+ - **User rules — `user-rules.md`**: a seed-once file beside AGENT.md for the user's
517
+ own standing rules, obeyed with the same force as the laws (they may tighten a
518
+ law, never repeal one). Same host-state contract as `context.json`: every emit
519
+ seeds it once, never overwrites it, never records it in an owned manifest — so
520
+ user governance survives updates, reinstalls, and theme switches; unlike
521
+ `context.json` it is committable, so project rules can travel with a repo and
522
+ bind the team. Named `user-rules.md` (not `rules.md`) because the neutral theme
523
+ renders the laws themselves as "Rules". The context plugin and Claude hook
524
+ eager-load it in discovery mode. A new **rule skill** drafts and triages rules
525
+ (rule vs memory vs `context.json` vs already-covered), refuses law conflicts,
526
+ promotes recurring feedback memories into trial rules with consent, and runs
527
+ the review flow (graduate / demote / delete). Memory and notebook READMEs now
528
+ route "share with the team" there instead of the regenerated laws.
529
+ - **Web console Rules page** (`#/rules`, right under Laws in the rail): list your
530
+ rules with scope and trial chips, add/edit/retire them, graduate a trial rule,
531
+ and watch a budget meter that turns amber as the always-loaded set grows. A
532
+ **Promote to rule** control on memory facts turns a recurring lesson into a
533
+ trial rule with provenance and deletes the source fact. Backed by
534
+ `GET/POST /api/rules` + `/api/rules/promote` (token-gated); every write carries
535
+ a content fingerprint and 409s when an agent session edited the file
536
+ concurrently, and mutations splice one rule's block — the rest of the user's
537
+ file is never regenerated.
538
+
539
+ ### Fixed
540
+ - **On Windows, `geneseed build > log.txt` wrote an empty log.** Anything the harness ran as
541
+ a child process — the builder behind `build` and `rebuild-all`, and the same builder behind
542
+ the web UI's "build all" — had its output silently thrown away whenever the harness's own
543
+ output was redirected to a file or a pipe rather than going straight to a terminal. In a
544
+ terminal it looked fine, which is why it survived: the flag that suppresses console
545
+ pop-ups also hands the child a fresh hidden console to print into when nobody has asked
546
+ for the output to be piped. It is now applied only when the harness is capturing the child
547
+ itself, which is the case it was added for; console pop-ups are still suppressed there.
548
+ Found by the Node port — the same command printed the builder's summary line on one side
549
+ and nothing on the other.
550
+ - **The golden acceptance harness could render into your real install.** `tests/golden.py`
551
+ runs the generator over 259 cells, ~126 of which are `*-global` emits whose whole job is
552
+ to write into a host's global config dir, and it sandboxes them by redirecting `HOME`
553
+ and `XDG_CONFIG_HOME`. That was not enough: each host resolver checks its own relocation
554
+ variable *first* and returns before ever consulting those paths, so anyone with
555
+ `OPENCODE_CONFIG_DIR` set — the documented way to keep the harness in a git-tracked
556
+ folder — had every global cell rendering straight into the real target. Reproduced
557
+ against the pre-fix code: a single `opencode-global` cell wrote 135 files outside the
558
+ sandbox. The cell environment now clears `OPENCODE_CONFIG_DIR`, `BOB_CONFIG_DIR` and
559
+ `COPILOT_CONFIG_DIR`, plus every `GENESEED_*` knob except the one it sets itself —
560
+ cleared by prefix, so a knob added later is neutralised by default. Four tests pin it,
561
+ including one that re-derives the variable list from `_build_core`'s own source rather
562
+ than trusting a hand-written list to stay current.
563
+ - **Every login launcher told you to start the web UI in the foreground**: the VBS,
564
+ the `schtasks` task and the macOS LaunchAgent in SETUP.md (and its `autostart`
565
+ web slice) all ran `geneseed web --no-browser`. Only `web start` daemonizes and
566
+ writes the `.geneseed-web.json` pid record — bare `web` blocks in the foreground
567
+ and records nothing, so the server that came up at every login was invisible to
568
+ `web stop`, `web restart` and `web status`. They reported "no live server" while
569
+ it kept serving; worse, `restart` then spawned a second daemon that could not bind
570
+ the taken port, leaving three live processes and the *stale* one still answering.
571
+ That is how a `web/dist` rebuild turned into hard MIME failures in the browser: the
572
+ old server kept handing out the previous `index.html`, whose chunk hashes no longer
573
+ existed on disk, and the SPA 404-fallback returned them as `text/html`. All four
574
+ launchers now use `web start`, and the section says why in a callout.
575
+ - **Laws XXXVI and XXXVII render their Principle in the web ledger**: both shipped
576
+ with no row in `LAW_META` (`web/src/pages/Laws.jsx`), the map that holds each
577
+ rule's one-line Principle — display copy that lives nowhere else in the tree. An
578
+ absent row falls back to `['craft', '']`, so the two newest laws showed a blank
579
+ description and a wrong class chip while everything upstream stayed correct: the
580
+ catalog served them, the page rendered, `LAW_CLASS` was complete, doctor and both
581
+ suites were green. Rows added (XXXVI · security, XXXVII · process), and `doctor`
582
+ gained the gate that was missing (`_law_meta_problems`): every rule in
583
+ `universal.md` must have a `LAW_META` row with a non-empty principle and a known
584
+ class that agrees with `LAW_CLASS`, and no row may outlive its rule. Sibling of
585
+ the `LAW_CLASS` completeness gate added after Law XXXV shipped mis-classified —
586
+ same failure shape, the other half of the pair. `DESIGN.md` now lists the six
587
+ satellite edits a new Law drags along, so the next one is a checklist, not a
588
+ rediscovery.
589
+ - **Claude/Bob emits no longer ship dead skill-table links**: CLAUDE.md/AGENTS.md's
590
+ per-row skill/agent links (e.g. `.claude/skills/council.md`) were dead — the
591
+ native layer writes each skill as a folder (`.claude/skills/council/SKILL.md`).
592
+ `_strip_capability_links` already ran on this path, but `CAPABILITY_LINK_RE`
593
+ only matched a BARE `agents/`/`skills/` prefix; the claude/bob project-scope
594
+ render re-prefixes those tokens (`.claude/`, `.bob/`, `../`), which slid straight
595
+ past the regex. It now tolerates an optional relative-path prefix (never
596
+ `http(s)://` or a leading `/`), so the existing strip catches every prefixed form
597
+ too — same fix benefits the OpenCode emits' own prefixed edge cases. `doctor`
598
+ gained a matching check (`_claude_bob_emit_problems`): it previously validated
599
+ the `files` build and the opencode-global emit but never the claude/bob per-repo
600
+ emits, which is why this shipped unnoticed; `--validate-only --emit claude`/`bob`
601
+ are clean again, and the stale SETUP.md "known limitation" note is removed.
602
+ - **Renamed DIR_* dirs in the portable bundle no longer orphan**: the bundle's
603
+ owned dirs (`laws`/`agents`/`skills`, in their themed form) are wiped and
604
+ rebuilt each run, but the wipe was keyed only to the CURRENT theme's dir name —
605
+ if a theme ever renamed one of them between two builds into the same target,
606
+ the old dir was never targeted and lingered forever. A new local marker
607
+ (`.geneseed-srcdirs.json`) now remembers which dir name was actually used last
608
+ time, so a rename is also pruned. (Shipped themes don't currently vary DIR_*, so
609
+ this is future-proofing rather than an active drift; the global/Claude/Bob
610
+ scopes' equivalent case — a lean-footprint standalone laws dir surviving a
611
+ switch back to full — is already covered by the owned-file manifest.)
612
+ - **Bob installs now actually load the preamble/theme**: IBM Bob's only
613
+ always-injected instruction channel is the rules folder — a global
614
+ `~/.bob/AGENTS.md` is never auto-loaded (only a project-root one is), which left
615
+ Bob installs with working skills but no harness voice. Both Bob emits now also
616
+ ship the preamble as `rules/geneseed.md` (project `.bob/rules/`, global
617
+ `~/.bob/rules/`). The Claude-only `claudeMdExcludes` key is no longer written for
618
+ Bob (its Bob semantics are undocumented and a filename-keyed match would suppress
619
+ the project's own `AGENTS.md`); a re-emit strips one left by an older install.
620
+ Project-bypasses-global on Bob now rides on its native rule precedence: the
621
+ workspace `rules/geneseed.md` shadows the same-named global rule.
622
+ - **Lean installs no longer report permanent phantom drift — and Restore no longer
623
+ converts them to full**: everything that renders an "expected" copy of an install
624
+ must render it at that install's OWN footprint, read from its `.geneseed-footprint`
625
+ marker. Three callers did not. `diff` (and the Local-edits panel it feeds) rendered
626
+ at `full`, so every lean install reported two edits it could never clear by
627
+ rebuilding — `AGENT.md` (terse §1 digest vs the inlined laws) and
628
+ `laws/universal.md`, which only the lean global emit writes. `doctor` validated the
629
+ full emit only, so a lean-only regression could ship green. Worst of the three,
630
+ `Restore` in the web console rendered at `full` too: discarding a local edit on a
631
+ lean install rewrote `AGENT.md` with the inlined laws and DELETED
632
+ `laws/universal.md` — silently promoting the install to a full footprint. All three
633
+ now read the marker. Note that the web UI serves the code it was launched with:
634
+ restart the daemon (`geneseed web restart`) after upgrading, or the panel keeps
635
+ reporting the old verdict.
636
+
637
+ ### Changed
638
+ - **The host-config wiring moved into its own module, `_build_settings.py`.** The emit was
639
+ doing two unrelated jobs in one file: computing bundle content, and reconciling
640
+ Geneseed's claim inside files you also edit — `settings.json`, `opencode.json`, the
641
+ managed `CLAUDE.md` block — through JSONC parsing and surgical merges. The second job is
642
+ not really part of generation at all: nine of its ten entry points are called by the
643
+ *runtime* (deactivate, remerge, reactivate, uninstall, plus `exclude` and `mcp`), not by
644
+ a build. Splitting them takes `_build_emit.py` from 1466 lines to 734 and leaves a layer
645
+ whose dependency closure points one way only — nothing in it calls back into the render
646
+ or emit code. Nothing moved namespace: `build.py` splices the new module alongside the
647
+ others, so every existing call site resolves unchanged, and emitted output is identical
648
+ across all 259 golden cells. If you monkeypatch any of it, patch `_build_settings` —
649
+ patching another submodule's spliced copy binds a copy the real caller never reads, and
650
+ a test now fails on that shape.
651
+ - **The generator's configuration now has one owner instead of five copies.** `build.py`
652
+ splices its four `_build_*` submodules into a shared namespace, which gave each of them
653
+ its own copy of `SRC`, `THEMES`, `ROOT`, `CONFIG`, `PLUGIN_SRC`, `WORKFLOW_SRC`,
654
+ `COLOR_THEMES`, `CAPABILITY_LINK_RE`, `VENDORED_SKILL_DIRS`, the four
655
+ `_<host>_config_dir` resolvers and the posture/mode selection — and forced a facade
656
+ `__setattr__` that mirrored every write out to all four so that redirecting one
657
+ actually reached the render code. `_build_core` now owns those names outright: they are
658
+ held back from both its `__all__` and the splice, so no copy exists, and the mirror is
659
+ deleted. Emitted output is unchanged — verified byte-for-byte against the previous
660
+ revision across the full 259-cell matrix (14 themes × 9 emit modes × 2 footprints, plus
661
+ every posture and mode). Two consequences for anyone working on the generator: read
662
+ them as `_build_core.SRC`, not a bare `SRC` (a bare one now raises `NameError` instead
663
+ of silently reading a stale copy), and redirect them by writing `_build_core.SRC` —
664
+ `build.SRC` still reads but refuses writes, because `mock.patch.object(build, "SRC", …)`
665
+ deleted rather than restored the attribute on exit and leaked the redirect into every
666
+ later test in the process. A test now walks the suite and fails on any redirect of a
667
+ shared-but-unowned name, the shape that quietly stops covering what it claims to —
668
+ `_opencode_config_dir` was already in that state, one missing `cfg=` argument away from
669
+ sending a global emit into the developer's own `~/.config/opencode`.
670
+ - **`docs/specs/`, `docs/reviews/`, and `docs/superpowers/` are local working docs
671
+ now**: untracked from git and added to `.gitignore`. They are per-machine work
672
+ artifacts (dated specs are drafted, executed, then dropped — the existing
673
+ lifecycle); the repo's prose (README, DESIGN, SHIPPED) no longer links them as
674
+ distributed folders, and SHIPPED.md states its spec links are historical
675
+ pointers into that local record.
676
+ - **Bob installs stopped double-paying the preamble**: a per-repo Bob install's
677
+ `.bob/rules/geneseed.md` is now a slim shadow stub instead of a full second copy
678
+ of the preamble — the repo-root `AGENTS.md` (auto-loaded) carries the
679
+ instructions, and the stub's only job is to shadow the same-named global rules
680
+ file (Bob injects every workspace rule each turn, so the full copy doubled the
681
+ install's fixed per-turn token cost). The global Bob emit no longer writes
682
+ `~/.bob/AGENTS.md` at all — Bob never auto-loads a global one; `rules/geneseed.md`
683
+ is the sole carrier — and a re-emit removes the stale copy an older install left
684
+ behind. Existing installs heal on the next rebuild/upgrade.
685
+ - **Self-update is now `git pull`**: `geneseed upgrade`/`update`/`sync-self` fast-forward
686
+ the install's own git origin (host-agnostic — wherever it was cloned from), doctor-gate
687
+ the result (rolling back on failure), then rebuild — replacing the bespoke curl/urllib
688
+ archive-zip download stack. A dirty tree or non-git checkout is reported (CLI message + a
689
+ web info popup) instead of failing mid-run.
690
+
691
+ ### Removed
692
+ - The offline `geneseed upgrade --zip <file>` path and the web "Offline package" download
693
+ (`/api/offline-zip`) — use `git pull` directly.
694
+
695
+ ### Added
696
+ - **Per-agent memory** — each capability agent now keeps durable lessons in
697
+ `memory/agents/<name>.md`. Every agent spec reads its own file first at dispatch
698
+ (step 0 of its procedure); the write-back is mechanical and lands on **all three
699
+ hosts equally**: the OpenCode `geneseed-learn` plugin distils a finished subagent
700
+ session into one per-agent lesson, and the claude/bob emits gain a `SubagentStop`
701
+ hook that routes to the same Python path (`learn` reads the payload's
702
+ `hook_event_name`). Unresolvable subagent name → silent no-op, never a wrong write.
703
+ - **`learn --consolidate`** — rebuilds `MEMORY.md` from the fact files on disk:
704
+ re-indexes orphaned facts, prunes dead index lines, and reports duplicate
705
+ descriptions for the user to merge (never auto-merged).
706
+ - **`dispatch` workflow** — a saved OpenCode workflow that decomposes a multi-domain
707
+ goal, routes each subtask to its owning capability agent, and converges the
708
+ results. Where a host has no `workflow` tool, the same shape runs model-driven via
709
+ the parallel-agents skill. The **handoff envelope** (subtask goal, inputs, output
710
+ contract; no commit/push — Law XX stays with the caller; gaps reported, never
711
+ invented) is now written into `AGENT.md` for every emit, the OpenCode orchestrator,
712
+ the parallel-agents skill, and the agent template.
713
+ - **Downgrade warning + stale-overrides notice**: re-emitting over an existing
714
+ install now compares the deployed release (stamped in `.geneseed-version`
715
+ alongside the fingerprint) against the source tree's `harness.config.json`
716
+ version and prints a loud, warn-only notice when the deployed build is newer
717
+ ("did you forget git pull?") — never blocks, since a deliberate downgrade must
718
+ stay possible. `agent-overrides.json` is now stamped with `_version` at
719
+ creation; the file itself is never rewritten on re-emit, but if it carries real
720
+ overrides and its `_version` no longer matches the source, a one-line notice
721
+ points you at reviewing them against the updated agent specs.
722
+ - **`build.py --validate-only`**: a dry run — full render, all doctor validations,
723
+ and a sandboxed emit of the requested target, written to a temp dir and
724
+ discarded. Exits non-zero on any problem, writes nothing real. (Note: `--emit
725
+ claude|bob` currently reports known pre-existing dead skill-link problems;
726
+ that fix is tracked separately.)
727
+ - **`build.py --sync-themes`**: fills any key `themes/_TEMPLATE.json` has but a
728
+ theme JSON is missing — surgical line insertion in template order (no file
729
+ churn), never removes extras, and exits 1 when it changed files so CI can use
730
+ it as a check. The doctor's parity failure now points at it.
731
+ - **`AGENT_COLORS` theme key**: the OpenCode agent→colour-slot map moved from a
732
+ hardcoded table in the emitter into `themes/_TEMPLATE.json` (and all shipped
733
+ themes), so a theme can restyle agent UI grouping. Unknown slot values warn
734
+ and fall back to `secondary`; themes missing the key fall back to the old
735
+ built-in map.
736
+ - **Ask-tier bash for research agents**: `explorer` and `empiricist` now carry
737
+ the same marker `historian` already had — OpenCode emits `bash: ask` (instead
738
+ of deny) and Claude Code leaves Bash to its own permission prompts, so
739
+ read-only searches (grep, git log) no longer dead-end. Every other read-only
740
+ agent keeps the blanket deny.
741
+ - **`.opencode/` re-emits stopped wiping user files**: the project OpenCode emit
742
+ now tracks what it owns in `.opencode/.geneseed-manifest.json` and prunes only
743
+ stale owned files (write-before-delete), skipping user-authored files with a
744
+ warning — the same claim-on-create model the Claude path always had. The first
745
+ re-emit over a pre-manifest install treats existing files as yours and says so.
746
+ - **`harness uninstall` hardening**: a global uninstall now prints an inventory of
747
+ any surviving PROJECT installs elsewhere (each is self-contained — its hooks call
748
+ the shared checkout by absolute path, not the global config dir being removed —
749
+ so nothing is touched, just listed with the exact `--target` to remove it too); a
750
+ project uninstall now checks whether another host (Claude/OpenCode/Bob) also has
751
+ an install at the same repo root and says so. A settings.json left with a
752
+ leftover/locked owned file (Windows-plausible) no longer silently drops its
753
+ `.geneseed-emit` marker — the marker is kept and the run is reported INCOMPLETE
754
+ so the install can be found and retried. After every settings.json merge/unwire
755
+ (emit, deactivate, uninstall), a new integrity check (`_settings_integrity_check`)
756
+ verifies the manifest's claimed hooks/excludes actually match the file and warns
757
+ (never auto-fixes) on drift or an unrecorded Geneseed-pattern hook left behind.
758
+ - **Project bypasses global harness**: when a repo carries its own Geneseed
759
+ install, the same host's GLOBAL harness no longer double-loads there. For
760
+ Claude/Bob a project emit writes the global preamble into `claudeMdExcludes`
761
+ (native, repo-scoped) and the global SessionStart context hook stands down via
762
+ an up-walk marker check — so a session started anywhere in the repo gets the
763
+ project harness only, and the global one elsewhere. OpenCode already scopes its
764
+ context to the cwd (the context plugin dedups), and its `instructions[]`
765
+ preamble double-load remains the documented harmless cost (moving it would
766
+ strip subagents of the laws). Opt out — restore stacking — with
767
+ `GENESEED_STACK_GLOBAL=1` (honoured at emit and in the hook).
768
+ - **Law XXI — Commands Must Return**: a non-interactive-shell law forbidding
769
+ commands that hang on a TTY (interactive prompts, pagers, REPLs, editors,
770
+ unbounded processes) and directing the agent to the non-interactive form
771
+ (`--yes`, `--no-pager`, piped input, bounded long runs). Brings the law count
772
+ to 21. (Distilled from awesome-opencode's *Shell Strategy* plugin.)
773
+ - **Context plugin — self-awareness & command discovery**: `geneseed-context`
774
+ now surfaces the session's live model (read from the transcript, with a
775
+ `GENESEED_MODEL` fallback) and the project's runnable command targets
776
+ (`Makefile`, `package.json` scripts, `justfile`, `Taskfile`) in the injected
777
+ PROJECT CONTEXT block. (Distilled from awesome-opencode's *Model Announcer* and
778
+ *Command Inject* plugins.)
779
+ - **`geneseed-notify` plugin** (OpenCode): a fifth plugin that sends a native,
780
+ dependency-free OS notification (macOS `osascript`, Linux `notify-send`, Windows
781
+ PowerShell) when the agent finishes a turn — gated by `GENESEED_NOTIFY_MIN_SECONDS`
782
+ (default 30) so only genuinely long runs ping, and skipping subagent/throwaway
783
+ sessions. Toggle with `GENESEED_NOTIFY=off`. (Distilled from awesome-opencode's
784
+ *Opencode Notify*.)
785
+ - Three learning skills that teach the user rather than do the work for them:
786
+ - `crash-course` — go from zero to functional in a skill fast: what to learn
787
+ first, what to ignore, and the one high-leverage exercise.
788
+ - `drill` — turn shaky knowledge into reflex through Socratic practice on
789
+ realistic mistakes, withholding the answer until the user has tried.
790
+ - `decode` — make confusing material click via one keystone sentence, an
791
+ everyday analogy, and a three-question comprehension check.
792
+ These join `learning-path`, `gap-detector`, and `feynman`, bringing the
793
+ skill count to 33.
794
+
795
+ ## [2.0.0] — not yet published
796
+
797
+ *Nothing described here has been published to any registry: there is no tag, no release and no
798
+ install URL. `harness.config.json` and `package.json` both read `2.0.0`, which is the version this
799
+ build stamps into every bundle it emits — it is not evidence that anything was shipped.*
800
+
801
+ *⚠ The bump itself was the last thing this release found. Moving the label reddened 224 of 259
802
+ recorded emit cells, because the configured version is stamped into two places and only one of them
803
+ was ever blanked before comparison: `.geneseed-version`'s `[release …]`, and — undestamped until
804
+ now — `"_version"` inside the `agent-overrides.json` stub in every bundle. It hid because the sweep
805
+ that added the first arm hunted the bracketed spelling, and because `1.0.0` and `2.0.0` are the same
806
+ length, so the file size never moved. Left unfixed, the frozen corpus would have pinned this project
807
+ at `1.0.0` forever — every bump, not just this one. The comparison now blanks both sites; no recorded
808
+ byte was edited. See `docs/limits.md`.*
809
+
810
+ ### ⚠ Breaking — RE-INSTALL, do not upgrade
811
+
812
+ **If you installed Geneseed by cloning this repository, install the npm package fresh instead
813
+ of pulling this release into your checkout.** The reason is specific, and it is about your
814
+ hooks rather than about the code:
815
+
816
+ - A machine whose last emit ran through the old Python driver has a machine-wide hook shim at
817
+ `~/.geneseed/bin/geneseed-hook` whose body names your checkout's `rituals/harness.py`.
818
+ This release deletes that file. Pull 2.0 into that checkout and the shim points at nothing.
819
+ - **A dead gate does not shout.** `git-gate` (Law XX — approval before a commit or a push) and
820
+ `rule-gate` (Law VI — writes into your memory store) return 0 on *every* path and deliver
821
+ their verdict as a JSON document on **stdout**. No JSON, no verdict: the tool call proceeds
822
+ with nothing asked. A gate that cannot launch does not fail closed, it simply stops being
823
+ consulted — which is the failure you would rather find in release notes than in a diff you
824
+ did not approve. (The two gate commands are emitted without a `|| exit 0` tail, unlike the
825
+ `context` and `learn` hooks, so the launch failure itself is not swallowed. The missing
826
+ verdict still is.)
827
+ - **`geneseed doctor` catches the dead pointer.** Its shim check reads every quoted path back
828
+ out of the shim body and reports any that does not exist — `[shim] … pointed at …, which
829
+ does not exist — every hook in every install was dead`. That is the state a pulled checkout
830
+ leaves. It is *not* a check for "you are still on the old shape": a clone you leave untouched
831
+ keeps a shim whose two baked paths both still exist, so doctor is quiet about it and the
832
+ classification lives in `migrate` instead.
833
+ - **`geneseed migrate` is the repair**, and it is the supported path if you would rather move
834
+ an existing machine than start clean. It surveys every active install first and writes
835
+ nothing until the survey passes; it re-emits each one in *its own* theme, emit, footprint,
836
+ posture and mode; it refuses the whole run rather than guess at an install whose marker it
837
+ does not recognise; it copies every settings file it will touch and rolls all of them back if
838
+ any install fails, so you are never half-migrated; and it reports — never rewrites — hooks it
839
+ did not write and login-autostart entries you created by hand. `--dry-run` prints the plan.
840
+ A second run is a no-op. See *Migrate an existing install to npx* in the docs.
841
+
842
+ Either way, run `geneseed doctor` afterwards and confirm it reports no `[shim]` row.
843
+
844
+ ### What this release actually guarantees
845
+
846
+ **Less than the previous one, and this is the honest place to say so.** Until now there were
847
+ two implementations of this harness side by side, and three harnesses ran both on every cell
848
+ and compared every emitted byte, both streams and the exit code. That second implementation is
849
+ deleted. What replaced it is a **recording** of the answers it gave, frozen under
850
+ `tests/__snapshots__/` and replayed against the code that ships.
851
+
852
+ A green replay says *this code still answers what it answered when the recording was taken.*
853
+ It does not say the answer was ever right: where the two implementations agreed and were both
854
+ wrong, the recording froze the agreement, and there is no longer a second party who could
855
+ disagree. The recordings also cannot be re-taken — every program that could write one is gone,
856
+ and the replayers refuse to record — so a change that moves a recorded byte is a finding rather
857
+ than a step. `docs/limits.md` is the standing list of what that costs, row by row, including
858
+ four strings that are known to be wrong and are now permanently unfixable.
859
+
860
+ ### Removed
861
+
862
+ - **The second implementation.** 85 Python files, and with them the full-screen curses panel
863
+ (`tui` and `menu` are now verbs that refuse it by name and print the command list), the
864
+ Python launchers, and every `.py` in the tree — there are zero left.
865
+ - **The last Python inside a bundle.** The `token-report` skill shipped one script; it is now
866
+ `scripts/token_report.mjs` and runs under `node`. Nothing a bundle installs needs an
867
+ interpreter on any host, theme or footprint.
868
+ - **Python as a dependency of anything.** Including the one command you must always be able to
869
+ run: `geneseed upgrade` no longer shells out to an interpreter to update itself.
870
+
871
+ ### Added
872
+
873
+ - **Three verbs that were never subcommands of the old CLI**, because they are new faces on
874
+ capabilities that had only ever been web endpoints:
875
+ - `geneseed catalog agents|skills|laws` — everything this harness ships, each with its
876
+ one-line purpose and lifecycle status.
877
+ - `geneseed mcp` — the MCP servers wired into each active install, and the presets on offer.
878
+ - `geneseed memory list|rm` — the facts the agent reads, and removal by name.
879
+ - **A package with zero runtime dependencies.** No `dependencies`, `peerDependencies` or
880
+ `optionalDependencies`, and a test that fails if any appear. Node 22.3.0 or newer, three
881
+ commands (`geneseed`, `geneseed-hook`, `geneseed-build`), and the standard library.
882
+
883
+ ### Changed
884
+
885
+ - **All 25 subcommands and all four hook verbs answer from Node**, along with every web-console
886
+ endpoint and both generators. Nothing is left behind an interpreter.
887
+ - **`docs/port-ledger.md` is now `docs/limits.md`.** The file stopped being a ledger of a
888
+ migration in progress and became the standing answer to *what does this tool not prove about
889
+ itself?* — which outlives the port that started it. Read it before trusting a green suite.
890
+
891
+ ## [1.0.0] — 2026-06-13
892
+
893
+ First stable release. The harness, its tooling, and the local web console are
894
+ feature-complete and validated by a dependency-free CI (doctor + unit/node/web
895
+ suites) on Linux and Windows.
896
+
897
+ ### Harness
898
+ - One neutral `src/` rendered by a stdlib-only generator (`build.py`) into 14
899
+ themed, tool-agnostic bundles; structure stays theme-independent.
900
+ - 20 universal laws, 16 capability agents (6 execution + a 10-seat debate council),
901
+ 30 skills, the one-fact-per-file memory convention, and the agent's sovereign
902
+ notebook.
903
+
904
+ ### Tooling
905
+ - `geneseed` launchers for bash, cmd, and PowerShell; run-from-anywhere via
906
+ `link`/`unlink`; `bootstrap`/`upgrade`/`sync-self` with SHA-pinned, self-healing
907
+ updates.
908
+ - `doctor` (tokens, links, theme parity, authoring gates, bundle drift), `diff` +
909
+ improvements export, `status`/`version`, a curses TUI with a native-Windows VT
910
+ backend, and MCP wiring.
911
+
912
+ ### Web console
913
+ - Local, offline, installable (PWA) browser UI over the deployed harness: Dashboard,
914
+ Library, Graph, Docs, Specs, Changes, Doctor, Themes, Settings, About, plus a
915
+ Spotlight search and a streaming job console. Background daemon; `127.0.0.1`-bound
916
+ with a per-session CSRF token on every mutation.
917
+
918
+ ### Adapters
919
+ - OpenCode native agent/skill mapping and four plugins (context, learn, guard,
920
+ workflow); a Claude Code hook adapter.
921
+
922
+ ### Documentation & quality (this release)
923
+ - Added a whole-project review (`docs/reviews/`), a `SHIPPED.md` capability registry,
924
+ and a `docs/web-ui.md` console guide; demarcated `docs/superpowers/` as an archive.
925
+ - Added `themes/_TEMPLATE.json` + a theme-authoring guide, routed every theme
926
+ enumeration through a single `build.theme_files()` helper (scaffolds excluded).
927
+ - Tightened the safety net: fixture tests for all three emit modes, self-tests for
928
+ the doctor parity gate, the `context_delivery` node suite wired into CI, and a
929
+ universal `prefers-reduced-motion` pass in the web UI.
930
+ - Removed a leaked authoring note from Law VII.
931
+
932
+ ### Known follow-ups
933
+ Structural refactors identified in the review remain as post-1.0 work: generating the
934
+ `AGENT.md` capability tables from `src/`, unifying the three emit paths in `build.py`,
935
+ a route table for `web.py`, and replacing the `harness.py` namespace-merge facade with
936
+ explicit imports. None affect behaviour today.
937
+
938
+ [1.0.0]: https://github.com/Arylmera/Geneseed/releases/tag/v1.0.0