geneseed 3.17.0 → 3.19.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 (164) hide show
  1. package/CHANGELOG.md +39 -0
  2. package/DESIGN.md +1 -1
  3. package/README.md +23 -5
  4. package/SHIPPED.md +3 -3
  5. package/adapters/claude-code/skills/geneseed/SKILL.md +1 -1
  6. package/adapters/opencode/README.md +2 -2
  7. package/adapters/opencode/plugins/geneseed-context.js +19 -17
  8. package/adapters/opencode/plugins/geneseed-guard.js +7 -7
  9. package/bin/geneseed-cli.mjs +5 -0
  10. package/docs/concepts/exclusions.md +1 -1
  11. package/docs/concepts/skills.md +6 -2
  12. package/docs/extending.md +33 -0
  13. package/docs/guides/project-context.md +20 -0
  14. package/docs/guides/read-non-markdown.md +1 -1
  15. package/docs/guides/uninstall.md +1 -1
  16. package/docs/guides/upgrade.md +1 -1
  17. package/docs/guides/wiki.md +4 -4
  18. package/docs/opencode-plugin-setup.md +1 -1
  19. package/docs/reference/env-context.md +2 -2
  20. package/docs/reference/plugin-context.md +2 -2
  21. package/docs/reference/plugin-guard.md +1 -1
  22. package/docs/token-footprint.md +18 -15
  23. package/docs/understand/take-it-out.md +1 -1
  24. package/harness.config.json +1 -1
  25. package/js/README.md +4 -1
  26. package/js/build/args.mjs +22 -20
  27. package/js/build/bundle.mjs +1 -3
  28. package/js/build/emit-claude.mjs +5 -4
  29. package/js/build/emit-opencode.mjs +9 -2
  30. package/js/build/generate.mjs +6 -6
  31. package/js/build/render.mjs +19 -12
  32. package/js/build/source.mjs +82 -7
  33. package/js/build/stubs.mjs +35 -6
  34. package/js/build/themes.mjs +1 -3
  35. package/js/cli-table.json +53 -0
  36. package/js/hosts/hooks-context.mjs +13 -6
  37. package/js/hosts/hosts.mjs +1 -3
  38. package/js/hosts/installs.mjs +13 -7
  39. package/js/hosts/mcp.mjs +1 -1
  40. package/js/hosts/native.mjs +60 -5
  41. package/js/hosts/opencode.mjs +37 -6
  42. package/js/hosts/settings.mjs +1 -0
  43. package/js/hosts/shim.mjs +1 -0
  44. package/js/inspect/checks-authoring.mjs +4 -1
  45. package/js/inspect/checks-counts.mjs +8 -3
  46. package/js/inspect/checks-repo.mjs +166 -2
  47. package/js/inspect/diff.mjs +5 -1
  48. package/js/inspect/doctor.mjs +2 -1
  49. package/js/inspect/inventory.mjs +7 -9
  50. package/js/inspect/scorecard-checks.mjs +571 -0
  51. package/js/inspect/scorecard-svg.mjs +85 -0
  52. package/js/inspect/scorecard.mjs +839 -0
  53. package/js/lib/json.mjs +1 -1
  54. package/js/maintain/migrate.mjs +2 -1
  55. package/js/maintain/uninstall.mjs +2 -3
  56. package/js/maintain/update.mjs +10 -3
  57. package/js/ui/menu.mjs +2 -2
  58. package/js/ui/tui.mjs +1 -0
  59. package/js/web/api.mjs +2 -0
  60. package/js/web/catalog.mjs +24 -7
  61. package/js/web/daemon.mjs +2 -1
  62. package/js/web/routes.mjs +2 -0
  63. package/js/web/server.mjs +1 -1
  64. package/js/web/user-files.mjs +1 -0
  65. package/package.json +11 -3
  66. package/registry.json +12 -75
  67. package/src/AGENT.md.tmpl +19 -24
  68. package/src/agents/docs.md +1 -1
  69. package/src/agents/researcher.md +1 -1
  70. package/src/agents/reviewer.md +3 -0
  71. package/src/bricks/bruno-test.md +2 -2
  72. package/src/bricks/ci-fix.md +3 -3
  73. package/src/bricks/deps-audit.md +3 -3
  74. package/src/bricks/migration-plan.md +2 -2
  75. package/src/doctrines/comms.md +19 -0
  76. package/src/doctrines/process.md +2 -2
  77. package/src/laws/universal.md +2 -2
  78. package/src/skills/brainstorm.md +14 -10
  79. package/src/skills/bruno.md +84 -0
  80. package/src/skills/codebase-design.md +41 -23
  81. package/src/skills/daydream/SKILL.md +4 -3
  82. package/src/skills/daydream/VENDOR.md +6 -2
  83. package/src/skills/daydream/instructions.md +1 -1
  84. package/src/skills/debug/ci.md +11 -0
  85. package/src/skills/debug.md +11 -8
  86. package/src/skills/dependencies.md +65 -0
  87. package/src/skills/develop.md +9 -4
  88. package/src/skills/document-project.md +27 -22
  89. package/src/skills/explain-changes/SKILL.md +1 -1
  90. package/src/skills/fresh-eyes.md +1 -1
  91. package/src/skills/geneseed-code-review.md +21 -9
  92. package/src/skills/geneseed.md +4 -1
  93. package/src/skills/git-history.md +78 -0
  94. package/src/skills/handoff.md +4 -3
  95. package/src/skills/parallel-agents.md +2 -1
  96. package/src/skills/pipeline.md +1 -1
  97. package/src/skills/plan.md +5 -1
  98. package/src/skills/ponytail.md +1 -1
  99. package/src/skills/prototype.md +10 -7
  100. package/src/skills/react-view-transitions/SKILL.md +1 -0
  101. package/src/skills/react-view-transitions/VENDOR.md +4 -0
  102. package/src/skills/research.md +6 -1
  103. package/src/skills/review-response.md +8 -2
  104. package/src/skills/roast-me.md +8 -7
  105. package/src/skills/rule/consolidate.md +32 -0
  106. package/src/skills/rule.md +16 -4
  107. package/src/skills/security-audit.md +1 -1
  108. package/src/skills/ship.md +16 -9
  109. package/src/skills/teach.md +5 -3
  110. package/src/skills/wayfinder.md +19 -16
  111. package/src/skills/wiki.md +2 -2
  112. package/themes/_TEMPLATE.json +9 -17
  113. package/themes/biker.json +9 -17
  114. package/themes/commentator.json +9 -17
  115. package/themes/cyberpunk.json +9 -17
  116. package/themes/gamer.json +9 -17
  117. package/themes/imperial.json +9 -17
  118. package/themes/joker.json +9 -17
  119. package/themes/marvin.json +9 -17
  120. package/themes/mean.json +9 -17
  121. package/themes/military.json +9 -17
  122. package/themes/neutral.json +9 -17
  123. package/themes/pirate.json +9 -17
  124. package/themes/sports.json +9 -17
  125. package/themes/verstappen.json +9 -17
  126. package/themes/wizard.json +9 -17
  127. package/web/dist/assets/{Activity-DonKN1pi.js → Activity-IbwdHHyx.js} +1 -1
  128. package/web/dist/assets/{ActivityDetail-e47a3cdE.js → ActivityDetail-B5uivdWI.js} +1 -1
  129. package/web/dist/assets/{Dashboard-Cr7i0PsO.js → Dashboard-v6WQ37bD.js} +2 -2
  130. package/web/dist/assets/{Docs-Lne3nuzD.js → Docs-CypIfDBX.js} +1 -1
  131. package/web/dist/assets/FilterInput-BSfpStOZ.js +1 -0
  132. package/web/dist/assets/{GreenhouseView-4CbIuTpl.js → GreenhouseView-ClxP0hQG.js} +1 -1
  133. package/web/dist/assets/{Installs-CIzbV1Ks.js → Installs-CPkQeFjO.js} +1 -1
  134. package/web/dist/assets/{JournalView-BlBfuvzj.js → JournalView-BeEInhUf.js} +1 -1
  135. package/web/dist/assets/{Laws-B-pjcjHr.js → Laws-Ds6U5xBQ.js} +1 -1
  136. package/web/dist/assets/Library-BraUKPyQ.js +1 -0
  137. package/web/dist/assets/{Loops-DIOxW1xH.js → Loops-DWcy3mwK.js} +1 -1
  138. package/web/dist/assets/Markdown-C6fRd4A4.js +67 -0
  139. package/web/dist/assets/{OperatorHudView-D7S7z7CJ.js → OperatorHudView-CQyrJQ9m.js} +1 -1
  140. package/web/dist/assets/{Personal-Ws3v35AB.js → Personal-YWqs6qFL.js} +1 -1
  141. package/web/dist/assets/{Tabs-6Z1eziAq.js → Tabs-EhzEC-Xh.js} +1 -1
  142. package/web/dist/assets/{activity-Dr7ZMBI3.js → activity-dcg5vF9j.js} +1 -1
  143. package/web/dist/assets/{drawable-ATNeYKbT.js → drawable-CEKPNV7X.js} +1 -1
  144. package/web/dist/assets/{index-CDg5XUhG.js → index-CPi22b7y.js} +2 -2
  145. package/web/dist/assets/react-DRhoX0kS.js +9 -0
  146. package/web/dist/assets/{usePoll-DD8VjtSg.js → usePoll-BmR631BB.js} +1 -1
  147. package/web/dist/index.html +2 -2
  148. package/web/src/pages/Laws.jsx +5 -0
  149. package/src/skills/bruno-collection-generator.md +0 -52
  150. package/src/skills/bruno-test-writer.md +0 -51
  151. package/src/skills/ci-fix.md +0 -49
  152. package/src/skills/consolidate-memory.md +0 -50
  153. package/src/skills/deps-audit.md +0 -46
  154. package/src/skills/domain-modeling.md +0 -27
  155. package/src/skills/git-archaeology.md +0 -36
  156. package/src/skills/git-rescue.md +0 -58
  157. package/src/skills/migrate.md +0 -34
  158. package/src/skills/opencode-theme.md +0 -42
  159. package/src/skills/repo-map.md +0 -25
  160. package/src/skills/tickets.md +0 -33
  161. package/web/dist/assets/FilterInput-CVyqmYWM.js +0 -1
  162. package/web/dist/assets/Library-x8Nzg6yq.js +0 -1
  163. package/web/dist/assets/Markdown-X2a3qvOh.js +0 -38
  164. package/web/dist/assets/react-B9Z_tXRV.js +0 -8
