geneseed 3.9.0 → 3.11.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 (219) hide show
  1. package/CHANGELOG.md +89 -1
  2. package/DESIGN.md +1 -1
  3. package/README.md +52 -71
  4. package/SHIPPED.md +3 -3
  5. package/adapters/bob/README.md +18 -2
  6. package/adapters/claude-code/README.md +17 -12
  7. package/adapters/openclaude/README.md +2 -2
  8. package/adapters/opencode/README.md +4 -4
  9. package/adapters/opencode/plugins/geneseed-context.js +78 -8
  10. package/bin/build-driver.mjs +2 -0
  11. package/bin/geneseed-cli.mjs +17 -0
  12. package/bin/geneseed-hook.mjs +3 -1
  13. package/docs/README.md +42 -0
  14. package/docs/_groups.json +18 -0
  15. package/docs/candidate-hosts.md +12 -5
  16. package/docs/concepts/agents.md +44 -0
  17. package/docs/concepts/collaboration.md +62 -0
  18. package/docs/concepts/exclusions.md +55 -0
  19. package/docs/concepts/footprint.md +52 -0
  20. package/docs/concepts/foreman-mode.md +69 -0
  21. package/docs/concepts/hooks.md +101 -0
  22. package/docs/concepts/hosts.md +55 -0
  23. package/docs/concepts/lsp.md +50 -0
  24. package/docs/{web → concepts}/memory.md +2 -2
  25. package/docs/{web → concepts}/notebook.md +2 -2
  26. package/docs/concepts/rules.md +52 -0
  27. package/docs/concepts/skills.md +49 -0
  28. package/docs/concepts/themes.md +50 -0
  29. package/docs/extending.md +27 -21
  30. package/docs/guides/autostart.md +70 -0
  31. package/docs/guides/choose-your-setup.md +120 -0
  32. package/docs/guides/headless.md +22 -0
  33. package/docs/guides/install.md +161 -0
  34. package/docs/guides/mcp.md +195 -0
  35. package/docs/guides/migrate.md +41 -0
  36. package/docs/guides/project-context.md +87 -0
  37. package/docs/guides/run-anywhere.md +45 -0
  38. package/docs/guides/uninstall.md +51 -0
  39. package/docs/guides/upgrade.md +65 -0
  40. package/docs/guides/verify.md +65 -0
  41. package/docs/guides/wiki.md +69 -0
  42. package/docs/guides/worktree.md +47 -0
  43. package/docs/reference/about.md +7 -0
  44. package/docs/reference/cli.md +7 -0
  45. package/docs/reference/environment.md +99 -0
  46. package/docs/reference/glossary.md +33 -0
  47. package/docs/reference/opencode-plugins.md +131 -0
  48. package/docs/reference/troubleshooting.md +350 -0
  49. package/docs/token-footprint.md +26 -21
  50. package/docs/understand/a-day.md +77 -0
  51. package/docs/understand/enforced-vs-asked.md +64 -0
  52. package/docs/understand/harness.md +36 -0
  53. package/docs/understand/on-your-machine.md +76 -0
  54. package/docs/web-ui.md +2 -2
  55. package/harness.config.json +1 -1
  56. package/js/README.md +7 -6
  57. package/js/build/driver.mjs +26 -95
  58. package/js/build/emit-claude.mjs +76 -81
  59. package/js/build/generate.mjs +12 -2
  60. package/js/build/render.mjs +4 -0
  61. package/js/build/source.mjs +6 -0
  62. package/js/build/stubs.mjs +18 -2
  63. package/js/cli-table.json +6 -6
  64. package/js/hosts/hooks.mjs +86 -54
  65. package/js/hosts/hosts.mjs +5 -21
  66. package/js/hosts/installs.mjs +4 -6
  67. package/js/hosts/mcp.mjs +4 -14
  68. package/js/hosts/native.mjs +27 -50
  69. package/js/hosts/opencode.mjs +1 -1
  70. package/js/hosts/settings.mjs +17 -79
  71. package/js/inspect/checks-authoring.mjs +9 -4
  72. package/js/inspect/checks-repo.mjs +45 -1
  73. package/js/inspect/diff.mjs +11 -3
  74. package/js/inspect/doctor.mjs +4 -4
  75. package/js/inspect/excludes.mjs +0 -4
  76. package/js/inspect/inventory.mjs +1 -1
  77. package/js/inspect/registry.mjs +20 -3
  78. package/js/inspect/status.mjs +11 -6
  79. package/js/lib/node-floor.mjs +30 -0
  80. package/js/maintain/migrate.mjs +5 -5
  81. package/js/maintain/setup.mjs +112 -26
  82. package/js/maintain/uninstall.mjs +8 -42
  83. package/js/maintain/update.mjs +4 -15
  84. package/js/ui/cli.mjs +2 -2
  85. package/js/web/actions.mjs +4 -5
  86. package/js/web/api.mjs +7 -4
  87. package/js/web/daemon.mjs +52 -0
  88. package/js/web/docs.mjs +149 -65
  89. package/js/web/server.mjs +5 -2
  90. package/package.json +6 -5
  91. package/registry.json +7 -0
  92. package/src/AGENT.md.tmpl +73 -52
  93. package/src/laws/universal.md +3 -0
  94. package/src/ontology/universal.md +1 -1
  95. package/src/postures/mentor.md +1 -0
  96. package/src/skills/daydream/SKILL.md +10 -3
  97. package/src/skills/daydream/VENDOR.md +10 -2
  98. package/src/skills/daydream/instructions.md +2 -2
  99. package/src/skills/explain-changes/SKILL.md +1 -1
  100. package/src/skills/explain-changes/VENDOR.md +1 -1
  101. package/src/skills/geneseed.md +1 -1
  102. package/src/skills/learn-mode.md +89 -0
  103. package/src/skills/pipeline.md +2 -2
  104. package/src/skills/quiz.md +2 -1
  105. package/src/skills/react-view-transitions/SKILL.md +1 -1
  106. package/src/skills/react-view-transitions/VENDOR.md +7 -2
  107. package/src/skills/teach.md +2 -1
  108. package/src/skills/token-report/SKILL.md +2 -3
  109. package/src/skills/token-report/VENDOR.md +2 -3
  110. package/src/skills/token-report/scripts/token_report.mjs +7 -121
  111. package/src/skills/workflow.md +1 -1
  112. package/themes/_TEMPLATE.json +1 -0
  113. package/themes/biker.json +1 -0
  114. package/themes/commentator.json +1 -0
  115. package/themes/cyberpunk.json +1 -0
  116. package/themes/gamer.json +1 -0
  117. package/themes/imperial.json +1 -0
  118. package/themes/joker.json +1 -0
  119. package/themes/marvin.json +1 -0
  120. package/themes/mean.json +1 -0
  121. package/themes/military.json +1 -0
  122. package/themes/neutral.json +1 -0
  123. package/themes/pirate.json +1 -0
  124. package/themes/sports.json +1 -0
  125. package/themes/verstappen.json +1 -0
  126. package/themes/wizard.json +1 -0
  127. package/web/dist/assets/Activity-C52LEb-2.js +1 -0
  128. package/web/dist/assets/ActivityDetail-CjNLRvXg.js +1 -0
  129. package/web/dist/assets/Dashboard-B6_sSCHi.js +2 -0
  130. package/web/dist/assets/Docs-Dj7BmCSA.js +5 -0
  131. package/web/dist/assets/{GreenhouseView-Bq1QmaGO.js → GreenhouseView-BALwjQsA.js} +1 -1
  132. package/web/dist/assets/Installs-BbffDQm3.js +2 -0
  133. package/web/dist/assets/JournalView-JpAQ8Hqe.js +1 -0
  134. package/web/dist/assets/Laws-DK7eCWSm.js +3 -0
  135. package/web/dist/assets/Library-CoamHelE.js +1 -0
  136. package/web/dist/assets/{Markdown-CkFyfgNf.js → Markdown-qjM2_ofS.js} +5 -5
  137. package/web/dist/assets/{OperatorHudView-B-HVBqfY.js → OperatorHudView-DVx1HlBx.js} +1 -1
  138. package/web/dist/assets/Personal-eaXb1zcj.js +1 -0
  139. package/web/dist/assets/{Tabs-_pjUFIEI.js → Tabs-BmGtt8E2.js} +1 -1
  140. package/web/dist/assets/api-Dc8f3ca-.js +1 -0
  141. package/web/dist/assets/drawable-Du_PZrQj.js +1 -0
  142. package/web/dist/assets/index-Bz_KMRDH.css +1 -0
  143. package/web/dist/assets/index-CNFH7o55.js +2 -0
  144. package/web/dist/index.html +3 -2
  145. package/QUICKSTART.md +0 -50
  146. package/SETUP.md +0 -1183
  147. package/adapters/copilot/README.md +0 -105
  148. package/docs/web/_groups.json +0 -45
  149. package/docs/web/about.md +0 -6
  150. package/docs/web/adapters-claude-code.md +0 -8
  151. package/docs/web/adapters-opencode-loads.md +0 -8
  152. package/docs/web/adapters-opencode-spec.md +0 -8
  153. package/docs/web/adapters-opencode.md +0 -8
  154. package/docs/web/agents.md +0 -8
  155. package/docs/web/authoring.md +0 -11
  156. package/docs/web/autostart.md +0 -9
  157. package/docs/web/claude-hooks.md +0 -37
  158. package/docs/web/cli.md +0 -6
  159. package/docs/web/collaboration.md +0 -27
  160. package/docs/web/configure-wiki.md +0 -9
  161. package/docs/web/design.md +0 -7
  162. package/docs/web/env-knobs.md +0 -9
  163. package/docs/web/exclusions.md +0 -27
  164. package/docs/web/first-session.md +0 -28
  165. package/docs/web/footprint.md +0 -38
  166. package/docs/web/foreman-mode.md +0 -33
  167. package/docs/web/glossary.md +0 -6
  168. package/docs/web/harnesses.md +0 -30
  169. package/docs/web/headless.md +0 -9
  170. package/docs/web/ingest-docs.md +0 -9
  171. package/docs/web/install-paths.md +0 -9
  172. package/docs/web/install-quick.md +0 -35
  173. package/docs/web/lsp-overview.md +0 -37
  174. package/docs/web/mcp-claude-code.md +0 -10
  175. package/docs/web/mcp-filesystem.md +0 -9
  176. package/docs/web/mcp-gitlab.md +0 -9
  177. package/docs/web/mcp-markitdown.md +0 -9
  178. package/docs/web/mcp-overview.md +0 -34
  179. package/docs/web/mcp-trouble.md +0 -9
  180. package/docs/web/mcp-verify.md +0 -9
  181. package/docs/web/migrate.md +0 -39
  182. package/docs/web/model.md +0 -20
  183. package/docs/web/pipelines.md +0 -24
  184. package/docs/web/plugin-activity.md +0 -23
  185. package/docs/web/plugin-context.md +0 -26
  186. package/docs/web/plugin-guard.md +0 -24
  187. package/docs/web/plugin-learn.md +0 -27
  188. package/docs/web/plugin-notify.md +0 -24
  189. package/docs/web/plugin-ponytail.md +0 -23
  190. package/docs/web/plugin-setup.md +0 -7
  191. package/docs/web/plugin-workflow.md +0 -25
  192. package/docs/web/plugins.md +0 -17
  193. package/docs/web/project-context.md +0 -9
  194. package/docs/web/rules.md +0 -30
  195. package/docs/web/run-anywhere.md +0 -9
  196. package/docs/web/self-improve.md +0 -8
  197. package/docs/web/setup-choices.md +0 -64
  198. package/docs/web/skills.md +0 -8
  199. package/docs/web/themes-author.md +0 -20
  200. package/docs/web/themes.md +0 -9
  201. package/docs/web/token-footprint.md +0 -7
  202. package/docs/web/trouble.md +0 -38
  203. package/docs/web/upgrade.md +0 -9
  204. package/docs/web/verify.md +0 -30
  205. package/docs/web/wiki.md +0 -7
  206. package/docs/web/worktree.md +0 -10
  207. package/docs/wiki.md +0 -43
  208. package/web/dist/assets/Activity-DAzV-qQj.js +0 -1
  209. package/web/dist/assets/ActivityDetail-CwEwMtKl.js +0 -1
  210. package/web/dist/assets/Dashboard-C2ELBW-X.js +0 -2
  211. package/web/dist/assets/Docs-iZrvQP8J.js +0 -2
  212. package/web/dist/assets/Installs-BiqR8xdO.js +0 -2
  213. package/web/dist/assets/JournalView-6wilG5Zd.js +0 -1
  214. package/web/dist/assets/Laws-D8YXD_XE.js +0 -3
  215. package/web/dist/assets/Library-DwuTZ2-L.js +0 -1
  216. package/web/dist/assets/Personal-BbUTmZQR.js +0 -1
  217. package/web/dist/assets/drawable-CoIulEH2.js +0 -1
  218. package/web/dist/assets/index-BMwSp8BP.js +0 -2
  219. package/web/dist/assets/index-CDPDk2vj.css +0 -1
