geneseed 4.10.0 β†’ 4.15.1

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 (147) hide show
  1. package/CHANGELOG.md +106 -0
  2. package/README.md +5 -4
  3. package/SHIPPED.md +1 -1
  4. package/adapters/opencode/plugins/geneseed-guard.js +16 -1
  5. package/adapters/opencode/plugins/geneseed-learn.js +28 -12
  6. package/adapters/opencode/plugins/geneseed-workflow.js +19 -2
  7. package/docs/concepts/kits.md +14 -2
  8. package/docs/concepts/skills.md +1 -1
  9. package/docs/extending.md +3 -4
  10. package/docs/guides/install-bob.md +3 -1
  11. package/docs/guides/run-anywhere.md +2 -2
  12. package/docs/guides/upgrade.md +2 -2
  13. package/docs/reference/troubleshoot-install.md +1 -1
  14. package/docs/web-ui.md +6 -1
  15. package/harness.config.json +1 -1
  16. package/js/build/emit-claude.mjs +4 -2
  17. package/js/build/stubs.mjs +13 -0
  18. package/js/hosts/link.mjs +88 -1
  19. package/js/inspect/checks-build.mjs +8 -2
  20. package/js/inspect/cost.mjs +1 -1
  21. package/js/inspect/diff.mjs +53 -7
  22. package/js/inspect/inventory.mjs +1 -0
  23. package/js/lib/prompt.mjs +19 -2
  24. package/js/maintain/setup.mjs +92 -28
  25. package/js/maintain/update.mjs +2 -2
  26. package/js/web/actions.mjs +8 -0
  27. package/js/web/api.mjs +39 -17
  28. package/js/web/catalog.mjs +17 -2
  29. package/js/web/handler.mjs +1 -0
  30. package/js/web/server.mjs +11 -5
  31. package/js/web/state.mjs +38 -3
  32. package/package.json +1 -1
  33. package/registry.json +28 -0
  34. package/src/AGENT.md.tmpl +5 -5
  35. package/src/agents/_self-improvement.md +11 -0
  36. package/src/agents/_template.md +1 -8
  37. package/src/agents/advocate.md +1 -8
  38. package/src/agents/architect.md +1 -8
  39. package/src/agents/developer.md +1 -8
  40. package/src/agents/devops-engineer.md +1 -9
  41. package/src/agents/docker-expert.md +1 -9
  42. package/src/agents/docs.md +1 -8
  43. package/src/agents/empiricist.md +1 -8
  44. package/src/agents/explorer.md +1 -8
  45. package/src/agents/framer.md +1 -8
  46. package/src/agents/historian.md +1 -8
  47. package/src/agents/kubernetes-specialist.md +1 -9
  48. package/src/agents/memory-curator.md +1 -8
  49. package/src/agents/operator.md +1 -8
  50. package/src/agents/performance.md +1 -8
  51. package/src/agents/pragmatist.md +1 -8
  52. package/src/agents/react-engineer.md +38 -0
  53. package/src/agents/react-reviewer.md +42 -0
  54. package/src/agents/researcher.md +5 -10
  55. package/src/agents/reviewer.md +1 -8
  56. package/src/agents/security.md +1 -8
  57. package/src/agents/skeptic.md +1 -8
  58. package/src/agents/spring-boot-engineer.md +1 -9
  59. package/src/agents/spring-reviewer.md +1 -9
  60. package/src/agents/spring-security.md +1 -9
  61. package/src/agents/steward.md +1 -8
  62. package/src/agents/tester.md +1 -8
  63. package/src/agents/user-advocate.md +1 -8
  64. package/src/agents/visionary.md +1 -8
  65. package/src/doctrines/comms.md +21 -0
  66. package/src/kits/react/rules.md +13 -0
  67. package/src/kits/react.json +18 -0
  68. package/src/licenses/everything-claude-code.txt +21 -0
  69. package/src/skills/_self-improvement.md +22 -5
  70. package/src/skills/brainstorm.md +7 -2
  71. package/src/skills/codebase-design.md +6 -2
  72. package/src/skills/debug.md +1 -1
  73. package/src/skills/develop.md +4 -2
  74. package/src/skills/handoff.md +1 -1
  75. package/src/skills/parallel-agents.md +3 -1
  76. package/src/skills/plan.md +5 -2
  77. package/src/skills/prototype.md +4 -2
  78. package/src/skills/react/a11y.md +33 -0
  79. package/src/skills/react/vite.md +35 -0
  80. package/src/skills/react/webpack.md +40 -0
  81. package/src/skills/react-testing.md +68 -0
  82. package/src/skills/react.md +63 -0
  83. package/src/skills/research.md +4 -2
  84. package/src/skills/rule.md +4 -2
  85. package/src/skills/ship.md +6 -4
  86. package/src/skills/skill-forge.md +10 -5
  87. package/src/skills/wayfinder.md +6 -2
  88. package/src/skills/wiki.md +18 -5
  89. package/src/upstreams.json +7 -0
  90. package/themes/_TEMPLATE.json +5 -0
  91. package/themes/biker.json +5 -0
  92. package/themes/commentator.json +5 -0
  93. package/themes/cyberpunk.json +5 -0
  94. package/themes/gamer.json +5 -0
  95. package/themes/imperial.json +5 -0
  96. package/themes/joker.json +5 -0
  97. package/themes/marvin.json +5 -0
  98. package/themes/mean.json +5 -0
  99. package/themes/military.json +5 -0
  100. package/themes/neutral.json +5 -0
  101. package/themes/pirate.json +5 -0
  102. package/themes/sports.json +5 -0
  103. package/themes/verstappen.json +5 -0
  104. package/themes/wizard.json +5 -0
  105. package/web/dist/assets/Activity-M5qj6CxJ.js +1 -0
  106. package/web/dist/assets/ActivityDetail-DVCdNy73.js +1 -0
  107. package/web/dist/assets/Dashboard-B1rpgTz-.js +2 -0
  108. package/web/dist/assets/{Docs-DLVckkew.js β†’ Docs-D-EixVuX.js} +3 -3
  109. package/web/dist/assets/FilterInput-CZREvrjX.js +1 -0
  110. package/web/dist/assets/GreenhouseView-BvA4t12P.js +2 -0
  111. package/web/dist/assets/Installs-DP4WjTpD.js +3 -0
  112. package/web/dist/assets/JournalView-hf2eO133.js +1 -0
  113. package/web/dist/assets/KitApply-aORiqjFC.js +1 -0
  114. package/web/dist/assets/Kits-DpIEozdv.js +1 -0
  115. package/web/dist/assets/{Laws-BkKnZOBI.js β†’ Laws-cM_4CG9i.js} +2 -2
  116. package/web/dist/assets/Library-I1zEH3UW.js +1 -0
  117. package/web/dist/assets/Loops-CDa_mxP9.js +2 -0
  118. package/web/dist/assets/{Markdown-iHvBrpRN.js β†’ Markdown-zaXXXHz9.js} +13 -13
  119. package/web/dist/assets/OperatorHudView-CMf1DQMB.js +2 -0
  120. package/web/dist/assets/Personal-BqU9Pzt1.js +1 -0
  121. package/web/dist/assets/Tabs-JZ2FQBcz.js +1 -0
  122. package/web/dist/assets/activity-Jw8XcPiP.js +1 -0
  123. package/web/dist/assets/{drawable-CgYi0Dtg.js β†’ drawable-svc6-2Gp.js} +1 -1
  124. package/web/dist/assets/index-CZFrNe4N.js +2 -0
  125. package/web/dist/assets/{index-BCJz4_8C.css β†’ index-jYlWihN-.css} +1 -1
  126. package/web/dist/assets/{react-BOF6yL40.js β†’ react-DlYQp10C.js} +1 -1
  127. package/web/dist/assets/rolldown-runtime-hePW80VL.js +1 -0
  128. package/web/dist/assets/sections-ChwaobfW.js +1 -0
  129. package/web/dist/assets/usePoll-bDFN-Hr6.js +1 -0
  130. package/web/dist/index.html +5 -4
  131. package/web/src/pages/Laws.jsx +5 -0
  132. package/web/dist/assets/Activity-BjyJaf8e.js +0 -1
  133. package/web/dist/assets/ActivityDetail-Bo9nRDNV.js +0 -1
  134. package/web/dist/assets/Dashboard-BQJGU7vE.js +0 -2
  135. package/web/dist/assets/FilterInput-zLFXoSt6.js +0 -1
  136. package/web/dist/assets/GreenhouseView--DML7CW3.js +0 -2
  137. package/web/dist/assets/Installs-CxCiln1F.js +0 -3
  138. package/web/dist/assets/JournalView-ymgZleHi.js +0 -1
  139. package/web/dist/assets/Library-C8ercIZv.js +0 -1
  140. package/web/dist/assets/Loops-C95zhbFl.js +0 -2
  141. package/web/dist/assets/OperatorHudView-B9qwc3w3.js +0 -2
  142. package/web/dist/assets/Personal-DyR72AF-.js +0 -1
  143. package/web/dist/assets/Tabs-ChCr_HqV.js +0 -1
  144. package/web/dist/assets/activity-DvPxoS4Y.js +0 -1
  145. package/web/dist/assets/index-B32EvfDT.js +0 -2
  146. package/web/dist/assets/sections-BET3c1WT.js +0 -1
  147. package/web/dist/assets/usePoll-NSTzLOF4.js +0 -1