package/CHANGELOG.md CHANGED
@@ -8,6 +8,45 @@ label. For the capability ↔ spec map, see [SHIPPED.md](SHIPPED.md).
8
8
 
9
9
  ## [Unreleased]
10
10
 
11
+ ## [3.19.0] — 2026-10-09
12
+
13
+ ### Added
14
+ - Doctrine comms 3, Declare the Judgment Calls: after non-trivial work the agent lists the choices it made alone where a reasonable alternative existed, with the alternative set aside and whether it is cheaply reversible, riskiest first (data, security, production, public interfaces). Only genuine forks count, trivial work owes an empty list, and it never covers a call Echo the Intent says to ask about first. Reviewers read where the agent guessed instead of everything, or nothing. The idea is Victor Rentea's (Devoxx BE 2026, "Responsibly Dimming the Lights in the Software Factory"). It is in the toggleable comms pack, not a law, per DESIGN.md Decision 7; the full-footprint size ceiling rises by 205 characters for it. `explain-changes` now lists these calls among its risks.
15
+ - Reviews apply the nearest `REVIEW.md`: a repo states how its code is judged in a file read only at review time, so the coding context stays lean. The file closest to each changed file wins (folder, then root, then `CODING_STANDARDS.md` / `CONTRIBUTING.md`, then Geneseed's defaults, format included), and it never lifts a law. `geneseed-code-review` and the reviewer agent load it, `ship` runs a review before opening a pull request and stops on a blocking finding, and `review-response` is the only skill that writes it, on your word. One sentence in the always-on core makes host built-in reviews apply it too.
16
+ - `geneseed-code-review` flags architecture drift: when `docs/architecture.md` draws C4 and a diff adds, removes or rewires a container without touching the diagram, it raises a non-blocking issue pointing at `document-project`.
17
+
18
+ ### Changed
19
+ - `roast-me` now attacks your own ask, plan, idea or writing, premise first, and no longer critiques code. Code and diffs, "roast my code" included, go to `geneseed-code-review`, which keeps its findings unsoftened when asked to roast.
20
+ - `daydream` and `react-view-transitions` are user-only: they answer `/daydream` and `/react-view-transitions`, but the agent no longer starts them on its own and their descriptions leave the always-on list.
21
+ - `parallel-agents` and `pipeline` name their boundary: independent units side by side versus a relay in one worktree where each agent builds on the previous one's output.
22
+
23
+ ### Repository
24
+ Not in the package; how Geneseed itself is built and checked.
25
+ - The weekly scorecard run also scores the tree with `geneseed scorecard` and fails when any check differs from the upstream Python tool, so the port cannot drift in silence. The web CI job calls prettier and vitest directly, which the scorecard can see (95.3, 30 of 31 checks).
26
+ - README: the scorecard card sits above "Why Geneseed", the badge takes the upstream look, and the laws badge also counts doctrine rules.
27
+
28
+ ## [3.18.0] — 2026-10-09
29
+
30
+ ### Added
31
+ - `geneseed scorecard [path]` scores the repo a harness is installed in — its CI, tests and docs, not the harness files — with the AI Harness Scorecard's 31 checks and five weighted pillars, ported to JavaScript (no Python). It prints the grade, each pillar and every failing check with its fix, and always exits 0. `--json` gives the raw result; `--svg PATH` writes a grade-and-pillars card (light and dark) and prints the matching badge URL.
32
+ - Skills can carry side files: `src/skills/<name>/<file>.md` is emitted beside the skill's `SKILL.md` on every host and read only when the skill points at it. `debug` moves its CI section and `rule` its memory consolidation into side files, so each costs about 0.5k tokens less per use.
33
+
34
+ ### Changed
35
+ - Fewer, sharper skills: 56 become 47. `dependencies` replaces `deps-audit` and `migrate`, `bruno` replaces `bruno-collection-generator` and `bruno-test-writer`, and `git-history` replaces `git-archaeology` and `git-rescue`. `document-project` absorbs `repo-map`, `codebase-design` absorbs `domain-modeling` (the glossary is now `GLOSSARY.md`, `CONTEXT.md` still read), `debug` absorbs `ci-fix`, `rule` absorbs `consolidate-memory`, and `geneseed` absorbs `opencode-theme`. Every old name still works as a user-only `/name` alias of its new home, and so does `/grill-me` for `brainstorm`; an old name in `--exclude-skills` excludes the skill that absorbed it. Excluding one half of a merged pair (say `deps-audit`) now excludes the whole merged skill (`dependencies`, which also covers `migrate`). Parts of brainstorm, codebase-design, debug, develop, prototype, ship, wayfinder, parallel-agents, rule and geneseed-code-review adapt ideas from Matt Pocock's skills (github.com/mattpocock/skills, MIT).
36
+ - The wiki manifest is now `geneseed-wiki.jsonc`, so a shared `.claude/` or `.opencode/` folder shows who owns it. The next build or upgrade renames an existing `wiki.jsonc` (or older `wiki.json`) to the new name with its contents untouched, and adds the new name to a `.gitignore` that listed the old one. Until then the hook, the OpenCode plugins and the web console still read `wiki.jsonc`; that fallback goes in the release after 3.18.0. `GENESEED_WIKI` is unchanged.
37
+ - `document-project` and the docs agent default to Markdown. AsciiDoc is used only when you ask for it or the project's docs are already `.adoc`; the skill no longer proposes a switch on its own.
38
+ - `upgrade` and `migrate` print the alias and retired-name notices that `rebuild-all` already printed. `codebase-design` now triggers on "where should the seam go".
39
+
40
+ ### Removed
41
+ - The `tickets` skill, with no alias: `wayfinder` charts the decisions and hands execution to `plan`, sliced into thin end-to-end pieces. A `tickets` entry in `--exclude-skills` is dropped with a notice.
42
+
43
+ ### Repository
44
+ Not in the package; how Geneseed itself is built and checked.
45
+ - `SECURITY.md`, `CODEOWNERS`, a PR template and a weekly advisory scorecard run; `ARCHITECTURE.md` and decision records under `docs/adr/`.
46
+ - CI: a blocking `npm audit --audit-level=high` job, Dependabot, conventional PR titles (commitlint), `tsc --noEmit` with `checkJs` over `js/` and `bin/` (`npm run typecheck`), coverage with `c8`, a `lychee` link check, and the doctor scorecard ratchet with the README card and badge.
47
+ - Tests: fast-check property tests on the settings parser, a `fuzz/` target that drives the hook gates through the real entry point, and a weekly Stryker run. The mutation matrix runs on Windows, where two of its rows are real defects, and installs its devDependencies first.
48
+ - ESLint bans `eval`, implied eval, `new Function` and thrown literals in product code. Toolchain and web dependencies bumped by Dependabot (`web/dist` rebuilt).
49
+
11
50
  ## [3.17.0] — 2026-10-08
12
51
 
13
52
  ### Added
package/DESIGN.md CHANGED
@@ -44,7 +44,7 @@ vault or a specific tool's hooks.
44
44
  and the prose words the docs use: the core nouns `LAW(S)`/`DOCTRINE(S)`/`ONTOLOGY`/
45
45
  `AGENT(S)`/`SKILL(S)`/`MEMORY`/`NOTEBOOK`/`VAULT`/`WIKI`, plus `TAGLINE`,
46
46
  `LOADED_SIGIL`, `EPI_*`, `BENEDICTION`, `DESC_*`, `ROAST_PERSONA`, the invariant
47
- titles `LEX_<ID>`, the 28 doctrine-rule titles `DOC_<ID>` (keyed by stable rule id), the five pack
47
+ titles `LEX_<ID>`, the 29 doctrine-rule titles `DOC_<ID>` (keyed by stable rule id), the five pack
48
48
  names `PACK_CRAFT`/`PACK_RIGOR`/`PACK_OPS`/`PACK_PROCESS`/`PACK_COMMS`, and the section intros
49
49
  `INTRO_*`. Each theme defines its own nouns; **neutral keeps the plain words** (Rule,
50
50
  Doctrine, Agent, Skill, Memory, Workspace), so neutral output is unchanged.
package/README.md CHANGED
@@ -6,17 +6,18 @@
6
6
 
7
7
  [![npm](https://img.shields.io/npm/v/geneseed?color=cb3837&logo=npm)](https://www.npmjs.com/package/geneseed)
8
8
  [![CI](https://github.com/Arylmera/Geneseed/actions/workflows/ci.yml/badge.svg)](https://github.com/Arylmera/Geneseed/actions/workflows/ci.yml)
9
+ [![AI Harness Scorecard](https://img.shields.io/badge/AI%20Harness%20Scorecard-A%2095.3%2F100-brightgreen)](#ai-harness-scorecard)
9
10
  [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE)
10
11
  [![Node >= 22.3](https://img.shields.io/badge/node-%3E%3D22.3-5fa04e)](package.json)
11
12
  [![zero dependencies](https://img.shields.io/badge/deps-zero-success)](package.json)
12
13
  [![Themes](https://img.shields.io/badge/themes-14-9cf)](themes/)
13
- [![Skills](https://img.shields.io/badge/skills-56-blueviolet)](src/skills/)
14
+ [![Skills](https://img.shields.io/badge/skills-47-blueviolet)](src/skills/)
14
15
  [![Agents](https://img.shields.io/badge/agents-18-orange)](src/agents/)
15
- [![Laws](https://img.shields.io/badge/laws-9-critical)](src/laws/universal.md)
16
+ [![Laws and doctrines](https://img.shields.io/badge/laws-9%20%2B%2029%20doctrines-critical)](src/doctrines/)
16
17
  [![Plugins](https://img.shields.io/badge/plugins-7-teal)](adapters/opencode/plugins/)
17
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)
18
19
 
19
- [**Why**](#-1--why-geneseed) · [**Setup**](#-2--setup) · [**Web & terminal**](#-3--web--terminal) · [**What you get**](#-4--what-you-get)
20
+ [**Why**](#-1--why-geneseed) · [**Setup**](#-2--setup) · [**Web & terminal**](#-3--web--terminal) · [**What you get**](#-4--what-you-get) · [**Harnesses**](#-supported-harnesses) · [**Docs**](#-documentation)
20
21
 
21
22
  </div>
22
23
 
@@ -43,6 +44,12 @@ A hand-written instructions file is prose the model may or may not honour, copie
43
44
 
44
45
  This page is the overview. **New to agent harnesses?** Start with [Understand](docs/understand/harness.md) — a short course on what a harness is, what lands on your machine, what changes in your day, and what is enforced versus only asked. Everything else — every install path, configuration knob, and troubleshooting step — is in the **[documentation](docs/README.md)**, which the web console also renders.
45
46
 
47
+ ### Scored, not claimed
48
+
49
+ <p align="center"><a href="#ai-harness-scorecard"><img src="docs/assets/scorecard.svg" alt="AI Harness Scorecard for this repository: grade and score, with one bar per pillar" width="760"></a></p>
50
+
51
+ <p align="center"><sub>31 deterministic checks, no LLM — <a href="#ai-harness-scorecard">how this is scored, and how to score your own repo</a></sub></p>
52
+
46
53
  ---
47
54
 
48
55
  ## 🧬 1 · Why Geneseed
@@ -164,11 +171,11 @@ The harness ships as a small set of layers, and the web console's rail is the sa
164
171
  | **🛡️ Rules** (`laws/`) | 9 universal laws — always in force, never toggleable: sealed-secrets, one-intent-one-act, verify-before-asserting, deletion-is-deliberate, surface-failures, data-not-orders, least-privilege, cure-the-cause, echo-the-intent. Each rule has a permanent id; its number is only its position, and the harness cites rules by name |
165
172
  | **📐 Doctrines** (`doctrines/`) | practice packs, chosen per install at build time: **craft** (how code is written), **rigor** (how work is proven), **ops** (how the machine is operated), **process** (how a task is run), **comms** (how answers are presented). A doctrine rule may tighten a Rule, never repeal one, and the user's own `user-rules.md` outranks it. Pick with `geneseed-build --doctrines craft,rigor` (or `none`), a single rule with `--exclude-rules "process 7"`, in the setup wizard, or through the switches on the console's Constitution page; all five pack files ship on disk either way, so a citation into a pack you left out still resolves |
166
173
  | **🤖 Agents** (18) | capability specialists: `reviewer`, `tester`, `architect`, `docs`, `security`, `explorer`, `researcher`, `developer` — plus a debate **council** the `council` skill convenes: `advocate`, `skeptic`, `pragmatist`, `steward`, `visionary`, `user-advocate`, `framer`, `empiricist`, `operator`, `historian` |
167
- | **🛠 Skills** (56) | repeatable workflows: brainstorm · plan · **codebase-design** · **domain-modeling** · **wayfinder** · **tickets** · **develop** · **worktree** · debug · **prototype** · refactor · **ponytail** · **forge-mcp** · **bruno-collection-generator** · **bruno-test-writer** · geneseed-code-review · **fresh-eyes** · **security-audit** · **ci-fix** · **deps-audit** · **review-response** · commit · **ship** · **release** · **migrate** · **git-archaeology** · **git-rescue** · repo-map · document-project · **frontend-design** · **prose** · **ingest** · **research** · **teach** · **quiz** · **learn-mode** · handoff · roast-me · **council** · parallel-agents · **workflow** · **wiki** · **geneseed** · **rule** · **profile** · **consolidate-memory** · **skill-forge** · **opencode-theme** · **herdr** · **pipeline** · **loop** · **brick-forge** · **daydream** · **react-view-transitions** · **token-report** · **explain-changes** |
174
+ | **🛠 Skills** (47) | repeatable workflows: brainstorm · plan · **codebase-design** · **wayfinder** · **develop** · **worktree** · debug · **prototype** · refactor · **ponytail** · **forge-mcp** · **bruno** · geneseed-code-review · **fresh-eyes** · **security-audit** · **dependencies** · **review-response** · commit · **ship** · **release** · **git-history** · document-project · **frontend-design** · **prose** · **ingest** · **research** · **teach** · **quiz** · **learn-mode** · handoff · roast-me · **council** · parallel-agents · **workflow** · **wiki** · **geneseed** · **rule** · **profile** · **skill-forge** · **herdr** · **pipeline** · **loop** · **brick-forge** · **daydream** · **react-view-transitions** · **token-report** · **explain-changes** |
168
175
  | **🔌 Plugins** (OpenCode) | `geneseed-context` injects project docs *and your machine wiki* every session (and across compaction); `geneseed-learn` distils memory at session end; `geneseed-guard` enforces the safety Laws and protected wiki folders at the tool boundary; `geneseed-workflow` registers the `workflow` tool that runs saved orchestration scripts; `geneseed-notify` sends a native OS notification when a long run finishes; `geneseed-ponytail` holds a minimal-code mode (`/ponytail lite\|full\|ultra\|off`), opt-in, injecting the laziest-that-works ruleset every turn so it doesn't drift; `geneseed-activity` streams what each session is doing to the web console's Activity view |
169
176
  | **🧠 Memory** (`memory/`) | one-fact-per-file durable knowledge, indexed by `MEMORY.md` (git-ignored, personal) |
170
177
  | **📓 Notebook** (`notebook/`) | the agent's sovereign space — any medium (code, tools, data, notes), self-ruled via a seed-once charter, always git-ignored; only its `.gitignore` is build-asserted |
171
- | **🌐 Wiki** (`wiki.jsonc`) | your own machine-wide knowledge base — typically an Obsidian vault — declared once per machine: entry notes load eager/lazy, the agent reads and **writes** it under the vault's own conventions, with an inbox fallback and guard-enforced protected folders |
178
+ | **🌐 Wiki** (`geneseed-wiki.jsonc`) | your own machine-wide knowledge base — typically an Obsidian vault — declared once per machine: entry notes load eager/lazy, the agent reads and **writes** it under the vault's own conventions, with an inbox fallback and guard-enforced protected folders |
172
179
  | **🧭 Context** | the project's own docs — auto-discovered on OpenCode, or via a `context.json` manifest |
173
180
 
174
181
  ### 🤝 What the harness asks of you
@@ -291,6 +298,17 @@ node --test --test-reporter=tap "tests/**/*.test.mjs" # the suites (node expan
291
298
 
292
299
  `doctor` checks each theme for unresolved tokens, dead/non-hermetic links, theme-key parity, author-time gates (every spec has a purpose line, the plugins parse, the learn-prompt literal stays extractable), and that a committed bundle still matches a fresh render of `src/`. CI (`.github/workflows/ci.yml`) runs both on every push and PR, on both Linux and Windows. Publishing is a separate, manually-triggered workflow (`.github/workflows/publish.yml`) — see [Contributing](#-contributing).
293
300
 
301
+ ### AI Harness Scorecard
302
+
303
+ The card [at the top of this page](#scored-not-claimed) measures how safe this repository is to change with agents. It comes from the [AI Harness Scorecard](https://github.com/markmishaev76/ai-harness-scorecard): 31 deterministic checks, no LLM, in five weighted pillars. Geneseed ships its own JavaScript port, so you can score any repository a harness is installed in — it grades the repository (CI, tests, docs), not the harness files:
304
+
305
+ ```bash
306
+ geneseed scorecard # grade, one line per pillar, and what to fix
307
+ geneseed scorecard --json # every check with its evidence
308
+ ```
309
+
310
+ `geneseed scorecard --svg docs/assets/scorecard.svg` rewrites the card and prints the badge URL for the top of this page; `doctor` fails when either no longer matches the live score, and the checks this repository passes are a floor it may not drop below. A weekly workflow also runs the upstream Python tool as a cross-check.
311
+
294
312
  ## 🔄 Keeping it current
295
313
 
296
314
  **Installed from npm** — one command, and it rebuilds every active install for you:
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.17.0**.
23
+ > string. Current label: **3.19.0**.
24
24
 
25
25
  ## Capabilities
26
26
 
@@ -29,7 +29,7 @@ Every row below is present in the tree today; "Spec" names the design record.
29
29
  | Capability | What it is | Spec |
30
30
  | --- | --- | --- |
31
31
  | **Themed generator** | One neutral `src/` → 14 themed bundles via `geneseed-build` (zero dependencies); structure stays theme-independent | [DESIGN.md](DESIGN.md) |
32
- | **Laws / Agents / Skills / Memory / Notebook** | 9 laws, 18 agents, 56 skills, the memory convention, and the agent's sovereign notebook | `2026-06-11-notebook-sovereign-space` · `2026-06-10-notebook-agent-own-space` |
32
+ | **Laws / Agents / Skills / Memory / Notebook** | 9 laws, 18 agents, 47 skills, the memory convention, and the agent's sovereign notebook | `2026-06-11-notebook-sovereign-space` · `2026-06-10-notebook-agent-own-space` |
33
33
  | **Three-tier constitution** | The governance surface splits into an always-on **Ontology** (Telos, Evidence, Decisions, Conduct — the Pact absorbed into Telos), the nine always-on **Invariants**, and five toggleable **Doctrine** packs (craft, rigor, ops, process, comms) addressed `<pack> <n>`. Every rule carries a permanent id; its number is its position, computed at render time, and a citation renders as the rule's principle name. Packs are chosen at build time with `--doctrines` or the setup wizard; the whole catalogue ships on disk either way, so a citation into an inactive pack still resolves. Precedence, in order: Ontology + Invariants, then the user's `user-rules.md`, then the active Doctrines, then `PROFILE.md`. `doctor`'s `constitutionProblems` gates rule ids (declared, unique, never a retired one), the per-rule Principle column, every `{{LAW:<id>}}` / `{{DOCTRINE:<id>}}` citation in `src/`, and the rule that an always-on tier may never cite a toggleable one | `2026-08-19-three-tier-constitution-design` |
34
34
  | **`doctor`** | One check: unresolved tokens, dead/non-hermetic links, theme-key parity, authoring gates, rendered-bundle drift | `2026-06-07-theme-aware-doctor-diff` |
35
35
  | **`diff` + improvements export** | Deployed-vs-source drift report; export an `improvements.md` back-port | `2026-06-12-improvements-export` |
@@ -40,7 +40,7 @@ Every row below is present in the tree today; "Spec" names the design record.
40
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
- | **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` |
43
+ | **Wiki integration** | Machine-wide knowledge base (`geneseed-wiki.jsonc`): eager/lazy loading, conventions, protected folders enforced at the tool boundary | `2026-06-11-wiki-knowledge-base` |
44
44
  | **Collaboration layer** | Negotiated postures (peer/mentor/expert/assistant/artisan, chosen at setup, inlined in AGENT.md), the bidirectional Pact, epistemically-typed memory (`force:` + Bridge rule), and a seed-once `PROFILE.md` identity with a web editor tab and a `profile` skill that interviews the user to draft it | `2026-07-12-collaboration-layer` |
45
45
  | **Rule front door** | Both durable stores enter through the `rule` skill's fork (*standing rule, or fact to remember?* — always asked, never inferred): the memory branch elicits the binding `force` and shows the file before writing, the rule branch pressure-tests by reformulation and a mandatory counter-example. Doctrine process 1 carries the norm on every host; a `rule-gate` PreToolUse hook (Claude, Bob) and a `geneseed-guard` speed bump (OpenCode) hold it at the tool boundary | `2026-07-30-rule-front-door` |
46
46
  | **Entity registry** | `registry.json` records a lifecycle status, version, owner and add-date for every agent and skill in the tree (maintainer-side — never rendered into a bundle, so it costs no session context). `doctor` gates it against `src/` in both directions, sweeps everything that ships for credentials, and holds each vendored skill folder to an immutable upstream commit. The status surfaces as a badge in the web catalog, shown only where it deviates from `approved` | `2026-07-31-entity-registry` |
@@ -19,7 +19,7 @@ Pick the first that resolves; remember the path for the rest of the session.
19
19
 
20
20
  If none resolve, the user does not have Geneseed deployed here — say so and stop. Do not run `setup`, `build`, or `upgrade` on your own to "fix" this; that is a user decision.
21
21
 
22
- A live harness root contains: `AGENT.md`, `ontology/universal.md`, `laws/universal.md`, `doctrines/<pack>.md`, `agents/<name>.md`, `skills/<name>/SKILL.md`, `memory/MEMORY.md`, `notebook/NOTEBOOK.md`, `themes/`, and (on OpenCode) `plugins/`, `workflows/`, `opencode.jsonc`, `wiki.jsonc`.
22
+ A live harness root contains: `AGENT.md`, `ontology/universal.md`, `laws/universal.md`, `doctrines/<pack>.md`, `agents/<name>.md`, `skills/<name>/SKILL.md`, `memory/MEMORY.md`, `notebook/NOTEBOOK.md`, `themes/`, and (on OpenCode) `plugins/`, `workflows/`, `opencode.jsonc`, `geneseed-wiki.jsonc`.
23
23
 
24
24
  The constitution is **three tiers**: an always-on **Ontology** (four prose sections — Telos, Evidence, Decisions, Conduct), nine always-on **Rules** numbered I–IX, and the **Doctrines** — practice packs (`craft`, `rigor`, `ops`, `process`, `comms`) chosen per install at build time. `AGENT.md` carries all three inline (whole at the `full` footprint, heading-plus-first-line at `lean`), *and* the complete text ships as files beside it. All five pack files ship even when a pack was not built in, so a citation into an inactive pack still resolves on disk — which is why a question about a rule is answered from the tier file, never only from `AGENT.md`.
25
25
 
@@ -207,7 +207,7 @@ the harness live entirely in the global config dir with zero per-repo files.
207
207
  context needs re-pushing.
208
208
  - **Machine wiki (AGENT.md §8):** the same block carries a `MACHINE WIKI` segment
209
209
  for the user's own knowledge base(s) — typically an Obsidian vault — declared in
210
- `wiki.jsonc` (`$GENESEED_WIKI` → `$GENESEED_HARNESS/wiki.jsonc` → beside the
210
+ `geneseed-wiki.jsonc` (`$GENESEED_WIKI` → `$GENESEED_HARNESS/geneseed-wiki.jsonc` → beside the
211
211
  install). Per wiki: eager entries inject in full, lazy entries list, and the
212
212
  `conventions` / `inbox` / `protected` metadata is surfaced — on the **same**
213
213
  budgets, compaction and transform paths as the project context. Schema and
@@ -385,7 +385,7 @@ behaviour** — nothing changes the machine's current agent/model unless you opt
385
385
  - **Runtime guard plugin** (`geneseed-guard.js`, installed with the others). Enforces
386
386
  the safety Laws at the tool boundary: **blocks** writes to private-key/credential
387
387
  files (Sealed Secrets), catastrophic shell like `rm -rf /` (Deletion Is Deliberate), and any mutation under
388
- a declared wiki's `protected` folders (AGENT.md §8, from `wiki.jsonc`); **warns** on
388
+ a declared wiki's `protected` folders (AGENT.md §8, from `geneseed-wiki.jsonc`); **warns** on
389
389
  `.env` writes and force-push. `GENESEED_GUARD=off` disables it, `=warn` downgrades
390
390
  blocks to warnings. Every **block** appends one line to the install's
391
391
  `notebook/gates.jsonl` (rule `law-1` / `law-4` / `process-1` / `wiki`, a timestamp,
@@ -27,11 +27,11 @@
27
27
  // is added per request, outside the cached block; unknown -> omitted.
28
28
  //
29
29
  // MACHINE WIKI (AGENT.md §8): the same block also carries the user's own knowledge
30
- // base(s) — typically an Obsidian vault — declared once per machine in `wiki.jsonc`
31
- // ($GENESEED_WIKI -> $GENESEED_HARNESS/wiki.jsonc -> beside this plugin's install).
30
+ // base(s) — typically an Obsidian vault — declared once per machine in `geneseed-wiki.jsonc`
31
+ // ($GENESEED_WIKI -> $GENESEED_HARNESS/geneseed-wiki.jsonc -> beside this plugin's install).
32
32
  // Each wiki's eager entries inject in full and lazy entries list, drawing on the
33
33
  // SAME budgets as the project context; its conventions/inbox/protected metadata is
34
- // surfaced so the agent knows the house rules before writing. No wiki.jsonc, or an
34
+ // surfaced so the agent knows the house rules before writing. No wiki manifest, or an
35
35
  // empty `wikis` list, costs nothing.
36
36
  //
37
37
  // DELIVERY (invisible by default): the context rides into each request's message
@@ -159,8 +159,8 @@ const EAGER_ROOT = new Set([
159
159
  ".cursorrules", "README.md", "README.adoc", "CONTRIBUTING.md", "CONTRIBUTING.adoc",
160
160
  "user-rules.md", "PROFILE.md",
161
161
  ])
162
- // Project docs are Markdown or AsciiDoc (document-project writes AsciiDoc when a project has
163
- // none yet). Same set as js/hosts/hooks-context.mjs DOC_EXT.
162
+ // Project docs are Markdown or AsciiDoc (document-project writes AsciiDoc when the user asks
163
+ // for it). Same set as js/hosts/hooks-context.mjs DOC_EXT.
164
164
  const isDoc = (name) => /\.(md|adoc)$/i.test(name)
165
165
  // Doc trees walked recursively; everything found is lazy (listed, not injected).
166
166
  const LAZY_DIRS = ["docs", "doc", "documentation", "architecture", "adr", "ADR"]
@@ -178,14 +178,16 @@ async function isDir(p) { try { return (await fs.stat(p)).isDirectory() } catch
178
178
  // holds the installed AGENT.md: the repo root for a project install, the config dir for a
179
179
  // global one. Same list and seed hashes as SESSION_FILES/SEED_SHA256 in js/hosts/hooks.mjs;
180
180
  // tests/unit/claude.test.mjs gates both copies against SESSION_SEEDS in js/build/stubs.mjs.
181
- // context.json is not here: it is a manifest, honoured by resolveSource. wiki.jsonc is not
182
- // here either: the MACHINE WIKI block below already renders it in full.
181
+ // context.json is not here: it is a manifest, honoured by resolveSource. geneseed-wiki.jsonc
182
+ // is not here either: the MACHINE WIKI block below already renders it in full.
183
183
  const SESSION_FILES = ["user-rules.md", "PROFILE.md", "memory/MEMORY.md", "anamnesis/MEMORY.md",
184
184
  "notebook/NOTEBOOK.md"]
185
185
  const SEED_SHA256 = new Set([
186
186
  "5c2e92fb1acde041e02d9ebf158460d8ff7a07cbc2b447859631604610130721", // user-rules.md
187
187
  "29e012c3c4349ea62a9082cbd04bb25599a0ec280d62c33f6e10742809471816", // PROFILE.md
188
- "cccc917c34e6b990e821620bdb4739090151885ab71b6e85046f30a3b71fa5e8", // wiki.jsonc
188
+ "3a82c78ccc5d745033c16c354f5eda9d79350c704e9da8d605d380fb1e108d7a", // geneseed-wiki.jsonc
189
+ // The wiki seed before the rename: the build renames an untouched one byte for byte.
190
+ "cccc917c34e6b990e821620bdb4739090151885ab71b6e85046f30a3b71fa5e8", // wiki.jsonc (legacy)
189
191
  "99c786049c260f6baf7aec68a5c0f59907861afe9b867da009440613bdddb907", // MEMORY.md
190
192
  "9acb5c9d9cb5dac572104480f05b48cc144e676869bd60e86d8a15b1f6308184", // NOTEBOOK.md
191
193
  ])
@@ -221,8 +223,8 @@ async function readJson(p) {
221
223
  }
222
224
 
223
225
  // Strip JSONC niceties — // and /* */ comments plus trailing commas — string-aware,
224
- // so a "https://…" or "C:/Users/…" inside quotes is untouched. wiki.jsonc is seeded
225
- // with a commented example, so its readers must tolerate comments.
226
+ // so a "https://…" or "C:/Users/…" inside quotes is untouched. the wiki manifest is
227
+ // seeded with a commented example, so its readers must tolerate comments.
226
228
  function stripJsonc(text) {
227
229
  let out = "", inStr = false, esc = false
228
230
  for (let i = 0; i < text.length; i++) {
@@ -550,13 +552,13 @@ async function resolveSource(root, harness = null) {
550
552
  return { mode: "discover" }
551
553
  }
552
554
 
553
- // ---- machine wiki (wiki.jsonc) --------------------------------------------------
555
+ // ---- machine wiki (geneseed-wiki.jsonc) ------------------------------------------
554
556
  // The user's own knowledge base(s) — typically an Obsidian vault — declared once per
555
557
  // machine, not per repo (AGENT.md §8). Same injection mechanics as project context,
556
558
  // different scope. Resolution (first match wins, mirroring the learn plugin):
557
559
  // 1. $GENESEED_WIKI explicit manifest path
558
- // 2. $GENESEED_HARNESS/wiki.jsonc pinned install dir
559
- // 3. <plugin dir>/../wiki.jsonc auto-locate: beside the installed AGENT.md
560
+ // 2. $GENESEED_HARNESS/geneseed-wiki.jsonc pinned install dir
561
+ // 3. <plugin dir>/../geneseed-wiki.jsonc auto-locate: beside the installed AGENT.md
560
562
  async function resolveWikiFile() {
561
563
  const explicit = process.env.GENESEED_WIKI
562
564
  if (explicit && (await isFile(explicit))) return explicit
@@ -568,8 +570,8 @@ async function resolveWikiFile() {
568
570
  if (harness) bases.push(harness)
569
571
  bases.push(path.resolve(PLUGIN_DIR, ".."))
570
572
  for (const base of bases) {
571
- // wiki.json is the legacy name from earlier seeds — still honoured.
572
- for (const name of ["wiki.jsonc", "wiki.json"]) {
573
+ // wiki.jsonc and wiki.json are the legacy names from earlier seeds — still honoured.
574
+ for (const name of ["geneseed-wiki.jsonc", "wiki.jsonc", "wiki.json"]) {
573
575
  const p = path.join(base, name)
574
576
  if (await isFile(p)) return p
575
577
  }
@@ -602,7 +604,7 @@ async function walkWikiDir(dir, depth, acc) {
602
604
  // folders on demand instead.
603
605
  const WIKI_LAZY_LIMIT = envNum("GENESEED_WIKI_LAZY_LIMIT", 200)
604
606
 
605
- // Parse wiki.jsonc into renderable wikis: [{ name, root, desc, conventions, inbox,
607
+ // Parse the wiki manifest into renderable wikis: [{ name, root, desc, conventions, inbox,
606
608
  // protected, eager:[{rel,abs,desc}], lazy:[...], truncated }]. Entry paths resolve
607
609
  // against the wiki's own root and may name a single note OR a folder — a folder
608
610
  // applies its load mode to every note beneath it (`.` covers the whole vault).
@@ -613,7 +615,7 @@ const WIKI_LAZY_LIMIT = envNum("GENESEED_WIKI_LAZY_LIMIT", 200)
613
615
  async function wikiSets() {
614
616
  const file = await resolveWikiFile()
615
617
  if (!file) return []
616
- const data = await readJsonc(file) // wiki.jsonc is JSONC: stub ships commented
618
+ const data = await readJsonc(file) // the manifest is JSONC: stub ships commented
617
619
  const wikis = Array.isArray(data?.wikis) ? data.wikis : []
618
620
  const out = []
619
621
  for (const w of wikis) {
@@ -7,7 +7,7 @@
7
7
  // - Persist Insight (rule vs memory): speed-bump the first write to user-rules.md
8
8
  // memory file — that choice belongs to the user, via the rule skill.
9
9
  // - Wiki (AGENT.md §8): block mutations under a declared wiki's `protected`
10
- // folders — the user's knowledge base sets its own no-go zones in wiki.jsonc.
10
+ // folders — the user's knowledge base sets its own no-go zones in geneseed-wiki.jsonc.
11
11
  // High-confidence patterns only, so legitimate work is never caught. Borderline cases
12
12
  // (.env edits, force-push) are WARNED, not blocked.
13
13
  //
@@ -171,13 +171,13 @@ const SHELL_TOOLS = ["bash", "shell", "exec", "command", "terminal", "run"]
171
171
  const hasAny = (name, parts) => parts.some((s) => name.includes(s))
172
172
 
173
173
  // ---- protected wiki folders (AGENT.md §8) --------------------------------------
174
- // wiki.jsonc (the machine-level knowledge-base manifest) may list `protected` folders
174
+ // geneseed-wiki.jsonc (the machine-level knowledge-base manifest) may list `protected` folders
175
175
  // per wiki. Mutating anything under one is denied. Same resolution chain as the
176
- // context plugin: $GENESEED_WIKI -> $GENESEED_HARNESS/wiki.jsonc -> beside the install.
176
+ // context plugin: $GENESEED_WIKI -> $GENESEED_HARNESS/geneseed-wiki.jsonc -> beside the install.
177
177
  async function isFile(p) { try { return (await fs.stat(p)).isFile() } catch { return false } }
178
178
  async function isDir(p) { try { return (await fs.stat(p)).isDirectory() } catch { return false } }
179
179
 
180
- // wiki.jsonc is JSONC (the seeded stub carries a commented example): strip // and
180
+ // The wiki manifest is JSONC (the seeded stub carries a commented example): strip // and
181
181
  // /* */ comments plus trailing commas before parsing — string-aware, so quoted
182
182
  // "https://…" or "C:/…" values are untouched. Kept in sync with the context plugin's
183
183
  // copy (plugins stay self-contained, like the other shared helpers).
@@ -226,8 +226,8 @@ async function wikiFile() {
226
226
  if (process.env.GENESEED_HARNESS) bases.push(process.env.GENESEED_HARNESS)
227
227
  bases.push(path.resolve(PLUGIN_DIR, ".."))
228
228
  for (const base of bases) {
229
- // wiki.json is the legacy name from earlier seeds — still honoured.
230
- for (const name of ["wiki.jsonc", "wiki.json"]) {
229
+ // wiki.jsonc and wiki.json are the legacy names from earlier seeds — still honoured.
230
+ for (const name of ["geneseed-wiki.jsonc", "wiki.jsonc", "wiki.json"]) {
231
231
  const p = path.join(base, name)
232
232
  if (await isFile(p)) return p
233
233
  }
@@ -235,7 +235,7 @@ async function wikiFile() {
235
235
  return null
236
236
  }
237
237
 
238
- // Cached absolute prefixes, refreshed on a short TTL so a wiki.jsonc edit lands
238
+ // Cached absolute prefixes, refreshed on a short TTL so a manifest edit lands
239
239
  // without a restart. Compared slash-normalized and case-insensitive — vault paths on
240
240
  // Windows and macOS are case-insensitive in practice, and for a guard the rare
241
241
  // case-only over-match is the safe direction.
@@ -155,6 +155,11 @@ const VERBS = {
155
155
  // lives entirely inside this port, so — like the three above — it has no recorded cell to
156
156
  // compare against, only the absolute gates named beside it in `NATIVE`.
157
157
  loop: () => import('../js/loop/cli.mjs').then((m) => m.cmdLoop),
158
+ // A fifth native verb, and a port rather than an invention: the AI Harness Scorecard
159
+ // (upstream Python, pinned in the module's docblock). No Geneseed Python subparser ever
160
+ // existed for it, so there is no recorded cell — its absolute gate is
161
+ // tests/unit/scorecard.test.mjs. Lazy like every row: the 31 checks load only when asked.
162
+ scorecard: () => import('../js/inspect/scorecard.mjs').then((m) => m.cmdScorecard),
158
163
  };
159
164
 
160
165
  function die(code, msg) {
@@ -61,7 +61,7 @@ The install records it (`Excluded rules: process 7` beside its pack list) and ev
61
61
  Every installed skill costs a line in the host's skill listing, every session. Skills you never use can be left out of an install:
62
62
 
63
63
  ```bash
64
- geneseed build --emit claude-global --exclude-skills "bruno-test-writer,bruno-collection-generator,react-view-transitions"
64
+ geneseed build --emit claude-global --exclude-skills "bruno,react-view-transitions"
65
65
  ```
66
66
 
67
67
  The skill's files are not written, its catalogue row goes, and an OpenCode `/command` that runs it goes too. The install records the list (`Excluded skills: …` under its skill section), and every rebuild and upgrade keeps it. `--exclude-skills none` puts them all back.
@@ -17,7 +17,7 @@ A **skill** is a repeatable workflow written as a markdown playbook: when it app
17
17
 
18
18
  - **By name.** Ask for it — "brainstorm this", "run a council on it" — or, on hosts with slash commands, type `/<name>`.
19
19
  - **By trigger.** Every skill has a one-line description of its purpose and when it applies. The host shows those descriptions to the agent every turn, and the agent opens the matching skill when your request fits.
20
- - **User-only skills.** A few skills are marked to open only when *you* call them (a teaching drill, a tool tied to a setup the agent cannot see). They answer `/<name>` but the agent never starts them on its own, and their description stays out of the always-loaded list.
20
+ - **User-only skills.** A few skills are marked to open only when *you* call them (a teaching drill, a tool tied to a setup the agent cannot see, a guide for one stack or one personal vault). They answer `/<name>` but the agent never starts them on its own, and their description stays out of the always-loaded list.
21
21
 
22
22
  ### A tour
23
23
 
@@ -29,7 +29,7 @@ A **skill** is a repeatable workflow written as a markdown playbook: when it app
29
29
  | find a bug by evidence: reproduce, isolate, root-cause, verify | `debug` |
30
30
  | answer a question from the open web, every claim cross-checked | `research` |
31
31
  | have several viewpoints debate a decision | `council` |
32
- | get an adversarial critique of anything | `roast-me` |
32
+ | get an adversarial critique of your own ask, plan or idea | `roast-me` |
33
33
  | see what a change does before you agree to commit it | `explain-changes` |
34
34
  | stage the right paths and write a focused commit | `commit` |
35
35
  | open a pull request, or finish and merge a branch | `ship` |
@@ -42,6 +42,10 @@ The full list, with each description, is in the catalog.
42
42
 
43
43
  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
44
 
45
+ ### Old names keep working
46
+
47
+ When two skills merge, the old name still works as a slash command: `/deps-audit` runs `dependencies`, and `/ci-fix` runs `debug`. The old names are user-only, so the agent's list shows each skill once. If you had left out a skill that was later merged, a rebuild leaves out the merged skill instead. A skill removed with no replacement is dropped from that list, with a note.
48
+
45
49
  ### What they cost
46
50
 
47
51
  The skill *bodies* are read only when used. The *descriptions* are listed to the agent every turn so it can pick the right one — that list is part of the always-on cost described in [Footprint](footprint.md).
package/docs/extending.md CHANGED
@@ -349,6 +349,10 @@ Intent became IX.
349
349
 
350
350
  ## 3 — Adding a SKILL or an AGENT
351
351
 
352
+ **First, try not to.** Skills rot really fast. Can an existing skill absorb this, or can one be
353
+ merged or deleted to make room? Every skill adds a description to the always-on list and one more
354
+ candidate for routing to choose between, so add only what no sharpened existing skill covers.
355
+
352
356
  **Order matters at the first two steps.** `missingReferencedSpecs` (in `js/build/bundle.mjs`) *aborts the
353
357
  build* when `AGENT.md.tmpl` names a spec with no file — so the file comes before the table row, or
354
358
  nothing builds at all. The refusal is clean: `tests/unit/emit_gates.test.mjs:265` proves a refused
@@ -396,6 +400,35 @@ Two traps worth knowing before you write the spec:
396
400
  which drags in the `web/dist` rebuild — and an unknown category lands under Personal in the
397
401
  Library (`splitSkills` in `web/src/pages/Library.jsx`) with no warning.
398
402
 
403
+ **Merging or removing a skill keeps its old name working.** When a skill absorbs another, put
404
+ `<!-- aliases: old-name, other-old-name -->` on its own line under the surviving skill's purpose
405
+ blockquote. Every host then answers `/old-name` with the merged skill's body. Claude Code,
406
+ OpenClaude and Bob get a user-only `skills/<alias>/SKILL.md`, and OpenCode gets a
407
+ `command/<alias>.md`. Neither form is counted as a skill. An install that excluded the old name
408
+ now excludes the merged skill (`resolveSkillNames` in `js/build/source.mjs`), so a rebuild still
409
+ works. A skill removed with no successor goes into `RETIRED_SKILL_IDS` in the same file: its
410
+ exclusion is dropped with a notice instead of failing the rebuild, and the name can never be
411
+ used for a new skill. The doctor (`aliasProblems`) refuses an alias that is malformed, duplicated,
412
+ already a skill, retired, or the name of an OpenCode command.
413
+
414
+ **A rarely-needed half goes in a side file.** A skill body is paid in full every time the skill
415
+ loads. A branch only some runs need, or a big reference, can move into
416
+ `src/skills/<name>/<file>.md` beside the flat spec. The body keeps one pointer line, such as debug's
417
+ `**CI run red** → read [debug/ci.md](debug/ci.md) and follow it.` The side file costs nothing
418
+ until the agent follows that pointer, and then it costs its own size. So move a half only when
419
+ most runs skip it. The flat spec stays the source, so steps 1–9 are unchanged. The side file is
420
+ themed like a spec, and `{{LAW:id}}` citations resolve in it and are gated. Every emit writes it
421
+ next to the skill: `skills/<name>/<file>.md` in the flat bundle, and beside `SKILL.md` on every
422
+ native host, through `claim()`. Native hosts get a code-span path instead of the link:
423
+ `<this-skill-directory>` where the host announces the skill's directory, and the resolved
424
+ directory on Bob and in OpenCode commands, aliases included (`pointSideFiles` in
425
+ `js/hosts/native.mjs`). The doctor (`sideFileProblems`) requires a flat spec for the folder, `.md`
426
+ files one level down, no `SKILL.md`, and a link to every side file from the body.
427
+ `tests/unit/side_files.test.mjs` resolves every emitted pointer. The dead-link scan cannot,
428
+ because a code span is not a link. Measured on 2026-10-08, with the neutral theme at the lean
429
+ footprint: debug's SKILL.md went from 1.64k to 1.18k tokens and rule's from 2.33k to 1.83k
430
+ (chars/4).
431
+
399
432
 
400
433
  ---
401
434
 
@@ -65,6 +65,26 @@ A monorepo with docs scattered across packages might write:
65
65
 
66
66
  Keep the eager list to the few files a new teammate would read first. Three sharp docs beat ten broad ones. Use `"load": "lazy"` for anything a session should only read on demand.
67
67
 
68
+ ## Review rules: `REVIEW.md`
69
+
70
+ `AGENTS.md` (or `CLAUDE.md`) holds the rules for *doing* the work, and the agent loads it every session. `REVIEW.md` holds the rules for *judging* the work: what counts as serious, what to skip, how many nits are worth reporting, and checks that hold only in this codebase. It is read only when code is reviewed, so the agent writing the code never pays for it.
71
+
72
+ - **Nearest wins.** For each changed file, the reviewer applies the nearest `REVIEW.md` above it, up to the repo root. A `REVIEW.md` in `api/` overrides the root one for files under `api/`.
73
+ - **Precedence.** A folder's `REVIEW.md`, then the root `REVIEW.md`, then `CODING_STANDARDS.md` / `CONTRIBUTING.md`, then Geneseed's review defaults, output format included. A `REVIEW.md` never lifts a law: it cannot let the reviewer edit code or skip running the checks.
74
+ - **Who reads it.** The `geneseed-code-review` skill and the `reviewer` agent, which also serves the loop `review` brick and the pipeline reviewer seat. The `ship` skill runs that review before it opens a pull request.
75
+ - **Who writes it.** Nobody by default. Ask for a review rule, or let a finding recur, and the `review-response` skill offers the exact lines for the nearest `REVIEW.md`, creating it if it is missing, and writes them only when you agree.
76
+
77
+ A host's own review command does not read `REVIEW.md` by itself. The always-loaded root file carries one sentence that tells it to:
78
+
79
+ | Host | Built-in review command | Reads `REVIEW.md` natively | How it gets applied |
80
+ |---|---|---|---|
81
+ | Claude Code | `/code-review`, `/review` | No (only the managed GitHub Code Review does, root file only) | The sentence in `CLAUDE.md`, which the built-in review follows; or run `/geneseed-code-review` |
82
+ | OpenClaude | Undocumented | No | The sentence in `.openclaude/CLAUDE.md`; or run `/geneseed-code-review` |
83
+ | Bob | `/review`, Review panel | No | The sentence in `AGENTS.md` / `.bob/rules/geneseed.md`, which Bob injects in every mode |
84
+ | OpenCode | None | No | `/code-review` runs `geneseed-code-review`, which reads it |
85
+
86
+ For OpenClaude and Bob, that the built-in review honours the sentence follows from how each host loads its rules files; it has not been checked live yet. Keep `REVIEW.md` short, because every rule in it competes for the reviewer's attention.
87
+
68
88
  <!--harness:opencode-->
69
89
  *(OpenCode only)*
70
90
 
@@ -12,6 +12,6 @@ The agent's doc discovery sees markdown (`.md`) and AsciiDoc (`.adoc`) only. The
12
12
  - **Pandoc**: excellent for Office and HTML, and a single binary.
13
13
  - **Docling** (IBM): best for complex tables and scanned PDFs.
14
14
 
15
- When an MCP converter is available, the skill prefers it. A prompt like *"convert file:///path/to/spec.pdf to markdown"* then just works. The skill never installs a converter silently. If none is present, it tells you which one to add.
15
+ When an MCP converter is available, the skill prefers it. A prompt like "`convert file:///path/to/spec.pdf to markdown`" then just works. The skill never installs a converter silently. If none is present, it tells you which one to add.
16
16
 
17
17
  Converter not found, or an MCP converter listed but not connecting? See [Model, agent and MCP problems](../reference/troubleshoot-tools.md).
@@ -33,7 +33,7 @@ It also removes the install's row from the registry of installs. Start a new ses
33
33
  ## What it keeps
34
34
 
35
35
  - **`memory/` and `notebook/`.** These are never deleted. `--archive-memory` moves both aside, into sibling `archived-memory/<timestamp>/` and `archived-notebook/<timestamp>/` folders, instead of leaving them in place. Even then they are moved, not deleted.
36
- - **`wiki.jsonc`**, **`context.json`** and the **`improvements/`** folder. None of these are in the manifest.
36
+ - **`geneseed-wiki.jsonc`** (or `wiki.jsonc`, its name before the rename), **`context.json`** and the **`improvements/`** folder. None of these are in the manifest.
37
37
  - **Other installs.** Removing the global install does not touch any project install. Uninstall lists the project installs that remain, each with the command that removes it. If a repo carries installs for several hosts, uninstall removes one and tells you to run it again for the next.
38
38
 
39
39
  ## The hook shim
@@ -39,7 +39,7 @@ A dirty working tree, or a folder that is not a git clone, is reported rather th
39
39
  A rebuild only replaces files the install's manifest says Geneseed owns. It leaves these alone:
40
40
 
41
41
  - the `memory/` and `notebook/` stores;
42
- - your `context.json` and `wiki.jsonc`;
42
+ - your `context.json` and `geneseed-wiki.jsonc` (an older `wiki.jsonc` is renamed to it, contents untouched);
43
43
  - the marker files that record each install's choices (theme, footprint, packs, excluded rules), which every rebuild reads back;
44
44
  - your own agents, skills, plugins and hooks, and any `opencode.json` or `settings.json` keys you wrote yourself;
45
45
  - the `improvements/` folder (see below).
@@ -18,9 +18,9 @@ If you keep a personal knowledge base on this machine, such as an Obsidian vault
18
18
 
19
19
  When a memory fact or a notebook note hardens into knowledge worth keeping across projects, the agent promotes it into the wiki, so the truth lives in one place.
20
20
 
21
- ## Declare it in `wiki.jsonc`
21
+ ## Declare it in `geneseed-wiki.jsonc`
22
22
 
23
- The build writes a `wiki.jsonc` stub beside `AGENT.md` (for the OpenCode global install, `~/.config/opencode/wiki.jsonc`) and never overwrites it. The file is JSONC, so comments and trailing commas are fine. The stub contains this example, commented out:
23
+ The build writes a `geneseed-wiki.jsonc` stub beside `AGENT.md` (for the OpenCode global install, `~/.config/opencode/geneseed-wiki.jsonc`) and never overwrites it. The file is JSONC, so comments and trailing commas are fine. The stub contains this example, commented out:
24
24
 
25
25
  ```json
26
26
  {
@@ -47,7 +47,7 @@ The build writes a `wiki.jsonc` stub beside `AGENT.md` (for the OpenCode global
47
47
 
48
48
  You can declare several wikis. An empty `wikis` list keeps the feature off. The file may hold private paths. It is specific to this machine and must never be committed. A project install's own `.gitignore` already lists it.
49
49
 
50
- Geneseed looks for the file in this order: `$GENESEED_WIKI`, then `$GENESEED_HARNESS/wiki.jsonc`, then beside the installed `AGENT.md`. A `wiki.json` left by an older install is still read at each of those places.
50
+ Geneseed looks for the file in this order: `$GENESEED_WIKI`, then `$GENESEED_HARNESS/geneseed-wiki.jsonc`, then beside the installed `AGENT.md`. The build renames a `wiki.jsonc` or `wiki.json` left by an older install to `geneseed-wiki.jsonc`, contents untouched, and adds the new name to a `.gitignore` that listed the old one. Until that next build, the old `wiki.jsonc` is still read at each of those places.
51
51
 
52
52
  ## How each host honours it
53
53
 
@@ -60,7 +60,7 @@ The context plugin loads your eager entries and lists your lazy ones at session
60
60
  <!--harness:claude-->
61
61
  *(Claude Code only)*
62
62
 
63
- No hook reads the wiki. The instructions in your harness tell the agent to read `wiki.jsonc` at session start and to honour it, including the `protected` folders. That is an instruction the model follows, not a block. Nothing stops a write at the tool boundary. The same applies to Bob, OpenClaude and plain `AGENT.md` tools. See [Enforced vs. asked](../understand/enforced-vs-asked.md).
63
+ No hook reads the wiki. The instructions in your harness tell the agent to read `geneseed-wiki.jsonc` at session start and to honour it, including the `protected` folders. That is an instruction the model follows, not a block. Nothing stops a write at the tool boundary. The same applies to Bob, OpenClaude and plain `AGENT.md` tools. See [Enforced vs. asked](../understand/enforced-vs-asked.md).
64
64
  <!--/harness-->
65
65
 
66
66
  ## What the agent does with it
@@ -27,7 +27,7 @@ echo "export GENESEED_HARNESS=\"$GENESEED_HARNESS\"" >> ~/.zshrc # persist (
27
27
  ```
28
28
 
29
29
  `GENESEED_HARNESS` points the plugins at your deployed bundle so they find the
30
- memory store, `context.json`, and `wiki.jsonc` with no hand-typed path. Using a
30
+ memory store, `context.json`, and `geneseed-wiki.jsonc` with no hand-typed path. Using a
31
31
  non-default bundle location (`GENESEED_OUT`)? Set `GENESEED_HARNESS` to that
32
32
  path instead of `../Harness`.
33
33
 
@@ -18,7 +18,7 @@ What gets loaded into the agent's context at session start — your project's do
18
18
  | --- | --- | --- |
19
19
  | `GENESEED_CONTEXT` | context plugin, context hook | Explicit `context.json` manifest path; overrides discovery. |
20
20
  | `GENESEED_ROOT` | context hook | Repo root to discover docs from (default: the current directory). |
21
- | `GENESEED_WIKI` | context + guard plugins, context hook, web console | Explicit `wiki.jsonc` path (default `$GENESEED_HARNESS/wiki.jsonc`, else beside the install). |
21
+ | `GENESEED_WIKI` | context + guard plugins, context hook, web console | Explicit `geneseed-wiki.jsonc` path (default `$GENESEED_HARNESS/geneseed-wiki.jsonc`, else beside the install). |
22
22
  | `GENESEED_STACK_GLOBAL` | context hook, Claude Code project build | `1` lets a global and a project install of the same host both inject. By default the project install makes the global one stand down. Rebuild the project install after changing it. |
23
23
  | `GENESEED_CONTEXT_INJECT` | context plugin | `off` disables injection; the agent is only *asked* to read the docs. |
24
24
  | `GENESEED_CONTEXT_VISIBLE` | context plugin | `1` shows the visible `PROJECT CONTEXT` block instead of the invisible per-request delivery. |
@@ -33,7 +33,7 @@ Where distilled memories land at session end, and which model distils them. See
33
33
 
34
34
  | Variable | Read by | Effect |
35
35
  | --- | --- | --- |
36
- | `GENESEED_HARNESS` | learn, context, guard plugins; CLI | Base whose `memory/` is written (and where `wiki.jsonc` is looked up). Optional — the plugin finds the in-config store by itself; set it to pin the location. |
36
+ | `GENESEED_HARNESS` | learn, context, guard plugins; CLI | Base whose `memory/` is written (and where `geneseed-wiki.jsonc` is looked up). Optional — the plugin finds the in-config store by itself; set it to pin the location. |
37
37
  | `GENESEED_MEMORY` | learn plugin, CLI | Explicit memory dir; wins over `GENESEED_HARNESS`. |
38
38
  | `GENESEED_MODEL` | learn + context plugins | `provider/model` fallback when the session's model can't be read from the transcript. |
39
39
  | `GENESEED_LLM` | learn hook (Claude Code, Bob, OpenClaude) | Model CLI used to distil, e.g. `claude -p`. Unset, the hook prints the prompt instead of distilling. |
@@ -12,7 +12,7 @@ One of the [OpenCode plugins](opencode-plugins.md). Its switches are also listed
12
12
 
13
13
  - **Injected in full (eager):** root `README.md`, `CONTRIBUTING.md` (or `README.adoc`, `CONTRIBUTING.adoc`), `.cursorrules`, `user-rules.md`, `PROFILE.md`. Budget-capped; an oversized file is listed instead, never silently truncated. (`AGENT.md`, `AGENTS.md` and `CLAUDE.md` are not injected — OpenCode already loads them.)
14
14
  - **Listed (lazy, path + first heading, read on demand):** `docs/`, `doc/`, `documentation/`, `architecture/`, `adr/`, and `packages/*/README.md` / `apps/*/README.md` in a monorepo, AsciiDoc `.adoc` docs included. `node_modules`, `.git`, `dist`, `build`, `vendor` and similar are never scanned.
15
- - **Machine wiki:** the wikis declared in `wiki.jsonc` ride in the same block, on the same budgets. See [Wiki](../guides/wiki.md).
15
+ - **Machine wiki:** the wikis declared in `geneseed-wiki.jsonc` ride in the same block, on the same budgets. See [Wiki](../guides/wiki.md).
16
16
  - **Explicit manifest:** `$GENESEED_CONTEXT`, `.harness/context.json` or a root `context.json` takes over from discovery; `"extend": true` layers it on top instead. See [Project context](../guides/project-context.md).
17
17
 
18
18
  **When it runs.** On every request: the context rides invisibly in the request's message list, so it also survives compaction. If your OpenCode build lacks that (experimental) hook, the plugin notices and falls back to one visible message at session start, re-pushed when the session compacts.
@@ -23,5 +23,5 @@ One of the [OpenCode plugins](opencode-plugins.md). Its switches are also listed
23
23
  - `GENESEED_CONTEXT_INJECT=off` — no injection; the agent is only *asked* to read the docs.
24
24
  - `GENESEED_CONTEXT_VISIBLE=1` — force the visible block (legacy `GENESEED_CONTEXT_TRANSFORM=0` does the same).
25
25
  - `GENESEED_EAGER_FILE_KB` / `GENESEED_EAGER_TOTAL_KB` (default 16 / 48), `GENESEED_LAZY_HEADINGS` (64), `GENESEED_WIKI_LAZY_LIMIT` (200) — budgets.
26
- - `GENESEED_WIKI` — explicit `wiki.jsonc` path.
26
+ - `GENESEED_WIKI` — explicit `geneseed-wiki.jsonc` path.
27
27
  - `GENESEED_DEBUG=1` — log what it discovered and injected to stderr. Silence with this set means the plugin did not load.