geneseed 3.11.0 → 3.13.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 (265) hide show
  1. package/CHANGELOG.md +160 -0
  2. package/README.md +5 -5
  3. package/SHIPPED.md +2 -2
  4. package/adapters/bob/README.md +1 -1
  5. package/adapters/claude-code/README.md +1 -1
  6. package/adapters/openclaude/README.md +1 -1
  7. package/adapters/opencode/README.md +3 -3
  8. package/adapters/opencode/plugins/geneseed-guard.js +157 -2
  9. package/bin/geneseed-cli.mjs +4 -0
  10. package/docs/README.md +41 -22
  11. package/docs/concepts/agents.md +3 -1
  12. package/docs/concepts/collaboration.md +3 -1
  13. package/docs/concepts/exclusions.md +4 -2
  14. package/docs/concepts/footprint.md +3 -1
  15. package/docs/concepts/foreman-mode.md +4 -2
  16. package/docs/concepts/hook-gates.md +61 -0
  17. package/docs/concepts/hooks.md +8 -56
  18. package/docs/concepts/host-matrix.md +38 -0
  19. package/docs/concepts/hosts.md +6 -32
  20. package/docs/concepts/loop-branch.md +66 -0
  21. package/docs/concepts/loop-bricks.md +48 -0
  22. package/docs/concepts/loop-contracts.md +33 -0
  23. package/docs/concepts/loop-gates.md +30 -0
  24. package/docs/concepts/loop-notes.md +43 -0
  25. package/docs/concepts/loop-risk.md +36 -0
  26. package/docs/concepts/loop-templates.md +50 -0
  27. package/docs/concepts/loops.md +73 -0
  28. package/docs/concepts/lsp.md +2 -0
  29. package/docs/concepts/memory.md +3 -1
  30. package/docs/concepts/notebook.md +3 -1
  31. package/docs/concepts/rules.md +4 -2
  32. package/docs/concepts/skills.md +3 -1
  33. package/docs/concepts/themes.md +3 -1
  34. package/docs/extending.md +28 -8
  35. package/docs/guides/autostart.md +3 -1
  36. package/docs/guides/choose-your-setup.md +5 -66
  37. package/docs/guides/headless.md +5 -3
  38. package/docs/guides/install-agent-md.md +37 -0
  39. package/docs/guides/install-bob.md +20 -0
  40. package/docs/guides/install-claude-code.md +22 -0
  41. package/docs/guides/install-clone.md +34 -0
  42. package/docs/guides/install-openclaude.md +25 -0
  43. package/docs/guides/install-opencode.md +35 -0
  44. package/docs/guides/install-scripted.md +21 -0
  45. package/docs/guides/install.md +9 -118
  46. package/docs/guides/loop-finish.md +54 -0
  47. package/docs/guides/loop-running.md +66 -0
  48. package/docs/guides/loop-which-template.md +35 -0
  49. package/docs/guides/mcp-filesystem.md +41 -0
  50. package/docs/guides/mcp-gitlab.md +66 -0
  51. package/docs/guides/mcp-markitdown.md +36 -0
  52. package/docs/guides/mcp.md +8 -137
  53. package/docs/guides/migrate.md +3 -1
  54. package/docs/guides/project-context.md +4 -2
  55. package/docs/guides/read-non-markdown.md +17 -0
  56. package/docs/guides/run-a-loop.md +64 -0
  57. package/docs/guides/run-anywhere.md +2 -0
  58. package/docs/guides/setup-doctrines.md +55 -0
  59. package/docs/guides/setup-footprint.md +48 -0
  60. package/docs/guides/uninstall.md +3 -1
  61. package/docs/guides/upgrade.md +3 -1
  62. package/docs/guides/verify.md +3 -1
  63. package/docs/guides/wiki.md +3 -1
  64. package/docs/guides/worktree.md +3 -1
  65. package/docs/reference/about.md +3 -1
  66. package/docs/reference/cli.md +2 -0
  67. package/docs/reference/env-context.md +40 -0
  68. package/docs/reference/environment.md +10 -59
  69. package/docs/reference/glossary.md +7 -1
  70. package/docs/reference/loop-actions.md +20 -0
  71. package/docs/reference/opencode-plugins.md +14 -116
  72. package/docs/reference/plugin-activity.md +20 -0
  73. package/docs/reference/plugin-context.md +27 -0
  74. package/docs/reference/plugin-guard.md +27 -0
  75. package/docs/reference/plugin-learn.md +27 -0
  76. package/docs/reference/plugin-notify.md +20 -0
  77. package/docs/reference/plugin-ponytail.md +19 -0
  78. package/docs/reference/plugin-workflow.md +25 -0
  79. package/docs/reference/troubleshoot-doctor.md +50 -0
  80. package/docs/reference/troubleshoot-hooks.md +99 -0
  81. package/docs/reference/troubleshoot-install.md +108 -0
  82. package/docs/reference/troubleshoot-tools.md +56 -0
  83. package/docs/reference/troubleshoot-update.md +23 -0
  84. package/docs/reference/troubleshoot-web.md +66 -0
  85. package/docs/reference/troubleshooting.md +13 -337
  86. package/docs/understand/a-day.md +3 -1
  87. package/docs/understand/enforced-vs-asked.md +3 -1
  88. package/docs/understand/harness.md +2 -0
  89. package/docs/understand/machine-bob.md +17 -0
  90. package/docs/understand/machine-claude.md +35 -0
  91. package/docs/understand/machine-opencode.md +36 -0
  92. package/docs/understand/on-your-machine.md +12 -55
  93. package/docs/understand/take-it-out.md +13 -0
  94. package/docs/web-ui.md +36 -5
  95. package/harness.config.json +1 -1
  96. package/js/README.md +32 -2
  97. package/js/build/driver.mjs +14 -8
  98. package/js/build/generate.mjs +10 -6
  99. package/js/build/render.mjs +5 -0
  100. package/js/build/source.mjs +5 -1
  101. package/js/cli-table.json +261 -0
  102. package/js/hosts/gitref.mjs +99 -0
  103. package/js/hosts/hooks.mjs +88 -1
  104. package/js/hosts/installs.mjs +21 -0
  105. package/js/hosts/mcp.mjs +1 -1
  106. package/js/hosts/native.mjs +43 -5
  107. package/js/inspect/checks-authoring.mjs +10 -0
  108. package/js/inspect/checks-build.mjs +28 -0
  109. package/js/inspect/diff.mjs +3 -0
  110. package/js/inspect/doctor.mjs +2 -1
  111. package/js/inspect/inventory.mjs +1 -0
  112. package/js/inspect/status.mjs +1 -1
  113. package/js/loop/catalog.mjs +127 -0
  114. package/js/loop/cli.mjs +173 -0
  115. package/js/loop/graph.mjs +163 -0
  116. package/js/loop/registry.mjs +196 -0
  117. package/js/loop/score.mjs +182 -0
  118. package/js/loop/state.mjs +436 -0
  119. package/js/maintain/migrate.mjs +4 -2
  120. package/js/maintain/setup.mjs +1 -1
  121. package/js/web/actions.mjs +34 -3
  122. package/js/web/api.mjs +51 -2
  123. package/js/web/daemon.mjs +43 -5
  124. package/js/web/docs.mjs +64 -12
  125. package/js/web/handler.mjs +1 -0
  126. package/js/web/jobs.mjs +3 -1
  127. package/js/web/routes.mjs +5 -1
  128. package/js/web/server.mjs +5 -3
  129. package/package.json +1 -1
  130. package/registry.json +14 -0
  131. package/src/AGENT.md.tmpl +2 -0
  132. package/src/agents/explorer.md +2 -2
  133. package/src/agents/researcher.md +3 -3
  134. package/src/bricks/README.md +34 -0
  135. package/src/bricks/_template.md +32 -0
  136. package/src/bricks/adr-challenge.md +20 -0
  137. package/src/bricks/adr-draft.md +15 -0
  138. package/src/bricks/apply.md +17 -0
  139. package/src/bricks/baseline-green.md +17 -0
  140. package/src/bricks/bruno-test.md +16 -0
  141. package/src/bricks/characterize.md +17 -0
  142. package/src/bricks/ci-fix.md +18 -0
  143. package/src/bricks/ci-triage.md +20 -0
  144. package/src/bricks/compat-check.md +16 -0
  145. package/src/bricks/deps-audit.md +14 -0
  146. package/src/bricks/docs-update.md +15 -0
  147. package/src/bricks/done-check.md +16 -0
  148. package/src/bricks/fitness-define.md +22 -0
  149. package/src/bricks/flake-check.md +17 -0
  150. package/src/bricks/flake-repro.md +18 -0
  151. package/src/bricks/identify.md +23 -0
  152. package/src/bricks/lint.md +14 -0
  153. package/src/bricks/migration-plan.md +21 -0
  154. package/src/bricks/mutation-check.md +18 -0
  155. package/src/bricks/plan.md +17 -0
  156. package/src/bricks/red-test.md +16 -0
  157. package/src/bricks/reproduce.md +16 -0
  158. package/src/bricks/review.md +19 -0
  159. package/src/bricks/security-scan.md +17 -0
  160. package/src/bricks/spec.md +18 -0
  161. package/src/bricks/test.md +14 -0
  162. package/src/bricks/upgrade-scout.md +16 -0
  163. package/src/doctrines/process.md +11 -8
  164. package/src/loops/api-endpoint.json +31 -0
  165. package/src/loops/architecture-decision.json +22 -0
  166. package/src/loops/bugfix.json +23 -0
  167. package/src/loops/ci-repair.json +19 -0
  168. package/src/loops/deps-upgrade.json +29 -0
  169. package/src/loops/enforce-architecture-rule.json +28 -0
  170. package/src/loops/feature.json +24 -0
  171. package/src/loops/fix-flaky-tests.json +30 -0
  172. package/src/loops/legacy-refactor.json +26 -0
  173. package/src/loops/legacy-tests.json +29 -0
  174. package/src/loops/refactor.json +24 -0
  175. package/src/loops/remove-dead-code.json +30 -0
  176. package/src/loops/spec-first-feature.json +29 -0
  177. package/src/loops/tdd.json +25 -0
  178. package/src/loops/update-contract.json +33 -0
  179. package/src/skills/brick-forge.md +48 -0
  180. package/src/skills/bruno-collection-generator.md +3 -3
  181. package/src/skills/bruno-test-writer.md +3 -3
  182. package/src/skills/ci-fix.md +3 -3
  183. package/src/skills/consolidate-memory.md +4 -4
  184. package/src/skills/council.md +1 -1
  185. package/src/skills/fresh-eyes.md +1 -1
  186. package/src/skills/geneseed.md +1 -1
  187. package/src/skills/git-archaeology.md +1 -1
  188. package/src/skills/git-rescue.md +4 -3
  189. package/src/skills/handoff.md +1 -1
  190. package/src/skills/herdr.md +1 -1
  191. package/src/skills/learn-mode.md +2 -2
  192. package/src/skills/loop.md +111 -0
  193. package/src/skills/opencode-theme.md +3 -3
  194. package/src/skills/ponytail.md +1 -1
  195. package/src/skills/profile.md +3 -4
  196. package/src/skills/prose.md +2 -3
  197. package/src/skills/quiz.md +1 -1
  198. package/src/skills/react-view-transitions/SKILL.md +1 -1
  199. package/src/skills/react-view-transitions/VENDOR.md +8 -3
  200. package/src/skills/research.md +3 -3
  201. package/src/skills/review-response.md +2 -2
  202. package/src/skills/rule.md +3 -3
  203. package/src/skills/security-audit.md +4 -4
  204. package/src/skills/teach.md +1 -1
  205. package/src/skills/wiki.md +3 -3
  206. package/src/skills/workflow.md +4 -4
  207. package/src/skills/worktree.md +2 -2
  208. package/themes/_TEMPLATE.json +2 -0
  209. package/themes/biker.json +2 -0
  210. package/themes/commentator.json +2 -0
  211. package/themes/cyberpunk.json +2 -0
  212. package/themes/gamer.json +2 -0
  213. package/themes/imperial.json +2 -0
  214. package/themes/joker.json +2 -0
  215. package/themes/marvin.json +2 -0
  216. package/themes/mean.json +2 -0
  217. package/themes/military.json +2 -0
  218. package/themes/neutral.json +2 -0
  219. package/themes/pirate.json +2 -0
  220. package/themes/sports.json +2 -0
  221. package/themes/verstappen.json +2 -0
  222. package/themes/wizard.json +2 -0
  223. package/web/dist/assets/Activity-Ca2Aruu7.js +1 -0
  224. package/web/dist/assets/ActivityDetail-Bo7v4Z_r.js +1 -0
  225. package/web/dist/assets/Dashboard-BuMq46aT.js +2 -0
  226. package/web/dist/assets/Docs-BzccCllG.js +5 -0
  227. package/web/dist/assets/FilterInput-CBcJBQPI.js +1 -0
  228. package/web/dist/assets/GreenhouseView-BCIKcnGG.js +2 -0
  229. package/web/dist/assets/Installs-DMFJvq7s.js +2 -0
  230. package/web/dist/assets/JournalView-o1rmd1_1.js +1 -0
  231. package/web/dist/assets/Laws-BANxq_I_.js +3 -0
  232. package/web/dist/assets/Library-DW4x0fbh.js +1 -0
  233. package/web/dist/assets/Loops-DEBibbBP.js +2 -0
  234. package/web/dist/assets/{Markdown-qjM2_ofS.js → Markdown-CdTX0kLe.js} +14 -14
  235. package/web/dist/assets/OperatorHudView-CLD0fYaA.js +2 -0
  236. package/web/dist/assets/Personal-6uMJvyBG.js +1 -0
  237. package/web/dist/assets/Tabs-BubnyZhF.js +1 -0
  238. package/web/dist/assets/activity-CObqyxkL.js +1 -0
  239. package/web/dist/assets/{api-Dc8f3ca-.js → api-D_ixdyEY.js} +1 -1
  240. package/web/dist/assets/drawable-C_x5xncq.js +1 -0
  241. package/web/dist/assets/index-CMPgezFm.js +2 -0
  242. package/web/dist/assets/index-DMsT4Aa6.css +1 -0
  243. package/web/dist/assets/{react-B9Z_tXRV.js → react-Bbzhmq4v.js} +1 -1
  244. package/web/dist/assets/rolldown-runtime-hePW80VL.js +1 -0
  245. package/web/dist/assets/sections-Dg23Hel5.js +1 -0
  246. package/web/dist/assets/usePoll-BOqeunzF.js +1 -0
  247. package/web/dist/index.html +6 -5
  248. package/web/dist/assets/Activity-C52LEb-2.js +0 -1
  249. package/web/dist/assets/ActivityDetail-CjNLRvXg.js +0 -1
  250. package/web/dist/assets/Dashboard-B6_sSCHi.js +0 -2
  251. package/web/dist/assets/Docs-Dj7BmCSA.js +0 -5
  252. package/web/dist/assets/FilterInput-CVyqmYWM.js +0 -1
  253. package/web/dist/assets/GreenhouseView-BALwjQsA.js +0 -2
  254. package/web/dist/assets/Installs-BbffDQm3.js +0 -2
  255. package/web/dist/assets/JournalView-JpAQ8Hqe.js +0 -1
  256. package/web/dist/assets/Laws-DK7eCWSm.js +0 -3
  257. package/web/dist/assets/Library-CoamHelE.js +0 -1
  258. package/web/dist/assets/OperatorHudView-DVx1HlBx.js +0 -2
  259. package/web/dist/assets/Personal-eaXb1zcj.js +0 -1
  260. package/web/dist/assets/Tabs-BmGtt8E2.js +0 -1
  261. package/web/dist/assets/drawable-Du_PZrQj.js +0 -1
  262. package/web/dist/assets/index-Bz_KMRDH.css +0 -1
  263. package/web/dist/assets/index-CNFH7o55.js +0 -2
  264. package/web/dist/assets/sections-GalMS0Zv.js +0 -1
  265. package/web/dist/assets/usePoll-O0sJEw1Y.js +0 -1
