geneseed 3.9.0 → 3.10.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 (76) hide show
  1. package/CHANGELOG.md +32 -1
  2. package/QUICKSTART.md +1 -1
  3. package/README.md +27 -28
  4. package/SETUP.md +7 -42
  5. package/SHIPPED.md +2 -2
  6. package/adapters/bob/README.md +17 -1
  7. package/adapters/openclaude/README.md +1 -1
  8. package/adapters/opencode/plugins/geneseed-context.js +78 -8
  9. package/bin/geneseed-hook.mjs +1 -1
  10. package/docs/candidate-hosts.md +12 -5
  11. package/docs/token-footprint.md +26 -21
  12. package/docs/web/claude-hooks.md +1 -1
  13. package/docs/web/collaboration.md +1 -1
  14. package/docs/web/exclusions.md +0 -1
  15. package/docs/web/footprint.md +1 -1
  16. package/docs/web/harnesses.md +13 -13
  17. package/docs/web/install-quick.md +1 -1
  18. package/docs/web-ui.md +1 -1
  19. package/harness.config.json +1 -1
  20. package/js/README.md +4 -4
  21. package/js/build/driver.mjs +26 -95
  22. package/js/build/emit-claude.mjs +76 -81
  23. package/js/build/generate.mjs +0 -1
  24. package/js/build/render.mjs +4 -0
  25. package/js/build/stubs.mjs +18 -2
  26. package/js/cli-table.json +5 -5
  27. package/js/hosts/hooks.mjs +86 -54
  28. package/js/hosts/hosts.mjs +5 -21
  29. package/js/hosts/installs.mjs +4 -6
  30. package/js/hosts/mcp.mjs +3 -13
  31. package/js/hosts/native.mjs +27 -50
  32. package/js/hosts/opencode.mjs +1 -1
  33. package/js/hosts/settings.mjs +4 -78
  34. package/js/inspect/checks-authoring.mjs +4 -1
  35. package/js/inspect/checks-repo.mjs +45 -1
  36. package/js/inspect/diff.mjs +11 -3
  37. package/js/inspect/doctor.mjs +3 -3
  38. package/js/inspect/excludes.mjs +0 -4
  39. package/js/inspect/status.mjs +4 -4
  40. package/js/maintain/migrate.mjs +5 -5
  41. package/js/maintain/setup.mjs +3 -5
  42. package/js/maintain/uninstall.mjs +8 -42
  43. package/js/web/actions.mjs +4 -5
  44. package/js/web/api.mjs +4 -4
  45. package/package.json +1 -2
  46. package/src/AGENT.md.tmpl +69 -52
  47. package/src/laws/universal.md +3 -0
  48. package/src/ontology/universal.md +1 -1
  49. package/src/skills/daydream/SKILL.md +10 -3
  50. package/src/skills/daydream/VENDOR.md +10 -2
  51. package/src/skills/daydream/instructions.md +2 -2
  52. package/src/skills/explain-changes/SKILL.md +1 -1
  53. package/src/skills/explain-changes/VENDOR.md +1 -1
  54. package/src/skills/geneseed.md +1 -1
  55. package/src/skills/react-view-transitions/SKILL.md +1 -1
  56. package/src/skills/react-view-transitions/VENDOR.md +7 -2
  57. package/src/skills/token-report/SKILL.md +2 -3
  58. package/src/skills/token-report/VENDOR.md +2 -3
  59. package/src/skills/token-report/scripts/token_report.mjs +7 -121
  60. package/src/skills/workflow.md +1 -1
  61. package/web/dist/assets/{Activity-DAzV-qQj.js → Activity-BjVp522q.js} +1 -1
  62. package/web/dist/assets/{ActivityDetail-CwEwMtKl.js → ActivityDetail-8ep1bspW.js} +1 -1
  63. package/web/dist/assets/{Dashboard-C2ELBW-X.js → Dashboard-OkC_PCH6.js} +2 -2
  64. package/web/dist/assets/{Docs-iZrvQP8J.js → Docs-CKPWz00o.js} +1 -1
  65. package/web/dist/assets/{GreenhouseView-Bq1QmaGO.js → GreenhouseView-D0cbCJ5m.js} +1 -1
  66. package/web/dist/assets/{Installs-BiqR8xdO.js → Installs-BtGGdoTt.js} +1 -1
  67. package/web/dist/assets/{JournalView-6wilG5Zd.js → JournalView-Ckl4dmzR.js} +1 -1
  68. package/web/dist/assets/{Laws-D8YXD_XE.js → Laws-CLpdRRk8.js} +1 -1
  69. package/web/dist/assets/{Library-DwuTZ2-L.js → Library-wPPuKQrI.js} +1 -1
  70. package/web/dist/assets/{OperatorHudView-B-HVBqfY.js → OperatorHudView-CiAkAkQL.js} +1 -1
  71. package/web/dist/assets/{Personal-BbUTmZQR.js → Personal-D8CnDo9v.js} +1 -1
  72. package/web/dist/assets/{Tabs-_pjUFIEI.js → Tabs-B4HNrrCs.js} +1 -1
  73. package/web/dist/assets/{drawable-CoIulEH2.js → drawable-BiwaOo6x.js} +1 -1
  74. package/web/dist/assets/{index-BMwSp8BP.js → index-C1yil5j1.js} +2 -2
  75. package/web/dist/index.html +1 -1
  76. package/adapters/copilot/README.md +0 -105
package/CHANGELOG.md CHANGED
@@ -8,7 +8,38 @@ label. For the capability ↔ spec map, see [SHIPPED.md](SHIPPED.md).
8
8
 
9
9
  ## [Unreleased]
10
10
 