package/CHANGELOG.md CHANGED
@@ -8,6 +8,112 @@ label. For the capability ↔ spec map, see [SHIPPED.md](SHIPPED.md).
8
8
 
9
9
  ## [Unreleased]
10
10
 
11
+ ## [4.15.1] β€” 2026-10-23
12
+
13
+ Patch: two host fixes. The first npm release since 4.14.0, so it also carries 4.15.0's comms 4 doctrine.
14
+
15
+ ### Upgrade notes
16
+ - Run `geneseed rebuild-all`; nothing changes on a machine until something re-emits.
17
+
18
+ ### Fixed
19
+ - OpenCode 1.x: the guard and learn plugins no longer write `[geneseed-guard] …` / `[geneseed-learn] …` lines in red over the TUI input box. Their messages now go to OpenCode's own log (`client.app.log`, service `geneseed-guard` / `geneseed-learn`). OpenCode 2 and a refused log call still use stderr. The workflow plugin's one-line load banner stays on stderr.
20
+ - IBM Bob: the first reply now starts with the theme's readiness line. Both Bob carriers (global `rules/geneseed.md`, the project's `AGENTS.md` block) open with a short first-reply override; without it, Bob's own greeting won. A bare "hi" still gets Bob's fixed welcome. Run `geneseed rebuild-all` to pick it up.
21
+
22
+ ## [4.15.0] β€” 2026-10-22
23
+
24
+ Minor: a new comms doctrine rule makes every generated agent write its prose in ASD-STE100 Simplified Technical English.
25
+
26
+ ### Upgrade notes
27
+ - Run `geneseed rebuild-all` to get the new rule; nothing changes on a machine until something re-emits. To keep the old behaviour on one install, rebuild it with `--exclude-rules "comms 4"`.
28
+
29
+ ### Added
30
+ - **Doctrine comms 4, Simplified Technical English.** Every generated agent writes the prose of its replies and reports in ASD-STE100: one topic per sentence (at most 20 words in an instruction, 25 in a description), imperative steps with one action each and the condition first, the active voice, no -ing forms, no dropped articles, and one word per meaning. Code, commands, paths, identifiers and quoted output stay as they are. STE is an English standard and the ontology imposes no language, so an answer in another language keeps that language and the same sentence rules; the theme keeps its voice. It is in the toggleable comms pack, not a law, per DESIGN.md Decision 7: `--exclude-rules "comms 4"` turns it off. The carrier ceilings rise by 1 003 characters (full) and 472 (lean). Run `geneseed rebuild-all` to get it.
31
+
32
+ ## [4.14.0] β€” 2026-10-22
33
+
34
+ Minor: the React kit supports webpack projects as well as Vite.
35
+
36
+ ### Upgrade notes
37
+ - Run `geneseed rebuild-all` to get the new kit text; nothing changes on a machine until something re-emits.
38
+
39
+ ### Changed
40
+ - **The `react` kit supports webpack as well as Vite** (#368). The `react` skill reads the bundler from `package.json` and loads its side file: the new `react/webpack.md` (config, client-side routing with `historyApiFallback` and `publicPath`, `DefinePlugin` env values, a webpack build-failure table) or `react/vite.md`. The kit rules, both agents, the Jest configuration table in `react-testing` and every theme's descriptions now name both bundlers.
41
+
42
+ ## [4.13.0] β€” 2026-10-21
43
+
44
+ Minor: sharper ported skills, a wiki that keeps its history, and self-improvement notes that carry their evidence.
45
+
46
+ ### Upgrade notes
47
+ - Run `geneseed rebuild-all` to get the new skill and agent text; nothing changes on a machine until something re-emits. Notes already in `notebook/skill-notes/` and `notebook/agent-notes/` keep working as written; only new lines take the new format.
48
+
49
+ ### Changed
50
+ - **Self-improvement notes carry their evidence and their scope** (#366). A note is now one line, `- [skill|general] <correction> β€” seen: <what happened, against what was expected> (<date>)`, and an agent's `spec-feedback:` line takes the same shape. `seen:` is what a correction is judged by when `geneseed diff` hands it back for folding into `src/`, and pruning drops the lines without one first. `general` marks a correction that would fix other skills or agents too, so it belongs in a law, doctrine or memory rather than one file. The `geneseed diff` report explains both markers. Agents now share one self-improvement footer (`src/agents/_self-improvement.md`) instead of 29 copies; rendered agents differ only by the new wording.
51
+ - **The wiki writes history, not the present** (#365). Wiki claims are dated, code claims cite `owner/repo@commit`, and a correction supersedes a claim rather than rewriting it. A new report-only lint pass lists contradictions, orphans and overtaken claims without restructuring the wiki. Adapted from mattpocock/skills' chief-of-staff.
52
+ - **The mattpocock ports are sharpened against upstream `5beb35b`** (#365):
53
+ - `parallel-agents`: each slice branches off the integration tip when it is dispatched and merges the tip back before returning, so a later slice no longer misses its blocker's merged work. A whole-branch review follows.
54
+ - `codebase-design`: an interface is designed twice, and an ADR is not silently reopened.
55
+ - `research` and the `researcher` agent: one read in the source that owns a claim stands on its own; any other claim still needs two sources.
56
+ - `ship`: the docs check moves before the push it gates.
57
+ - `plan`, `wayfinder`, `prototype`, `develop`, `debug`, `rule`, `brainstorm`, `handoff` and `skill-forge` get smaller fixes: slice sizing, ticket graduation, mocking only at boundaries, checking for an existing guardrail before proposing one, and trigger pruning.
58
+ - New credits on `parallel-agents`, `skill-forge`, `brainstorm` and `wiki`.
59
+
60
+ ## [4.12.0] β€” 2026-10-21
61
+
62
+ Minor: a second opt-in kit, `react`, and the setup wizard asks about each kit on its own.
63
+
64
+ ### Upgrade notes
65
+ - Nothing to rebuild unless you want the new kit. Default installs are unchanged: no kit is on. To turn it on, run `geneseed build --emit <target> --kits react` (or `--kits react,spring-boot` for both), or use **Installs β†’ Kits** in the web console.
66
+
67
+ ### Added
68
+ - **The `react` kit** (#362), for React 18 or 19 apps built with Vite, in TypeScript or JavaScript, tested with Jest and React Testing Library. Skills `react` (with side files for Vite and accessibility) and `react-testing`; agents `react-engineer` and `react-reviewer` (read-only); kit rules, and a banned-API gate that keeps `ReactDOM.render(`, `findDOMNode`, Enzyme, `react-test-renderer` and `@testing-library/react-hooks` out of kit files. Adapted from affaan-m/everything-claude-code (MIT), rewritten and condensed for Vite and Jest, with no Server Components material.
69
+
70
+ ### Changed
71
+ - **The setup wizard asks one yes/no per kit** (#362). A single pick could not turn on two kits at once.
72
+
73
+ ### Repository
74
+ Not in the package; how Geneseed itself is built and checked.
75
+ - CI's golden cells run as two parallel jobs per platform, emit and CLI (#361). On Windows that leg drops from about 7 minutes in sequence to about 4. The unit suite runs at `--test-concurrency=8` on Linux and in the publish job; Windows keeps the default, where the flag bought nothing. If branch protection names the old `node-cells (<os>)` checks, they now report as `node-cells (<os>, emit)` and `node-cells (<os>, cli)`.
76
+ - The unit suite drops three repeated full-cost runs (#363): two update-flow arms use a doctor stand-in (the real rejection and exact rollback stay in `update_git`), the packaging test counts themes in process instead of a second `doctor --all`, and `--no-deletion-gate` replays only the 67 real-loss rows. 151 s to 139 s locally, same 2012 tests.
77
+
78
+ ## [4.11.2] β€” 2026-10-21
79
+
80
+ Patch: a clone install on macOS or Linux puts the `geneseed` command on your PATH.
81
+
82
+ ### Upgrade notes
83
+ - Nothing to rebuild. If `geneseed` is not found in a new terminal, run `./geneseed link` from your clone and accept the offer to add `~/.local/bin` to your shell's startup file.
84
+
85
+ ### Fixed
86
+ - **A clone install puts `geneseed` on your PATH on macOS and Linux** (#359). `./install` never linked the command, and `geneseed link` wrote it to `~/.local/bin`, which macOS zsh does not search, so `geneseed` was not found (reported 2026-10). `./install` now runs `link` when `geneseed` is not found yet, and `link` offers, in a terminal, to add the folder to your shell's startup file (`~/.zshrc`, or `~/.bashrc` / `~/.bash_profile` for bash). It appends one marked block, never twice; `geneseed unlink` removes it. Outside a terminal it prints the line to add, as before.
87
+
88
+ ## [4.11.1] β€” 2026-10-21
89
+
90
+ Patch: the web console on a machine with only IBM Bob (or any host but OpenCode): it opens on the install you have, the first-deploy form asks a per-repo mode for its folder, and the doctor stops reading a misplaced project install as a broken bundle.
91
+
92
+ ### Upgrade notes
93
+ - Restart the console after updating (`geneseed web restart`) so it serves the rebuilt UI. If a per-repo install landed in `Harness/` inside your Geneseed clone, remove it with `./geneseed uninstall --target Harness --yes`, then delete `Harness/`.
94
+
95
+ ### Fixed
96
+ - **The web console works on a machine without OpenCode** (#357). It always opened on the OpenCode global dir, so with only IBM Bob installed the Overview showed the first-deploy form over a working `~/.bob`, and nothing could re-point it (the harness selector hides itself below two installs). When nothing is deployed where it looks, the console now shows the first active install it finds, a global before a project, and follows a first deploy to where it landed.
97
+ - **The first-deploy form asks a project mode for its folder** (#357). Picking a per-repo mode (`bob`, `claude`, `opencode`, `openclaude`) sent a Build with no folder, so the files landed in `Harness/` inside the Geneseed clone, where the host never looks. The form now asks for the folder (typed or Browse…) and deploys there; Build refuses a per-repo mode it has no folder for; the portable `files` bundle is left to the CLI. To remove an install misplaced this way, run `./geneseed uninstall --target Harness --yes` in the clone, then delete `Harness/`.
98
+ - **The doctor's committed-bundle check no longer reads a Claude, Bob or OpenClaude project install as a broken bundle** (#357). Such a tree has a `.bob/`-style data dir, not the bundle layout, so every file read "missing" (178 lines on the reported machine) and no rebuild could clear them.
99
+
100
+ ## [4.11.0] β€” 2026-10-21
101
+
102
+ Minor: the self-improvement loops write to notebook notes instead of the installed skill or agent file, the web console gains a Kits section, and `./install` waits for your answers and finds tools installed for one user.
103
+
104
+ ### Upgrade notes
105
+ - Run `geneseed rebuild-all` once after updating so installed skills, agents and AGENT.md carry the new self-improvement footer. Lessons the loops wrote into installed files before this release are still exported by `upgrade` into `improvements/`, as before.
106
+
107
+ ### Added
108
+ - **Web console: Kits section** (#353). A top-level Kits page between Library and Loops: a list and a detail page per kit (rules, banned APIs, members linked to the Library, upstream pin and compare link, a switch per install that rebuilds through the install job). Installs β†’ Kits shares its staging and Apply control. `GET /api/kits` now carries rules, word budget, banned APIs and credits, and the Library shows a `kit:` badge on kit members.
109
+
110
+ ### Changed
111
+ - **Self-improvement writes to a sidecar, not the skill** (#354). The skill and agent loops used to edit the rendered file in place, which the doctor reported as stale and the next rebuild erased. They now write corrections to `notebook/skill-notes/<name>.md` and `notebook/agent-notes/<name>.md` (seed-once, agent-owned, never overwritten), and read them back before the skill runs or the agent is dispatched. `geneseed diff` lists the notes and `--out` exports them for back-porting into `src/`. AGENT.md names the notes paths, so the carrier ceilings rise by exactly that text (full 62_263, lean 39_156).
112
+
113
+ ### Fixed
114
+ - **Setup's prompts no longer answer themselves in a real terminal** (#356). Reading `process.stdin` puts a terminal's input in non-blocking mode, and the line reader took the resulting `EAGAIN` for end of input: "Continue without one? (y/N)" printed and answered N at once, so `./install` stopped before anyone could type, and every other wizard question silently took its default. The reader now waits for the keypress.
115
+ - **A tool installed for one user is found** (#356). Setup looked only on PATH, so an IBM Bob installed under the user's profile read as missing. It now also checks `~/.local/bin`, `~/bin`, each tool's own installer dir (`~/.opencode/bin`, `~/.claude/local`), the per-user npm prefix on Windows, and Bob's desktop app folder (`%LOCALAPPDATA%\Programs` on Windows, `/Applications` and `~/Applications` on macOS); a tool found there is listed with its path. When nothing is found, setup asks for the tool's path before offering to stop. The double-clickable `install.command` now waits for Enter before its window can close, as `install.cmd` already did.
116
+
11
117
  ## [4.10.0] β€” 2026-10-20
12
118
 
13
119
  Minor: opt-in kits (and a first one, `spring-boot`), credits for adapted content, a weekly upstream-drift check, and a web Kits tab.
package/README.md CHANGED
@@ -13,7 +13,7 @@
13
13
  [![Themes](https://img.shields.io/badge/themes-14-9cf)](themes/)
14
14
  [![Skills](https://img.shields.io/badge/skills-47-blueviolet)](src/skills/)
15
15
  [![Agents](https://img.shields.io/badge/agents-20-orange)](src/agents/)
16
- [![Laws and doctrines](https://img.shields.io/badge/laws-9%20%2B%2029%20doctrines-critical)](src/doctrines/)
16
+ [![Laws and doctrines](https://img.shields.io/badge/laws-9%20%2B%2030%20doctrines-critical)](src/doctrines/)
17
17
  [![Plugins](https://img.shields.io/badge/plugins-7-teal)](adapters/opencode/plugins/)
18
18
  [![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)
19
19
 
@@ -157,7 +157,7 @@ geneseed web stop # stop the daemon
157
157
  geneseed web status # is it running, and where
158
158
  ```
159
159
 
160
- The sidebar has six pages: **Overview** (what's deployed, health, recent jobs), **Constitution** (the rules and doctrine switches), **Library** (skills, agents, the wiki), **Personal** (your rules, profile, memory, notebook), **Installs** (hosts, local edits, doctor, server) and **Docs** β€” this documentation, opening on the Understand track, with a map of what Geneseed put on your machine.
160
+ The sidebar has eight pages: **Overview** (what's deployed, health, recent jobs), **Constitution** (the rules and doctrine switches), **Library** (skills, agents, the wiki), **Kits** (opt-in stack bundles), **Loops** (the loop catalogue), **Personal** (your rules, profile, memory, notebook), **Installs** (hosts, local edits, doctor, server) and **Docs** β€” this documentation, opening on the Understand track, with a map of what Geneseed put on your machine.
161
161
 
162
162
  It binds to `127.0.0.1` only and runs entirely offline β€” no npm needed at runtime; the UI build ships in `web/dist/`. Mutating actions run in the background and report back as toasts (fire-and-notify), guarded by a per-session token so other sites can't trigger them. A global **Spotlight** search in the topbar jumps to any agent, skill, rule, doc, or MCP server. Rebuild the UI after changing anything under `web/src/` with `cd web && npm install && npm run build`. If `web/dist/` is missing (fresh clone, never built), `geneseed web` offers to run that build for you β€” answer `Y` and it installs, builds, and starts the server; in non-interactive shells it prints the manual recipe instead.
163
163
 
@@ -334,7 +334,7 @@ geneseed rebuild-all # re-render every registered install in its own theme + m
334
334
  ./geneseed upgrade # just the content refresh (remembers theme + emit mode)
335
335
  ```
336
336
 
337
- **Local edits survive.** If the agent refined its deployed agent/skill files in place, an upgrade exports that drift to an `improvements/` file inside the install before overwriting. Details: [Upgrade](docs/guides/upgrade.md).
337
+ **Local edits survive.** The self-improvement loops write to notes under `notebook/`, which no rebuild touches. If you or the agent edited deployed agent/skill files in place anyway, an upgrade exports that drift to an `improvements/` file inside the install before overwriting. Details: [Upgrade](docs/guides/upgrade.md).
338
338
 
339
339
  ## πŸ“š Documentation
340
340
 
@@ -373,12 +373,13 @@ Some skills and agents are adapted from other open-source skill collections, und
373
373
 
374
374
  - `daydream` β€” [glebis/claude-skills](https://github.com/glebis/claude-skills) by Gleb Kalinin (MIT): the vendored `daydream` skill.
375
375
  - `react-view-transitions` β€” [vercel-labs/agent-skills](https://github.com/vercel-labs/agent-skills) by Vercel Engineering (MIT): the vendored `react-view-transitions` skill.
376
- - `mattpocock-skills` β€” [mattpocock/skills](https://github.com/mattpocock/skills) by Matt Pocock (MIT): the vocabulary and procedures behind codebase-design, wayfinder, prototype, develop, handoff and research, the spec pass of geneseed-code-review, the question rounds of brainstorm, the slicing of plan, and the reproduction step of debug.
376
+ - `mattpocock-skills` β€” [mattpocock/skills](https://github.com/mattpocock/skills) by Matt Pocock (MIT): the vocabulary and procedures behind codebase-design, wayfinder, prototype, develop, handoff and research, the spec pass of geneseed-code-review, the question rounds and questionnaire of brainstorm, the slicing of plan, the reproduction step of debug, the integration-branch rules of parallel-agents, the trigger-pruning of skill-forge, and the dated-history rule of wiki.
377
377
  - `mattpocock-skills-frozen` β€” [mattpocock/skills](https://github.com/mattpocock/skills) by Matt Pocock (MIT), pinned at 391a2701, the last commit carrying `resolving-merge-conflicts` (deleted upstream since): the merge-conflict step of git-history, from a skill upstream has since deleted, so the weekly drift check skips it.
378
378
  - `mattpocock-skills-2509` β€” [mattpocock/skills](https://github.com/mattpocock/skills) by Matt Pocock (MIT), a second key for the same repo, at the same pin as `mattpocock-skills` today (5beb35b0): the PR body of ship and the guardrail clause of rule.
379
379
  - `superpowers` β€” [obra/superpowers](https://github.com/obra/superpowers) by Jesse Vincent (MIT): the core of debug, the size step and builder check of brainstorm, the plan rules of plan, the reviewer brief behind geneseed-code-review and the reviewer agent, the review-handling steps of review-response, and the ruling format of pipeline and parallel-agents.
380
380
  - `vibe-wise` β€” [nykooi1/vibe-wise](https://github.com/nykooi1/vibe-wise) by Noah Kim (MIT): the state file, levels and checkpoints of learn-mode.
381
381
  - `piomin-spring-boot` β€” [piomin/claude-ai-spring-boot](https://github.com/piomin/claude-ai-spring-boot) by Piotr MiΕ„kowski (Apache-2.0): the Spring Boot kit's skills and agents, rewritten and condensed for Boot 4.
382
+ - `everything-claude-code` β€” [affaan-m/everything-claude-code](https://github.com/affaan-m/everything-claude-code) by Affaan Mustafa (MIT): the React kit's skills and agents, rewritten and condensed for Vite and Jest.
382
383
 
383
384
  ## πŸ“„ License
384
385
 
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: **4.10.0**.
23
+ > string. Current label: **4.15.1**.
24
24
 
25
25
  ## Capabilities
26
26
 
@@ -153,7 +153,21 @@ const gateOff = (marker) => new RegExp(`^${marker}:[ \\t]*off[ \\t]*\\r?$`, "m")
153
153
  const DELETION_GATE_OFF = gateOff("Deletion gate")
154
154
  const SECRETS_GATE_OFF = gateOff("Secrets gate")
155
155
 
156
- function log(msg) { console.error(`[geneseed-guard] ${msg}`) }
156
+ // OpenCode 1.x paints a plugin's stderr over its TUI input box (in red); its own log API
157
+ // writes to the log file instead. The V1 entry sets LOG_CLIENT; V2 and tests have no
158
+ // client and keep stderr, as does a refused log call, so no line is lost. Never throws:
159
+ // a log line must not break a tool call.
160
+ let LOG_CLIENT = null
161
+ function say(msg, level = "warn") {
162
+ try {
163
+ if (LOG_CLIENT?.app?.log) {
164
+ Promise.resolve(LOG_CLIENT.app.log({ body: { service: "geneseed-guard", level, message: msg } })).catch(() => console.error(`[geneseed-guard] ${msg}`))
165
+ return
166
+ }
167
+ } catch { /* fall through to stderr */ }
168
+ console.error(`[geneseed-guard] ${msg}`)
169
+ }
170
+ const log = (msg) => say(msg)
157
171
 
158
172
  // ---- the gate ledger ------------------------------------------------------------
159
173
  // The twin of `ledger()` in js/hosts/hooks.mjs: one JSON line per BLOCK into
@@ -1369,6 +1383,7 @@ async function recordUse(tool, args) {
1369
1383
  }
1370
1384
 
1371
1385
  export const GeneseedGuard = async (ctx) => {
1386
+ if (ctx?.client) LOG_CLIENT = ctx.client
1372
1387
  // The session's working directory, the same resolution the context plugin uses.
1373
1388
  const root = () => ctx?.worktree || ctx?.directory || process.cwd()
1374
1389
  return {
@@ -38,6 +38,21 @@ import * as path from "node:path"
38
38
  import { fileURLToPath } from "node:url"
39
39
  import { homedir } from "node:os"
40
40
 
41
+ // OpenCode 1.x paints a plugin's stderr over its TUI input box (in red); its own log API
42
+ // writes to the log file instead. The V1 entry sets LOG_CLIENT; V2 and tests have no
43
+ // client and keep stderr, as does a refused log call, so no line is lost. Never throws:
44
+ // a log line must not break a tool call.
45
+ let LOG_CLIENT = null
46
+ function say(msg, level = "warn") {
47
+ try {
48
+ if (LOG_CLIENT?.app?.log) {
49
+ Promise.resolve(LOG_CLIENT.app.log({ body: { service: "geneseed-learn", level, message: msg } })).catch(() => console.error(`[geneseed-learn] ${msg}`))
50
+ return
51
+ }
52
+ } catch { /* fall through to stderr */ }
53
+ console.error(`[geneseed-learn] ${msg}`)
54
+ }
55
+
41
56
  // The plugin's own directory. In the global install the layout is
42
57
  // <cfg>/plugins/geneseed-learn.js beside <cfg>/memory, so the store can be found
43
58
  // relative to this file β€” no manual `export GENESEED_HARNESS` needed.
@@ -471,17 +486,18 @@ async function storeDistil(output, { isChild, memDir, agentName, existing }) {
471
486
  const lesson = output.trim().split("\n")[0].replace(/^[-*]\s*/, "").trim()
472
487
  if (lesson.length < 10 || lesson.length > 300) return // junk / truncation guard
473
488
  const f = await appendAgentLesson(memDir, agentName, lesson)
474
- console.error(`[geneseed-learn] agent lesson -> ${f}`)
489
+ say(`agent lesson -> ${f}`, "info")
475
490
  return
476
491
  }
477
492
  const res = await writeMemories(output, memDir, existing)
478
493
  for (const [verb, slugs] of [["wrote", res.created], ["updated", res.updated], ["archived", res.archived]]) {
479
- if (slugs.length) console.error(`[geneseed-learn] ${verb} ${slugs.length} memory file(s): ${slugs.join(", ")}`)
494
+ if (slugs.length) say(`${verb} ${slugs.length} memory file(s): ${slugs.join(", ")}`, "info")
480
495
  }
481
496
  }
482
497
 
483
498
  export const GeneseedLearn = async (ctx) => {
484
499
  const { client } = ctx ?? {}
500
+ if (client) LOG_CLIENT = client
485
501
  const ours = new Set() // throwaway distil sessions β€” never mine our own output
486
502
  const timers = new Map() // sid -> debounce timer, re-armed on each idle
487
503
  const inFlight = new Set() // sid currently being distilled (guards against overlap)
@@ -510,8 +526,8 @@ export const GeneseedLearn = async (ctx) => {
510
526
  if (!memDir) {
511
527
  if (!warnedNoDir) {
512
528
  warnedNoDir = true
513
- console.error(
514
- "[geneseed-learn] no memory dir β€” set $GENESEED_HARNESS or $GENESEED_MEMORY."
529
+ say(
530
+ "no memory dir β€” set $GENESEED_HARNESS or $GENESEED_MEMORY."
515
531
  )
516
532
  }
517
533
  return
@@ -524,8 +540,8 @@ export const GeneseedLearn = async (ctx) => {
524
540
  notes = notes.slice(-MAX_NOTES_CHARS)
525
541
  model = model ?? envModel()
526
542
  if (!model) {
527
- console.error(
528
- "[geneseed-learn] could not determine a model β€” set $GENESEED_MODEL=provider/model."
543
+ say(
544
+ "could not determine a model β€” set $GENESEED_MODEL=provider/model."
529
545
  )
530
546
  return
531
547
  }
@@ -540,7 +556,7 @@ export const GeneseedLearn = async (ctx) => {
540
556
  const newId = session?.id ?? session?.data?.id
541
557
  if (!newId) {
542
558
  // Prompting with {id: undefined} would 404 silently on every idle.
543
- console.error("[geneseed-learn] session.create returned no id β€” skipping this distil.")
559
+ say("session.create returned no id β€” skipping this distil.")
544
560
  return
545
561
  }
546
562
  ours.add(newId)
@@ -558,7 +574,7 @@ export const GeneseedLearn = async (ctx) => {
558
574
  await storeDistil(output, { isChild, memDir, agentName, existing })
559
575
  } catch (err) {
560
576
  // Never break the session over a memory write.
561
- console.error(`[geneseed-learn] skipped: ${err?.message ?? err}`)
577
+ say(`skipped: ${err?.message ?? err}`)
562
578
  } finally {
563
579
  inFlight.delete(sid)
564
580
  }
@@ -647,7 +663,7 @@ async function setupV2(ctx) {
647
663
  if (!memDir) {
648
664
  if (!warnedNoDir) {
649
665
  warnedNoDir = true
650
- console.error("[geneseed-learn] no memory dir β€” set $GENESEED_HARNESS or $GENESEED_MEMORY.")
666
+ say("no memory dir β€” set $GENESEED_HARNESS or $GENESEED_MEMORY.")
651
667
  }
652
668
  return
653
669
  }
@@ -660,7 +676,7 @@ async function setupV2(ctx) {
660
676
  model = env ? { providerID: env.providerID, id: env.modelID } : null
661
677
  }
662
678
  if (!model) {
663
- console.error("[geneseed-learn] could not determine a model β€” set $GENESEED_MODEL=provider/model.")
679
+ say("could not determine a model β€” set $GENESEED_MODEL=provider/model.")
664
680
  return
665
681
  }
666
682
 
@@ -673,7 +689,7 @@ async function setupV2(ctx) {
673
689
  })
674
690
  await storeDistil(String(reply?.text ?? ""), { isChild, memDir, agentName, existing })
675
691
  } catch (err) {
676
- console.error(`[geneseed-learn] skipped: ${err?.message ?? err}`)
692
+ say(`skipped: ${err?.message ?? err}`)
677
693
  } finally {
678
694
  inFlight.delete(sid)
679
695
  }
@@ -695,7 +711,7 @@ async function setupV2(ctx) {
695
711
  if (prev) clearTimeout(prev)
696
712
  timers.set(sid, setTimeout(() => { timers.delete(sid); runDistill(sid) }, DEBOUNCE_MS))
697
713
  }
698
- })().catch((err) => console.error(`[geneseed-learn] event stream ended: ${err?.message ?? err}`))
714
+ })().catch((err) => say(`event stream ended: ${err?.message ?? err}`))
699
715
  return () => {
700
716
  controller.abort()
701
717
  for (const t of timers.values()) clearTimeout(t)
@@ -25,7 +25,21 @@ import * as path from "node:path"
25
25
  import { fileURLToPath, pathToFileURL } from "node:url"
26
26
 
27
27
  const DEBUG = !!process.env.GENESEED_DEBUG
28
- function dlog(m) { if (DEBUG) console.error(`[geneseed-workflow] ${m}`) }
28
+ function dlog(m) { if (DEBUG) say(m, "debug") }
29
+ // OpenCode 1.x paints a plugin's stderr over its TUI input box (in red); its own log API
30
+ // writes to the log file instead. The V1 entry sets LOG_CLIENT; V2 and tests have no
31
+ // client and keep stderr, as does a refused log call, so no line is lost. Never throws:
32
+ // a log line must not break a tool call.
33
+ let LOG_CLIENT = null
34
+ function say(msg, level = "warn") {
35
+ try {
36
+ if (LOG_CLIENT?.app?.log) {
37
+ Promise.resolve(LOG_CLIENT.app.log({ body: { service: "geneseed-workflow", level, message: msg } })).catch(() => console.error(`[geneseed-workflow] ${msg}`))
38
+ return
39
+ }
40
+ } catch { /* fall through to stderr */ }
41
+ console.error(`[geneseed-workflow] ${msg}`)
42
+ }
29
43
 
30
44
  const __dir = path.dirname(fileURLToPath(import.meta.url))
31
45
  const WORKFLOWS_DIR = process.env.GENESEED_WORKFLOWS_DIR
@@ -184,7 +198,9 @@ const NAME_DESCRIPTION = "saved workflow name; omit to list available"
184
198
  const ARGS_DESCRIPTION = "inputs passed to the workflow script as `args` (object, or a JSON object string)"
185
199
 
186
200
  // One-line load banner (always on) so a restart visibly confirms the plugin loaded and the
187
- // `workflow` tool is registered. tests/host_canary.mjs reads it as V1's proof of load.
201
+ // `workflow` tool is registered. tests/host_canary.mjs reads it as V1's proof of load, so it
202
+ // stays on stderr, not `say`: `opencode debug config` never prints a `client.app.log` line. It
203
+ // runs once, before the TUI draws, so it does not land in the input box as `say`'s lines did.
188
204
  async function loadBanner(warn = "") {
189
205
  try {
190
206
  const names = await listWorkflows()
@@ -194,6 +210,7 @@ async function loadBanner(warn = "") {
194
210
 
195
211
  export const GeneseedWorkflow = async (ctx) => {
196
212
  const { client, directory, worktree } = ctx
213
+ if (client) LOG_CLIENT = client
197
214
  let toolHelper
198
215
  try { ({ tool: toolHelper } = await import("@opencode-ai/plugin")) }
199
216
  catch { dlog("@opencode-ai/plugin tool helper unavailable β€” registering a raw tool def") }
@@ -26,10 +26,22 @@ The first kit is `spring-boot`, for Spring Boot 4 (Spring Framework 7, Java 21+)
26
26
 
27
27
  The kit is adapted from [piomin/claude-ai-spring-boot](https://github.com/piomin/claude-ai-spring-boot) by Piotr MiΕ„kowski (Apache-2.0), rewritten and condensed for Boot 4. Each of its skill folders ships `LICENSE-piomin-spring-boot.txt`, and each agent carries a credit line.
28
28
 
29
+ The second kit is `react`, for React 18 or 19 apps built with Vite or webpack, in TypeScript or JavaScript, tested with Jest and React Testing Library. It adds four members:
30
+
31
+ | Member | Kind | What it is for |
32
+ |---|---|---|
33
+ | `react` | skill | Components, hooks, state placement, data fetching, TypeScript or JavaScript, React security; side files for Vite and for webpack (config, client-side routing, env variables, build failures), read by whichever the project uses, and accessibility |
34
+ | `react-testing` | skill | Jest and Testing Library: role queries, `userEvent`, MSW network mocks, `jest-axe`, and the Jest configuration a Vite or webpack project needs |
35
+ | `react-engineer` | agent | Implements a React feature, or makes a broken Vite or webpack build or Jest run green |
36
+ | `react-reviewer` | agent | Framework-aware review: hooks, state, data fetching, accessibility, React security, tests |
37
+
38
+ It is adapted from [affaan-m/everything-claude-code](https://github.com/affaan-m/everything-claude-code) by Affaan Mustafa (MIT), rewritten and condensed for Vite and Jest; the webpack side file is first-party. It has no Server Components material: a client-rendered app has no server render.
39
+
29
40
  ### Switching kits on and off
30
41
 
31
42
  ```bash
32
43
  geneseed build --emit claude-global --kits spring-boot
44
+ geneseed build --emit claude-global --kits react,spring-boot
33
45
  geneseed build --emit claude-global --kits none
34
46
  ```
35
47
 
@@ -37,7 +49,7 @@ geneseed build --emit claude-global --kits none
37
49
 
38
50
  A build does exactly what its flags say. A plain `build` without `--kits` therefore turns off a kit the install has on. Before it does, it warns: `this install has kit <k>; this build turns it off β€” pass --kits <k> to keep it`.
39
51
 
40
- The setup wizard asks one question listing the kits, with the install's current kits as the default. It asks it only when at least one kit exists.
52
+ The setup wizard asks one yes/no question per kit, each defaulting to whether the install has that kit on. It asks them only when at least one kit exists.
41
53
 
42
54
  ### What an install records
43
55
 
@@ -47,7 +59,7 @@ An install with a kit on records it in its instructions file, under the skill se
47
59
 
48
60
  `geneseed status` shows `kits: spring-boot` on the install's row, and `status --json` carries the same list.
49
61
 
50
- In the web console, **Installs β†’ Kits** (`#/installs/kits`) lists every install (disabled ones read-only) with one switch per kit. Toggling stages the set; **Apply** asks for confirmation, then rebuilds that one install with exactly that set as a console job (replace, not replay). Files you edited in a kit that is now off are kept, and the row names them so you can delete them by hand.
62
+ In the web console, **Installs β†’ Kits** (`#/installs/kits`) lists every install (disabled ones read-only) with one switch per kit. Toggling stages the set; **Apply** asks for confirmation, then rebuilds that one install with exactly that set as a console job (replace, not replay). Files you edited in a kit that is now off are kept, and the row names them so you can delete them by hand. The top-level **Kits** page (`#/kits`) lists the kits; a kit's page (`#/kits/<kit>`) shows its rules, banned APIs and upstream credits with the same per-install switch, and the Library tags each member skill or agent with a `kit:` badge.
51
63
 
52
64
  ### What a kit adds to an install
53
65
 
@@ -41,7 +41,7 @@ The full list, with each description, is in the catalog.
41
41
 
42
42
  ### Skills improve themselves
43
43
 
44
- Every skill ends with one beat of reflection: if a step misled or a step was missing, the agent proposes the exact edit to that skill and applies it only with your assent. Most runs end with nothing to change.
44
+ Every skill ends with one beat of reflection: if a step misled or a step was missing, the agent writes the exact correction, with your assent, into that skill's notes file, `notebook/skill-notes/<name>.md`, and reads those notes the next time the skill runs. It never edits the installed skill itself: that file is rendered from `src/`, a rebuild would overwrite the edit, and `doctor` would report it as drift. Agents work the same way through `notebook/agent-notes/`. Each note is one line that carries its evidence, `- [skill|general] <correction> β€” seen: <what happened, against what was expected> (<date>)`: `seen:` is what you judge the correction by before folding it in, and `general` marks one that belongs in a law, doctrine or memory rather than in that one skill. `geneseed diff` lists the notes so you can fold them back into `src/`. Most runs end with nothing to change.
45
45
 
46
46
  ### Old names keep working
47
47
 
package/docs/extending.md CHANGED
@@ -513,10 +513,9 @@ enumerates skills would miss it. `src/kits/<kit>/` holds only `rules.md`.
513
513
  to a kit member (it would dangle in an install without the kit), and a kit file that links to
514
514
  another kit's member. Links run kit β†’ core only. A kit's links to its own members do not
515
515
  protect them from `--exclude-skills`; its link to a core skill still protects that skill.
516
- 5. **The setup wizard.** It asks its kits question only when at least one kit exists. The shipped
517
- `spring-boot` kit therefore added one answer line to the stdin strings in
518
- `tests/unit/wizard.test.mjs`, and the `wizard-no-kit` job holds that the question is skipped on a
519
- tree with no kit.
516
+ 5. **The setup wizard.** It asks one yes/no per kit, and only when at least one kit exists. Each
517
+ shipped kit therefore adds one answer line to the stdin strings in `tests/unit/wizard.test.mjs`,
518
+ and the `wizard-no-kit` job holds that the questions are skipped on a tree with no kit.
520
519
  6. **Golden cells**: the matrix (`tests/helpers/matrix/emit.*.json`) carries kit on for `claude` and
521
520
  `opencode`, the kit-off baseline (`kits: []`, spelled `--kits none`), and three deletion cells
522
521
  (kit on to off). One deletion cell sets `edit` (a map of sandbox path to appended text) so a member
@@ -13,7 +13,9 @@ geneseed build --emit bob-global # ~/.bob
13
13
  geneseed build --emit bob --out /path/to/repo --root /path/to/repo # one repo
14
14
  ```
15
15
 
16
- Bob is shaped like Claude Code, so it gets the same agents and skills. Per repo, the preamble goes into a root `AGENTS.md` and the rest into `.bob/`. Globally, everything goes under `~/.bob` (`$BOB_CONFIG_DIR` moves it), and the preamble rides `rules/geneseed.md`, because Bob does not auto-load a global `AGENTS.md`. Bob's hooks refuse an action with exit code 2, and Bob has no `SubagentStop` or `PreCompact` events. Bob support has not yet been verified against a live install.
16
+ Bob is shaped like Claude Code, so it gets the same agents and skills. Per repo, the preamble goes into a root `AGENTS.md` and the rest into `.bob/`. Globally, everything goes under `~/.bob` (`$BOB_CONFIG_DIR` moves it), and the preamble rides `rules/geneseed.md`, because Bob does not auto-load a global `AGENTS.md`. Bob's hooks refuse an action with exit code 2, and Bob has no `SubagentStop` or `PreCompact` events.
17
+
18
+ Both scopes open Bob's carrier with a short first-reply override, so the theme's readiness line (for example "🧬 Gene-seed implanted…") starts the first reply. Without it, Bob's own greeting outranked the instruction lower in the file. A bare greeting such as "hi" still gets Bob's fixed welcome; the line appears on the first real request. That much was checked by hand in the Bob IDE (2026-10); the rest of the Bob support has not been verified against a live install.
17
19
 
18
20
  ---
19
21
 
@@ -8,7 +8,7 @@ description: "Put the geneseed command on your PATH from a clone."
8
8
  ---
9
9
  **Installed from npm? You have nothing to do.** `npm install -g geneseed` already puts `geneseed`, `geneseed-build` and `geneseed-hook` on your `PATH`.
10
10
 
11
- From a clone, you call the launcher inside the clone: `./geneseed` (Windows: `.\geneseed.cmd`). To type plain `geneseed` from any folder, link it.
11
+ From a clone, you call the launcher inside the clone: `./geneseed` (Windows: `.\geneseed.cmd`). To type plain `geneseed` from any folder, link it. On macOS and Linux, `./install` does this for you when `geneseed` is not found yet.
12
12
 
13
13
  ## macOS and Linux
14
14
 
@@ -17,7 +17,7 @@ From a clone, you call the launcher inside the clone: `./geneseed` (Windows: `.\
17
17
  ./geneseed link /usr/local/bin # or another bin folder (may ask for sudo)
18
18
  ```
19
19
 
20
- `link` writes a small shell launcher that runs this clone by its absolute path. It also tells you whether the target folder is on your `PATH`, and if it is not, the one line to add to your shell profile. Then:
20
+ `link` writes a small shell launcher that runs this clone by its absolute path. If the target folder is not on your `PATH` (macOS zsh does not search `~/.local/bin`), it offers to add it to your shell's startup file: `~/.zshrc` for zsh, `~/.bashrc` for bash on Linux, `~/.bash_profile` for bash on macOS. It appends one marked block, never twice, and `geneseed unlink` removes it. Outside a terminal, or for another shell, it prints the line to add instead. Open a new terminal, then:
21
21
 
22
22
  ```
23
23
  geneseed # the web console (or the command list), from any folder
@@ -46,7 +46,7 @@ A rebuild only replaces files the install's manifest says Geneseed owns. It leav
46
46
 
47
47
  ## Local edits, and the improvements file
48
48
 
49
- The agent can refine its own deployed agent and skill files as it works, and so can you. A rebuild would overwrite those edits, so **setup, re-theme and upgrade export them first**. When the files they are about to overwrite differ from a fresh render, the differences are written to a markdown **improvements file** in `improvements/`, inside the install's own folder (for the OpenCode global install, `~/.config/opencode/improvements/`). The manifest does not list that folder, so rebuilds never overwrite it and uninstall never removes it.
49
+ The agent records what it learns about a skill or agent in notes under `notebook/skill-notes/` and `notebook/agent-notes/`, which rebuilds never touch. Edits made to the deployed agent and skill files themselves, by you or by an older harness, are another matter: a rebuild would overwrite those, so **setup, re-theme and upgrade export them first**. When the files they are about to overwrite differ from a fresh render, the differences are written to a markdown **improvements file** in `improvements/`, inside the install's own folder (for the OpenCode global install, `~/.config/opencode/improvements/`). The manifest does not list that folder, so rebuilds never overwrite it and uninstall never removes it.
50
50
 
51
51
  A rebuild also refuses to overwrite a file you edited. The manifest records a fingerprint of every file Geneseed wrote; when a file no longer matches it, the rebuild leaves it alone and prints `kept your edited <file> β€” delete it to get Geneseed's copy back`. From then on the file is yours and later rebuilds skip it. A file the new version no longer ships is kept the same way, with `(no longer shipped)`. Line-ending changes from a git checkout do not count as edits. Installs made before fingerprints existed are overwritten as before.
52
52
 
@@ -58,7 +58,7 @@ geneseed diff --full # with line-level diffs
58
58
  geneseed diff --out improvements.md # write the improvements file
59
59
  ```
60
60
 
61
- `diff` compares the global OpenCode install by default. Pass `--target <config dir>` to compare another install. A file you replaced with a link to your own copy (a skill folder junctioned or symlinked elsewhere, say) is listed as `linked`: Geneseed never writes through a link, so it is yours and not drift, and it stays out of the improvements file. The improvements file is self-contained. To make the changes permanent, hand it to an agent in a Geneseed clone and ask it to fold them back into `src/`. Then they survive every future build. The web console's **Changes** page exports the same file.
61
+ `diff` compares the global OpenCode install by default. Pass `--target <config dir>` to compare another install. A file you replaced with a link to your own copy (a skill folder junctioned or symlinked elsewhere, say) is listed as `linked`: Geneseed never writes through a link, so it is yours and not drift, and it stays out of the improvements file. `diff` also lists every non-empty self-improvement note, and `--out` copies them into the improvements file; the upgrade export does not fire on notes alone, since a rebuild cannot lose them. The improvements file is self-contained. To make the changes permanent, hand it to an agent in a Geneseed clone and ask it to fold them back into `src/`. Then they survive every future build. The web console's **Changes** page exports the same file.
62
62
 
63
63
  ## Moving from a clone to npm
64
64
 
@@ -97,7 +97,7 @@ reports `version "21` or higher.
97
97
  .\geneseed.cmd link
98
98
  ```
99
99
 
100
- On Windows, `link` writes to `%LOCALAPPDATA%\Geneseed\bin` and adds it to your user PATH β€” only **new** terminals see it, so close and reopen yours.
100
+ On macOS and Linux, `link` offers to add `~/.local/bin` to your shell's startup file when it is not on your PATH; accept, then open a **new** terminal. On Windows, `link` writes to `%LOCALAPPDATA%\Geneseed\bin` and adds it to your user PATH β€” only **new** terminals see it, so close and reopen yours.
101
101
 
102
102
  **Confirm.**
103
103
 
package/docs/web-ui.md CHANGED
@@ -114,6 +114,11 @@ streams the output of background jobs and keeps their history across reloads.
114
114
  **Promote to rule** control turns a recurring lesson into a trial rule in
115
115
  `user-rules.md` β€” provenance recorded, the source fact deleted so it isn't loaded
116
116
  twice β€” landing you on the Rules page.
117
+ - **Kits** (`#/kits`, `#/kits/<kit>`) β€” the list of shipped kits and, per kit, a detail page
118
+ with its rules, word budget, banned APIs, upstream credits and one switch per install.
119
+ `GET /api/kits` carries `rules`, `rulesWordBudget`, `banned` and `credits` per kit; the
120
+ catalog and item endpoints for skills and agents carry `kit` (the owning kit or `null`),
121
+ which the Library shows as a `kit:` badge.
117
122
  - **Loops** (`#/loops`) β€” the loop catalogue `geneseed loop` runs from, read-only, laid out
118
123
  like the Library: a rail of sections (**Templates**, **Bricks**, **Active**, each with its
119
124
  count; `#/loops/<section>/<item>` opens an entry), with the selected section's groups
@@ -194,7 +199,7 @@ streams the output of background jobs and keeps their history across reloads.
194
199
  card (shown once a global install exists) manages sovereign repos β€” folders where every
195
200
  global harness goes dormant (hooks stay silent, the global preamble never loads);
196
201
  add or remove one here, the web mirror of `harness exclude add|remove|list`.
197
- - **Kits** (`#/installs/kits`) β€” every install (disabled ones read-only) as a card with one switch per kit.
202
+ - **Kits** (`#/installs/kits`) β€” every install (disabled ones read-only) as a panel with one switch per kit.
198
203
  Toggling only stages the set; **Apply** asks first, then rebuilds that install with
199
204
  exactly that set as a console job. Files you edited in a kit that is now off are kept,
200
205
  and the row lists them.
@@ -2,5 +2,5 @@
2
2
  "_comment": "version is a human-readable release label only; the canonical identity of an installed harness is the source fingerprint stamped in .geneseed-version (see `harness version`), not this string.",
3
3
  "theme": "neutral",
4
4
  "product": "Geneseed",
5
- "version": "4.10.0"
5
+ "version": "4.15.1"
6
6
  }
@@ -21,7 +21,7 @@ import {
21
21
  } from './emit-common.mjs';
22
22
  import { kitsBody, renderAll, renderFile } from './render.mjs';
23
23
  import {
24
- BOB_RULES_STUB, ensureContextStub, ensureExcludesStub, ensureNotebookIndex,
24
+ BOB_RULES_STUB, bobFirstReply, ensureContextStub, ensureExcludesStub, ensureNotebookIndex,
25
25
  ensureProfileStub,
26
26
  ensureRulesStub, ensureWikiStub, WIKI_FILE,
27
27
  } from './stubs.mjs';
@@ -100,7 +100,7 @@ export function emitClaudeRender(cfg, job) {
100
100
  if (isBob && agentText !== null) {
101
101
  const rulesMd = path.join(cfgDir, 'rules', 'geneseed.md');
102
102
  claimAndWrite(cfgDir, rulesMd, 'rules/geneseed.md', scope === 'project' ? BOB_RULES_STUB
103
- : stripCapabilityLinks(prefixedAgentText('../') || agentText), owned);
103
+ : bobFirstReply(theme.LOADED_SIGIL) + stripCapabilityLinks(prefixedAgentText('../') || agentText), owned);
104
104
  }
105
105
 
106
106
  ensureAgentOverridesStub(cfg, cfgDir);
@@ -179,6 +179,8 @@ export function emitClaudeRender(cfg, job) {
179
179
  let claudeMdText = null;
180
180
  if (agentText !== null && !(isBob && scope === 'global')) {
181
181
  claudeMdText = stripCapabilityLinks(prefixedAgentText(lawsPrefix) || agentText);
182
+ // Bob only: its greeting persona outranks the template's sigil paragraph β€” see `bobFirstReply`.
183
+ if (isBob) claudeMdText = bobFirstReply(theme.LOADED_SIGIL) + claudeMdText;
182
184
  }
183
185
 
184
186
  // WIRE β€” see `claudeWire` below. One child per emit, so the two halves are two
@@ -139,6 +139,19 @@ file (\`~/.bob/rules/geneseed.md\`) so the global preamble does not stack on top
139
139
  the project's own. Follow the root \`AGENTS.md\`.
140
140
  `;
141
141
 
142
+ /**
143
+ * The paragraph a Bob emit puts FIRST in what Bob auto-loads (global `rules/geneseed.md`,
144
+ * the project's `AGENTS.md` block). Tried live in the Bob IDE (2026-10-23): with only the
145
+ * template's sigil paragraph β€” below the banner β€” the first reply to a real request carried
146
+ * no sigil; with this paragraph on top it did. Bob's own greeting persona outranks a rule
147
+ * that does not say it overrides it. A bare "hi" still gets Bob's fixed welcome either way.
148
+ */
149
+ export function bobFirstReply(sigil) {
150
+ return '**First-reply override β€” highest priority.** Your very first reply in every '
151
+ + 'conversation MUST begin with this exact line, before anything else and instead of any '
152
+ + `default greeting or self-introduction:\n\n> ${sigil}\n\n`;
153
+ }
154
+
142
155
  /** `_build_render.PROFILE_FILE`. */
143
156
  const PROFILE_FILE = 'PROFILE.md';
144
157