package/CHANGELOG.md CHANGED
@@ -8,6 +8,166 @@ label. For the capability ↔ spec map, see [SHIPPED.md](SHIPPED.md).
8
8
 
9
9
  ## [Unreleased]
10
10
 
11
+ ## [3.13.0] — 2026-10-04
12
+
13
+ **Upgrading:** re-emit (`geneseed rebuild-all`) so the installed `loop` skill knows the new
14
+ templates, human gates and note files; then `geneseed web restart` (and a hard reload) for the
15
+ new Loops and Docs pages.
16
+
17
+ ### Added
18
+ - **Template `category`** — `architecture`, `tests`, `development`, `refactoring` or `day-to-day`;
19
+ every shipped template carries one, and the console's Loops page groups templates by it.
20
+ - **Five loop templates** — `tdd` (plan, then write each failing test before the code that passes
21
+ it), `legacy-tests` (pin undocumented behaviour with characterization tests, mutation-checked,
22
+ production code untouched), `legacy-refactor` (pin current behaviour once, then refactor behind
23
+ that net), `deps-upgrade` (upgrade one package or group per iteration, breaking changes read
24
+ before the bump, lockfiles excluded from the deletion count so their churn doesn't force a
25
+ blocking score), and `ci-repair` (triage the current commit's failing CI checks and fix one
26
+ code failure per iteration).
27
+ - **Five bricks** backing the templates above — `red-test`, `characterize`, `mutation-check`
28
+ (reports `unavailable` rather than a silent `pass` when no mutation tool is on the stack),
29
+ `upgrade-scout`, `ci-triage` (reports `done` rather than green when CI has no run for HEAD).
30
+ - **`geneseed loop record --note` / `--note-file`** — carries a `read` brick's finding (a plan, a
31
+ review finding, a mutation gap, a CI classification) into `LOOP.md`'s notes so it survives into
32
+ the next brick and the next iteration; `--note-file` for anything multi-line or that mentions
33
+ `git commit`/`push`, which a shell argument can't carry safely.
34
+ - **Console: Loops › Active tab** — every loop `geneseed loop init` has launched, discovered via a
35
+ new **loop registry** (`$XDG_CONFIG_HOME/geneseed/loops.json`, identity only — `LOOP.md` stays
36
+ the source of state) instead of a worktree scan. `GET /api/loops/active` reports each loop's
37
+ branch, status, iteration, current node and preset; a card per loop, an `awaiting` loop
38
+ highlighted with what it's waiting on (answered in the agent's session, never the page),
39
+ finished loops kept muted for 7 days. Selecting a card draws its ring with the current node and
40
+ its iteration history. A per-loop preset picker (`POST /api/loops/preset`) rewrites `LOOP.md`'s
41
+ `preset`, applying from the next score on — the tab's only write; no `decide` and no relaunch
42
+ from the page. Only loops launched on this version or later are registered.
43
+
44
+ - **Seven more loop templates** — `architecture-decision` (one ADR per decision, challenged by a
45
+ skeptic brick, reviewed by the user), `enforce-architecture-rule` (encode a rule as a test with
46
+ an allowlist of today's violations, fix one violation per iteration), `update-contract` (expand,
47
+ migrate one consumer per iteration, contract, with contract files gated for a human by default),
48
+ `spec-first-feature` (write the spec first, build one task per iteration, closed by an
49
+ independent `done-check`), `api-endpoint` (plan, apply, test, a Bruno request and a security
50
+ review per endpoint), `remove-dead-code` (confirm green, delete one coherent unused group per
51
+ iteration, deletions scored soft) and `fix-flaky-tests` (confirm by repeated runs, fix the root
52
+ cause per iteration, never a retry or a sleep).
53
+ - **Nine bricks** backing the templates above — `adr-draft`, `adr-challenge`, `fitness-define`,
54
+ `migration-plan`, `spec`, `done-check`, `compat-check`, `flake-repro`, `flake-check`.
55
+ - **Human gates** — a brick's frontmatter can carry `gate: human` (optionally `gateOn:
56
+ <outcomes>`), holding its transition for a person regardless of preset or score. `geneseed loop
57
+ decide --verdict ok|no|amend` answers it: `ok` follows the reported outcome (a held failure
58
+ still stops), `no` stops the loop, `amend` re-runs the brick with a note and restarts its ring
59
+ budget, capped at 3 amends per brick per iteration. A passed gate is named under the closing
60
+ commit's new `Loop-Gates` trailer. In the console, a gated brick carries a person badge on the
61
+ loop ring ("Human gate", or "Human gate on pass") and a "human gate" tag in its rows, and the
62
+ Active section shows a gated loop as `Awaiting gate at <node>`.
63
+ - **Template `contracts` and `ignoreDeletions` globs** — `contracts` names interface/schema files
64
+ that always escalate a touching iteration to at least the `api` risk weight; copied from the
65
+ template at `loop init`, extendable with `--contracts` or by hand in `LOOP.md`.
66
+ `ignoreDeletions` excludes matched files from the >20-deleted-lines escalation only — the write
67
+ set still applies to them.
68
+ - **`rules` on every node** — a template may carry `rules`, a list of one-line instructions
69
+ (`loop check` refuses anything else); `geneseed loop next` hands them to every brick it runs,
70
+ not only the iteration head, so a template-wide proviso is visible everywhere, including to
71
+ `review`. `description` stays the catalogue blurb and is never sent as rules. The shipped
72
+ templates' instructions moved out of their descriptions into `rules`.
73
+ - **A guide to running a loop** — `docs/guides/run-a-loop.md`, `loop-running.md` and
74
+ `loop-finish.md`: what you need, how to ask, which template for which job, the trust preset,
75
+ answering a blocking score or a human gate, watching, stopping, merging, driving the engine by
76
+ hand, and a symptom table.
77
+ - **Console: rendered brick view** — the Loops page's Bricks reader renders a brick's body as
78
+ markdown under its facts (effect, outcomes, gate), with the raw source one click away.
79
+
80
+ ### Changed
81
+ - **Categories nest under the selected rail entry** — on the Library (skill types), Docs
82
+ (sections) and Loops (template categories, brick origins, run statuses) pages, a selected
83
+ entry's categories open in the rail beneath it, with counts and a share bar, replacing the
84
+ full-width banner above the page.
85
+ - **The Docs selector names all four hosts** — OpenCode, Claude Code, OpenClaude and IBM Bob. A
86
+ page or inline block tagged with a family still shows to every host in it; a page can now name
87
+ several hosts (`harness: ["claude", "openclaude"]`), so Bob no longer sees the Claude Code /
88
+ OpenClaude machine page.
89
+ - **Docs in the Library layout** — the console's Docs tab is a rail of parts (Understand, Guides,
90
+ Concepts, Reference), a filterable list grouped by section, and a reader with a breadcrumb,
91
+ the page's outline and Previous / Next within its section. Pages carry a new `section` and
92
+ `description` in their frontmatter.
93
+ - **Long doc pages split into short ones**, each a section of its part: the install guide (one
94
+ page per host, from a clone, without the wizard), what lands on your machine (one page per
95
+ host, taking it back out), troubleshooting (installing, hooks, updating, doctor, web console),
96
+ the OpenCode plugins (one page per plugin), loops (templates, bricks, notes and rules, risk,
97
+ human gates, contracts, the loop branch) and the run-a-loop guide. The `geneseed loop` actions
98
+ table moved to Reference. Then the rest of the long ones: choose your setup (voice and working
99
+ style · doctrine packs and single rules · footprint, loop trust and changing later), MCP servers
100
+ (a hub, one page per preset, reading non-markdown docs; the won't-connect checklist moved to
101
+ Troubleshooting), hooks (the hooks · gates, settings and the shim), environment variables (the
102
+ context and memory ones on their own page; plugin switches live on each plugin's page), the
103
+ host capability matrix, and which loop template. Every first page keeps its old address.
104
+ - **The Understand track has more pages** — what lands on your machine is now one page per host
105
+ plus taking it back out, so a returning reader's "New here?" progress shows the new steps
106
+ as unread.
107
+ - **Console Loops page in the Library layout** — a rail (Templates · Bricks · Active, with
108
+ counts) replaces the tabs; each section is a filterable list grouped like the Library's
109
+ (templates by `category`, bricks by origin, active loops by status, awaiting first) beside a
110
+ detail pane: the ring, the template's `rules`, and its bricks as compact rows that a click on a
111
+ ring node highlights. Inner-ring nodes no longer overlap (`api-endpoint`).
112
+ - **`feature`** now closes through an independent `done-check` — it maps every requirement to a
113
+ passing test before `$close` instead of trusting the iterations that already ran.
114
+ - **`deps-upgrade`** marks lockfiles with `ignoreDeletions` instead of a lowered `delete` weight,
115
+ so lockfile churn stays out of the deletion count without lowering the weight for any other
116
+ deletion in the same iteration.
117
+ - **Write-set entries accept globs** when they have at least one literal path segment (a tool's
118
+ generated store, say); a wildcard-only entry (`**`, `**/*.java`) still matches nothing rather
119
+ than declaring the whole repo writable.
120
+
121
+ ### Fixed
122
+ - **Skill and agent descriptions follow the skill-authoring rules** — no trigger sentence is cut
123
+ mid-way in any theme, and no description carries XML-like tags (#179).
124
+ - **The install page no longer scrolls on open** — the reader's own host is lit (its link on the
125
+ Install page, its scope's heading on the OpenCode page) without moving the page.
126
+ - The bricks README link on the loops page pointed at a repository that does not exist; the
127
+ console's wiki button opened a docs page that does not exist.
128
+ - A read-setup brick's plan or review findings no longer vanish between steps — `record --note`
129
+ / `--note-file` writes them into `LOOP.md`'s notes instead of leaving them in the brick's own,
130
+ discarded context.
131
+
132
+ ## [3.12.0] — 2026-10-03
133
+
134
+ **Upgrading:** re-emit after installing (`geneseed rebuild-all`) to get the `loop` and
135
+ `brick-forge` skills, the loop-branch git-gate rule and the amended consent doctrine; then
136
+ `geneseed web restart` for the Loops page.
137
+
138
+ ### Added
139
+ - **Loops** — work a requirement in small validated iterations on a `loop/*` branch. A loop is a
140
+ graph of reusable **bricks** (13 shipped in `src/bricks/`; templates `bugfix`, `refactor`,
141
+ `feature` in `src/loops/`), or a graph the model composes from the catalogue. Your own bricks
142
+ live in `$XDG_CONFIG_HOME/geneseed/` or a repo's `.geneseed/`, and override shipped ones by name.
143
+ - **`geneseed loop check|init|next|score|record|decide`** — a deterministic state machine: the
144
+ model only reports outcomes. Each iteration's risk is the max of its declared actions' weights,
145
+ re-scored on the real diff before commit; `LOOP.md` holds the state and every iteration commit
146
+ carries `Loop-*` trailers. Ceilings: 20 iterations, 2 empty diffs, one re-split of an exhausted
147
+ inner ring.
148
+ - **`--trust prudent|balanced|aggressive`** build axis (default balanced, also in the console's
149
+ install form) — how much a loop may do before it stops: silent (trailers only), soft (listed for
150
+ review at the end), or blocking (the run ends and `geneseed loop decide` resumes it).
151
+ - **`loop` and `brick-forge` skills.**
152
+ - **Console: Loops page** — templates drawn as rings (inner rings for apply ⇄ test and review ⇄
153
+ fix, a gate before the first code-changing step), every brick with its source and origin, and
154
+ catalogue problems.
155
+ - **Documentation for loops** (`docs/concepts/loops.md`): bricks, templates and the three
156
+ origins, the trust presets and the three validation levels, `LOOP.md` and its trailers, the
157
+ `loop/*` branch exemption and why merging always asks, and the `geneseed loop` actions table.
158
+ Cross-linked from `foreman-mode.md`; `glossary.md` gains `brick`, `iteration`, `loop` and
159
+ `trust preset`.
160
+
161
+ ### Changed
162
+ - **Consent Before Push**: a launched loop's batch covers commit and push on its own `loop/*`
163
+ branch, in a fixed set of command forms (`git commit -F <file>`, `git push <remote> HEAD:<loop
164
+ branch>`); anything else asks, the final commit asks, and merging never belongs to the batch.
165
+ Enforced by the git gate on Claude Code, Bob and OpenClaude, and by `geneseed-guard` on OpenCode.
166
+
167
+ ### Fixed
168
+ - **`geneseed web stop|restart|status --port N`** act on that port only; a stop aimed at a test
169
+ instance no longer shuts down the console recorded on another port (#175).
170
+
11
171
  ## [3.11.0] — 2026-10-03
12
172
 
13
173
  **Upgrading:** re-emit after installing (`geneseed rebuild-all`) — it also repairs a dead hook
package/README.md CHANGED
@@ -10,7 +10,7 @@
10
10
  [![Node >= 22.3](https://img.shields.io/badge/node-%3E%3D22.3-5fa04e)](package.json)
11
11
  [![zero dependencies](https://img.shields.io/badge/deps-zero-success)](package.json)
12
12
  [![Themes](https://img.shields.io/badge/themes-14-9cf)](themes/)
13
- [![Skills](https://img.shields.io/badge/skills-54-blueviolet)](src/skills/)
13
+ [![Skills](https://img.shields.io/badge/skills-56-blueviolet)](src/skills/)
14
14
  [![Agents](https://img.shields.io/badge/agents-18-orange)](src/agents/)
15
15
  [![Laws](https://img.shields.io/badge/laws-9-critical)](src/laws/universal.md)
16
16
  [![Plugins](https://img.shields.io/badge/plugins-7-teal)](adapters/opencode/plugins/)
@@ -37,11 +37,11 @@ Want to read what it leaves behind before installing anything? [**geneseed-demo*
37
37
  A hand-written instructions file is prose the model may or may not honour, copied into every repo and drifting in each one. Geneseed is a build, and that changes four things:
38
38
 
39
39
  - **Laws are enforced, not suggested.** A force-push, a `reset --hard`, or a credential written into a tracked file is caught by a hook *before* the tool runs, in the host's own dialect — a prompt on Claude Code and OpenClaude, a hard block on OpenCode, exit 2 on Bob. The gates fail closed, and every catch is one line in a ledger that `geneseed status` counts.
40
- - **One source, five targets.** Skills are byte-identical on every host; only the wiring differs. Every commit renders all 261 emit configurations, and a second emit into the same tree must change nothing.
40
+ - **One source, five targets.** Skills are byte-identical on every host; only the wiring differs. Every commit renders all 263 emit configurations, and a second emit into the same tree must change nothing.
41
41
  - **Costs are measured, not guessed.** Zero runtime dependencies. The hook path loads in about 14 ms per tool call. The default *lean* footprint keeps the always-on context small and puts the full rationale one read away — the numbers are in [docs/token-footprint.md](docs/token-footprint.md).
42
42
  - **It follows you.** Install once, globally; every repo inherits it. One `git pull` or `npm install -g geneseed@latest` rebuilds every active install.
43
43
 
44
- This page is the overview. **New to agent harnesses?** Start with [Understand](docs/understand/harness.md) — four short pages on what a harness is, what lands on your machine, what changes in your day, and what is enforced versus only asked. Everything else — every install path, configuration knob, and troubleshooting step — is in the **[documentation](docs/README.md)**, which the web console also renders.
44
+ This page is the overview. **New to agent harnesses?** Start with [Understand](docs/understand/harness.md) — a short course on what a harness is, what lands on your machine, what changes in your day, and what is enforced versus only asked. Everything else — every install path, configuration knob, and troubleshooting step — is in the **[documentation](docs/README.md)**, which the web console also renders.
45
45
 
46
46
  ---
47
47
 
@@ -164,7 +164,7 @@ The harness ships as a small set of layers, and the web console's rail is the sa
164
164
  | **🛡️ Rules** (`laws/`) | 9 universal laws — always in force, never toggleable: sealed-secrets, one-intent-one-act, verify-before-asserting, deletion-is-deliberate, surface-failures, data-not-orders, least-privilege, cure-the-cause, echo-the-intent. Each rule has a permanent id; its number is only its position, and the harness cites rules by name |
165
165
  | **📐 Doctrines** (`doctrines/`) | practice packs, chosen per install at build time: **craft** (how code is written), **rigor** (how work is proven), **ops** (how the machine is operated), **process** (how a task is run), **comms** (how answers are presented). A doctrine rule may tighten a Rule, never repeal one, and the user's own `user-rules.md` outranks it. Pick with `geneseed-build --doctrines craft,rigor` (or `none`), a single rule with `--exclude-rules "process 7"`, in the setup wizard, or through the switches on the console's Constitution page; all five pack files ship on disk either way, so a citation into a pack you left out still resolves |
166
166
  | **🤖 Agents** (18) | capability specialists: `reviewer`, `tester`, `architect`, `docs`, `security`, `explorer`, `researcher`, `developer` — plus a debate **council** the `council` skill convenes: `advocate`, `skeptic`, `pragmatist`, `steward`, `visionary`, `user-advocate`, `framer`, `empiricist`, `operator`, `historian` |
167
- | **🛠 Skills** (54) | repeatable workflows: brainstorm · plan · **codebase-design** · **domain-modeling** · **wayfinder** · **tickets** · **develop** · **worktree** · debug · **prototype** · refactor · **ponytail** · **forge-mcp** · **bruno-collection-generator** · **bruno-test-writer** · geneseed-code-review · **fresh-eyes** · **security-audit** · **ci-fix** · **deps-audit** · **review-response** · commit · **ship** · **release** · **migrate** · **git-archaeology** · **git-rescue** · repo-map · document-project · **frontend-design** · **prose** · **ingest** · **research** · **teach** · **quiz** · **learn-mode** · handoff · roast-me · **council** · parallel-agents · **workflow** · **wiki** · **geneseed** · **rule** · **profile** · **consolidate-memory** · **skill-forge** · **opencode-theme** · **herdr** · **pipeline** · **daydream** · **react-view-transitions** · **token-report** · **explain-changes** |
167
+ | **🛠 Skills** (56) | repeatable workflows: brainstorm · plan · **codebase-design** · **domain-modeling** · **wayfinder** · **tickets** · **develop** · **worktree** · debug · **prototype** · refactor · **ponytail** · **forge-mcp** · **bruno-collection-generator** · **bruno-test-writer** · geneseed-code-review · **fresh-eyes** · **security-audit** · **ci-fix** · **deps-audit** · **review-response** · commit · **ship** · **release** · **migrate** · **git-archaeology** · **git-rescue** · repo-map · document-project · **frontend-design** · **prose** · **ingest** · **research** · **teach** · **quiz** · **learn-mode** · handoff · roast-me · **council** · parallel-agents · **workflow** · **wiki** · **geneseed** · **rule** · **profile** · **consolidate-memory** · **skill-forge** · **opencode-theme** · **herdr** · **pipeline** · **loop** · **brick-forge** · **daydream** · **react-view-transitions** · **token-report** · **explain-changes** |
168
168
  | **🔌 Plugins** (OpenCode) | `geneseed-context` injects project docs *and your machine wiki* every session (and across compaction); `geneseed-learn` distils memory at session end; `geneseed-guard` enforces the safety Laws and protected wiki folders at the tool boundary; `geneseed-workflow` registers the `workflow` tool that runs saved orchestration scripts; `geneseed-notify` sends a native OS notification when a long run finishes; `geneseed-ponytail` holds a minimal-code mode (`/ponytail lite\|full\|ultra\|off`), opt-in, injecting the laziest-that-works ruleset every turn so it doesn't drift; `geneseed-activity` streams what each session is doing to the web console's Activity view |
169
169
  | **🧠 Memory** (`memory/`) | one-fact-per-file durable knowledge, indexed by `MEMORY.md` (git-ignored, personal) |
170
170
  | **📓 Notebook** (`notebook/`) | the agent's sovereign space — any medium (code, tools, data, notes), self-ruled via a seed-once charter, always git-ignored; only its `.gitignore` is build-asserted |
@@ -199,7 +199,7 @@ Pick with `--theme NAME` or via the setup wizard; upgrades remember it. More in
199
199
 
200
200
  ### 🪶 Footprint (lean vs full)
201
201
 
202
- A second per-install dial sets how much of the constitution the root file carries *inline* every turn — a token-cost knob, not a change to which Rules apply. **lean** (the default) carries each rule's hand-written short form and points to the full text on disk; **full** inlines every rule with its rationale. Every rule is in force either way. More in [Footprint](docs/concepts/footprint.md) and [Choose your setup](docs/guides/choose-your-setup.md).
202
+ A second per-install dial sets how much of the constitution the root file carries *inline* every turn — a token-cost knob, not a change to which Rules apply. **lean** (the default) carries each rule's hand-written short form and points to the full text on disk; **full** inlines every rule with its rationale. Every rule is in force either way. More in [Footprint](docs/concepts/footprint.md) and [Footprint, loop trust and changing later](docs/guides/setup-footprint.md).
203
203
 
204
204
  ---
205
205
 
package/SHIPPED.md CHANGED
@@ -20,7 +20,7 @@ historical references, not files distributed with the repo.
20
20
  > **On version numbers.** [`harness.config.json`](harness.config.json)'s `version` is a
21
21
  > human-readable label only. The canonical identity of an installed harness is the
22
22
  > **source fingerprint** stamped in `.geneseed-version` (see `geneseed version`), not the
23
- > string. Current label: **3.11.0**.
23
+ > string. Current label: **3.13.0**.
24
24
 
25
25
  ## Capabilities
26
26
 
@@ -29,7 +29,7 @@ Every row below is present in the tree today; "Spec" names the design record.
29
29
  | Capability | What it is | Spec |
30
30
  | --- | --- | --- |
31
31
  | **Themed generator** | One neutral `src/` → 14 themed bundles via `geneseed-build` (zero dependencies); structure stays theme-independent | [DESIGN.md](DESIGN.md) |
32
- | **Laws / Agents / Skills / Memory / Notebook** | 9 laws, 18 agents, 54 skills, the memory convention, and the agent's sovereign notebook | `2026-06-11-notebook-sovereign-space` · `2026-06-10-notebook-agent-own-space` |
32
+ | **Laws / Agents / Skills / Memory / Notebook** | 9 laws, 18 agents, 56 skills, the memory convention, and the agent's sovereign notebook | `2026-06-11-notebook-sovereign-space` · `2026-06-10-notebook-agent-own-space` |
33
33
  | **Three-tier constitution** | The governance surface splits into an always-on **Ontology** (Telos, Evidence, Decisions, Conduct — the Pact absorbed into Telos), the nine always-on **Invariants**, and five toggleable **Doctrine** packs (craft, rigor, ops, process, comms) addressed `<pack> <n>`. Every rule carries a permanent id; its number is its position, computed at render time, and a citation renders as the rule's principle name. Packs are chosen at build time with `--doctrines` or the setup wizard; the whole catalogue ships on disk either way, so a citation into an inactive pack still resolves. Precedence, in order: Ontology + Invariants, then the user's `user-rules.md`, then the active Doctrines, then `PROFILE.md`. `doctor`'s `constitutionProblems` gates rule ids (declared, unique, never a retired one), the per-rule Principle column, every `{{LAW:<id>}}` / `{{DOCTRINE:<id>}}` citation in `src/`, and the rule that an always-on tier may never cite a toggleable one | `2026-08-19-three-tier-constitution-design` |
34
34
  | **`doctor`** | One check: unresolved tokens, dead/non-hermetic links, theme-key parity, authoring gates, rendered-bundle drift | `2026-06-07-theme-aware-doctor-diff` |
35
35
  | **`diff` + improvements export** | Deployed-vs-source drift report; export an `improvements.md` back-port | `2026-06-12-improvements-export` |
@@ -1,6 +1,6 @@
1
1
  # 🤖 IBM Bob adapter
2
2
 
3
- > [← Back to README](../../README.md) · [Install guide](../../docs/guides/install.md) · [Claude Code adapter](../claude-code/README.md) · [OpenCode adapter](../opencode/README.md)
3
+ > [← Back to README](../../README.md) · [Install guide](../../docs/guides/install-bob.md) · [Claude Code adapter](../claude-code/README.md) · [OpenCode adapter](../opencode/README.md)
4
4
 
5
5
  [IBM Bob](https://bob.ibm.com) is **Claude-Code-shaped**: a project `.bob/`
6
6
  layer, an `AGENTS.md` instructions file, `SKILL.md` skills, subagents, and a
@@ -1,6 +1,6 @@
1
1
  # 🪝 Claude Code adapter
2
2
 
3
- > [← Back to README](../../README.md) · [Install guide](../../docs/guides/install.md) · [OpenCode adapter](../opencode/README.md)
3
+ > [← Back to README](../../README.md) · [Install guide](../../docs/guides/install-claude-code.md) · [OpenCode adapter](../opencode/README.md)
4
4
 
5
5
  Optional. Claude Code supports lifecycle **hooks**, so a team using it can make
6
6
  parts of the harness fire automatically instead of relying on agent
@@ -1,6 +1,6 @@
1
1
  # 🦀 OpenClaude adapter
2
2
 
3
- > [← Back to README](../../README.md) · [Install guide](../../docs/guides/install.md) · [Claude Code adapter](../claude-code/README.md) · [OpenCode adapter](../opencode/README.md)
3
+ > [← Back to README](../../README.md) · [Install guide](../../docs/guides/install-openclaude.md) · [Claude Code adapter](../claude-code/README.md) · [OpenCode adapter](../opencode/README.md)
4
4
 
5
5
  [OpenClaude](https://openclaude.gitlawb.com/) (`@gitlawb/openclaude`, binary
6
6
  `openclaude`) is an open-source coding-agent CLI that "originated from the Claude
@@ -1,6 +1,6 @@
1
1
  # 🔌 OpenCode adapter
2
2
 
3
- > [← Back to README](../../README.md) · [Install guide](../../docs/guides/install.md) · [How OpenCode loads](HOW-OPENCODE-LOADS.md) · [Global harness spec](GLOBAL-HARNESS-SPEC.md)
3
+ > [← Back to README](../../README.md) · [Install guide](../../docs/guides/install-opencode.md) · [How OpenCode loads](HOW-OPENCODE-LOADS.md) · [Global harness spec](GLOBAL-HARNESS-SPEC.md)
4
4
 
5
5
  [OpenCode](https://opencode.ai) is `AGENTS.md`-native and has first-class
6
6
  **subagents** and **commands**, so Geneseed fits it cleanly. Pick the depth you
@@ -468,9 +468,9 @@ OpenCode runs, so the command has to resolve — the `uvx` form above needs only
468
468
  call). No uv? `pipx install markitdown-mcp` and swap the command to `["markitdown-mcp"]`.
469
469
  Or drop the block entirely — the skill falls back to a CLI converter (MarkItDown /
470
470
  Pandoc / Docling) and never installs one silently. Listed but not connecting? The
471
- command isn't on PATH — see [the MCP guide](../../docs/guides/mcp.md).
471
+ command isn't on PATH — see [Model, agent and MCP problems](../../docs/reference/troubleshoot-tools.md).
472
472
  Full runbook, including the corporate-TLS (`UV_SYSTEM_CERTS`) step and the OCR extras:
473
- [the MCP guide](../../docs/guides/mcp.md).
473
+ [the MarkItDown guide](../../docs/guides/mcp-markitdown.md).
474
474
 
475
475
  ## Optional add-on — git-worktree isolation (third-party, not vendored)
476
476
 
@@ -16,8 +16,22 @@
16
16
  //
17
17
  // Install: dropped into the plugins dir by `build --emit opencode[-global]` (the *.js
18
18
  // glob), exactly like the context and learn plugins. Errors never break a tool call.
19
+ //
20
+ // `permission.ask` — the loop/* exemption (Consent Before Push). OpenCode's static
21
+ // `permission.bash` globs (`git commit*`/`git push*` = "ask", written by
22
+ // js/hosts/settings.mjs) cannot see which branch is checked out — they are a build-time
23
+ // string match with no request-time context. This hook is the ONLY seam where Geneseed can
24
+ // look at the live branch, and it only DOWNGRADES an ask to allow: only a fixed set of
25
+ // commit/push forms (see `loopExempt` below, the twin of js/hosts/hooks.mjs's) on a `loop/*`
26
+ // branch a loop was actually LAUNCHED on — not just named `loop/...`. It is a WHITELIST, not
27
+ // a blacklist: a false ask costs one prompt, a false allow publishes. It never raises the
28
+ // bar: anything not on the whitelist, anything off a launched loop branch, a status this hook
29
+ // did not itself leave as the default "ask", or any non-bash permission leaves `output.status`
30
+ // untouched and OpenCode's own ask (or another hook's deny) stands. A host version that never
31
+ // fires `permission.ask` simply never reaches this hook — the static ask still fires, so the
32
+ // failure mode is one extra prompt, never a silent allow.
19
33
 
20
- import { promises as fs } from "node:fs"
34
+ import { promises as fs, existsSync, statSync, lstatSync, readFileSync, openSync, readSync, closeSync } from "node:fs"
21
35
  import * as path from "node:path"
22
36
  import { fileURLToPath } from "node:url"
23
37
  import { homedir } from "node:os"
@@ -267,7 +281,131 @@ function ruleStoreTarget(p) {
267
281
  // substring stance: over-matching the class is harmless (see WRITE_TOOLS note).
268
282
  const WIKI_MUTATE_TOOLS = [...WRITE_TOOLS, "delete", "remove", "rename", "move", "trash"]
269
283
 
270
- export const GeneseedGuard = async () => {
284
+ // ---- the loop/* exemption (Consent Before Push) --------------------------------
285
+ // Twin of js/hosts/gitref.mjs (currentBranch/loopLaunched) and js/hosts/hooks.mjs's
286
+ // git-gate (the rest) — keep in step. Node's native sync `fs` (not the `fs.promises`
287
+ // import above): a worktree's `.git` is read the same way the Claude/Bob hook reads it, so
288
+ // the two decide the exemption identically. This plugin cannot import from `js/` at all
289
+ // (it is copied whole into an OpenCode install, outside this repo's module graph), so it
290
+ // keeps its own standalone copy rather than the single shared owner the Node side has.
291
+
292
+ const GIT_GATE_RE = /\bgit\b[^\n]*\b(?:commit|push)\b/
293
+
294
+ // No newline, backtick, or `$(` substitution anywhere, no `<`/`>` redirect, and no single
295
+ // `&` (a shell runs `a & b` as two commands exactly like `a && b`) — these can smuggle a
296
+ // second command (or a shared-branch target) past every check below. `(?<!&)&(?!&)` matches
297
+ // a lone `&` without matching either half of a doubled `&&`.
298
+ const UNSAFE_CHARS_RE = /[\n`<>]|\$\(|(?<!&)&(?!&)/
299
+
300
+ // The only three git shapes a loop's own automation ever needs — see js/hosts/hooks.mjs's
301
+ // identically-named constants for the full rationale. The token class `[\w./:@^~=+,-]`
302
+ // excludes quotes, braces, `!`, `*`, `$` and `&` — a brace/glob expansion is exactly how a
303
+ // shell turns one whitelisted-looking token into several unknown ones, which is also why the
304
+ // `-F`/`--file` path uses this same class rather than the looser `[^\s'"]+` it once did: that
305
+ // loose class let `git commit -F {m,--amend}` brace-expand into an amend of the last commit.
306
+ const ARG_RE = "[\\w./:@^~=+,-]+"
307
+ const SEG_ADD_RE = new RegExp(`^git\\s+add(\\s+${ARG_RE})*$`)
308
+ const SEG_COMMIT_RE = new RegExp(`^git\\s+commit(\\s+-q)?\\s+(-F\\s+|--file[=\\s])${ARG_RE}(\\s+-q)?$`)
309
+ const SEG_READONLY_RE = new RegExp(`^git\\s+(status|diff|log|rev-parse|show)(\\s+${ARG_RE})*$`)
310
+
311
+ /**
312
+ * `git push`, exactly: `[-u|--set-upstream] <remote> HEAD:<branch>` or
313
+ * `HEAD:refs/heads/<branch>` — the ONLY exempt form, same as js/hosts/hooks.mjs's
314
+ * `pushSegmentOk`. An explicit refspec is immune to `push.default`/`remote.*.push`
315
+ * redirection and refuses to coexist with a mirror/`+`/`:`-prefixed form; nothing else is.
316
+ */
317
+ function pushSegmentOk(seg, branch) {
318
+ const m = /^git\s+push(?:\s+(.*))?$/.exec(seg)
319
+ if (!m) return false
320
+ const rest = (m[1] || "").trim()
321
+ if (!rest) return false
322
+ const tokens = rest.split(/\s+/)
323
+ let i = 0
324
+ if (tokens[i] === "-u" || tokens[i] === "--set-upstream") i += 1
325
+ const remote = tokens[i]
326
+ if (remote === undefined || !/^[A-Za-z0-9][A-Za-z0-9._-]*$/.test(remote)) return false
327
+ i += 1
328
+ const ref = tokens[i]
329
+ i += 1
330
+ if (ref === undefined || i !== tokens.length) return false
331
+ return ref === `HEAD:${branch}` || ref === `HEAD:refs/heads/${branch}`
332
+ }
333
+
334
+ const LOOP_STATE_MARKER = "<!-- loop-state:begin -->"
335
+
336
+ /**
337
+ * Whether `<root>/LOOP.md` carries the engine's state marker — read at most 64 KB.
338
+ * `lstatSync` (never `statSync`, which follows a link) must find an ordinary file: a FIFO
339
+ * would block the read, a symlink could point anywhere outside the repo.
340
+ */
341
+ function loopLaunched(gitRoot) {
342
+ let fd
343
+ try {
344
+ const p = path.join(gitRoot, "LOOP.md")
345
+ if (!lstatSync(p).isFile()) return false
346
+ fd = openSync(p, "r")
347
+ const buf = Buffer.alloc(65536)
348
+ const n = readSync(fd, buf, 0, buf.length, 0)
349
+ return buf.toString("utf8", 0, n).includes(LOOP_STATE_MARKER)
350
+ } catch {
351
+ return false
352
+ } finally {
353
+ if (fd !== undefined) { try { closeSync(fd) } catch { /* already gone */ } }
354
+ }
355
+ }
356
+
357
+ /**
358
+ * The branch checked out in `cwd`, and the directory holding `.git` for it, read from
359
+ * .git/HEAD without spawning git — a worktree's `.git` is a FILE naming its gitdir, so both
360
+ * shapes are followed. `{ branch: null, root: null }` on anything unexpected (detached HEAD,
361
+ * no repo, unreadable): the caller then leaves the ask alone.
362
+ */
363
+ function currentBranch(cwd) {
364
+ try {
365
+ let dir = path.resolve(cwd)
366
+ for (;;) {
367
+ const dotgit = path.join(dir, ".git")
368
+ if (existsSync(dotgit)) {
369
+ let gitdir = dotgit
370
+ if (statSync(dotgit).isFile()) {
371
+ const m = /^gitdir:\s*(.+?)\s*$/m.exec(readFileSync(dotgit, "utf8"))
372
+ if (!m) return { branch: null, root: null }
373
+ gitdir = path.resolve(dir, m[1])
374
+ }
375
+ const ref = /^ref:\s*refs\/heads\/(.+?)\s*$/m.exec(readFileSync(path.join(gitdir, "HEAD"), "utf8"))
376
+ return { branch: ref ? ref[1] : null, root: dir }
377
+ }
378
+ const up = path.dirname(dir)
379
+ if (up === dir) return { branch: null, root: null }
380
+ dir = up
381
+ }
382
+ } catch {
383
+ return { branch: null, root: null }
384
+ }
385
+ }
386
+
387
+ /**
388
+ * Consent Before Push's loop/* exemption — the twin of js/hosts/hooks.mjs's `loopExempt`.
389
+ * True only when the command carries none of the unsafe characters, every `&&`/`;`/`||`/`|`
390
+ * segment is one of the three whitelisted git shapes (every push segment also passing
391
+ * `pushSegmentOk`), and the branch checked out in `cwd` starts with `loop/` AND its git root
392
+ * carries a launched LOOP.md.
393
+ */
394
+ function loopExempt(command, cwd) {
395
+ if (typeof command !== "string" || UNSAFE_CHARS_RE.test(command)) return false
396
+ const { branch, root } = currentBranch(cwd)
397
+ if (!branch || !branch.startsWith("loop/")) return false
398
+ if (!root || !loopLaunched(root)) return false
399
+ const segments = command.split(/&&|\|\||[;|]/).map((s) => s.trim()).filter(Boolean)
400
+ if (!segments.length) return false
401
+ return segments.every((seg) => SEG_ADD_RE.test(seg) || SEG_COMMIT_RE.test(seg)
402
+ || SEG_READONLY_RE.test(seg) || pushSegmentOk(seg, branch))
403
+ }
404
+
405
+ export const GeneseedGuard = async (ctx) => {
406
+ // The session's working directory, the same resolution the context plugin uses — a
407
+ // worktree session's `.git` is a FILE, which `currentBranch` already follows.
408
+ const root = () => ctx?.worktree || ctx?.directory || process.cwd()
271
409
  return {
272
410
  "tool.execute.before": async (input, output) => {
273
411
  if (OFF) return
@@ -318,6 +456,23 @@ export const GeneseedGuard = async () => {
318
456
  log(`inspect error (ignored): ${err?.message ?? err}`)
319
457
  }
320
458
  },
459
+ "permission.ask": async (input, output) => {
460
+ // Never throw from a permission hook — leave `output.status` untouched on any
461
+ // error, exactly as a crashed check here must default to the static ask standing.
462
+ try {
463
+ if (OFF) return
464
+ // Never loosen anything but the plain "ask" this hook itself would otherwise leave
465
+ // alone — a deny (or any other status another hook already set) is never overwritten.
466
+ if (output?.status && output.status !== "ask") return
467
+ if (input?.type !== "bash") return
468
+ // ONLY `input.metadata?.command` — no pattern/title fallback. A value this hook did
469
+ // not itself read in full is a value it must not reason about.
470
+ const command = input?.metadata?.command
471
+ if (typeof command !== "string" || !command || !GIT_GATE_RE.test(command)) return
472
+ if (await sovereignBypass(root())) return
473
+ if (loopExempt(command, root())) output.status = "allow"
474
+ } catch { /* leave output.status untouched */ }
475
+ },
321
476
  }
322
477
  }