package/SETUP.md DELETED
@@ -1,1183 +0,0 @@
1
- <div align="center">
2
-
3
- # 🧬 Geneseed — Setup Guide
4
-
5
- **From bare repository to a disciplined agent in a few minutes.**
6
-
7
- [← Back to README](README.md) · [Design](DESIGN.md) · [OpenCode adapter](adapters/opencode/README.md) · [Claude Code adapter](adapters/claude-code/README.md)
8
-
9
- </div>
10
-
11
- > **In a hurry?** The 5-minute recommended path is **[QUICKSTART.md](QUICKSTART.md)**.
12
- > This page is the full reference: every install path, knob, and troubleshooting step.
13
-
14
- ---
15
-
16
- You pick a **theme** — the voice and vocabulary the harness wears — and an **install mode**;
17
- the build implants the gene-seed and the agent wakes speaking in that voice. Pick the path
18
- that matches your tool, then configure and verify. For the conceptual overview see the
19
- [README](README.md); for OpenCode internals see [adapters/opencode/](adapters/opencode/README.md).
20
-
21
- ## 📋 Prerequisites
22
-
23
- - **Node ≥ 22.3** — the only hard requirement. Geneseed ships as an npm package with
24
- **zero dependencies**; `npx geneseed` needs nothing else.
25
- - **Your agent tool** — OpenCode (recommended), Claude Code, Bob, Copilot, OpenClaude, or anything
26
- that reads a root instructions file.
27
- - *Only for a git checkout:* **git**. Nothing else — a checkout runs the same Node
28
- entry points the npm package installs.
29
- - *Optional, for the `ingest` skill:* a document converter — **MarkItDown**, Pandoc,
30
- or Docling — if you want the agent to read PDFs/Office files (see
31
- [Reading non-markdown docs](#reading-non-markdown-docs)).
32
-
33
- ### 🟩 One runtime — Node, and nothing else
34
-
35
- Nothing in this guide needs a second interpreter. Three things are worth stating plainly,
36
- because each is a live constraint rather than a footnote:
37
-
38
- - **Every command runs on Node.** There is no full-screen browse panel: `geneseed tui`
39
- and `geneseed menu` are verbs that say the panel is not here and print the command list
40
- instead. Bare `geneseed` — from the launchers and from an npm install alike — runs
41
- `home`, which opens the web console when it can and otherwise prints the command list;
42
- `geneseed --help` lists every command.
43
- - **Nothing you install needs an interpreter.** The `token-report` skill is a script
44
- rather than prose, and it ships as `scripts/token_report.mjs`, run with `node`;
45
- `daydream` and `herdr` hand their inline code to `node -e`.
46
- So **every bundle carries** nothing that needs one: no Python file, and no skill that
47
- shells out to an interpreter — on any host, any theme, either footprint. Three tests
48
- freeze that, down to a byte-for-byte replay of the report script over seeded
49
- transcripts for all four hosts.
50
- - **The self-update commands are for a git checkout.** `upgrade`, `update`, `sync-self`
51
- and `bootstrap` `git pull` the install's own origin. From an npm install they stop
52
- before touching anything and name `npm install -g geneseed@latest` instead.
53
-
54
- One more, in the web console rather than the CLI: the **"browse…" folder picker** would
55
- open an OS-native dialog on the machine running the daemon, and the server declines to.
56
- The button reports itself unavailable and the path field beside it stays editable.
57
-
58
- ## 🛣️ Choose your path
59
-
60
- **Easiest:** `npx geneseed setup` — no clone, nothing installed permanently.
61
- It runs the same guided wizard as a checkout does: it asks for a theme and an install
62
- mode, runs the right build, and offers a health check. To keep the command around, put
63
- it on PATH with `npm install -g geneseed`.
64
-
65
- **From a clone:** `./geneseed setup` on macOS/Linux, `.\geneseed.cmd setup` on Windows.
66
- It is the same dependency-free wizard the npx route runs — plain text prompts, every
67
- console, every OS.
68
-
69
- **Already installed from a clone, and moving to npm?** `geneseed migrate` re-emits every
70
- install you already have onto the npm shape in a single all-or-nothing pass, keeping each
71
- one's own theme, emit, footprint, posture and mode. `--dry-run` prints the plan and
72
- writes nothing. It **reports rather than rewrites** anything it did not create — your own
73
- hooks, third-party hooks, and the login autostart entry you hand-wrote. Your old clone
74
- keeps working for a full release; there is no cliff.
75
- See [Migrate an existing install](docs/web/migrate.md).
76
-
77
- As you move through the theme picker the wizard **previews each theme live** — its
78
- tagline, loaded-sigil, and voice — so you hear the flavour before you choose; once
79
- you pick, it speaks in that theme's accent through confirm and build, and the
80
- install ends on the theme's own **banner and benediction**.
81
-
82
- **Already installed?** Bare **`geneseed`** (a checkout: `./geneseed`, Windows: `.\geneseed.cmd`) opens the
83
- **web console**, which is where browsing, local edits, rebuilds, memory, status, MCP
84
- servers and uninstall all live — see [The web console](docs/web-ui.md). `GENESEED_NO_WEB=1`
85
- suppresses that and prints the command list instead. Uninstall from the CLI is
86
- `geneseed uninstall --target <repo>` (bare `--target` runs against whichever project
87
- install the cwd sits in). **`./geneseed bootstrap`** jumps straight to
88
- update-then-setup; **`./geneseed setup`** straight to the wizard. Prefer to do it by
89
- hand? Pick a path below.
90
-
91
- | Path | Use when |
92
- | --- | --- |
93
- | [A — OpenCode, global](#path-a--opencode-global-recommended) | **Recommended.** One install, every repo inherits it, nothing committed into projects. |
94
- | [B — OpenCode, per-repo](#path-b--opencode-per-repo) | You want a committed `.opencode/` layer in one repository. |
95
- | [C — Claude Code](#path-c--claude-code) | You drive Claude Code and want the lifecycle hooks. |
96
- | [C′ — GitHub Copilot](#path-c--github-copilot) | You drive the Copilot CLI, coding agent, or VS Code agent mode. |
97
- | [C″ — OpenClaude](#path-c--openclaude) | You drive OpenClaude, the any-model Claude Code fork. |
98
- | [D — Any `AGENT.md` tool](#path-d--any-agentmd-tool) | Cursor, Aider, or any tool that reads a root instructions file. |
99
- | [E — No runtime on the target at all](#path-e--no-runtime-on-the-target-at-all) | The machine that *uses* the harness cannot run Node. |
100
-
101
- > **Every `geneseed-build …` below is the generator.** `npm install -g geneseed` puts it
102
- > on your `PATH`; without installing anything, `npx -p geneseed geneseed-build --emit
103
- > opencode-global` is the same command. From a checkout it is
104
- > `node bin/build-driver.mjs` with the same flags. Every commit re-emits with it across every
105
- > theme × host × footprint combination and checks the result with `doctor --all`, on Linux
106
- > and Windows both. Until 2026-08-17 that output was also compared byte for byte against
107
- > recordings taken from the Python implementation; those were retired (see the 2.0.0 entry
108
- > in [CHANGELOG.md](CHANGELOG.md)).
109
-
110
- ---
111
-
112
- ### Path A — OpenCode, global (recommended)
113
-
114
- Installs the whole harness into OpenCode's config dir; every repo you open inherits it.
115
-
116
- ```
117
- # from inside the Geneseed folder
118
- geneseed-build --emit opencode-global # add --theme imperial for the 40k voice
119
- # GENESEED_HARNESS is optional — the learn plugin auto-locates the in-config memory
120
- # store. Set it only to pin the location explicitly (and persist it to your rc):
121
- export GENESEED_HARNESS="$HOME/.config/opencode"
122
- echo 'export GENESEED_HARNESS="$HOME/.config/opencode"' >> ~/.zshrc
123
- ```
124
-
125
- **Windows (PowerShell)** — identical, no bash/WSL needed:
126
- ```powershell
127
- # from inside the Geneseed folder
128
- geneseed-build --emit opencode-global # add --theme imperial for the 40k voice
129
- setx GENESEED_HARNESS "$env:USERPROFILE\.config\opencode" # optional; pins the memory store
130
- ```
131
- On Windows the config dir is the same homedir-relative path,
132
- `C:\Users\<user>\.config\opencode` — OpenCode uses `~/.config/opencode` on every OS.
133
-
134
- This writes into `$OPENCODE_CONFIG_DIR` (else `$XDG_CONFIG_HOME/opencode`, else
135
- `~/.config/opencode`): `AGENT.md`, `agents/`, `skills/<name>/SKILL.md`, a single
136
- `plugins/` copy, the `memory/` store, and a merged `opencode.json` pointing
137
- `instructions` at the absolute `AGENT.md`. No `context.json` — the context plugin
138
- auto-discovers each repo's docs.
139
-
140
- It is **non-destructive**: a `.geneseed-manifest.json` tracks only the files it owns
141
- and prunes stale ones on re-emit; your own agents/skills/plugins and the memory store
142
- are never touched. Full design + checklist:
143
- [GLOBAL-HARNESS-SPEC.md](adapters/opencode/GLOBAL-HARNESS-SPEC.md).
144
-
145
- ### Path B — OpenCode, per-repo
146
-
147
- ```
148
- geneseed-build --emit opencode --target /path/to/your-repo
149
- ```
150
-
151
- Writes the full bundle (`AGENT.md`, `agents/`, `skills/`, `memory/`, `notebook/`)
152
- plus the OpenCode-native layer (`opencode.json` and `.opencode/{agents,skills,plugins,workflows}`)
153
- into the target dir. Commit them or not. **Want the bundle in a subfolder?** add `--root`
154
- so instruction paths resolve from the project root:
155
-
156
- ```
157
- geneseed-build --emit opencode --out /path/to/repo/Harness --root /path/to/repo
158
- ```
159
-
160
- Depth, native mapping, and the manual fallback: [adapters/opencode/](adapters/opencode/README.md).
161
-
162
- ### Path C — Claude Code
163
-
164
- Merge [`adapters/claude-code/settings.json`](adapters/claude-code/settings.json) into
165
- your repo's `.claude/settings.json` (paths assume the bundle is at the repo root).
166
- It wires:
167
-
168
- - **PreToolUse** (matcher `Bash`) — runs `harness git-gate`, a tool-boundary backstop
169
- for Doctrine `process 5`. The hook inspects the command and forces an `ask` on every
170
- `git commit` or `git push` (even chained or `-C`-flagged), un-suppressible by a
171
- one-time "don't ask again". Every other Bash command is deferred to the normal
172
- permission flow. It is wired only when **Doctrine process 5 itself** is active — build
173
- with `--doctrines` leaving `process` out, or with `--exclude-rules "process 5"`, and this
174
- hook is not installed at all. The prompt and the boundary move together by construction:
175
- the gate is keyed on the rule, not on its pack.
176
- - **SessionStart** (`startup`/`clear`) — prints `AGENT.md` and injects the project
177
- context (`harness context`, which auto-discovers the repo's docs);
178
- - **SessionStart** (`resume`/`compact`) — refreshes the project context only, without
179
- re-printing the static `AGENT.md`. `compact` matters: auto-compaction summarises away the
180
- injected context, memory index and notebook TOC, and this re-seeds them;
181
- - Every gate **ask** appends one line to `notebook/gates.jsonl` in the install (rule and
182
- timestamp, never the command); `geneseed status` counts them by rule and says when an
183
- `excludes.json` entry has the gates standing down for the current directory. A defer
184
- writes nothing. The OpenCode guard plugin writes the same file on every **block**, so
185
- the count spans every host.
186
- - **Stop** — runs `harness learn` to capture durable memory. Opt in by setting
187
- `GENESEED_LLM` (e.g. `claude -p`); unset, it's a harmless no-op. Geneseed never
188
- embeds an API key.
189
- - **PreCompact** — runs `harness learn` once more, right before auto-compaction
190
- summarises the transcript tail that `learn` distils from. Memory is captured before
191
- the summary; the SessionStart `compact` matcher re-seeds context after it.
192
-
193
- All the hooks are emitted as one stable path — the **hook shim** at
194
- `~/.geneseed/bin/geneseed-hook` (`geneseed-hook.cmd` on Windows) — instead of writing
195
- this machine's runtime and this checkout into your `settings.json`. The shim
196
- carries those two volatile paths itself, so moving or replacing the clone no longer
197
- breaks the hooks in every install at once: one `geneseed build` rewrites the shim and
198
- every install is live again. It is refreshed on every emit, and `geneseed doctor`
199
- reports it if it was ever stale. `GENESEED_HOME` relocates it.
200
-
201
- Detail: [adapters/claude-code/](adapters/claude-code/README.md).
202
-
203
- ### Sovereign repos — excluding folders from the global harness
204
-
205
- Some repos are complete agent harnesses of their own (an Obsidian vault with its
206
- own laws, hooks and memory conventions). Inside such a repo the global Geneseed
207
- layer would stack on top of the local one — conflicting doctrine and wasted
208
- tokens. Exclude the folder instead:
209
-
210
- harness exclude add ~/Documents/git/Terra
211
- harness exclude list
212
- harness exclude remove ~/Documents/git/Terra
213
-
214
- Inside an excluded folder the global install is fully dormant: the context,
215
- learn and git-gate hooks exit silently (they check `<config dir>/excludes.json`
216
- on every call — edits take effect immediately, no re-emit), and the global
217
- preamble is suppressed natively (Claude: `claudeMdExcludes` written to the
218
- repo's own `.claude/settings.local.json`, and OpenClaude's in `.openclaude/settings.local.json`;
219
- Bob: the workspace rules shadow stub;
220
- OpenCode: the plugins stand down). Everything is reversed by `exclude remove`.
221
-
222
- Limitations: GitHub Copilot has no per-repo suppression mechanism, so the global
223
- `copilot-instructions.md` still loads there; and globally installed skills/
224
- subagents remain listed by the host (no native per-repo disable exists). A
225
- global install emitted later starts with an empty list — re-run
226
- `harness exclude add` (`exclude list` flags installs that diverge).
227
-
228
- ### Path C′ — GitHub Copilot
229
-
230
- ```
231
- geneseed-build --emit copilot-global # personal: render into ~/.copilot
232
- geneseed-build --emit copilot --out . --root . # per-repo: AGENTS.md + .github/, committed
233
- ```
234
-
235
- Copilot is Claude-shaped where it counts: skills are the same `SKILL.md` folders
236
- (Copilot's Agent Skills — `.github/skills/` in a repo, `~/.copilot/skills/`
237
- personally), agents render in Copilot's own custom-agent dialect
238
- (`agents/<name>.agent.md`, a `tools:` allowlist instead of Claude's denylist), and
239
- the preamble rides a file Copilot auto-loads: the repo-root `AGENTS.md` (CLI, coding
240
- agent, and VS Code agent mode) or the personal `~/.copilot/copilot-instructions.md`
241
- (CLI). Two differences from the Claude paths:
242
-
243
- - **Hooks at global scope only.** The global emit adds entries to four events in
244
- `~/.copilot/settings.json`: `sessionStart` (eager project-context injection),
245
- `preToolUse` (both gates behind one command, since entries carry no matcher —
246
- every rule **asks**, as on Claude Code), and `agentStop` + `preCompact` (`learn`,
247
- from the payload's `transcriptPath`). The per-repo emit wires nothing: a
248
- machine-absolute command in a shared `.github/` would fail on every teammate's
249
- machine.
250
- - **The per-repo layer lives in the shared `.github/`** (Copilot's repo config
251
- surface). Safe by construction: the ownership manifest + claim-on-create never
252
- touch files Geneseed didn't write — your workflows and same-named agents/skills
253
- survive every emit and uninstall.
254
-
255
- MCP servers go in `~/.copilot/mcp-config.json` (the Settings/MCP screens know the
256
- shape). `$COPILOT_CONFIG_DIR` relocates the personal dir, mirroring
257
- `$BOB_CONFIG_DIR`. Note both carriers stack if you install globally *and* per-repo —
258
- the global emit warns when that's about to happen.
259
-
260
- ### Path C″ — OpenClaude
261
-
262
- ```
263
- geneseed-build --emit openclaude-global # render into ~/.openclaude
264
- geneseed-build --emit openclaude --out . --root . # per-repo: .openclaude/, committed
265
- ```
266
-
267
- [OpenClaude](https://openclaude.gitlawb.com/) grew out of the Claude Code codebase, so this
268
- is Path C with another config dir: the same agents, skills, hook groups and `ask` verdicts.
269
- It never reads `~/.claude` or a project `.claude/`, so a Claude Code install does not reach
270
- it. Both installs can live side by side. Two differences:
271
-
272
- - **The per-repo preamble is `.openclaude/CLAUDE.md`**, not a root file. OpenClaude skips a
273
- root `CLAUDE.md` whenever the repo has an `AGENTS.md`, and reads `.openclaude/CLAUDE.md`
274
- always. Hooks go in `.openclaude/settings.local.json` (gitignored) with a
275
- `claudeMdExcludes` for the global preamble, as on Claude Code.
276
- - **`$OPENCLAUDE_CONFIG_DIR` relocates the global dir.** It is OpenClaude's own variable.
277
- MCP servers go in `~/.openclaude.json`, or in `.openclaude.json` inside that dir when it is
278
- set. Per repo they go in `.mcp.json`.
279
-
280
- Details in [adapters/openclaude/](adapters/openclaude/README.md).
281
-
282
- ### Path D — Any `AGENT.md` tool
283
-
284
- ```
285
- geneseed-build # renders the plain bundle to ./Harness
286
- ```
287
-
288
- Point your tool's instructions/rules setting at `Harness/AGENT.md`. If the tool only
289
- auto-loads a specific name, rename or symlink (`AGENT.md` → `AGENTS.md` / `CLAUDE.md`).
290
- The rules work on agent self-discipline alone; the plugins (context, memory) are an
291
- OpenCode convenience.
292
-
293
- Three tools on this path read more than the instructions file, by their own docs:
294
-
295
- - **Codex CLI** auto-loads a repo-root `AGENTS.md` and `~/.codex/AGENTS.md`, and
296
- discovers skills in `~/.codex/skills` or `.agents/skills`.
297
- - **Cursor** auto-loads `AGENTS.md` (root and nested) and skills from `.cursor/skills`,
298
- `.agents/skills` — and, for compatibility, `.claude/skills`, so a Claude project
299
- install already gives Cursor the skill catalogue.
300
- - **Gemini CLI** reads `GEMINI.md` by default; set `context.fileName` in its
301
- `settings.json` to include `AGENTS.md`. Skills load from `.gemini/skills` or
302
- `.agents/skills`.
303
-
304
- Copy or symlink the bundle's `skills/` to `.agents/skills/` and all three see it. None
305
- of these is a wired host yet — what each would take is costed in
306
- [`docs/candidate-hosts.md`](docs/candidate-hosts.md).
307
-
308
- ### Path E — No runtime on the target at all
309
-
310
- A maintainer runs it once, on a machine that can run Node:
311
-
312
- ```
313
- npx geneseed prompt --theme neutral > install-geneseed.md
314
- ```
315
-
316
- That emits a self-contained prompt that recreates the entire file tree verbatim.
317
- Paste it into any capable agent on the target machine — nothing to install, no build step.
318
- Any theme works the same way — substitute its name after `--theme`. The prompt is
319
- always rendered fresh from `src/`, so it can never drift from the current harness.
320
-
321
- ---
322
-
323
- ## 🎛 Configure
324
-
325
- ### Theme
326
-
327
- Choose any of the 14 themes in `themes/` — `neutral` (plain), `imperial` (Warhammer 40k),
328
- `military`, `pirate`, `wizard`, `cyberpunk`, `gamer`, `sports` (play-by-play),
329
- `biker`, `commentator`, `joker`, `marvin`, `mean`, or `verstappen` — with
330
- `--theme NAME` (the wizard lists them all with live previews). It is remembered in a
331
- `.geneseed-theme` marker, so later upgrades keep it. Adding your own is one JSON file
332
- of voice tokens; `doctor` checks every theme defines the same keys.
333
-
334
- Adding a new voice token to `themes/_TEMPLATE.json` means all 14 theme files need it
335
- too, or the parity check fails. `geneseed-build --sync-themes` does the mechanical
336
- part: it copies any key the template has but a theme is missing into that theme
337
- (filled with the template's placeholder text), in template order, and prints exactly
338
- which keys were added so you can restyle them in that theme's voice. It never deletes
339
- a key a theme has that the template doesn't — those are only reported. The edit is
340
- surgical (only the inserted lines change; nothing is reformatted), and the exit code
341
- doubles as a CI drift check: `1` when it had to change files, `0` when every theme was
342
- already in sync, and `2` when `_TEMPLATE.json` itself is missing or unreadable — the one
343
- case where a `0` would have meant "in sync" without having checked anything.
344
-
345
- ### Doctrine packs
346
-
347
- The constitution is three tiers, and only one of them is a choice. The **Ontology** (how the
348
- agent thinks — Telos, Evidence, Decisions, Conduct) and the nine **Rules** (what it never
349
- trades away) are always on and cannot be switched off. The **Doctrines** are practices rather
350
- than principles, and they ship as five packs:
351
-
352
- | Pack | What it governs |
353
- | --- | --- |
354
- | **craft** | how code is written — reuse first, house conventions, docs in the same change, the smallest diff |
355
- | **rigor** | how work is proven — idempotence, honest tests, cover-and-verify, gates that can actually fail |
356
- | **ops** | how the machine is driven — tool discovery, commands that return, complete teardowns, restart is not reload |
357
- | **process** | how a session runs — planning, context economy, docs first, bounded loops, and the consent gate on every commit and push |
358
- | **comms** | how answers are presented — stable reference codes on tracked items, a diagram or a table only where it earns its place |
359
-
360
- They are picked **at build time**, once, on the generator — there is no runtime toggle — and
361
- the default is all five:
362
-
363
- geneseed-build --doctrines craft,rigor # two packs
364
- geneseed-build --doctrines none # ontology and the nine Rules only
365
- geneseed-build # all five (the default)
366
-
367
- `harness.config.json`'s `doctrines` array sets this checkout's own default, and `doctor`
368
- refuses one that names a pack the checkout does not ship. Order is fixed by the harness
369
- (craft → rigor → ops → process → comms) regardless of the order you type.
370
-
371
- ### One rule at a time
372
-
373
- A pack is coarse: `--doctrines` can only keep all of **process** or none of it.
374
- `--exclude-rules` is the finer axis, and it takes rule addresses:
375
-
376
- geneseed-build --exclude-rules "process 7" # keep the pack, drop one rule
377
- geneseed-build --exclude-rules "process 5,craft 2" # several
378
- geneseed-build --exclude-rules none # exclude nothing (the default)
379
-
380
- Both spellings of an address work — `process 7` as the constitution writes it, or `process.7`
381
- as the console addresses it. The two axes compose: a pack whose every rule is excluded drops
382
- out of `Active packs:` entirely, so you never get a pack header with nothing under it.
383
-
384
- An install records what it excluded in a second marker line, `Excluded rules: process 7`,
385
- written **only when something is excluded** — so a build with the default keeps every byte it
386
- had before this axis existed. `upgrade`, `rebuild-all` and the web console all read that line
387
- back and preserve it, exactly as they preserve the pack list.
388
-
389
- ⚠ **`process 5` is special**: excluding it also unwires the commit/push consent hook, because
390
- the tool boundary is keyed on that rule. That is by design — the prompt and the boundary must
391
- never disagree — and both the console and the wizard say so before applying it.
392
-
393
- The web console has the switches: **Constitution → Doctrines**, one per rule, staged locally
394
- with a single **Apply** that rebuilds the install once.
395
-
396
- The setup wizard asks too — one *all* / *choose* gate, then a yes/no per pack with its
397
- one-line description — and it **pre-selects what the install already carries**, read off the
398
- `Active packs:` marker line in the deployed `AGENT.md`. So re-running the wizard and holding
399
- Enter cannot silently widen a set you deliberately narrowed.
400
-
401
- **The whole catalogue always ships.** Every pack file lands under `doctrines/` beside
402
- `AGENT.md` at both footprints whether or not it was built in, so a rule that cites a pack you
403
- left out is still readable on disk — only the rendered `AGENT.md` is narrower. `doctor` reports
404
- such citations as a `[note]`, printed and not counted, because a narrowed build is a
405
- configuration you chose rather than a defect.
406
-
407
- ⚠ **Turning `process` off also removes the commit/push consent gate.** Doctrine `process 5`
408
- (*Consent Before Push*) is enforced twice: as prose in `AGENT.md`, and at the tool boundary —
409
- the `PreToolUse` gate hook on Claude Code and Bob, and the `git commit*` / `git push*`
410
- permission entries on OpenCode. A build without the `process` pack wires neither, and
411
- rebuilding an install that had them takes the Claude hook back out of `settings.json`. That is
412
- deliberate and it is the rule the tiering rests on: **prompt and boundary must never
413
- disagree.** A gate that stops every command to ask consent for a rule the install did not adopt
414
- is a gate the agent cannot explain and you did not ask for. Two details worth knowing:
415
-
416
- - **What stays in every build regardless:** `rm -rf *`, `git push --force*` and `git push -f*`.
417
- Those are Rule IV's territory — an always-on invariant — not the process pack's.
418
- - **On OpenCode, an existing `opencode.json` is not stripped.** That file is co-owned, nothing
419
- on disk records who wrote a given permission entry, and Geneseed will not delete a line you
420
- might have typed yourself. A pack-off rebuild leaves an already-written `git commit*` in
421
- place and *reports* it instead. A fresh install has no git gate at all.
422
-
423
- `process` is the only pack whose removal changes what the machine does rather than only what
424
- the agent reads — which is why the wizard's blurb for it says so.
425
-
426
- ### Footprint (lean vs full)
427
-
428
- **Footprint** sets how much of the constitution `AGENT.md` carries *inline* on every turn — a
429
- token-cost dial, not a change to which Rules apply. Both states keep all Rules in force:
430
-
431
- - **lean** (default) — Sections 1–2 carry the heading and the authored short form of each Rule
432
- and each active doctrine rule, then a pointer to the full text. Lighter every turn; the complete
433
- `laws/universal.md`, `ontology/` and `doctrines/` still ship beside `AGENT.md` and the agent
434
- reads them on demand (and is told to before acting on secrets, deletion, git history, scope,
435
- or untrusted content).
436
- - **full** — Sections 1–2 inline every Rule's and every active doctrine rule's complete text
437
- *and* rationale. Maximum guidance density; the largest always-loaded block in the harness.
438
-
439
- **Nothing at lean is truncated — it is written.** Every tier carries a hand-authored short form
440
- beside its full text: the Ontology (whose four flowing sections would have read as four orphan
441
- sentences if cut), each Rule, and each doctrine rule. What lean ships is decided by an author
442
- rather than by where a sentence happens to end — so a short form is judged on whether an agent
443
- can act on it, which is something a reviewer can see.
444
-
445
- **Why:** context is scarce and metered. Lean reclaims that budget — and the tokens you
446
- pay for it — for the task, moving the *rationale* one read away while keeping the rules
447
- themselves present. **Pros & cons:** full = always-present reasoning (better for smaller
448
- models, zero indirection) at the highest token cost; lean = cheaper, leaner context every
449
- turn at the cost of one extra fetch when a rule's nuance matters. Prefer **lean** for long
450
- sessions, large repos, or cost-sensitive runs; keep **full** when cost is a non-issue or
451
- you run a smaller model.
452
-
453
- **Same harness, either way.** Footprint changes neither what the harness *is* nor what it
454
- can *do*: lean and full emit identical files (same agents, skills, plugins, commands, memory,
455
- notebook, hooks) and every Rule is present and binding. The only structural difference is
456
- that a lean install on a global / Claude / Bob / Copilot / OpenClaude target also ships the standalone
457
- `laws/universal.md` and `ontology/` (project bundles already carry them, and `doctrines/`
458
- ships at both footprints on every target); the only behavioural difference is that the
459
- reasoning loads on demand instead of every turn. Lean is the default; full, with the rationale
460
- always in front of the model, applies a rule's nuance more reliably on subtle edge cases or
461
- with a weaker model, and is one flag away.
462
-
463
- Set it with `--footprint lean|full` (alongside any `--emit`), the **Footprint** toggle in
464
- the web Settings, the per-harness dropdown in the Harnesses tab, or the setup wizard. It is
465
- remembered in a `.geneseed-footprint` marker and preserved across every rebuild, on every
466
- host (OpenCode, Claude Code, Bob, Copilot, OpenClaude).
467
-
468
- ### Dry-run a build (`validate`)
469
-
470
- ```
471
- geneseed validate --theme imperial --emit opencode --out /path/to/repo/Harness
472
- ```
473
-
474
- (It is a verb on the CLI rather than a flag on the generator because it runs `doctor`, and
475
- the generator is deliberately unable to start a process — `geneseed-build` refuses
476
- `--validate-only` outright.)
477
-
478
- Renders and emits the requested `--theme`/`--emit`/`--out`/`--root`/`--footprint`
479
- combination into a throwaway sandbox — nothing under the real `--out`/`--root` is
480
- written, no marker files, no settings merge, no install-registry record — then runs
481
- every doctor-grade check against it (unresolved tokens, dead/non-hermetic links, theme
482
- parity, authoring gates, AGENT.md table parity). Prints a per-layer file count of what
483
- would have been written (`-v`/`--verbose` for the full path list) and exits non-zero on
484
- any problem, `0` when clean. Useful in CI, or before pointing a real deploy at a repo you
485
- don't want to touch yet.
486
-
487
- ### Project context (usually nothing)
488
-
489
- On OpenCode the context plugin auto-discovers a repo's docs every session:
490
-
491
- - **Eager** (injected in full, budget-capped): root `AGENTS.md`/`AGENT.md`/`CLAUDE.md`/
492
- `.cursorrules`, `README.md`, `CONTRIBUTING.md`.
493
- - **Lazy** (listed, read on demand): `docs/`, `doc/`, `documentation/`, `architecture/`,
494
- `adr/`, `ADR/`, monorepo `packages/*/README.md` and `apps/*/README.md`, other root
495
- `*.md`. `node_modules`, `.git`, `dist`, `build`, `vendor`, `.next`, `target`,
496
- `.venv`, `__pycache__`, `.opencode`, and `.harness` are never scanned.
497
-
498
- Override only when the convention doesn't fit — drop a `.harness/context.json` (or
499
- `./context.json`, or point `$GENESEED_CONTEXT`):
500
-
501
- ```json
502
- {
503
- "extend": true,
504
- "context": [
505
- { "path": "docs/house-rules.md", "load": "eager", "description": "Branch policy, DoD." },
506
- { "path": "docs/**/*.md", "load": "lazy" },
507
- { "path": "internal/secrets.md", "load": "exclude" }
508
- ]
509
- }
510
- ```
511
-
512
- `path` is absolute, repo-relative, or a glob; `load` is `eager` | `lazy` | `exclude`;
513
- `"extend": true` layers the manifest on top of discovery. Schema:
514
- [GLOBAL-HARNESS-SPEC.md §3](adapters/opencode/GLOBAL-HARNESS-SPEC.md).
515
-
516
- #### 📌 Worked example — a monorepo's `context.json`
517
-
518
- The harness stays lean because project knowledge does not go into it — it goes
519
- into this per-repo manifest, which the context plugin auto-loads at session
520
- start. A monorepo with docs scattered across packages might write:
521
-
522
- ```json
523
- {
524
- "extend": true,
525
- "context": [
526
- { "path": "docs/architecture.md", "load": "eager", "description": "system map" },
527
- { "path": "api/README.md", "load": "eager" },
528
- { "path": "web/README.md", "load": "eager" }
529
- ]
530
- }
531
- ```
532
-
533
- `"extend": true` keeps auto-discovery running (so `README.md`, `AGENT.md`, and
534
- the rest of the convention still apply) and layers these three eager entries on
535
- top. Keep the eager list to the few files a new teammate would read first —
536
- each `eager` entry is injected in full into every session in this repo, so it
537
- has a permanent token cost; prefer three sharp docs over ten broad ones, and
538
- reach for `"load": "lazy"` for anything a session should only read on demand.
539
-
540
- **Self-orientation extras.** The same injected block also carries two best-effort
541
- lines so the agent starts oriented: the repo's **runnable commands** (targets from
542
- `Makefile`, `package.json` scripts — with the right runner per lockfile — `justfile`,
543
- and `Taskfile`), and the session's **current model** (read from the transcript, or
544
- `GENESEED_MODEL=provider/model` as a fallback). Both degrade silently when absent —
545
- no commands file, no known model → the line is simply omitted.
546
-
547
- **Delivery — invisible by default.** The plugin delivers the context by prepending
548
- it to each outgoing request via OpenCode's `experimental.chat.messages.transform`
549
- hook: nothing shows in the conversation, and the context survives compaction
550
- inherently because it is re-sent per request. The hook is experimental — on an
551
- OpenCode build that lacks it, the plugin notices the first time a request completes
552
- without it and **falls back automatically** to the classic visible delivery (the
553
- `PROJECT CONTEXT` block posted as a session message), so no build is ever left
554
- without context; `GENESEED_DEBUG=1` logs the fallback when it engages. Prefer to
555
- *see* what the agent received? Set `GENESEED_CONTEXT_VISIBLE=1` (persist with
556
- `export` in your rc, or `setx` on Windows) to force the visible block up front —
557
- legacy `GENESEED_CONTEXT_TRANSFORM=0`/`off` does the same, while `=1`, the old
558
- opt-in, now simply matches the default. To drop injection entirely, set
559
- `GENESEED_CONTEXT_INJECT=off` and rely on the AGENT.md law.
560
-
561
- ### Wiki — your own knowledge base (optional)
562
-
563
- If you keep a personal knowledge base on this machine — an Obsidian vault, or any
564
- folder of interlinked markdown — declare it once in **`wiki.jsonc`** and the agent
565
- becomes a citizen of it: entry notes load each session (eager) or on demand (lazy),
566
- and it reads *and writes* notes under your vault's own conventions (AGENT.md §8,
567
- the `wiki` skill). Unlike `context.json` this is **per machine, not per repo**.
568
-
569
- The build seeds `wiki.jsonc` beside `AGENT.md` (for a global install:
570
- `~/.config/opencode/wiki.jsonc`) and never overwrites it. The file is **JSONC** —
571
- comments and trailing commas are fine — and the seeded stub carries this very
572
- example commented out, ready to copy and edit in place. Resolution:
573
- `$GENESEED_WIKI` → `$GENESEED_HARNESS/wiki.jsonc` → beside the installed `AGENT.md`
574
- (a `wiki.json` from an earlier install is still honoured at each location).
575
- Fill it in:
576
-
577
- ```json
578
- {
579
- "wikis": [{
580
- "name": "Brain",
581
- "path": "/home/me/Documents/Brain",
582
- "description": "my machine-wide knowledge base",
583
- "entries": [
584
- { "path": "ARCHITECTURE.md", "load": "eager", "description": "the root map" },
585
- { "path": ".", "load": "lazy" }
586
- ],
587
- "conventions": "STYLE.md",
588
- "inbox": "Inbox/",
589
- "protected": ["Journal/"]
590
- }]
591
- }
592
- ```
593
-
594
- `path` is the vault root (absolute; on Windows use forward slashes —
595
- `C:/Users/me/Brain`); entry paths are relative to it, with the same `eager`/`lazy`
596
- semantics as `context.json`. An entry may name a single note **or a folder**: a
597
- folder applies its mode to every note beneath it (`"."` = the whole vault,
598
- dot-folders like `.obsidian` skipped), a file entry overrides its folder's mode
599
- whatever the order, and `"load": "exclude"` prunes a note or folder from the
600
- listing. The example above is the canonical shape — root index eager, everything
601
- else on demand. A big vault's lazy listing truncates at 200 lines with a visible
602
- count (`GENESEED_WIKI_LAZY_LIMIT` adjusts it). `conventions` names the note the agent must read before
603
- its first write; `inbox` is where it drops notes it cannot confidently file;
604
- `protected` folders are write-blocked by the guard plugin at the tool boundary
605
- (`GENESEED_GUARD` modes apply). Several wikis may be declared; an empty `wikis`
606
- list keeps the feature off. The file may hold private paths — it is host-specific,
607
- covered by the bundle `.gitignore`, and never committed.
608
-
609
- On tools without the plugins (plain `AGENT.md`, Claude Code), the same contract
610
- holds through prose: AGENT.md §8 instructs the agent to read `wiki.jsonc` at session
611
- start and honour it.
612
-
613
- ### Memory
614
-
615
- Durable facts live as one-file-per-fact under the memory store, indexed by `MEMORY.md`
616
- (git-ignored — personal to the machine). The learn plugin writes to the first that
617
- resolves: `$GENESEED_MEMORY` → `$GENESEED_HARNESS/memory` → `./memory` or
618
- `./Harness/memory`. For a global install, set `GENESEED_HARNESS` once (Path A).
619
- Convention: [src/memory/README.md](src/memory/README.md).
620
-
621
- ### Reading non-markdown docs
622
-
623
- The `ingest` skill teaches the agent to convert a PDF/Word/PPTX/Excel/HTML file or a
624
- URL to markdown before reading it — discovery and the read-the-docs law only see
625
- markdown. Install one converter and the skill uses it:
626
-
627
- - **MarkItDown** (Microsoft) — broadest (`pip install markitdown`), or its MCP server
628
- (see [MarkItDown via MCP](#markitdown-via-mcp) below — preferred on an
629
- MCP-capable host: zero per-call install, one low-cost tool);
630
- - **Pandoc** — excellent for Office/HTML (single binary);
631
- - **Docling** (IBM) — best for complex tables / scanned PDFs.
632
-
633
- The skill never installs a converter silently — if none is present it reports which to add.
634
-
635
- ### MCP servers
636
-
637
- Beyond document conversion, Geneseed ships ready-to-wire MCP server presets —
638
- **MarkItDown** (below), **GitLab** (two slots, `gitlab` and `gitlab-2`, so you can
639
- point at two instances), and **Filesystem** — four preset entries in total. Each
640
- is a *local* server the agent launches on demand: registering one only points the agent
641
- at a command — *you* install the tool (or let `npx`/`pipx` fetch it) and supply any
642
- credentials. On OpenCode they live under the `mcp` key of an `opencode.json`, each entry
643
- shaped:
644
-
645
- ```json
646
- "<name>": { "type": "local", "command": ["…"], "environment": {}, "enabled": true }
647
- ```
648
-
649
- > **Never commit a real token.** The presets and the reference
650
- > [`adapters/opencode/opencode.json`](adapters/opencode/opencode.json) carry **empty**
651
- > `GITLAB_PERSONAL_ACCESS_TOKEN` placeholders (and a sample filesystem path) — fill them
652
- > in your own config, never in a tracked file (universal Law I — secrets).
653
-
654
- **Don't want to hand-edit JSON?** `./geneseed` → **Settings** → **MCP servers** toggles
655
- any preset into your project or global `opencode.json` — and enables, disables, or
656
- removes them — for you. The reference config ships MarkItDown enabled and the GitLab /
657
- Filesystem entries disabled, so a merge never activates a credential-less server: fill
658
- the blanks, then flip the one(s) you want on.
659
-
660
- #### MarkItDown via MCP
661
-
662
- Wire Microsoft's MarkItDown in as a **local MCP server** so the agent can convert
663
- PDF / Word / Excel / PowerPoint / HTML → Markdown on demand, exposing a single tool
664
- `convert_to_markdown(uri)` (`uri` accepts `file:`, `http:`, `https:`, or `data:`).
665
- The server runs locally and, once cached, does not hit PyPI again.
666
-
667
- > **A config entry alone does nothing.** A `local` MCP server is just a command your
668
- > agent launches — if that command isn't on PATH in the shell the agent starts from, the
669
- > server still *appears* in the list but never connects ("shown but not working"). The
670
- > `uvx` form below is the zero-install way to guarantee it resolves.
671
-
672
- **1. Make the command resolve.** Pick one:
673
-
674
- - **`uvx` (recommended, zero-install).** If you have [uv](https://docs.astral.sh/uv/)
675
- (`uvx` on PATH), nothing to install — `uvx markitdown-mcp` fetches and caches the
676
- server on first call. This is the command the reference config and the harness toggle
677
- now use.
678
- - **`pipx` (pinned install).** No uv? `pipx install markitdown-mcp` puts a
679
- `markitdown-mcp` binary on PATH; then use `"command": ["markitdown-mcp"]` instead.
680
- Verify with `markitdown-mcp --help`.
681
-
682
- ```
683
- # uv route (recommended) — confirm it resolves:
684
- uvx markitdown-mcp --help
685
- # pipx route — only if you don't have uv:
686
- brew install pipx && pipx ensurepath # macOS; Debian/Ubuntu: sudo apt install pipx && pipx ensurepath
687
- pipx install markitdown-mcp && markitdown-mcp --help
688
- ```
689
-
690
- Optional OCR / image / audio extras (needed for scanned/image-only PDFs, which
691
- otherwise return empty): `uvx --with "markitdown[all]" markitdown-mcp` for the uv route,
692
- or `pipx inject markitdown-mcp "markitdown[all]"` for the pipx route (same venv).
693
-
694
- **2. Corporate TLS (only on a network with SSL inspection).** uv ships its own root CAs
695
- and ignores the OS trust store, so a proxy's internal CA fails with `invalid peer
696
- certificate: UnknownIssuer`. Point uv at the OS trust store — don't disable verification:
697
-
698
- ```
699
- echo 'export UV_SYSTEM_CERTS=true' >> ~/.zshrc && source ~/.zshrc # older uv: UV_NATIVE_TLS=true
700
- # fallback: export SSL_CERT_FILE=/path/to/corporate-root-ca.pem
701
- ```
702
-
703
- **3. Register it in your host's MCP config** — add the server entry to the file your
704
- agent reads, alongside any servers you already have:
705
-
706
- <!--harness:opencode-->
707
- On OpenCode that's `opencode.json` (global `~/.config/opencode/opencode.json`, the
708
- `.jsonc` variant if you keep one — the file OpenCode reads — or per-repo), under the
709
- `mcp` key. Geneseed's
710
- [`adapters/opencode/opencode.json`](adapters/opencode/opencode.json) already carries
711
- this block:
712
-
713
- ```json
714
- {
715
- "$schema": "https://opencode.ai/config.json",
716
- "mcp": {
717
- "markitdown": { "type": "local", "command": ["uvx", "markitdown-mcp"], "enabled": true }
718
- }
719
- }
720
- ```
721
-
722
- On the pipx route, swap the command to `["markitdown-mcp"]`. Prefer not to hand-edit
723
- JSON? `./geneseed` → **Settings** → **MCP servers** toggles this exact block in for you.
724
- <!--/harness-->
725
- <!--harness:claude-->
726
- On Claude Code that's `.mcp.json` under `mcpServers`:
727
-
728
- ```json
729
- { "mcpServers": { "markitdown": { "command": "uvx", "args": ["markitdown-mcp"] } } }
730
- ```
731
-
732
- See the **Claude Code** section for the GitLab / Filesystem shapes.
733
- <!--/harness-->
734
-
735
- **4. Verify.** Restart your agent; its MCP list should show `markitdown` **connected**
736
- (not just listed). The `ingest` skill auto-prefers an MCP
737
- converter when one is exposed,
738
- so a prompt like *"convert file:///path/to/spec.pdf to markdown"* now just works. Still
739
- not connecting? See [MCP server won't connect](#mcp-server-wont-connect) below.
740
-
741
- #### GitLab (one entry per instance)
742
-
743
- Wire GitLab in via [`@zereight/mcp-gitlab`](https://github.com/zereight/gitlab-mcp) —
744
- repo, merge-request, issue, and CI tools over the GitLab API, run through `npx` (nothing
745
- installed globally; the first run fetches it). It is self-hosted ready, so the same
746
- command serves gitlab.com and any private instance.
747
-
748
- **1. Mint a Personal Access Token** on *each* instance — User Settings → Access Tokens,
749
- scopes `api` and `read_repository`. Treat it like a password.
750
-
751
- **2. Register one entry per instance** — same command, different `GITLAB_API_URL`
752
- and token. Two instances (e.g. gitlab.com plus a self-hosted server) → two entries.
753
- The MCP screen ships a one-click row for the **first** entry only; a second instance is a
754
- hand-added copy of that block, which is all it ever was:
755
-
756
- <!--harness:opencode-->
757
- On OpenCode, under the `mcp` key of `opencode.json`:
758
-
759
- ```json
760
- {
761
- "mcp": {
762
- "gitlab": {
763
- "type": "local",
764
- "command": ["npx", "-y", "@zereight/mcp-gitlab"],
765
- "environment": {
766
- "GITLAB_PERSONAL_ACCESS_TOKEN": "glpat-…",
767
- "GITLAB_API_URL": "https://gitlab.com/api/v4"
768
- },
769
- "enabled": true
770
- },
771
- "gitlab-2": {
772
- "type": "local",
773
- "command": ["npx", "-y", "@zereight/mcp-gitlab"],
774
- "environment": {
775
- "GITLAB_PERSONAL_ACCESS_TOKEN": "glpat-…",
776
- "GITLAB_API_URL": "https://gitlab.example.com/api/v4"
777
- },
778
- "enabled": true
779
- }
780
- }
781
- }
782
- ```
783
- <!--/harness-->
784
- <!--harness:claude-->
785
- On Claude Code, under `mcpServers` in `.mcp.json` — same command, but `env` (not
786
- `environment`) and `command` + `args` split. See the **Claude Code** section for the
787
- exact block; add one `mcpServers` entry per instance.
788
- <!--/harness-->
789
-
790
- The entry key is just a label — name them `gitlab` / `gitlab-2`, or after each instance
791
- (`gitlab`, `gitlab-acme`). What separates the two is the `GITLAB_API_URL` + token pair;
792
- keep the `/api/v4` suffix on the URL.
793
-
794
- **Don't know where this file lives?** Run `geneseed web`, open **Harnesses**, and expand an
795
- active install — each MCP target prints the full path of the config file it writes, right
796
- above its server rows. That is the file the token and the URL go into. From the terminal,
797
- `geneseed mcp` prints the same paths without starting anything.
798
-
799
- #### Filesystem
800
-
801
- Give the agent scoped file access via
802
- [`@modelcontextprotocol/server-filesystem`](https://github.com/modelcontextprotocol/servers/tree/main/src/filesystem),
803
- also through `npx`. The **allowed directories are command-line arguments** — the server
804
- can touch *only* the paths you list, so grant the narrowest set that works:
805
-
806
- <!--harness:opencode-->
807
- On OpenCode, under the `mcp` key of `opencode.json`:
808
-
809
- ```json
810
- {
811
- "mcp": {
812
- "filesystem": {
813
- "type": "local",
814
- "command": [
815
- "npx", "-y", "@modelcontextprotocol/server-filesystem",
816
- "/path/to/project", "/path/to/another/allowed/dir"
817
- ],
818
- "enabled": true
819
- }
820
- }
821
- }
822
- ```
823
- <!--/harness-->
824
- <!--harness:claude-->
825
- On Claude Code, under `mcpServers` in `.mcp.json` (`command` + `args` split):
826
-
827
- ```json
828
- { "mcpServers": { "filesystem": { "command": "npx", "args": ["-y", "@modelcontextprotocol/server-filesystem", "/path/to/project"] } } }
829
- ```
830
- <!--/harness-->
831
-
832
- > **Replace the placeholder.** The reference config and the harness toggle ship the
833
- > literal arg `/path/to/allowed/dir`. Enabling the server without swapping that for a
834
- > real path leaves it running but able to touch nothing — the classic "filesystem MCP
835
- > sees nothing." Edit the path(s) before (or right after) you flip it on.
836
-
837
- > **Least privilege.** Prefer the narrowest set of dirs the task needs over `$HOME` or
838
- > `/` — the server refuses any path outside them, and a broad grant lets the agent reach
839
- > everything under it.
840
-
841
- #### Claude Code
842
-
843
- Claude Code reads the same servers from a `.mcp.json` `mcpServers` map — note the key is
844
- `env` (not `environment`) and the command and its args are split into `command` +
845
- `args`:
846
-
847
- ```json
848
- {
849
- "mcpServers": {
850
- "gitlab": {
851
- "command": "npx",
852
- "args": ["-y", "@zereight/mcp-gitlab"],
853
- "env": {
854
- "GITLAB_PERSONAL_ACCESS_TOKEN": "glpat-…",
855
- "GITLAB_API_URL": "https://gitlab.com/api/v4"
856
- }
857
- },
858
- "filesystem": {
859
- "command": "npx",
860
- "args": ["-y", "@modelcontextprotocol/server-filesystem", "/path/to/allowed/dir"]
861
- },
862
- "markitdown": { "command": "uvx", "args": ["markitdown-mcp"] }
863
- }
864
- }
865
- ```
866
-
867
- Register it with `claude mcp add` or by editing `.mcp.json` directly; the same
868
- token-safety rule applies.
869
-
870
- #### Verify
871
-
872
- Restart your agent.
873
- <!--harness:opencode-->
874
- On OpenCode, `opencode mcp` lists each server and whether it **connected**.
875
- <!--/harness-->
876
- <!--harness:claude-->
877
- On Claude Code, `/mcp` lists each server and whether it connected.
878
- <!--/harness-->
879
- Listed ≠ working — a `local` server
880
- appears in the list whether or not its command actually launches.
881
-
882
- #### MCP server won't connect
883
-
884
- A `local` MCP entry is just a command OpenCode/Claude Code runs. If it's listed but
885
- not connected, walk these in order:
886
-
887
- 1. **Does the command resolve?** Run the exact command from a fresh terminal —
888
- `uvx markitdown-mcp --help`, `npx -y @modelcontextprotocol/server-filesystem --help`.
889
- "command not found" means the binary isn't on PATH in the shell your agent launches
890
- from. Fix: use the `uvx`/`npx` zero-install form (these only need uv / Node), or
891
- install the tool and point at the absolute path. This is the #1 cause of
892
- "shown but not working" for **markitdown** (no `markitdown-mcp` on PATH, no pipx).
893
- 2. **Filesystem sees nothing?** The allowed-dir arg is still the placeholder
894
- `/path/to/allowed/dir`, or points somewhere that doesn't exist. Swap in a real path.
895
- 3. **GitLab won't connect?** Almost always a missing / over-scoped token or the wrong
896
- `GITLAB_API_URL` — keep the `/api/v4` suffix.
897
- <!--harness:opencode-->
898
- 4. **Right file?** OpenCode reads `opencode.jsonc` if present, else `opencode.json`, at
899
- the project root and `~/.config/opencode/`. Editing the wrong one is silent. Use
900
- `./geneseed` → **Settings** → **MCP servers** to write to the file OpenCode actually reads.
901
- <!--/harness-->
902
- <!--harness:claude-->
903
- 4. **Right file?** Claude Code reads `.mcp.json` (project) and the `mcpServers` block in
904
- `~/.claude.json` / settings. Editing the wrong one is silent — `claude mcp list`
905
- shows which servers actually loaded.
906
- <!--/harness-->
907
-
908
- ### Environment knobs
909
-
910
- | Variable | Used by | Effect |
911
- | --- | --- | --- |
912
- | `GENESEED_HOME` | emit / hooks | dir holding the hook shim `bin/geneseed-hook` (default: `~/.geneseed`). Change it and re-run the build, so emitted hooks point at the new location |
913
- | `GENESEED_HARNESS` | learn plugin | base whose `memory/` the plugin writes to (optional — the plugin auto-locates the in-config store; set to pin it) |
914
- | `GENESEED_MEMORY` | learn plugin / CLI | explicit memory dir (overrides the above) |
915
- | `GENESEED_CONTEXT` | context plugin / CLI | explicit `context.json` path |
916
- | `GENESEED_WIKI` | context + guard plugins | explicit `wiki.jsonc` path (default: `$GENESEED_HARNESS/wiki.jsonc`, else beside the installed `AGENT.md`) |
917
- | `GENESEED_ROOT` | `harness context` | repo root to discover docs from (default: cwd) |
918
- | `GENESEED_MODEL` | learn + context plugins | `provider/model` fallback if the session model can't be read (learn distils with it; context shows it in the self-awareness line) |
919
- | `GENESEED_LLM` | `harness learn` (Claude) | model CLI for distillation, e.g. `claude -p` |
920
- | `GENESEED_EMIT` | `geneseed upgrade` | `opencode-global` \| `opencode` \| unset (plain bundle) |
921
- | `GENESEED_OUT` / `GENESEED_ROOT` | `geneseed upgrade` | bundle / project-root locations |
922
- | `GENESEED_DEBUG` | context + notify + ponytail plugins | `1` re-enables discovery/inject logs (context), decision/delivery logs (notify), and level-switch logs (ponytail) |
923
- | `GENESEED_CONTEXT_INJECT` | context plugin | `off` disables the injected block (rely on the AGENT.md law) |
924
- | `GENESEED_EAGER_FILE_KB` / `GENESEED_EAGER_TOTAL_KB` | context plugin | per-file / total eager injection budget (default 16 / 48) |
925
- | `GENESEED_LAZY_HEADINGS` | context plugin | cap on lazy-file heading reads per session (default 64) |
926
- | `GENESEED_WIKI_LAZY_LIMIT` | context plugin | cap on lazy notes LISTED per wiki per session (default 200; beyond it the listing truncates with a count) |
927
- | `GENESEED_CONTEXT_VISIBLE` | context plugin | `1` shows the classic visible `PROJECT CONTEXT` block instead of the invisible per-request delivery (see [Project context](#project-context-usually-nothing)) |
928
- | `GENESEED_CONTEXT_TRANSFORM` | context plugin | legacy — `0`/`off` forces the visible delivery (same as `GENESEED_CONTEXT_VISIBLE=1`); `1` matches the default |
929
- | `GENESEED_LEARN_DEBOUNCE_MS` | learn plugin | quiet period before distilling (default 60000) |
930
- | `GENESEED_GUARD` | guard plugin | `warn` downgrades blocks to warnings; `off` disables the safety guard |
931
- | `GENESEED_WORKFLOWS_DIR` | workflow plugin | override the directory the `workflow` tool reads saved scripts from |
932
- | `GENESEED_NOTIFY` | notify plugin | `off` disables end-of-run desktop notifications |
933
- | `GENESEED_NOTIFY_MIN_SECONDS` | notify plugin | minimum turn length, in seconds, before notifying (default 30; `0` = every turn) |
934
- | `GENESEED_NOTIFY_TITLE` | notify plugin | override the notification title (default `Geneseed`) |
935
- | `GENESEED_PONYTAIL` | ponytail plugin | default minimal-code level for new installs: `lite` \| `full` \| `ultra` \| `off` (default `off`; switch live with `/ponytail <level>`) |
936
- | `GENESEED_PRIMARY` | `geneseed-build` | `1` also emits the primary orchestrator agent |
937
- | `GENESEED_COMMANDS` | `geneseed-build` | `1` also emits the `/slash` command layer |
938
- | `GENESEED_TUI_ASCII` / `GENESEED_TUI_PLAIN` | terminal output | force pure-ASCII / drop emoji + animation in what the CLI prints |
939
- | `GENESEED_NO_ANIM` | install animation | disable the themed install animation |
940
- | `GENESEED_LOG` | `geneseed upgrade` | override the install/upgrade log path |
941
- | `GENESEED_NET_TIMEOUT` | `upgrade` | seconds before download attempts give up (default 20, floor 5) |
942
- | `GENESEED_NO_WEB` | `home` | `1` disables the web-first default of bare `geneseed` — it prints the command list instead |
943
- | `GENESEED_STACK_GLOBAL` | context hook | `1` disables project-bypasses-global: a project install of the same host no longer makes the global install's hook stand down, so both inject |
944
- | `OPENCODE_CONFIG_DIR` / `XDG_CONFIG_HOME` | global emit | where the global install is written |
945
- | `OPENCLAUDE_CONFIG_DIR` | `openclaude-global` emit | OpenClaude's own config dir variable (default `~/.openclaude`); also moves `.openclaude.json` |
946
- | `OPENCODE_DISABLE_LSP_DOWNLOAD` | OpenCode (LSP) | `true` stops OpenCode auto-downloading built-in language servers (typescript, pyright, jdtls) — set it on air-gapped machines and pre-install each server yourself |
947
-
948
- ---
949
-
950
- ## ✅ Verify it works
951
-
952
- 1. **Sigil** — the agent's first reply opens with the readiness line (the `✅`/`🧬`
953
- sigil for neutral/imperial). If it's missing, the instructions aren't pointed at
954
- `AGENT.md`.
955
- 2. **Context (OpenCode)** — start a session; with `GENESEED_DEBUG=1` the context
956
- plugin logs what it discovered and injected.
957
- 3. **Memory (OpenCode)** — do a little work and end the session; after the debounce
958
- the learn plugin logs `wrote N memory file(s)` or a skip reason to stderr. Total
959
- silence means it didn't load — re-check the filename, `.js` extension, and that it
960
- sits in the plugins dir.
961
- 4. **Harness health** — `geneseed doctor` should print `ok` (`npx geneseed doctor` without
962
- installing). From a checkout, `node bin/geneseed-cli.mjs doctor` runs the same checks.
963
- To run the full suite the way CI does: `node --test "tests/**/*.test.mjs"`.
964
-
965
- Browsing agents, skills and laws, and running build/doctor/diff without retyping a
966
- command, is what the web console is for — bare `./geneseed` opens it.
967
-
968
- ## 🚀 Run `geneseed` from anywhere
969
-
970
- **From npm this is already done.** `npm install -g geneseed` puts `geneseed`,
971
- `geneseed-hook` and `geneseed-build` on your `PATH` through npm's own bin linking; there
972
- is nothing to link and `geneseed link` is not needed. The rest of this section is for a
973
- git checkout.
974
-
975
- By default you invoke the launcher as `./geneseed` from inside the repo. To call it
976
- like any other command — plain `geneseed` from any directory — put it on your `PATH`:
977
-
978
- ```
979
- ./geneseed link # a launcher shim in ~/.local/bin (no sudo); pass a dir to override
980
- ./geneseed link /usr/local/bin # e.g. a system-wide bin dir (may prompt for sudo)
981
- ```
982
-
983
- (Or, in the web console: **Settings** → the Maintenance card's PATH link / unlink.)
984
-
985
- `link` writes a small `#!/bin/sh` shim that runs this checkout by absolute path, and
986
- tells you whether the target dir is on your `PATH` (and, if not, the one line to add
987
- it). The shim names this checkout's CLI entry point by absolute path, so it finds the
988
- harness no matter where the shim itself lives — the same shape the Windows arm has
989
- always used. Once it's on `PATH`, drop the `./`:
990
-
991
- ```
992
- geneseed # the web console (else the command list), from any directory
993
- geneseed build # …and every subcommand
994
- ```
995
-
996
- Remove it with `./geneseed unlink` (it clears the `geneseed` shims it wrote — and any
997
- symlink an older version left — from `PATH` and the common bin dirs; a `geneseed` it
998
- did not write is left alone). Prefer a shell function? Add one to your rc instead —
999
- it does the same job:
1000
-
1001
- ```
1002
- echo 'geneseed() { "'"$PWD"'/geneseed" "$@"; }' >> ~/.zshrc # or ~/.bashrc
1003
- ```
1004
-
1005
- **Windows** — use the native launcher `geneseed.cmd`, which routes to the same Node CLI with
1006
- no bash. PowerShell runs a `.cmd` directly, so it is the PowerShell spelling too:
1007
-
1008
- ```powershell
1009
- .\geneseed.cmd setup
1010
- .\geneseed.cmd link # writes a geneseed.cmd shim into %LOCALAPPDATA%\Geneseed\bin
1011
- # and adds that dir to your user PATH (no admin / symlink needed)
1012
- ```
1013
-
1014
- Open a new terminal after `link`, then call `geneseed` from any directory. Remove it
1015
- again with `.\geneseed.cmd unlink`.
1016
-
1017
- ## 🔌 Start the web UI at login
1018
-
1019
- The web UI is the only long-running Geneseed process. `geneseed web **start**`
1020
- spawns a **detached daemon** on `127.0.0.1:4747` and returns immediately, so a login
1021
- hook that runs `geneseed web start --no-browser` once — no browser tab — leaves the
1022
- UI ready whenever you open [http://127.0.0.1:4747](http://127.0.0.1:4747). It is
1023
- **per-user and per-machine**: each laptop runs its own daemon on its own loopback, so
1024
- Windows and macOS are set up independently and never collide. The daemon is a
1025
- singleton — a second `start` just no-ops — so re-running it (or logging in twice) is
1026
- harmless.
1027
-
1028
- > **Use `web start`, not bare `web`, in every launcher below.** Without the
1029
- > `start` action the server runs in the **foreground** and writes no
1030
- > `.geneseed-web.json` record, so it becomes invisible to `web stop`, `web restart`
1031
- > and `web status` — they report "no live server" while it keeps serving, and a
1032
- > `restart` will orphan a second daemon that cannot bind the taken port. Recovering
1033
- > then means finding it by port and killing it by hand.
1034
-
1035
- > **These are files YOU create, and Geneseed never writes one.** Nothing in this project
1036
- > has ever created a Startup entry or a LaunchAgent, and nothing ever edits one — including
1037
- > `geneseed migrate`, which detects a login item still naming an old checkout, prints the
1038
- > path and the line to put there, and leaves the file alone. It is your login
1039
- > configuration; deleting the file is the only uninstall it has.
1040
-
1041
- **Windows** — drop a hidden VBS launcher in the Startup folder (runs at login, no
1042
- console flash, removed by deleting the file). Open the folder with **Win+R** →
1043
- `shell:startup`, then create `geneseed-web.vbs`:
1044
-
1045
- ```vbs
1046
- ' geneseed-web.vbs — start the Geneseed web daemon at login (hidden, no browser).
1047
- CreateObject("WScript.Shell").Run "cmd /c ""%LOCALAPPDATA%\Geneseed\bin\geneseed.cmd"" web start --no-browser", 0, False
1048
- ```
1049
-
1050
- Expand `%LOCALAPPDATA%` to its real path (e.g. `C:\Users\you\AppData\Local`) — VBS
1051
- does not expand environment variables inside a string. **Disable** by deleting the
1052
- file. Prefer a scheduled task (runs hidden, can restart on failure)? Use:
1053
-
1054
- ```powershell
1055
- schtasks /Create /TN "Geneseed Web" /SC ONLOGON /TR "\"%LOCALAPPDATA%\Geneseed\bin\geneseed.cmd\" web start --no-browser" /RL LIMITED /F
1056
- schtasks /Delete /TN "Geneseed Web" /F # to remove
1057
- ```
1058
-
1059
- **macOS** — the launcher is the `geneseed` shim that `./geneseed link` writes (default
1060
- `~/.local/bin/geneseed`). Use a **LaunchAgent** with `RunAtLoad` — and **no**
1061
- `KeepAlive`, because the launcher exits after spawning the detached daemon (the
1062
- daemon runs in its own session and survives). Write
1063
- `~/Library/LaunchAgents/dev.geneseed.web.plist`:
1064
-
1065
- ```xml
1066
- <?xml version="1.0" encoding="UTF-8"?>
1067
- <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN"
1068
- "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
1069
- <plist version="1.0">
1070
- <dict>
1071
- <key>Label</key> <string>dev.geneseed.web</string>
1072
- <key>ProgramArguments</key>
1073
- <array>
1074
- <string>/Users/you/.local/bin/geneseed</string>
1075
- <string>web</string>
1076
- <string>start</string>
1077
- <string>--no-browser</string>
1078
- </array>
1079
- <key>RunAtLoad</key> <true/>
1080
- </dict>
1081
- </plist>
1082
- ```
1083
-
1084
- Use the **absolute** path to your `geneseed` launcher (LaunchAgents don't see your
1085
- shell `PATH`). Then load it — it also runs it once now:
1086
-
1087
- ```bash
1088
- launchctl load ~/Library/LaunchAgents/dev.geneseed.web.plist # enable + start now
1089
- launchctl unload ~/Library/LaunchAgents/dev.geneseed.web.plist # disable
1090
- ```
1091
-
1092
- On either OS, `geneseed web stop` stops the running daemon without touching the
1093
- login hook, and `geneseed web status` reports whether it's up.
1094
-
1095
- ## 🤖 Headless / CI (OpenCode)
1096
-
1097
- Once the harness is installed (Path A or B), OpenCode can run **non-interactively** —
1098
- no TUI — so the harness's agents, rules, and skills apply in scripts and pipelines:
1099
-
1100
- ```
1101
- opencode run "review the staged diff and list any correctness bugs" # one-shot, prints to stdout
1102
- opencode run -m anthropic/claude-sonnet-4-5 "…" # pin a model for the run
1103
- cat issue.md | opencode run "triage this and propose a fix plan" # pipe input in
1104
- ```
1105
-
1106
- `opencode run` loads the same `opencode.json` (so `instructions` → `AGENT.md`, the
1107
- permission gates, and any per-agent overrides all take effect) and the same
1108
- `.opencode/` agents/skills/plugins. Useful for CI checks, cron jobs, or scripting a
1109
- capability agent. Notes:
1110
-
1111
- - **Permissions still gate.** The consent-before-commit/push / `rm -rf` `ask` rules
1112
- will *block* in a non-interactive run (nothing to answer the prompt). Both
1113
- `git commit` and `git push` are gated on every branch whenever the **process** pack
1114
- is active (Doctrine `process 5`; a build without it wires neither), so a CI job that
1115
- commits must opt those commands back to `"allow"` in its own `permission.bash` map,
1116
- or scope the run to read-only work — don't blanket-disable the guards.
1117
- - **`--pure`** runs OpenCode ignoring local/global config — handy to reproduce a bug
1118
- without the harness in the way, or to confirm a behaviour is the harness's doing.
1119
- - The **learn** plugin (`session.idle` → memory) and **context** plugin still load in
1120
- headless runs; set `GENESEED_GUARD=warn`/`off` or `GENESEED_DEBUG=1` per the
1121
- [adapter README](adapters/opencode/README.md) if a run needs different behaviour.
1122
-
1123
- This is a usage note, not an emitted feature — the harness writes nothing for it.
1124
-
1125
- ## Upgrade
1126
-
1127
- **Installed from npm:**
1128
-
1129
- ```
1130
- npm install -g geneseed@latest # get the new version
1131
- geneseed rebuild-all # re-render every active install in its own theme + mode
1132
- ```
1133
-
1134
- `upgrade` / `update` / `sync-self` / `bootstrap` are the *git checkout* route — they pull
1135
- the install's own origin. Run one from an npm install and it stops before touching
1136
- anything, naming the `npm install -g` line above instead.
1137
-
1138
- **Installed from a clone:**
1139
-
1140
- ```
1141
- ./geneseed upgrade # track the checkout's current branch; keep theme + emit mode
1142
- ./geneseed upgrade imperial # force a theme
1143
- ```
1144
-
1145
- It git-pulls the install's own origin (fast-forward only), validates it (a blocking
1146
- `doctor` pass, rolling back on failure), then re-renders in place — leaving host state
1147
- (memory, `context.json`, markers) untouched. Theme and emit mode are remembered between
1148
- runs. `./geneseed update` and `./geneseed sync-self` are aliases of `upgrade` (one pull
1149
- refreshes launchers and factory together), and `./geneseed bootstrap` continues into the
1150
- setup wizard. A dirty tree or a non-git checkout is reported, not force-updated.
1151
-
1152
- **Reviewing local edits** — if the deployed harness was tweaked in place (you, or the
1153
- agent's own self-improvement loops) and you want to see what diverged from source:
1154
-
1155
- ```
1156
- ./geneseed diff # summary — --full for line-level diffs
1157
- ./geneseed diff --out improvements.md # export a markdown improvements file
1158
- ```
1159
-
1160
- The `--out` file is a self-contained back-port artifact: hand it to an agent in the
1161
- Geneseed source repo and ask it to fold the changes into `src/`. You rarely need to
1162
- run it by hand — **setup, re-theme, and upgrade auto-export one** whenever the
1163
- harness they are about to overwrite carries local edits, so a rebuild never silently
1164
- destroys what the agent learned. The auto-export lands in `improvements/` **inside
1165
- the deployed harness dir** (e.g. `~/.config/opencode/improvements/`) — beside the
1166
- install it describes; it is not in the manifest, so re-emits never clobber it, diff
1167
- never reports it, and uninstall leaves it in place (the same contract as memory).
1168
- The web console's **Changes** page exports the same file.
1169
-
1170
- ## 🩺 Troubleshooting
1171
-
1172
- | Symptom | Fix |
1173
- | --- | --- |
1174
- | No readiness sigil | Instructions not pointed at `AGENT.md` — check `opencode.json` `instructions` (or your tool's rules setting). |
1175
- | `PROJECT CONTEXT` block appears twice | Two copies of the context plugin (global + a leftover `.opencode/plugins/`). Remove the project copy. |
1176
- | Full `PROJECT CONTEXT` block visible in the terminal | Either `GENESEED_CONTEXT_VISIBLE=1` (or legacy `GENESEED_CONTEXT_TRANSFORM=0/off`) is set, or your OpenCode build lacks the experimental transform hook and the plugin fell back to visible delivery — run with `GENESEED_DEBUG=1` to see which (see [Project context](#project-context-usually-nothing)). |
1177
- | Learn plugin silent / no memory written | Set `GENESEED_HARNESS` (or `GENESEED_MEMORY`); confirm the `.js` files are in the plugins dir. |
1178
- | `could not determine a model` | Set `GENESEED_MODEL=provider/model`. |
1179
- | PDFs / Office docs ignored | Use the `ingest` skill and install a converter (MarkItDown / Pandoc / Docling). |
1180
- | A "read-only" agent won't run a command | By design — read-only agents are denied `bash`. Agents that must run read-only commands (reviewer, security) allow it via a spec marker. |
1181
- | Skills not tracked in git | A parent `.gitignore` blanket-ignores the bundle dir — remove the bare `Harness/` line; the bundle's own `.gitignore` scopes correctly. |
1182
-
1183
- More OpenCode-specific notes (why a file loads twice, plugin loading): [HOW-OPENCODE-LOADS.md](adapters/opencode/HOW-OPENCODE-LOADS.md).