11
- _Nothing yet._
11
+ ## [3.10.0] — 2026-10-01
12
+
13
+ **Upgrading:** re-emit after installing (`geneseed rebuild-all`). A Copilot install is no longer
14
+ maintained: `geneseed uninstall` it before upgrading, or leave its files as they are — nothing
15
+ re-emits them any more. Breaking for Copilot users only; every other host gains features.
16
+
17
+ ### Removed
18
+ - **GitHub Copilot is no longer a host** — dropped for lack of support and of cross-tool
19
+ support. `--emit copilot` / `--emit copilot-global`, the `--host copilot` hook dialect, the
20
+ Copilot agent dialect, its MCP target, the setup and web-console options and
21
+ `adapters/copilot/` are gone. Geneseed now emits for OpenCode, Claude Code, Bob and
22
+ OpenClaude, plus the plain `AGENT.md` bundle (#166).
23
+
24
+ ### Fixed
25
+ - **The session files reach the session.** The root file names `user-rules.md`, `PROFILE.md`,
26
+ the Memory and Notebook indexes, `wiki.jsonc` and `context.json` for session start, but on a
27
+ Claude-shaped install (Claude Code, Bob, OpenClaude) the context hook only looked at the repo
28
+ root — so none of them were ever injected, and the root told the model they sit "beside this
29
+ file", where they are not. The hook and the OpenCode context plugin now inject them from the
30
+ install's own folder as a `SESSION FILES` block, skipping any file still at its seed; the root
31
+ gives each host's real path; Claude-shaped installs now seed `context.json`; and the OpenCode
32
+ plugin finds `wiki.jsonc` on a project install (#167).
33
+ - **Bob folder skills know where they live.** Bob hands a skill's text without its directory, so
34
+ a folder skill's `<this-skill-directory>/…` paths were unresolvable; the Bob emit now writes the
35
+ real path. `daydream` gained its missing frontmatter, `react-view-transitions` is named after
36
+ its folder, and `doctor` checks every folder skill's `name`/`description` (#164).
37
+
38
+ ### Changed
39
+ - **A lighter lean root.** Restated prose is full-footprint only: the laws, Ethos, doctrine,
40
+ posture and mode intros, §3's dispatch envelope and council roster (they live in the
41
+ parallel-agents and council skills), §10 Scripts, and the folder-skill list on hosts that list
42
+ skills natively. The lean Claude root drops from ~33k to ~29k characters (#165).
12
43
 
13
44
  ## [3.9.0] — 2026-09-30
14
45
 
package/QUICKSTART.md CHANGED
@@ -43,7 +43,7 @@ or a login item it did not create. Your clone keeps working meanwhile.
43
43
 
44
44
  ## Everything else
45
45
 
46
- Claude Code, Bob, Copilot, OpenClaude and plain-`AGENT.md` installs, per-repo mode, MCP servers, all
46
+ Claude Code, Bob, OpenClaude and plain-`AGENT.md` installs, per-repo mode, MCP servers, all
47
47
  environment knobs, and troubleshooting live in the full **[Setup guide](SETUP.md)**.
48
48
 
49
49
  Once installed, point the agent at your repo's own docs with a tiny
package/README.md CHANGED
@@ -14,7 +14,7 @@
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/)
17
- [![OpenCode · Claude Code · Bob · Copilot · OpenClaude · AGENT.md](https://img.shields.io/badge/works%20with-OpenCode%20·%20Claude%20Code%20·%20Bob%20·%20Copilot%20·%20OpenClaude%20·%20AGENT.md-1f6feb)](#-supported-harnesses)
17
+ [![OpenCode · Claude Code · Bob · OpenClaude · AGENT.md](https://img.shields.io/badge/works%20with-OpenCode%20·%20Claude%20Code%20·%20Bob%20·%20OpenClaude%20·%20AGENT.md-1f6feb)](#-supported-harnesses)
18
18
 
19
19
  [**Why**](#-1--why-geneseed) · [**Setup**](#-2--setup) · [**Web & terminal**](#-3--web--terminal) · [**What you get**](#-4--what-you-get)
20
20
 
@@ -24,7 +24,7 @@
24
24
 
25
25
  <p align="center"><img src="docs/assets/demo.svg" alt="geneseed setup, then two laws catching a force-push and a credential at the tool boundary" width="760"></p>
26
26
 
27
- **Geneseed compiles your agent's rules instead of asking you to write them.** One source in `src/` renders into a ready-made harness for OpenCode, Claude Code, Bob, Copilot, OpenClaude, or any `AGENT.md` tool: a constitution of laws and doctrines, a roster of capability agents, native skills, a memory convention — and, wherever the host has a hook surface, gates that *enforce* the laws at the tool boundary instead of hoping the model remembers them.
27
+ **Geneseed compiles your agent's rules instead of asking you to write them.** One source in `src/` renders into a ready-made harness for OpenCode, Claude Code, Bob, OpenClaude, or any `AGENT.md` tool: a constitution of laws and doctrines, a roster of capability agents, native skills, a memory convention — and, wherever the host has a hook surface, gates that *enforce* the laws at the tool boundary instead of hoping the model remembers them.
28
28
 
29
29
  ```bash
30
30
  npx geneseed setup
@@ -36,8 +36,8 @@ Want to read what it leaves behind before installing anything? [**geneseed-demo*
36
36
 
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
- - **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, Copilot 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, six targets.** Skills are byte-identical on every host; only the wiring differs. Every commit renders all 317 emit configurations, and a second emit into the same tree must change nothing.
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.
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
 
@@ -212,7 +212,7 @@ A second per-install dial, **footprint**, sets how much of the constitution `AGE
212
212
 
213
213
  Both footprints put the full text on disk beside `AGENT.md`: `laws/`, `ontology/` and `doctrines/` all ship in the bundle at **full** text whatever the footprint, and **all five pack files ship whether or not the pack was built in** — which is what lets a citation into an inactive pack resolve. So lean is a context/token optimization, **not** a rules cut.
214
214
 
215
- Lean is the default: the rationale is one read away and the context it frees is paid back on every turn. Switch to **full** when token cost is a non-issue or you run a smaller model, which leans harder on always-present rationale. Set it with `--footprint lean|full`, the Settings toggle, the per-harness dropdown in the Harnesses tab, or the setup wizard. It's remembered in a `.geneseed-footprint` marker and preserved across rebuilds, on every host (OpenCode, Claude Code, Bob, Copilot).
215
+ Lean is the default: the rationale is one read away and the context it frees is paid back on every turn. Switch to **full** when token cost is a non-issue or you run a smaller model, which leans harder on always-present rationale. Set it with `--footprint lean|full`, the Settings toggle, the per-harness dropdown in the Harnesses tab, or the setup wizard. It's remembered in a `.geneseed-footprint` marker and preserved across rebuilds, on every host (OpenCode, Claude Code, Bob, OpenClaude).
216
216
 
217
217
  Either way the harness is otherwise identical — same files, Rules, capabilities, and guards; lean only relocates the *reasoning* to on-demand (and adds the standalone law, ontology and doctrine files to global/Claude/Bob installs). The one behavioural edge: with the rationale always in context, **full** applies a rule's nuance more reliably on subtle edge cases — or with a weaker model that may not reach for the pointer.
218
218
 
@@ -222,37 +222,37 @@ Want to check a build before it touches anything real? `geneseed validate --them
222
222
 
223
223
  ## 🔌 Supported harnesses
224
224
 
225
- One source, six emit targets. Geneseed builds into whichever host you point it
225
+ One source, five emit targets. Geneseed builds into whichever host you point it
226
226
  at — each with a per-repo and a global (`-global`) variant — plus a portable
227
227
  `files` bundle any `AGENT.md`-aware tool can read. **OpenCode** runs its own
228
- engine (JS plugins, colour themes, LSP); **Claude Code**, **Bob**, **Copilot**
228
+ engine (JS plugins, colour themes, LSP); **Claude Code**, **Bob**
229
229
  and **OpenClaude** share one Claude-shaped engine that diverges only by host dialect.
230
230
 
231
231
  The harness — its Rules, Agents, Skills, Memory convention, and preamble voice —
232
232
  is **identical on every host**. What differs is how much of it the host can
233
233
  *automate* for you (via plugins or hooks) versus carry as preamble discipline.
234
234
 
235
- | Capability | OpenCode | Claude Code | Bob | Copilot | OpenClaude |
236
- | --- | :---: | :---: | :---: | :---: | :---: |
237
- | **Instructions file** | `AGENT.md` + `opencode.json` | `CLAUDE.md` | `AGENTS.md` + `rules/geneseed.md` | `AGENTS.md` / `copilot-instructions.md` | `CLAUDE.md` (in `.openclaude/` per repo) |
238
- | **Agents** (capability specialists) | ✅ native | ✅ | ✅ | ✅ `.agent.md` | ✅ |
239
- | **Skills** (byte-identical) | ✅ | ✅ | ✅ | ✅ | ✅ |
240
- | **Memory & Notebook** | ✅ | ✅ | ✅ | ✅ | ✅ |
241
- | **Context injection** | ⚙️ plugin | 🪝 hook | 🪝 hook¹ | 🪝 hook³ | 🪝 hook⁴ |
242
- | **Memory write-back** (learn) | ⚙️ plugin | 🪝 hook | 🪝 hook¹ | 🪝 hook³ | 🪝 hook⁴ |
243
- | **Git-gate consent** (process 5) | ⚙️ plugin | 🪝 hook | 🪝 hook¹ (warn) | 🪝 hook³ | 🪝 hook⁴ |
244
- | **Rule-gate consent** (process 1) | ⚙️ plugin² | 🪝 hook | 🪝 hook¹ (warn) | 🪝 hook³ | 🪝 hook⁴ |
245
- | **Laws I / IV at the boundary** | ⚙️ plugin (block) | 🪝 hook (ask) | 🪝 hook¹ (exit 2) | 🪝 hook³ (ask) | 🪝 hook⁴ (ask) |
246
- | **Sovereign-repo excludes** | ⚙️ plugin | ✅ `claudeMdExcludes` | ✅ rules-shadow | ➖ none | ✅ `claudeMdExcludes` |
247
- | **MCP server wiring** | ✅ `mcp` | ✅ `mcpServers` | ✅ `mcp.json` | ✅ `mcp-config.json` | ✅ `mcpServers` |
248
- | **Colour themes** | ✅ full palette | ➖ | ➖ | ➖ | ➖ |
249
- | **LSP · workflow runner · primary-agent · `/`-commands** | ✅ | ➖ | ➖ | ➖ | ➖ |
250
-
251
- <sub>✅ native support · ⚙️ OpenCode plugin · 🪝 `settings.json` hook · 📄 carried by preamble prose only · ➖ no host mechanism (harness discipline still applies) · ¹ Bob's own hook contract: global hooks in `~/.bob/settings/settings.json`, Claude's event names but stdout ignored on `PreToolUse` — a refusal is **exit code 2**. So Laws I/IV exit 2, the consent rules are a stderr line, `SessionStart` context is plain stdout, `Stop` runs learn; `SubagentStop`/`PreCompact` are not Bob events and are not written. Unverified live (no Bob install on the authoring machine); the harness still holds via the rules preamble. · ² OpenCode's `tool.execute.before` can only allow or throw, with no "ask the user" tier, so the rule gate is a one-shot speed bump there rather than a prompt. · ³ Copilot's `~/.copilot/settings.json` hooks (`sessionStart`, `preToolUse`, `agentStop`, `preCompact`) wired by the **global** emit only; `preToolUse` has an ask tier, so every rule asks as on Claude Code. Unverified live (no Copilot CLI on the authoring machine). · ⁴ OpenClaude is a Claude Code fork: Claude's hook groups and verdicts verbatim, in `~/.openclaude/settings.json` (global) or `.openclaude/settings.local.json` (per repo). Unverified live (no OpenClaude install on the authoring machine).</sub>
235
+ | Capability | OpenCode | Claude Code | Bob | OpenClaude |
236
+ | --- | :---: | :---: | :---: | :---: |
237
+ | **Instructions file** | `AGENT.md` + `opencode.json` | `CLAUDE.md` | `AGENTS.md` + `rules/geneseed.md` | `CLAUDE.md` (in `.openclaude/` per repo) |
238
+ | **Agents** (capability specialists) | ✅ native | ✅ | ✅ | ✅ |
239
+ | **Skills** (byte-identical) | ✅ | ✅ | ✅ | ✅ |
240
+ | **Memory & Notebook** | ✅ | ✅ | ✅ | ✅ |
241
+ | **Context injection** | ⚙️ plugin | 🪝 hook | 🪝 hook¹ | 🪝 hook³ |
242
+ | **Memory write-back** (learn) | ⚙️ plugin | 🪝 hook | 🪝 hook¹ | 🪝 hook³ |
243
+ | **Git-gate consent** (process 5) | ⚙️ plugin | 🪝 hook | 🪝 hook¹ (warn) | 🪝 hook³ |
244
+ | **Rule-gate consent** (process 1) | ⚙️ plugin² | 🪝 hook | 🪝 hook¹ (warn) | 🪝 hook³ |
245
+ | **Laws I / IV at the boundary** | ⚙️ plugin (block) | 🪝 hook (ask) | 🪝 hook¹ (exit 2) | 🪝 hook³ (ask) |
246
+ | **Sovereign-repo excludes** | ⚙️ plugin | ✅ `claudeMdExcludes` | ✅ rules-shadow | ✅ `claudeMdExcludes` |
247
+ | **MCP server wiring** | ✅ `mcp` | ✅ `mcpServers` | ✅ `mcp.json` | ✅ `mcpServers` |
248
+ | **Colour themes** | ✅ full palette | ➖ | ➖ | ➖ |
249
+ | **LSP · workflow runner · primary-agent · `/`-commands** | ✅ | ➖ | ➖ | ➖ |
250
+
251
+ <sub>✅ native support · ⚙️ OpenCode plugin · 🪝 `settings.json` hook · 📄 carried by preamble prose only · ➖ no host mechanism (harness discipline still applies) · ¹ Bob's own hook contract: global hooks in `~/.bob/settings/settings.json`, Claude's event names but stdout ignored on `PreToolUse` — a refusal is **exit code 2**. So Laws I/IV exit 2, the consent rules are a stderr line, `SessionStart` context is plain stdout, `Stop` runs learn; `SubagentStop`/`PreCompact` are not Bob events and are not written. Unverified live (no Bob install on the authoring machine); the harness still holds via the rules preamble. · ² OpenCode's `tool.execute.before` can only allow or throw, with no "ask the user" tier, so the rule gate is a one-shot speed bump there rather than a prompt. · ³ OpenClaude is a Claude Code fork: Claude's hook groups and verdicts verbatim, in `~/.openclaude/settings.json` (global) or `.openclaude/settings.local.json` (per repo). Unverified live (no OpenClaude install on the authoring machine).</sub>
252
252
 
253
253
  **Reading the matrix.** Everything above the divider is at full parity — no host
254
254
  drops an Agent, Skill, or the memory convention. The asymmetry is entirely in
255
- *automation mechanism*: OpenCode's plugin surface and the Claude/Bob/Copilot/OpenClaude hook
255
+ *automation mechanism*: OpenCode's plugin surface and the Claude/Bob/OpenClaude hook
256
256
  surfaces enforce a few Rules for you, each in the tier its host offers (a prompt on
257
257
  Claude Code, a hard block or a logged warning where the host has no prompt to
258
258
  give), and what no host can automate rides the preamble. The OpenCode-only extras (themes, LSP,
@@ -260,7 +260,7 @@ workflow runner, primary-agent) have no analogue on a Claude-shaped host.
260
260
 
261
261
  Per-host wiring in depth: **[OpenCode](adapters/opencode/README.md)** ·
262
262
  **[Claude Code](adapters/claude-code/README.md)** ·
263
- **[Bob](adapters/bob/README.md)** · **[Copilot](adapters/copilot/README.md)** ·
263
+ **[Bob](adapters/bob/README.md)** ·
264
264
  **[OpenClaude](adapters/openclaude/README.md)**.
265
265
  Token cost per host: **[docs/token-footprint.md](docs/token-footprint.md)**.
266
266
 
@@ -294,7 +294,7 @@ Geneseed/
294
294
  ├── tests/ Node test suites, golden.mjs (every emit config) and mutate.mjs
295
295
  ├── docs/ guides (web-ui, wiki, …) + docs/web/ (the console's Docs pages);
296
296
  │ specs/, reviews/, superpowers/ are local working docs — git-ignored
297
- ├── adapters/ per-host glue (opencode/, claude-code/, bob/, copilot/, openclaude/)
297
+ ├── adapters/ per-host glue (opencode/, claude-code/, bob/, openclaude/)
298
298
  └── .github/workflows/ ci.yml (doctor + tests) · publish.yml (npm, OIDC, manual only)
299
299
  ```
300
300
 
@@ -345,7 +345,6 @@ Details and precedence rules: [SETUP.md → Upgrade](SETUP.md#upgrade).
345
345
  | ⤷ [HOW-OPENCODE-LOADS.md](adapters/opencode/HOW-OPENCODE-LOADS.md) | Why a file shows up twice; plugin loading |
346
346
  | **[adapters/claude-code/](adapters/claude-code/README.md)** | The Claude Code hook adapter |
347
347
  | **[adapters/bob/](adapters/bob/README.md)** | The IBM Bob adapter — Claude-shaped, rules-file preamble |
348
- | **[adapters/copilot/](adapters/copilot/README.md)** | The GitHub Copilot adapter — global hooks (`sessionStart`, `preToolUse`, `agentStop`, `preCompact`) |
349
348
  | **[adapters/openclaude/](adapters/openclaude/README.md)** | The OpenClaude adapter — the Claude engine under `~/.openclaude` / `.openclaude/` |
350
349
  | **[src/memory/README.md](src/memory/README.md)** | The memory convention |
351
350
  | **[src/notebook/README.md](src/notebook/README.md)** | The agent's own freeform-space convention |
package/SETUP.md CHANGED
@@ -22,7 +22,7 @@ that matches your tool, then configure and verify. For the conceptual overview s
22
22
 
23
23
  - **Node ≥ 22.3** — the only hard requirement. Geneseed ships as an npm package with
24
24
  **zero dependencies**; `npx geneseed` needs nothing else.
25
- - **Your agent tool** — OpenCode (recommended), Claude Code, Bob, Copilot, OpenClaude, or anything
25
+ - **Your agent tool** — OpenCode (recommended), Claude Code, Bob, OpenClaude, or anything
26
26
  that reads a root instructions file.
27
27
  - *Only for a git checkout:* **git**. Nothing else — a checkout runs the same Node
28
28
  entry points the npm package installs.
@@ -93,8 +93,7 @@ hand? Pick a path below.
93
93
  | [A — OpenCode, global](#path-a--opencode-global-recommended) | **Recommended.** One install, every repo inherits it, nothing committed into projects. |
94
94
  | [B — OpenCode, per-repo](#path-b--opencode-per-repo) | You want a committed `.opencode/` layer in one repository. |
95
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. |
96
+ | [C′ — OpenClaude](#path-c--openclaude) | You drive OpenClaude, the any-model Claude Code fork. |
98
97
  | [D — Any `AGENT.md` tool](#path-d--any-agentmd-tool) | Cursor, Aider, or any tool that reads a root instructions file. |
99
98
  | [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
99
 
@@ -219,45 +218,11 @@ repo's own `.claude/settings.local.json`, and OpenClaude's in `.openclaude/setti
219
218
  Bob: the workspace rules shadow stub;
220
219
  OpenCode: the plugins stand down). Everything is reversed by `exclude remove`.
221
220
 
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
221
+ Limitation: globally installed skills/subagents remain listed by the host (no
222
+ native per-repo disable exists). A global install emitted later starts with an empty list — re-run
226
223
  `harness exclude add` (`exclude list` flags installs that diverge).
227
224
 
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
225
+ ### Path C′ — OpenClaude
261
226
 
262
227
  ```
263
228
  geneseed-build --emit openclaude-global # render into ~/.openclaude
@@ -453,7 +418,7 @@ you run a smaller model.
453
418
  **Same harness, either way.** Footprint changes neither what the harness *is* nor what it
454
419
  can *do*: lean and full emit identical files (same agents, skills, plugins, commands, memory,
455
420
  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
421
+ that a lean install on a global / Claude / Bob / OpenClaude target also ships the standalone
457
422
  `laws/universal.md` and `ontology/` (project bundles already carry them, and `doctrines/`
458
423
  ships at both footprints on every target); the only behavioural difference is that the
459
424
  reasoning loads on demand instead of every turn. Lean is the default; full, with the rationale
@@ -463,7 +428,7 @@ with a weaker model, and is one flag away.
463
428
  Set it with `--footprint lean|full` (alongside any `--emit`), the **Footprint** toggle in
464
429
  the web Settings, the per-harness dropdown in the Harnesses tab, or the setup wizard. It is
465
430
  remembered in a `.geneseed-footprint` marker and preserved across every rebuild, on every
466
- host (OpenCode, Claude Code, Bob, Copilot, OpenClaude).
431
+ host (OpenCode, Claude Code, Bob, OpenClaude).
467
432
 
468
433
  ### Dry-run a build (`validate`)
469
434
 
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.9.0**.
23
+ > string. Current label: **3.10.0**.
24
24
 
25
25
  ## Capabilities
26
26
 
@@ -37,7 +37,7 @@ Every row below is present in the tree today; "Spec" names the design record.
37
37
  | **Terminal rendering** | There is no full-screen control panel: `tui` and `menu` are verbs that say so and print the command list. The display-width and glyph layer ships on, behind `status` and the install animation | `2026-06-07-tui-refactor-polish` · `2026-06-08-tui-modern-refresh` · `2026-06-11-windows-tui` |
38
38
  | **Web console** | Local browser UI (Dashboard; Codex: Constitution, Rules, Profile, Skills, Agents, Library, Docs; Care: Activity, Changes, Doctor; Setup: Harness, Settings), auto-build, in-app docs menu | `2026-06-12-web-ui-v2` · `2026-06-12-web-auto-build` · `2026-06-13-docs-menu` |
39
39
  | **OpenCode adapter** | Native agents/skills mapping + plugins (context, learn, guard, workflow, notify, ponytail, activity); global-emit link integrity; JSONC config target | `2026-06-07-opencode-adapter-features` · `2026-06-07-global-emit-link-integrity` · `2026-06-12-opencode-jsonc-target` · `2026-06-16-ponytail-minimal-code-mode` |
40
- | **Host hooks, per dialect** | Every host gets the hook surface its runtime offers, spoken in that runtime's own verdict dialect via `--host`: Claude Code asks (`permissionDecision`), OpenClaude asks exactly as Claude does (a Claude Code fork, under `~/.openclaude` / `.openclaude/`), Copilot asks as Claude does (`sessionStart`, `preToolUse`, `agentStop`, `preCompact` in `~/.copilot/settings.json`, global scope only), Bob refuses by exit code 2 (five Claude-named events, nested `~/.bob/settings/settings.json`, no subagent event), OpenCode's guard throws. Laws I/IV are the hard tier everywhere; the consent rules ask where a host can ask and warn where it cannot. `tool-gate` fuses the two gates for hosts that run one command per event; `PreCompact` runs `learn` before Claude compacts; every block or ask lands in `notebook/gates.jsonl` on every host | [copilot](adapters/copilot/README.md) · [bob](adapters/bob/README.md) · [claude-code](adapters/claude-code/README.md) · [candidate hosts](docs/candidate-hosts.md) |
40
+ | **Host hooks, per dialect** | Every host gets the hook surface its runtime offers, spoken in that runtime's own verdict dialect via `--host`: Claude Code asks (`permissionDecision`), OpenClaude asks exactly as Claude does (a Claude Code fork, under `~/.openclaude` / `.openclaude/`), Bob refuses by exit code 2 (five Claude-named events, nested `~/.bob/settings/settings.json`, no subagent event), OpenCode's guard throws. Laws I/IV are the hard tier everywhere; the consent rules ask where a host can ask and warn where it cannot. `tool-gate` fuses the two gates for hosts that run one command per event; `PreCompact` runs `learn` before Claude compacts; every block or ask lands in `notebook/gates.jsonl` on every host | [bob](adapters/bob/README.md) · [claude-code](adapters/claude-code/README.md) · [candidate hosts](docs/candidate-hosts.md) |
41
41
  | **Workflow primitive** | Saved, code-driven subagent orchestration (`workflow` tool + runtime); shipped scripts include `dispatch` — decompose a goal, route each subtask to its owning agent, converge | `2026-06-09-opencode-workflow-primitive` |
42
42
  | **Per-agent memory** | Each capability agent keeps durable lessons in `memory/agents/<name>.md`: read at dispatch, written back mechanically by `learn` on session/subagent end (OpenCode plugin + Claude `SubagentStop`; Bob has no subagent event); `learn --consolidate` rebuilds the index | `2026-07-04-orchestration-memory-upgrade` |
43
43
  | **Wiki integration** | Machine-wide knowledge base (`wiki.jsonc`): eager/lazy loading, conventions, protected folders enforced at the tool boundary | `2026-06-11-wiki-knowledge-base` |
@@ -23,7 +23,8 @@ limitation to be aware of on a shared repo.
23
23
  - `agents/<name>.md` — the **Claude subagent dialect** verbatim (`name` +
24
24
  `description` + a `disallowedTools:` denylist for read-only agents).
25
25
  - `skills/<name>/SKILL.md` — **byte-identical** to every other host; skills
26
- are model-invoked via the `skill` tool.
26
+ are model-invoked via the `skill` tool. The one exception is the folder skills'
27
+ own directory — see *Bob-ism 3*.
27
28
  - `rules/geneseed.md` — a **slim shadow stub** (see *Bob-ism 1* below).
28
29
  - `settings.json` — Geneseed's lifecycle hooks (gitignored by the emit's
29
30
  `.bob/.gitignore`, see the caveat below).
@@ -64,6 +65,21 @@ never gets one; the `rules/geneseed.md` shadow above covers the same
64
65
  project-bypasses-global need. An older Bob install that wrote a stale exclude is
65
66
  **self-healed** (the entry is removed) on the next emit.
66
67
 
68
+ ## Bob-ism 3 — a folder skill is told where it lives
69
+
70
+ A folder skill (`explain-changes`, `token-report`, `daydream`, …) ships scripts or
71
+ prompts beside its `SKILL.md` and names them `<this-skill-directory>/…`. Claude Code
72
+ answers that placeholder itself — it gives the model each skill's base directory on load.
73
+ Bob gives the skill's text only, so the model was left with a path it could not resolve
74
+ and fell back to searching the filesystem. The Bob emit therefore writes the directory in:
75
+
76
+ - per repo, relative to the workspace root — `node .bob/skills/token-report/scripts/…` —
77
+ which is where Bob runs commands, and stays valid in a teammate's checkout;
78
+ - globally, the absolute path under `~/.bob/skills/`.
79
+
80
+ `doctor` also requires every folder skill's `SKILL.md` to open with a frontmatter whose
81
+ `name` is the folder's and which has a `description` — what any host registers a skill from.
82
+
67
83
  ## Hooks — Bob's own protocol
68
84
 
69
85
  Bob documents lifecycle hooks (its hooks page and the 2.0.2 changelog; see
@@ -58,7 +58,7 @@ which root file OpenClaude already loads (`AGENTS.md` when present, else
58
58
  ## Not supported
59
59
 
60
60
  - **Workflows.** OpenClaude ships its `WorkflowTool` disabled, so the `workflow`
61
- skill falls back to parallel agents, as on Bob and Copilot.
61
+ skill falls back to parallel agents, as on Bob.
62
62
  - **Live verification.** The emit follows OpenClaude's source (`src/utils/envUtils.ts`,
63
63
  `src/utils/claudemd.ts`, `src/utils/config.ts`, `src/types/hooks.ts`) as of
64
64
  2026-09. It has not been run against an installed OpenClaude yet.
@@ -56,6 +56,7 @@ import { promises as fs } from "node:fs"
56
56
  import * as path from "node:path"
57
57
  import { fileURLToPath } from "node:url"
58
58
  import { homedir } from "node:os"
59
+ import { createHash } from "node:crypto"
59
60
 
60
61
  const MARKER = "<!-- geneseed-context:v2 -->"
61
62
  const PLUGIN_DIR = path.dirname(fileURLToPath(import.meta.url))
@@ -156,6 +157,49 @@ const EXCLUDE_DIRS = new Set([
156
157
  async function isFile(p) { try { return (await fs.stat(p)).isFile() } catch { return false } }
157
158
  async function isDir(p) { try { return (await fs.stat(p)).isDirectory() } catch { return false } }
158
159
 
160
+ // ---- session files (the harness's own) --------------------------------------
161
+ // The files AGENT.md names for session start, relative to the HARNESS dir — the dir that
162
+ // holds the installed AGENT.md: the repo root for a project install, the config dir for a
163
+ // global one. Same list and seed hashes as SESSION_FILES/SEED_SHA256 in js/hosts/hooks.mjs;
164
+ // tests/unit/claude.test.mjs gates both copies against SESSION_SEEDS in js/build/stubs.mjs.
165
+ // context.json is not here: it is a manifest, honoured by resolveSource. wiki.jsonc is not
166
+ // here either: the MACHINE WIKI block below already renders it in full.
167
+ const SESSION_FILES = ["user-rules.md", "PROFILE.md", "memory/MEMORY.md", "anamnesis/MEMORY.md",
168
+ "notebook/NOTEBOOK.md"]
169
+ const SEED_SHA256 = new Set([
170
+ "5c2e92fb1acde041e02d9ebf158460d8ff7a07cbc2b447859631604610130721", // user-rules.md
171
+ "29e012c3c4349ea62a9082cbd04bb25599a0ec280d62c33f6e10742809471816", // PROFILE.md
172
+ "cccc917c34e6b990e821620bdb4739090151885ab71b6e85046f30a3b71fa5e8", // wiki.jsonc
173
+ "99c786049c260f6baf7aec68a5c0f59907861afe9b867da009440613bdddb907", // MEMORY.md
174
+ "9acb5c9d9cb5dac572104480f05b48cc144e676869bd60e86d8a15b1f6308184", // NOTEBOOK.md
175
+ ])
176
+
177
+ // $GENESEED_HARNESS when set, else the first of <plugin dir>/.. (global: the config dir) and
178
+ // <plugin dir>/../.. (project: .opencode/plugins -> the repo root) that holds AGENT.md.
179
+ async function harnessDir() {
180
+ if (process.env.GENESEED_HARNESS && (await isDir(process.env.GENESEED_HARNESS))) {
181
+ return process.env.GENESEED_HARNESS
182
+ }
183
+ for (const d of [path.resolve(PLUGIN_DIR, ".."), path.resolve(PLUGIN_DIR, "..", "..")]) {
184
+ if (await isFile(path.join(d, "AGENT.md"))) return d
185
+ }
186
+ return null
187
+ }
188
+
189
+ // Session files present under the harness dir and changed from their seed: [{ rel, abs, text }].
190
+ async function sessionFiles(dir) {
191
+ const found = []
192
+ if (!dir) return found
193
+ for (const rel of SESSION_FILES) {
194
+ const abs = path.join(dir, rel)
195
+ let text
196
+ try { text = (await fs.readFile(abs, "utf8")).replace(/\r\n/g, "\n") } catch { continue }
197
+ if (SEED_SHA256.has(createHash("sha256").update(text).digest("hex"))) continue
198
+ found.push({ rel, abs, text: text.replace(/\n+$/, "") })
199
+ }
200
+ return found
201
+ }
202
+
159
203
  async function readJson(p) {
160
204
  try { return JSON.parse(await fs.readFile(p, "utf8")) } catch { return null }
161
205
  }
@@ -474,11 +518,13 @@ async function fromManifest(manifestFile, root) {
474
518
  return { eager: eager.sort(byRel), lazy: lazy.sort(byRel) }
475
519
  }
476
520
 
477
- async function resolveSource(root) {
521
+ async function resolveSource(root, harness = null) {
478
522
  const explicit = process.env.GENESEED_CONTEXT
479
523
  if (explicit && (await isFile(explicit))) return { mode: "manifest", file: explicit }
480
- for (const rel of [path.join(".harness", "context.json"), "context.json"]) {
481
- const p = path.join(root, rel)
524
+ // The harness dir last: a repo's own manifest outranks the one seeded beside the install.
525
+ const cands = [path.join(root, ".harness", "context.json"), path.join(root, "context.json")]
526
+ if (harness) cands.push(path.join(harness, "context.json"))
527
+ for (const p of cands) {
482
528
  if (await isFile(p)) return { mode: "manifest", file: p }
483
529
  }
484
530
  return { mode: "discover" }
@@ -494,8 +540,12 @@ async function resolveSource(root) {
494
540
  async function resolveWikiFile() {
495
541
  const explicit = process.env.GENESEED_WIKI
496
542
  if (explicit && (await isFile(explicit))) return explicit
543
+ // The harness dir (which honours $GENESEED_HARNESS) first: on a PROJECT install the plugin
544
+ // sits in .opencode/plugins, so <plugin dir>/.. is .opencode, not the dir the seed landed in.
545
+ // <plugin dir>/.. stays as the fallback for an install without an AGENT.md.
497
546
  const bases = []
498
- if (process.env.GENESEED_HARNESS) bases.push(process.env.GENESEED_HARNESS)
547
+ const harness = await harnessDir()
548
+ if (harness) bases.push(harness)
499
549
  bases.push(path.resolve(PLUGIN_DIR, ".."))
500
550
  for (const base of bases) {
501
551
  // wiki.json is the legacy name from earlier seeds — still honoured.
@@ -652,9 +702,27 @@ async function renderSet(out, { eager, lazy }, state) {
652
702
  state.lazy += lazyLines.length
653
703
  }
654
704
 
655
- async function buildBlock(sets, wikis = [], commands = []) {
705
+ async function buildBlock(sets, wikis = [], commands = [], session = []) {
656
706
  const state = { spent: 0, injected: 0, lazy: 0, headingsRead: 0 }
657
707
 
708
+ // A session file discovery also found (user-rules.md at the root of a project install,
709
+ // whose harness dir IS the repo root) is injected once, in the session block.
710
+ const seen = new Set(session.map((s) => path.resolve(s.abs)))
711
+ const fresh = (x) => !seen.has(path.resolve(x.abs))
712
+ sets = { eager: sets.eager.filter(fresh), lazy: sets.lazy.filter(fresh) }
713
+ const ses = []
714
+ for (const s of session) {
715
+ const size = Buffer.byteLength(s.text, "utf8")
716
+ ses.push(`----- ${s.rel} -----`)
717
+ if (size > EAGER_FILE_KB * 1024) {
718
+ ses.push(`[demoted: ${s.rel} exceeded ${EAGER_FILE_KB} KB — read ${s.abs} on demand]`, "")
719
+ continue
720
+ }
721
+ ses.push(s.text, "")
722
+ state.spent += size
723
+ state.injected++
724
+ }
725
+
658
726
  const proj = []
659
727
  await renderSet(proj, sets, state)
660
728
 
@@ -675,8 +743,9 @@ async function buildBlock(sets, wikis = [], commands = []) {
675
743
  if (w.truncated) wik.push(` [+${w.truncated} more notes in this wiki — explore its folders on demand]`, "")
676
744
  }
677
745
 
678
- if (!proj.length && !wik.length) return null
746
+ if (!ses.length && !proj.length && !wik.length) return null
679
747
  const out = [MARKER]
748
+ if (ses.length) out.push("=== SESSION FILES — your harness files, injected at session start (untouched seeds skipped) ===", "", ...ses)
680
749
  if (proj.length) out.push("=== PROJECT CONTEXT — binding for this repo ===", "", ...proj)
681
750
  if (wik.length) out.push("=== MACHINE WIKI — the user's knowledge base, binding per AGENT.md §8 ===", "", ...wik)
682
751
  return { text: out.join("\n"), injected: state.injected, lazy: state.lazy, kb: kb(state.spent) }
@@ -686,13 +755,14 @@ async function buildBlock(sets, wikis = [], commands = []) {
686
755
  // and render the injection block — shared by the session.created injection and the
687
756
  // compaction hook (the transform path reuses it via cachedBlockText).
688
757
  async function resolveBlock(root) {
689
- const src = await resolveSource(root)
758
+ const harness = await harnessDir()
759
+ const src = await resolveSource(root, harness)
690
760
  const sets = src.mode === "manifest"
691
761
  ? await fromManifest(src.file, root)
692
762
  : await discover(root)
693
763
  const wikis = await wikiSets()
694
764
  const commands = await discoverCommands(root)
695
- return { block: await buildBlock(sets, wikis, commands), src }
765
+ return { block: await buildBlock(sets, wikis, commands, await sessionFiles(harness)), src }
696
766
  }
697
767
 
698
768
  // Per-process cache of the rendered block text for the transform path (root is fixed
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  /**
3
3
  * The hook entry point — a Node twin of `rituals/harness.py` for the verbs the emitted
4
- * `settings.json` actually invokes (four from the reference, plus `tool-gate` for Copilot).
4
+ * `settings.json` actually invokes (four from the reference, plus `tool-gate` for Bob).
5
5
  *
6
6
  * WHY IT IS A SECOND BINARY AND NOT A SUBCOMMAND OF `bin/build-driver.mjs`. Three reasons,
7
7
  * and each alone would be enough:
@@ -38,8 +38,7 @@ current host gets. Skills are the largest surface by file count and they cost no
38
38
  Claude's, and `permissionDecision: "ask"` exists. The Claude engine with `host: "codex"`
39
39
  covers instructions (`AGENTS.md`), skills (`.agents/skills`) and the hook verbs
40
40
  unchanged; the only new code is the carrier writer (a `hooks.json` merge or a TOML
41
- table) and the config-dir resolver (`~/.codex`, `$CODEX_HOME`). Roughly the Copilot
42
- port minus the dialect work.
41
+ table) and the config-dir resolver (`~/.codex`, `$CODEX_HOME`).
43
42
 
44
43
  - **Gemini CLI — Claude's groups, Gemini's names.** The hook groups are Claude's
45
44
  `event → [{matcher, hooks}]` and the payload fields are Claude's, but the events are
@@ -54,7 +53,7 @@ current host gets. Skills are the largest surface by file count and they cost no
54
53
  - **Cursor — a third verdict dialect.** `AGENTS.md` and `.agents/skills` are free; hooks
55
54
  are `hooks.json` with a `{command}` list per event and a `permission: allow|deny`
56
55
  verdict, `additional_context` in snake_case for `sessionStart`. Same block-or-warn stance
57
- as Copilot, one more output spelling in `js/hosts/hooks.mjs`, one more carrier writer.
56
+ as Bob, one more output spelling in `js/hosts/hooks.mjs`, one more carrier writer.
58
57
  Cursor also reads `.claude/skills/`, so a Claude project install already gives a Cursor
59
58
  user the skills.
60
59
 
@@ -64,8 +63,16 @@ If a fifth host is wanted, Codex first: it reuses the most and it is the only ca
64
63
  where the gates can *ask* rather than block. Before any of them, a `--emit agents` for
65
64
  the shared `.agents/skills/` folder would give Codex, Cursor and Gemini users the whole
66
65
  skill catalogue for the price of one directory name, with no host-specific code at all.
67
- A Gemini host would be the fourth verdict spelling in `js/hosts/hooks.mjs` (after Claude's
68
- ask, Copilot's block, Bob's exit code 2), plus a resolver and a carrier.
66
+ A Gemini host would be the third verdict spelling in `js/hosts/hooks.mjs` (after Claude's
67
+ ask and Bob's exit code 2), plus a resolver and a carrier.
68
+
69
+ ## Evaluated, dropped
70
+
71
+ - **GitHub Copilot** — shipped as a host through 3.9.0, removed in 3.10.0. Dropped for lack
72
+ of support: its hooks were never verified live, its `postToolUse` output does not reach
73
+ the model, and it shared no cross-tool surface with the other hosts (camelCase payloads,
74
+ matcherless hook entries, its own agent dialect and carrier), so every feature needed a
75
+ Copilot-only decision.
69
76
 
70
77
  ## Not verified
71
78
 
@@ -15,33 +15,33 @@ heavier on the root file.
15
15
 
16
16
  The context every host injects at session start, before you type anything:
17
17
 
18
- | Component | Claude Code | OpenCode | Bob | Copilot |
19
- |---|---|---|---|---|
20
- | Root instruction file | ~7.3k (`CLAUDE.md`) | ~7.3k (`AGENT.md`) | ~7.7k (`AGENTS.md`, §3 table inline) | ~9.0k (`AGENTS.md`, §3+§4 tables inline) |
21
- | Skill metadata (name + description) | ~4.1k | ~4.1k | ~4.1k (native) | — (§4 table; native catalogue unverified) |
22
- | Agent metadata | ~0.5k | ~0.5k | — (no agents directory) | — (§3 table) |
23
- | Eager memory/notebook injection | ~1.2k (SessionStart hook) | ~1.2k (context plugin) | ~1.2k (SessionStart hook) | ~1.2k (sessionStart hook) |
24
- | **Total** | **~13k** | **~13k** | **~13k** | **~10k** |
18
+ | Component | Claude Code | OpenCode | Bob |
19
+ |---|---|---|---|
20
+ | Root instruction file | ~7.2k (`CLAUDE.md`) | ~7.2k (`AGENT.md`) | ~7.5k (`AGENTS.md`, §3 table inline) |
21
+ | Skill metadata (name + description) | ~4.1k | ~4.1k | ~4.1k (native) |
22
+ | Agent metadata | ~0.5k | ~0.5k | — (no agents directory) |
23
+ | Session files (rules, profile, Memory/Notebook indexes, wiki) | 0 fresh, grows with use (SessionStart hook) | 0 fresh, grows with use (context plugin) | 0 fresh, grows with use (SessionStart hook) |
24
+ | **Total** | **~12k** | **~12k** | **~12k** |
25
25
 
26
- The emits are at parity by design: ~10–13k tokens, about 6% of a 200k
26
+ The emits are at parity by design: ~12k tokens, about 6% of a 200k
27
27
  window. Bob catalogues skills natively but has no agents directory, so its
28
28
  root keeps the §3 Agents table and drops the §4 Skills table — the catalogue
29
29
  flag is per kind (`hostCatalogsNatively`), not one boolean. Before the 2026-09 footprint pass every hooked host paid roughly double
30
30
  this: the context hook re-injected the root file the host had already loaded
31
31
  natively, and skill descriptions ran to 900 characters each — see the
32
- "Where the tokens go" list below for what changed. Bob and Copilot carry the §3/§4 catalogue tables inline because their
33
- hosts expose no native skill/agent inventory; Claude Code and OpenCode ship a
34
- pointer to the host's own inventory instead, ~1.9k tokens lighter. Copilot's
35
- eager injection rides its `sessionStart` hook, which the **global** emit wires;
36
- a project-scope Copilot install has no hooks, so there the memory/notebook
37
- indexes load when the agent reads them, not eagerly. The
32
+ "Where the tokens go" list below for what changed. Bob carries the §3/§4 catalogue tables inline because its host exposes
33
+ no native skill/agent inventory; Claude Code and OpenCode ship a
34
+ pointer to the host's own inventory instead, ~1.9k tokens lighter. A session file still
35
+ byte-identical to its seed is skipped — it says nothing — so a fresh install injects none
36
+ of them; until 2026-10 the hook read them from the repo root, where a Claude-shaped install
37
+ never puts them, and none reached the session at all. The
38
38
  eager-injection path is budget-capped identically everywhere — 16 KB per file
39
39
  (cut at a line break, with a marker saying so) and 48 KB per session (files past
40
40
  the budget are listed lazy with the reason) — so a 40k-character README no
41
41
  longer leaves whole every session, and growing Memory degrades every host the
42
42
  same way instead of one silently falling behind. The hook also **never injects
43
43
  the root file the host loads by itself** (`CLAUDE.md` on Claude Code,
44
- `AGENTS.md` on Bob and Copilot, `AGENT.md`/`AGENTS.md`/`CLAUDE.md` on OpenCode):
44
+ `AGENTS.md` on Bob, `AGENT.md`/`AGENTS.md`/`CLAUDE.md` on OpenCode):
45
45
  until 2026-09 it did, and the whole harness was paid twice per session.
46
46
 
47
47
  ## Where the tokens go
@@ -72,10 +72,17 @@ until 2026-09 it did, and the whole harness was paid twice per session.
72
72
  capped at 320 characters (`skillDescription` in `js/hosts/native.mjs`); at
73
73
  the earlier 900-character cap the catalogue weighed ~5.6k tokens. The later
74
74
  trigger sentences still live in the body, read as soon as the skill is chosen.
75
- - **§5–§10 carry authored lean halves too** (Memory, Notebook, Workspace, Wiki,
76
- Context, Scripts): each keeps its obligations — read `MEMORY.md`, read
75
+ - **§5–§9 carry authored lean halves too** (Memory, Notebook, Workspace, Wiki,
76
+ Context): each keeps its obligations — read `MEMORY.md`, read
77
77
  `context.json` before the first reply, the git-ignored folders — and points at
78
- the on-disk README or config file for the rest.
78
+ the on-disk README or config file for the rest. §10 (Scripts) is full-only: it
79
+ describes the CLI to a reader, not an obligation to the agent.
80
+ - **Restated prose is full-only** (2026-10): the laws and Ethos intros, the §2
81
+ pack intro, the posture/mode intros, §3's dispatch envelope and council roster
82
+ (they live in the parallel-agents and council Skills; the lean root keeps
83
+ "dispatched agents never commit or push"), and the folder-Skill list, which
84
+ now sits in the §4 catalogue half and so drops wherever the host catalogues
85
+ Skills natively.
79
86
  - **Skill bodies (~53k) and agent bodies (~10k) are lazy** on every host —
80
87
  loaded only when invoked. A typical skill costs ≤3k per invocation; the
81
88
  heaviest (`react-view-transitions`, ~17.5k with its reference files) loads
@@ -97,9 +104,7 @@ token counter also includes, none of which Geneseed controls:
97
104
  definitions. On OpenCode this is typically 5–10k tokens before any
98
105
  harness content loads.
99
106
  2. **Your repo's docs, injected eagerly** — the context delivery
100
- (plugin on OpenCode, SessionStart hook on Claude Code / Bob, `sessionStart`
101
- hook on a global Copilot install; a project-scope Copilot install has no
102
- hooks, so it reads docs on demand instead) discovers and
107
+ (plugin on OpenCode, SessionStart hook on Claude Code / Bob / OpenClaude) discovers and
103
108
  injects `README.md`, `CONTRIBUTING.md`, and files under `docs/`, up to the
104
109
  48 KB budget (≈12k tokens). A doc-heavy repo fills it.
105
110
  3. **Wiki eager entries** plus the lazy listing of the rest, if a wiki is
@@ -11,7 +11,7 @@ Claude Code has no `instructions` array and no JS plugin dir — the harness rea
11
11
  - **Context injection** — `SessionStart` (startup, clear, resume) runs `geneseed-hook context`: auto-discovers the repo's docs by convention and injects them before your first turn, plus your machine wiki. It honours the same `GENESEED_CONTEXT` manifest as the OpenCode context plugin.
12
12
  - **Git gate** — `PreToolUse` on Bash runs `geneseed-hook git-gate`: a `git commit` or `git push` anywhere in the command line — a compound one-liner and a `-C <path>` form included — asks first, at the tool boundary and before the shell runs it (**Doctrine process 5**). It is the one hook that rides a doctrine pack: an install built without **process** never gets this group, because a boundary that keeps asking for a rule the install did not adopt is a gate arguing with its own harness.
13
13
  - **Rule gate** — `PreToolUse` on the write tools runs `geneseed-hook rule-gate`: a write to `user-rules.md` or to a memory file asks first, because whether something you want kept is a standing rule or a durable fact is *your* call, settled through the [rule skill](#/docs/skills) (**Doctrine process 1**). Ordinary edits are untouched.
14
- - **Tool gate** — `geneseed-hook tool-gate` is the git gate and the rule gate fused behind one command, for hosts whose hook config has no per-tool matcher (Copilot, Bob). Claude Code matches per tool, so its `settings.json` wires the two gates above instead.
14
+ - **Tool gate** — `geneseed-hook tool-gate` is the git gate and the rule gate fused behind one command, for hosts whose hook config has no per-tool matcher (Bob). Claude Code matches per tool, so its `settings.json` wires the two gates above instead.
15
15
  - **Learn** — `Stop` and `SubagentStop` run `geneseed-hook learn`: distils durable memories into the install's `memory/` store at session end; a subagent's stop routes to the per-agent lesson path (`memory/agents/<name>.md`).
16
16
 
17
17
  ### Where they live