323
478
 
@@ -149,6 +149,10 @@ const VERBS = {
149
149
  catalog: () => import('../js/build/catalog.mjs').then((m) => m.cmdCatalog),
150
150
  mcp: () => import('../js/hosts/mcp.mjs').then((m) => m.cmdMcp),
151
151
  memory: () => import('../js/maintain/memory.mjs').then((m) => m.cmdMemory),
152
+ // Task 5. A fourth native verb: there was never a Python subparser for a state machine that
153
+ // lives entirely inside this port, so — like the three above — it has no recorded cell to
154
+ // compare against, only the absolute gates named beside it in `NATIVE`.
155
+ loop: () => import('../js/loop/cli.mjs').then((m) => m.cmdLoop),
152
156
  };
153
157
 
154
158
  function die(code, msg) {
package/docs/README.md CHANGED
@@ -2,40 +2,59 @@
2
2
 
3
3
  [← Back to README](../README.md)
4
4
 
5
- **New to agent harnesses?** Read **Understand** first — four short pages, about ten minutes, and every other page assumes them. The same pages open the **Docs** tab of the web console (`geneseed web`), which adds an interactive map of your own install and filters host-specific passages to the tool you use.
5
+ **New to agent harnesses?** Read **Understand** first — a short track, about ten minutes, that every other page assumes. The same pages open the **Docs** tab of the web console (`geneseed web`), which groups each part into sections, adds an interactive map of your own install, and filters host-specific passages to the tool you use.
6
6
 
7
7
  ## 1 · Understand
8
8
 
9
- 1. **[What a harness is](understand/harness.md)** — git hooks + CI + a runbook, but for your AI agent.
10
- 2. **[What lands on your machine](understand/on-your-machine.md)** — every file and hook an install writes, what it does for you, what it costs, how to turn it off.
11
- 3. **[A day with the harness](understand/a-day.md)** — the moments you will actually meet: a push that asks first, a skill, a delegation, a memory.
12
- 4. **[Enforced vs. asked](understand/enforced-vs-asked.md)** — what is guaranteed by code, and what the model is only asked to do.
9
+ **Start here** — [What a harness is](understand/harness.md): git hooks + CI + a runbook, but for your AI agent.
10
+
11
+ **On your machine** — [What lands on your machine](understand/on-your-machine.md) · [On OpenCode](understand/machine-opencode.md) · [On Claude Code and OpenClaude](understand/machine-claude.md) · [On Bob, or any AGENT.md tool](understand/machine-bob.md) · [Taking it back out](understand/take-it-out.md): every file and hook an install writes, what it does for you, what it costs, how to turn it off.
12
+
13
+ **Day to day** — [A day with the harness](understand/a-day.md): the moments you will actually meet · [Enforced vs. asked](understand/enforced-vs-asked.md): what is guaranteed by code, and what the model is only asked to do.
13
14
 
14
15
  ## 2 · Guides
15
16
 
16
- | Guide | When |
17
- | --- | --- |
18
- | [Install](guides/install.md) | First time — npx, a clone, or a specific host |
19
- | [Choose your setup](guides/choose-your-setup.md) | Theme, doctrine packs, one rule at a time, footprint, posture, mode |
20
- | [Verify it works](guides/verify.md) | Right after installing, or when something feels off |
21
- | [Upgrade](guides/upgrade.md) | Getting a new version onto every install |
22
- | [Uninstall](guides/uninstall.md) | Removing an install — and what stays behind |
23
- | [Project context](guides/project-context.md) | Choosing which of a repo's docs the agent loads |
24
- | [Connect your wiki](guides/wiki.md) | Giving the agent your own notes, machine-wide |
25
- | [MCP servers](guides/mcp.md) | MarkItDown, GitLab, Filesystem — and reading non-markdown docs |
26
- | [Run geneseed from anywhere](guides/run-anywhere.md) | Putting the CLI on your PATH from a clone |
27
- | [Start the web console at login](guides/autostart.md) | Keeping the console running |
28
- | [Run in CI / headless](guides/headless.md) | OpenCode without a terminal |
29
- | [Add git-worktree isolation](guides/worktree.md) | OpenCode, optional third-party add-on |
30
- | [Migrate from a clone to npm](guides/migrate.md) | Moving an old clone install to the npm package |
17
+ | Section | Guide | When |
18
+ | --- | --- | --- |
19
+ | Install | [Install](guides/install.md) | First time — one command, and the page for each host |
20
+ | Install | [From a clone](guides/install-clone.md) | npm is out of reach, or you want to change the harness |
21
+ | Install | [OpenCode](guides/install-opencode.md) · [Claude Code](guides/install-claude-code.md) · [OpenClaude](guides/install-openclaude.md) · [IBM Bob](guides/install-bob.md) · [Any AGENT.md tool](guides/install-agent-md.md) | Installing for one host, global or per repo |
22
+ | Install | [Without the wizard](guides/install-scripted.md) | A script, a CI job, a shell with no terminal |
23
+ | Install | [Run geneseed from anywhere](guides/run-anywhere.md) | Putting the CLI on your PATH from a clone |
24
+ | Set up | [Choose your setup](guides/choose-your-setup.md) · [Doctrine packs and single rules](guides/setup-doctrines.md) · [Footprint, loop trust and changing later](guides/setup-footprint.md) | Theme, posture, mode; doctrine packs and single rules; footprint, loop trust, changing a choice |
25
+ | Set up | [Verify it works](guides/verify.md) | Right after installing, or when something feels off |
26
+ | Set up | [Project context](guides/project-context.md) | Choosing which of a repo's docs the agent loads |
27
+ | Set up | [Connect your wiki](guides/wiki.md) | Giving the agent your own notes, machine-wide |
28
+ | Set up | [MCP servers](guides/mcp.md) · [MarkItDown](guides/mcp-markitdown.md) · [GitLab](guides/mcp-gitlab.md) · [Filesystem](guides/mcp-filesystem.md) · [Reading non-markdown docs](guides/read-non-markdown.md) | Where the config lives, the three presets, and reading PDF and Office files |
29
+ | Loops | [Run a loop](guides/run-a-loop.md) · [Which loop template](guides/loop-which-template.md) · [While a loop runs](guides/loop-running.md) · [Finish a loop](guides/loop-finish.md) | Working a requirement as small, validated, committed iterations |
30
+ | Keep it running | [Upgrade](guides/upgrade.md) | Getting a new version onto every install |
31
+ | Keep it running | [Migrate from a clone to npm](guides/migrate.md) | Moving an old clone install to the npm package |
32
+ | Keep it running | [Start the web console at login](guides/autostart.md) | Keeping the console running |
33
+ | Keep it running | [Uninstall](guides/uninstall.md) | Removing an install — and what stays behind |
34
+ | OpenCode extras | [Run in CI / headless](guides/headless.md) | OpenCode without a terminal |
35
+ | OpenCode extras | [Add git-worktree isolation](guides/worktree.md) | OpenCode, optional third-party add-on |
31
36
 
32
37
  ## 3 · Concepts
33
38
 
34
- [Hosts](concepts/hosts.md) · [Rules](concepts/rules.md) · [Agents](concepts/agents.md) · [Skills](concepts/skills.md) · [Hooks](concepts/hooks.md) · [Memory](concepts/memory.md) · [Notebook](concepts/notebook.md) · [Footprint](concepts/footprint.md) · [Collaboration](concepts/collaboration.md) · [Foreman mode](concepts/foreman-mode.md) · [Exclusions](concepts/exclusions.md) · [Themes](concepts/themes.md) · [Code intelligence (LSP)](concepts/lsp.md)
39
+ **Harness** — [Hosts](concepts/hosts.md) · [What each host automates](concepts/host-matrix.md) · [Rules](concepts/rules.md) · [Agents](concepts/agents.md) · [Skills](concepts/skills.md) · [Hooks](concepts/hooks.md) · [Hook gates, settings and the shim](concepts/hook-gates.md)
40
+
41
+ **Memory** — [Memory](concepts/memory.md) · [Notebook](concepts/notebook.md)
42
+
43
+ **Configuration** — [Footprint](concepts/footprint.md) · [Themes](concepts/themes.md) · [Exclusions](concepts/exclusions.md) · [Code intelligence (LSP)](concepts/lsp.md)
44
+
45
+ **Working together** — [Collaboration](concepts/collaboration.md) · [Foreman mode](concepts/foreman-mode.md)
46
+
47
+ **Loops** — [Loops](concepts/loops.md) · [Templates](concepts/loop-templates.md) · [Bricks and their origins](concepts/loop-bricks.md) · [Notes and rules](concepts/loop-notes.md) · [Risk, trust and validation levels](concepts/loop-risk.md) · [Human gates](concepts/loop-gates.md) · [Contracts and ignored deletions](concepts/loop-contracts.md) · [LOOP.md, trailers and the loop branch](concepts/loop-branch.md)
35
48
 
36
49
  ## 4 · Reference
37
50
 
38
- [CLI](reference/cli.md) · [Environment variables](reference/environment.md) · [Glossary](reference/glossary.md) · [Troubleshooting](reference/troubleshooting.md) (by symptom) · [OpenCode plugins](reference/opencode-plugins.md) · [About](reference/about.md)
51
+ **CLI & environment** — [CLI](reference/cli.md) · [Loop actions](reference/loop-actions.md) · [Environment variables](reference/environment.md) · [Context and memory variables](reference/env-context.md)
52
+
53
+ **Troubleshooting** (by symptom) — [Overview](reference/troubleshooting.md) · [Install](reference/troubleshoot-install.md) · [Hooks, context and memory](reference/troubleshoot-hooks.md) · [Model, agents and MCP](reference/troubleshoot-tools.md) · [Updating](reference/troubleshoot-update.md) · [Doctor findings](reference/troubleshoot-doctor.md) · [Web console](reference/troubleshoot-web.md)
54
+
55
+ **OpenCode plugins** — [Overview](reference/opencode-plugins.md) · [context](reference/plugin-context.md) · [guard](reference/plugin-guard.md) · [learn](reference/plugin-learn.md) · [workflow](reference/plugin-workflow.md) · [notify](reference/plugin-notify.md) · [ponytail](reference/plugin-ponytail.md) · [activity](reference/plugin-activity.md)
56
+
57
+ **Glossary & about** — [Glossary](reference/glossary.md) · [About](reference/about.md)
39
58
 
40
59
  ## For contributors
41
60
 
@@ -1,8 +1,10 @@
1
1
  ---
2
2
  group: concepts
3
- order: 3
3
+ order: 4
4
4
  title: "Agents"
5
5
  kind: "concept"
6
+ section: "Harness"
7
+ description: "The specialists the main session can hand work to."
6
8
  link: {"hash": "#/section/agents", "label": "Browse the catalog →"}
7
9
  ---
8
10
  An **agent** is a specialist the main session can hand a piece of work to. Each one is a markdown file with its own instructions, installed where your host looks for subagents (`agents/` in the install). It runs in its own context and returns a result, so its reading and searching does not fill your conversation.
@@ -1,8 +1,10 @@
1
1
  ---
2
2
  group: concepts
3
- order: 9
3
+ order: 14
4
4
  title: "Collaboration"
5
5
  kind: "concept"
6
+ section: "Working together"
7
+ description: "Register, contract, how firmly a memory binds, and who you are."
6
8
  ---
7
9
  Beside the [rules](rules.md), a few pieces shape *how* the agent works with you: the register it speaks in, the contract between you, how firmly a memory binds, and who you are. All of them are plain text in the install, so they reach every host unchanged.
8
10
 
@@ -1,8 +1,10 @@
1
1
  ---
2
2
  group: concepts
3
- order: 11
3
+ order: 12
4
4
  title: "Exclusions"
5
5
  kind: "concept"
6
+ section: "Configuration"
7
+ description: "Two ways to switch things off: one rule, or every hook in a folder."
6
8
  link: {"hash": "#/harness", "label": "Manage in Harness →"}
7
9
  ---
8
10
  Geneseed has two different ways to switch something off, and they work at different scales:
@@ -52,4 +54,4 @@ The finer switch removes a single doctrine rule from an install while keeping th
52
54
  geneseed build --emit claude-global --exclude-rules "process 7"
53
55
  ```
54
56
 
55
- The install records it (`Excluded rules: process 7` beside its pack list) and every rebuild and upgrade keeps it. The always-on Rules and the Ethos cannot be excluded. Picking packs and rules is covered in [Choose your setup](../guides/choose-your-setup.md); what the layers are is in [Rules](rules.md).
57
+ The install records it (`Excluded rules: process 7` beside its pack list) and every rebuild and upgrade keeps it. The always-on Rules and the Ethos cannot be excluded. Picking packs and rules is covered in [Doctrine packs and single rules](../guides/setup-doctrines.md); what the layers are is in [Rules](rules.md).