geneseed 2.1.0 → 3.0.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 (187) hide show
  1. package/CHANGELOG.md +108 -0
  2. package/DESIGN.md +112 -61
  3. package/QUICKSTART.md +1 -1
  4. package/README.md +24 -14
  5. package/SETUP.md +83 -17
  6. package/SHIPPED.md +5 -4
  7. package/adapters/bob/README.md +3 -3
  8. package/adapters/claude-code/README.md +6 -4
  9. package/adapters/claude-code/skills/geneseed/SKILL.md +10 -6
  10. package/adapters/copilot/README.md +5 -4
  11. package/adapters/opencode/GLOBAL-HARNESS-SPEC.md +11 -6
  12. package/adapters/opencode/HOW-OPENCODE-LOADS.md +1 -1
  13. package/adapters/opencode/README.md +15 -9
  14. package/adapters/opencode/agents/orchestrator.md +1 -1
  15. package/adapters/opencode/plugins/geneseed-context.js +7 -7
  16. package/adapters/opencode/plugins/geneseed-guard.js +6 -6
  17. package/adapters/opencode/workflows/dispatch.js +1 -1
  18. package/bin/geneseed.mjs +72 -6
  19. package/docs/extending.md +164 -55
  20. package/docs/limits.md +4 -4
  21. package/docs/token-footprint.md +15 -4
  22. package/docs/web/authoring.md +1 -1
  23. package/docs/web/claude-hooks.md +2 -2
  24. package/docs/web/collaboration.md +3 -3
  25. package/docs/web/first-session.md +2 -2
  26. package/docs/web/footprint.md +14 -7
  27. package/docs/web/foreman-mode.md +2 -2
  28. package/docs/web/harnesses.md +5 -3
  29. package/docs/web/install-quick.md +1 -1
  30. package/docs/web/model.md +3 -3
  31. package/docs/web/plugin-context.md +2 -2
  32. package/docs/web/plugin-guard.md +3 -3
  33. package/docs/web/plugin-ponytail.md +1 -1
  34. package/docs/web/rules.md +23 -3
  35. package/docs/web/setup-choices.md +20 -7
  36. package/docs/web/themes-author.md +13 -1
  37. package/docs/web-ui.md +36 -12
  38. package/harness.config.json +1 -1
  39. package/js/catalog.mjs +29 -4
  40. package/js/checkout.mjs +24 -1
  41. package/js/cli-table.json +8 -6
  42. package/js/diff.mjs +8 -3
  43. package/js/doctor.mjs +307 -4
  44. package/js/emit.mjs +48 -11
  45. package/js/generate.mjs +39 -5
  46. package/js/hooks.mjs +8 -7
  47. package/js/installs.mjs +101 -4
  48. package/js/inventory.mjs +150 -21
  49. package/js/migrate.mjs +10 -4
  50. package/js/render.mjs +110 -7
  51. package/js/settings.mjs +218 -27
  52. package/js/setup.mjs +95 -5
  53. package/js/status.mjs +45 -4
  54. package/js/tui.mjs +44 -1
  55. package/js/uninstall.mjs +25 -6
  56. package/js/web/actions.mjs +56 -5
  57. package/js/web/api.mjs +95 -16
  58. package/js/web/docs.mjs +33 -5
  59. package/js/web/jobs.mjs +12 -3
  60. package/js/web/server.mjs +6 -0
  61. package/package.json +1 -1
  62. package/src/AGENT.md.tmpl +75 -65
  63. package/src/agents/_template.md +4 -4
  64. package/src/agents/advocate.md +4 -4
  65. package/src/agents/architect.md +2 -2
  66. package/src/agents/developer.md +5 -5
  67. package/src/agents/docs.md +2 -2
  68. package/src/agents/empiricist.md +3 -3
  69. package/src/agents/explorer.md +3 -3
  70. package/src/agents/framer.md +3 -3
  71. package/src/agents/historian.md +3 -3
  72. package/src/agents/operator.md +3 -3
  73. package/src/agents/pragmatist.md +3 -3
  74. package/src/agents/reviewer.md +2 -2
  75. package/src/agents/security.md +2 -2
  76. package/src/agents/skeptic.md +4 -4
  77. package/src/agents/steward.md +3 -3
  78. package/src/agents/tester.md +2 -2
  79. package/src/agents/user-advocate.md +3 -3
  80. package/src/agents/visionary.md +3 -3
  81. package/src/doctrines/README.md +41 -0
  82. package/src/doctrines/craft.md +51 -0
  83. package/src/doctrines/ops.md +61 -0
  84. package/src/doctrines/process.md +87 -0
  85. package/src/doctrines/rigor.md +52 -0
  86. package/src/laws/universal.md +17 -336
  87. package/src/memory/README.md +2 -2
  88. package/src/modes/README.md +2 -2
  89. package/src/modes/foreman.md +1 -1
  90. package/src/notebook/README.md +2 -2
  91. package/src/ontology/universal.md +89 -0
  92. package/src/postures/README.md +3 -3
  93. package/src/postures/artisan.md +3 -3
  94. package/src/postures/assistant.md +1 -1
  95. package/src/postures/expert.md +1 -1
  96. package/src/postures/mentor.md +1 -1
  97. package/src/postures/peer.md +2 -2
  98. package/src/skills/_template.md +2 -2
  99. package/src/skills/brainstorm.md +2 -2
  100. package/src/skills/clarify.md +2 -2
  101. package/src/skills/codebase-design.md +1 -1
  102. package/src/skills/commit.md +5 -5
  103. package/src/skills/council.md +4 -4
  104. package/src/skills/crash-course.md +1 -1
  105. package/src/skills/daydream/SKILL.md +1 -1
  106. package/src/skills/debug.md +2 -2
  107. package/src/skills/decode.md +1 -1
  108. package/src/skills/develop.md +6 -6
  109. package/src/skills/document-project.md +4 -4
  110. package/src/skills/domain-modeling.md +1 -1
  111. package/src/skills/drill.md +1 -1
  112. package/src/skills/feynman.md +1 -1
  113. package/src/skills/forge-mcp.md +3 -3
  114. package/src/skills/fresh-eyes.md +4 -4
  115. package/src/skills/frontend-design.md +1 -1
  116. package/src/skills/gap-detector.md +1 -1
  117. package/src/skills/geneseed-code-review.md +1 -1
  118. package/src/skills/geneseed.md +4 -4
  119. package/src/skills/git-archaeology.md +1 -1
  120. package/src/skills/git-rescue.md +3 -3
  121. package/src/skills/handoff.md +4 -4
  122. package/src/skills/herdr.md +1 -1
  123. package/src/skills/ingest.md +3 -3
  124. package/src/skills/learning-path.md +1 -1
  125. package/src/skills/migrate.md +5 -5
  126. package/src/skills/opencode-theme.md +1 -1
  127. package/src/skills/parallel-agents.md +2 -2
  128. package/src/skills/pipeline.md +2 -2
  129. package/src/skills/plan.md +2 -2
  130. package/src/skills/ponytail.md +1 -1
  131. package/src/skills/profile.md +1 -1
  132. package/src/skills/prose.md +2 -2
  133. package/src/skills/prototype.md +2 -2
  134. package/src/skills/refactor.md +2 -2
  135. package/src/skills/release.md +4 -4
  136. package/src/skills/repo-map.md +5 -5
  137. package/src/skills/research.md +6 -6
  138. package/src/skills/review-response.md +3 -3
  139. package/src/skills/roast-me.md +1 -1
  140. package/src/skills/rule.md +5 -5
  141. package/src/skills/ship.md +3 -3
  142. package/src/skills/tdd.md +2 -2
  143. package/src/skills/tickets.md +1 -1
  144. package/src/skills/wayfinder.md +1 -1
  145. package/src/skills/wiki.md +4 -4
  146. package/src/skills/workflow.md +2 -2
  147. package/themes/README.md +17 -7
  148. package/themes/_TEMPLATE.json +37 -36
  149. package/themes/biker.json +37 -36
  150. package/themes/commentator.json +37 -36
  151. package/themes/cyberpunk.json +37 -36
  152. package/themes/gamer.json +37 -36
  153. package/themes/imperial.json +37 -36
  154. package/themes/joker.json +37 -36
  155. package/themes/marvin.json +37 -36
  156. package/themes/mean.json +37 -36
  157. package/themes/military.json +37 -36
  158. package/themes/neutral.json +37 -36
  159. package/themes/pirate.json +37 -36
  160. package/themes/sports.json +37 -36
  161. package/themes/verstappen.json +37 -36
  162. package/themes/wizard.json +37 -36
  163. package/web/dist/assets/{About-BYXlmbyo.js → About-C0Mk0igT.js} +1 -1
  164. package/web/dist/assets/{Activity-us5MPf4u.js → Activity-C4aJJVXz.js} +1 -1
  165. package/web/dist/assets/{ActivityDetail-CiaQXUk2.js → ActivityDetail-DaQ85za0.js} +1 -1
  166. package/web/dist/assets/{Diff-Bh0qbZ2s.js → Diff-B3tlO2Yj.js} +1 -1
  167. package/web/dist/assets/{Doctor-BIlQME45.js → Doctor-BNC-5Dmo.js} +1 -1
  168. package/web/dist/assets/{Graph-4dYD1dPG.js → Graph-us0T6ZcV.js} +1 -1
  169. package/web/dist/assets/{Harnesses-PzYZ3LOC.js → Harnesses-DAMgyfM_.js} +1 -1
  170. package/web/dist/assets/Laws-rOxegJ75.js +1 -0
  171. package/web/dist/assets/{Library-CjMbksJW.js → Library-KmwrHA1J.js} +1 -1
  172. package/web/dist/assets/{Markdown-Bk81c3aZ.js → Markdown-0eQOVGSF.js} +1 -1
  173. package/web/dist/assets/{Profile-Curui_-j.js → Profile-ZU7WV6Xl.js} +1 -1
  174. package/web/dist/assets/{Rules-Bm283wdv.js → Rules-CtDoPhhf.js} +1 -1
  175. package/web/dist/assets/{Skills-gruqYuhl.js → Skills-BhoOxdkD.js} +1 -1
  176. package/web/dist/assets/{StatusBadge-EiM_FPqv.js → StatusBadge-CGvYVCwa.js} +1 -1
  177. package/web/dist/assets/{Themes-DU99j4Hr.js → Themes-Dr7OOkD7.js} +1 -1
  178. package/web/dist/assets/{activity-0rvQ6Vra.js → activity-B8aq3qtl.js} +1 -1
  179. package/web/dist/assets/index-2wqPDxuN.css +1 -0
  180. package/web/dist/assets/{index-0b2hobOo.js → index-AhMzkdbI.js} +1 -1
  181. package/web/dist/assets/index-CRftEtBX.js +12 -0
  182. package/web/dist/assets/{index-IiGFmCW_.js → index-D0lPN_qW.js} +1 -1
  183. package/web/dist/index.html +2 -2
  184. package/web/src/pages/Laws.jsx +282 -91
  185. package/web/dist/assets/Laws-DtZweXal.js +0 -1
  186. package/web/dist/assets/index-D5VY3TY_.js +0 -12
  187. package/web/dist/assets/index-DUCsDv7z.css +0 -1
@@ -6,7 +6,7 @@ kind: "concept"
6
6
  ---
7
7
  The sustained counterpart to the `ponytail` skill: once you opt in, it appends the laziest-that-works ruleset to the system prompt **every turn**, so the agent doesn't drift back to over-building mid-session, and it persists the level across turns.
8
8
 
9
- - **Opt-in:** the mode starts at `off` and injects nothing until you switch it on. Geneseed treats ponytail as a skill, not an always-on Law.
9
+ - **Opt-in:** the mode starts at `off` and injects nothing until you switch it on. Geneseed treats ponytail as a skill you reach for, not as part of the [constitution](#/docs/rules): it is neither an always-on invariant nor a doctrine pack you build in, so nothing about it binds until you ask for it.
10
10
  - **Toggle:** `/ponytail lite|full|ultra|off` (a bare `/ponytail` means `full`). The level is written to `.geneseed-ponytail` beside OpenCode's config and applies from the next turn.
11
11
  - **Hooks:** `experimental.chat.system.transform` appends the ruleset; `command.execute.before` records the switch. Every failure is swallowed; on a build without the system-transform hook it simply never injects (the skill still covers the invokable path).
12
12
 
package/docs/web/rules.md CHANGED
@@ -1,8 +1,28 @@
1
1
  ---
2
2
  group: concepts
3
3
  order: 1
4
- title: "Rules (Laws)"
4
+ title: "The constitution"
5
5
  kind: "concept"
6
- link: {"hash": "#/laws", "label": "Browse the ledger →"}
6
+ link: {"hash": "#/laws", "label": "Browse the constitution →"}
7
7
  ---
8
- {N_LAWS} universal laws the agent obeys — secrets handling, scope discipline, verify-before-assert, surface-failures, context economy, load-the-docs, tool-discovery, non-interactive-shell, and more. They are authored as one numbered list in `src/laws/universal.md`, and the rendered list lives in `AGENT.md`. They bind regardless of theme: an imperial deploy reads them as *Dictates*, a neutral deploy as *Rules*, but the numbering and the rule itself never move.
8
+ The agent's standing rules come in **three tiers**, and the tier decides how a rule binds and whether this install carries it at all. All three are authored under `src/` and rendered into `AGENT.md`; the console shows them as three bands under **Constitution**.
9
+
10
+ ### Ontology — always on
11
+
12
+ {N_ONTOLOGY} sections of flowing prose in `src/ontology/universal.md`: what the agent is for, how it grades evidence, how it decides, how it conducts itself. It is the mind the other tiers govern — never numbered, never toggleable, and it is where the **Pact** (the mutual contract between you and the agent) is stated. Cited by section name, `Ontology: Decisions`, and its section names are theme-independent so a citation and its heading can never drift apart.
13
+
14
+ ### Invariants — always on
15
+
16
+ {N_LAWS} rules in `src/laws/universal.md`, numbered in Roman from `I`: sealed secrets, one intent per act, verify before asserting, deliberate deletion, surface failures, data not orders, least privilege, cure the cause, and the external gate. They hold in every task and every repository, they are never traded away, and no install can switch one off. Cited by numeral — `Rule IV`.
17
+
18
+ ### Doctrines — chosen at build time
19
+
20
+ Practices rather than principles: **craft** (how code is written), **rigor** (how work is proven), **ops** (how the machine is operated), **process** (how a task is run), one file each under `src/doctrines/`. A repository picks its set with `geneseed-build --doctrines <list>` or through the setup wizard — all {N_PACKS} are on by default. This install built in {N_PACKS_ACTIVE}, carrying {N_DOCTRINE_RULES} rules between them. Cited by pack and number — `Doctrine process 5`.
21
+
22
+ A pack you leave out **still ships in the bundle**: every pack file lands under `doctrines/` beside `AGENT.md` whether or not it was built in. So a rule that cites one in an inactive pack still resolves on disk, and you can read the alternatives before turning one on. What an inactive pack loses is bindingness, not availability.
23
+
24
+ ### Which outranks which
25
+
26
+ Ontology and Invariants first, then your own `user-rules.md`, then the active Doctrines, then `PROFILE.md`. A rule you write in `user-rules.md` **outranks a doctrine rule** — a practice pack chosen at build time never overrides an instruction you wrote for your own repo — and nothing outranks an invariant: a user rule or a doctrine rule may tighten one, never repeal it.
27
+
28
+ Themes rename the nouns, never the structure: an imperial deploy reads the invariants as *Dictates*, a neutral deploy as *Rules*. The tier, the address and the rule itself do not move.
@@ -1,10 +1,10 @@
1
1
  ---
2
2
  group: start
3
3
  order: 1
4
- title: "Posture & footprint"
4
+ title: "Posture, doctrines & footprint"
5
5
  kind: "concept"
6
6
  ---
7
- The setup wizard asks four starting parameters. The first, the **theme**, is the *voice* — banner, sigil, prose register — previewed live as you move through the wizard; it never changes structure or rules, so pick whatever reads best to you ([voice vs structure](#/docs/themes)). The other three shape how the agent works and are explained below. All four have safe defaults — accept them and move on, or pick deliberately here. All are set-and-forget: preserved across every rebuild and re-theme, changeable later from **Settings**, the **Harnesses** page, or the wizard.
7
+ The setup wizard asks five starting parameters. The first, the **theme**, is the *voice* — banner, sigil, prose register — previewed live as you move through the wizard; it never changes structure or rules, so pick whatever reads best to you ([voice vs structure](#/docs/themes)). The other four shape how the agent works and are explained below. All five have safe defaults — accept them and move on, or pick deliberately here. All are set-and-forget: preserved across every rebuild and re-theme, changeable later from **Settings**, the **Harnesses** page, or the wizard.
8
8
 
9
9
  ### Posture — the relationship register
10
10
 
@@ -27,13 +27,26 @@ How the session runs the work you hand it, fixed at build time:
27
27
 
28
28
  Pick **direct** unless you want the session managing a crew for you. Switch back any time with `--mode direct`.
29
29
 
30
- ### Footprint — full or lean Rules
30
+ ### Doctrine packs — which practices bind
31
31
 
32
- How much of the Rules `AGENT.md` carries inline every turn. A token-cost dial, not a rules cut — every Rule always applies:
32
+ Which practice rules this install adopts, fixed at build time. Unlike the dials above this one really does change *which rules apply*: the [Ontology and the Rules](#/docs/rules) are always on, the doctrines are yours to pick. All four ship enabled, and leaving one out is a deliberate choice, not a default:
33
33
 
34
- - **full** *(default)* — every Rule's text *and* rationale inline. Best when token cost is a non-issue or you run a smaller model.
35
- - **lean** — one line per Rule plus a pointer to the complete laws file, read on demand. Trims the Rules section by roughly 40% for long sessions or cost-sensitive runs.
34
+ - **craft** — how code is written: reuse first, house conventions, docs in step, the smallest diff.
35
+ - **rigor** — how work is proven: idempotence, honest tests, coverage, gates that can actually fail.
36
+ - **ops** — how the machine is driven: tool discovery, commands that return, complete teardowns.
37
+ - **process** — how a session runs: planning, context economy, docs first, and the **consent gate on every commit and push**.
38
+
39
+ Turning **process** off takes that consent gate with it, at the tool boundary as well as in the prose: the OpenCode permission block and the Claude/Bob `PreToolUse` hook that ask before a commit or a push are wired only when the pack is built in, because a boundary that keeps asking for a rule the install never adopted is a gate arguing with its own harness. The invariant-territory refusals — `rm -rf`, a force-push — stay in every build; they are the Rules' territory, not the pack's.
40
+
41
+ A pack you leave out still ships in the bundle under `doctrines/`, so you can read it before turning it on, and a rule that cites it still resolves. Change the set with `geneseed-build --doctrines craft,rigor` (or `--doctrines none`), or in `harness.config.json`.
42
+
43
+ ### Footprint — how much of the constitution loads inline
44
+
45
+ How much of the constitution `AGENT.md` carries inline every turn. A token-cost dial, not a rules cut — whatever this install adopted always applies:
46
+
47
+ - **lean** *(default)* — the Ontology whole, then each Rule and each doctrine rule as its heading plus its first line, with a pointer to the complete text shipped beside `AGENT.md` and read on demand.
48
+ - **full** — every Rule's and every active doctrine rule's complete text *and* rationale inline. Best when token cost is a non-issue or you run a smaller model, which applies a rule's nuance more reliably with the *why* eagerly in context.
36
49
 
37
50
  ---
38
51
 
39
- **Deeper:** [The collaboration layer](#/docs/collaboration) · [Footprint (lean vs full)](#/docs/footprint) · **Next:** [Verify it works](#/docs/verify)
52
+ **Deeper:** [The constitution](#/docs/rules) · [The collaboration layer](#/docs/collaboration) · [Footprint (lean vs full)](#/docs/footprint) · **Next:** [Verify it works](#/docs/verify)
@@ -5,4 +5,16 @@ title: "Write a new theme"
5
5
  kind: "concept"
6
6
  link: {"hash": "#/themes", "label": "Open the theme gallery →"}
7
7
  ---
8
- A theme is one JSON file under `themes/` declaring voice tokens only: `BANNER`, `TAGLINE`, `LOADED_SIGIL`, `VOICE`, the core nouns (`LAW(S)`/`AGENT(S)`/`SKILL(S)`/`MEMORY`/`NOTEBOOK`/`WIKI`), the law titles `LEX_*`, the section intros `INTRO_*`, the epigraphs `EPI_*`, the `BENEDICTION`, the `ROAST_PERSONA`, and `DESC_*` blurbs. Copy `themes/neutral.json` and edit. `geneseed build --theme yours` renders it; `doctor` checks for missing tokens.
8
+ A theme is one JSON file under `themes/` declaring voice tokens only: `BANNER`, `TAGLINE`, `LOADED_SIGIL`, `VOICE`, the core nouns (`ONTOLOGY`/`LAW(S)`/`DOCTRINE(S)`/`AGENT(S)`/`SKILL(S)`/`MEMORY`/`NOTEBOOK`/`WIKI`), the section intros `INTRO_*`, the epigraphs `EPI_*`, the `BENEDICTION`, the `ROAST_PERSONA`, and `DESC_*` blurbs. Copy `themes/neutral.json` and edit. `geneseed build --theme yours` renders it; `doctor` checks for missing tokens.
9
+
10
+ ### The constitution's titles
11
+
12
+ Every rule in the constitution gets its title from a theme key, and a theme that omits one ships a rule with a blank heading:
13
+
14
+ - `LEX_I`…`LEX_IX` — one title per invariant. `doctor` holds this to an **equality**, not mere presence: a `LEX_*` outside `I`–`IX` is a title for a rule that does not exist and fails the check too.
15
+ - `DOC_*` — one title per doctrine rule, named after its address (`DOC_CRAFT_1`, `DOC_PROCESS_5`, …). `doctor` reads the pack files under `src/doctrines/` and requires exactly the set they name — a missing one is a blank heading, an extra one is a dead key.
16
+ - `PACK_*` — one name per pack (`PACK_CRAFT`, `PACK_RIGOR`, `PACK_OPS`, `PACK_PROCESS`), used for the pack's own sub-heading.
17
+
18
+ The Ontology's section names are **not** theme keys: a citation reads `({{ONTOLOGY}}: {{ONT_TELOS}})`, token on both sides, so heading and reference always move together. They live in the build's fixed structure table and you neither declare nor rename them.
19
+
20
+ > ⚠ `LAW` and `DOCTRINE` must each be a **single word**. Both heading parsers match the tier noun with `\S+`, so a two-word value does not error — the heading simply stops matching and the whole tier parses to nothing, in silence. `doctor` gates this for every real voice (`_TEMPLATE.json` is exempt; its values are placeholders).
package/docs/web-ui.md CHANGED
@@ -50,14 +50,15 @@ The left rail mirrors the harness's own shape:
50
50
 
51
51
  | Group | Views |
52
52
  | --- | --- |
53
- | **🧬 Harness** | Dashboard · Rules · Library · Graph |
54
- | **📚 Learn** | Docs · Specs |
53
+ | **🧬 Harness** | Dashboard · Activity · Constitution · Rules · Profile · Skills · Agents · Library · Docs · Graph |
55
54
  | **🔧 Maintain** | Changes · Doctor |
56
55
  | **🎨 Configure** | Harnesses · Themes · Settings |
57
56
  | **ℹ️ About** | About |
58
57
 
59
58
  A global **Spotlight** search lives in the topbar — press <kbd>/</kbd> to focus it, type
60
- to jump to any agent, skill, law, doc, spec, or MCP server; <kbd>↑</kbd>/<kbd>↓</kbd> to
59
+ to jump to any agent, skill, doc, spec, MCP server, or constitutional rule — the `laws`
60
+ catalog it indexes is the whole constitution, so an ontology section, an invariant and a
61
+ doctrine rule are all reachable by name; <kbd>↑</kbd>/<kbd>↓</kbd> to
61
62
  move, <kbd>Enter</kbd> to open, <kbd>Esc</kbd> to clear. A bottom **Console** drawer
62
63
  streams the output of background jobs and keeps their history across reloads.
63
64
 
@@ -66,9 +67,17 @@ streams the output of background jobs and keeps their history across reloads.
66
67
  ### 🧬 Harness
67
68
 
68
69
  - **Dashboard** (`#/`) — a live readout of what's deployed. Three lenses: **Status**
69
- (readiness ring, KPI counts of agents/skills/laws/memory, a genome grid, recent
70
- activity), **Lineage** (a mini cross-link graph), and **Operator** (a searchable table
71
- of every deployed capability). Headlines reflect the active theme's voice.
70
+ (readiness ring, a KPI band, a genome grid, recent activity), **Lineage** (a mini
71
+ cross-link graph), and **Operator** (a searchable table of every deployed capability).
72
+ Headlines reflect the active theme's voice.
73
+
74
+ The KPI band reads **Agents · Skills · Invariants · Local edits**. That third tile is
75
+ labelled *Invariants* and not *Constitution* on purpose: its value is the invariant count
76
+ alone, and calling it the constitution would under-report the ontology and the doctrine
77
+ packs. The two Status *layouts* that have room for it add the missing half: Greenhouse
78
+ puts an active-packs fraction under the tile (`3/4 packs · N rules`), and the Operator HUD
79
+ gives it its own cell (`PACKS 3/4`). That is what makes a narrowed install *look* different
80
+ from a full one at a glance.
72
81
  - **Rules** (`#/rules`) — your own standing rules, read from and written to the
73
82
  `user-rules.md` beside the deployed AGENT.md (the seed-once file no update ever
74
83
  touches). List with scope (user/project) and trial chips, add/edit/retire forms, a
@@ -76,17 +85,32 @@ streams the output of background jobs and keeps their history across reloads.
76
85
  amber as the always-loaded set gets heavy. Every write carries the fingerprint of the
77
86
  content the page last read — if an agent session edited the file meanwhile, the save
78
87
  409s and the page reloads instead of clobbering it.
79
- - **Library** (`#/library`) — browse the harness content: **Laws · Agents · Skills ·
80
- Memory · Notebook** (plus Wiki/Config). Drill into a section, then an item, to read its
88
+ - **Constitution** (`#/laws`) — the whole governance surface on one page, in three bands:
89
+ the **Ontology** (four prose sections), the **Invariants** (the nine numbered Rules, with
90
+ a class facet — only non-empty classes render, and two of the six have had no invariant
91
+ since the split), and the **Doctrines** (one group per pack, each marked active or not for
92
+ this install). Every row expands to its full body, lazily fetched. The rail entry is
93
+ labelled *Constitution* while the route, the id and the badge key stay `laws`; deep links
94
+ are `#/item/law/ont:telos`, `#/item/law/IV` and `#/item/law/process.5` — three address
95
+ shapes that cannot collide, because a slug carries a colon no numeral has and a doctrine
96
+ address carries a dot.
97
+ - **Library** (`#/library`) — browse the content that has no tab of its own: **Memory ·
98
+ Notebook · Knowledge** (the wiki chip, which also carries the two setup manifests).
99
+ Constitution, Skills and Agents each have their own rail entry instead. Drill into a section, then an item, to read its
81
100
  rendered markdown body and follow its cross-links. On a memory fact, a **Forget this
82
101
  fact** control deletes it (token-gated; bare-slug guarded server-side), and a
83
102
  **Promote to rule** control turns a recurring lesson into a trial rule in
84
103
  `user-rules.md` — provenance recorded, the source fact deleted so it isn't loaded
85
104
  twice — landing you on the Rules page.
86
- - **Graph** (`#/graph`) — the full cross-link constellation across the whole harness:
87
- every `[[wikilink]]` between agents/skills plus every `Rule N` mention that lands on a
88
- real law. Hover to isolate a neighbourhood, scroll to zoom, drag to pan, search to
89
- highlight; orphans dim out. Click a node to open its spec.
105
+ - **Graph** (`#/graph`) — the cross-link constellation across agents, skills and the
106
+ **invariants only**: every `[[wikilink]]` between agents/skills, plus every `Rule N`
107
+ mention that lands on a real invariant. ⚠ The reference pattern matches the tier noun
108
+ followed by a **Roman numeral** — `Rule`, `Law`, or whatever the active theme calls one,
109
+ which is how `Dictate III` still resolves under `imperial`. A doctrine address is
110
+ `<pack> <n>` and matches nothing, so **doctrine cross-links are not drawn**; the graph is
111
+ a view of the invariant backbone, not of the whole constitution. Hover to isolate a
112
+ neighbourhood, scroll to zoom, drag to pan, search to highlight; orphans dim out. Click a
113
+ node to open its spec.
90
114
 
91
115
  ### 📚 Learn
92
116
 
@@ -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": "2.1.0"
5
+ "version": "3.0.0"
6
6
  }
package/js/catalog.mjs CHANGED
@@ -29,15 +29,36 @@ import { defaultTheme, installedDefaults } from './installs.mjs';
29
29
  import { pyPrint } from './lib/fs.mjs';
30
30
  import { dwidth, fit, icon, truncd, tuiEntries } from './tui.mjs';
31
31
 
32
- /** The listing's section names, and the row kind each one selects. */
33
- export const CATALOG_KINDS = { agents: 'agent', skills: 'skill', laws: 'law' };
32
+ /**
33
+ * The listing's section names, and the row kind each one selects.
34
+ *
35
+ * FIVE SINCE THE CONSTITUTION BECAME THREE TIERS, in constitutional order between the two
36
+ * entity sections and after them — `ontology`, `laws`, `doctrines` read as one block. The
37
+ * order here is only the no-section filter's; the printed order is `tuiEntries`'.
38
+ *
39
+ * ⚠ THE SET IS DECLARED IN TWO FILES AND `tests/unit/catalog.test.mjs` TIES THEM. The verb's
40
+ * `section` positional takes its `choices` from `js/cli-table.json`, so a kind added here and
41
+ * not there is a section the endpoint serves and the front door refuses. `catalog` has no
42
+ * recorded help text and no golden cell, which is what makes the pair editable at all.
43
+ */
44
+ export const CATALOG_KINDS = {
45
+ agents: 'agent', skills: 'skill', ontology: 'ontology', laws: 'law', doctrines: 'doctrine',
46
+ };
34
47
 
35
48
  /**
36
49
  * The badge column: what the catalog endpoint carries beside the name that is not the
37
50
  * purpose. An agent has a lifecycle status, a skill has that and a category, a law has a
38
51
  * governance class and no status at all — which is the endpoint's shape, not a shortcut.
52
+ *
53
+ * A doctrine rule's badge is its PACK plus whether this install built it in. The pack is
54
+ * already the rule's class (there is no second taxonomy over a doctrine), and `off` is the
55
+ * one thing a reader cannot infer from the row: an inactive pack is listed, not hidden, so
56
+ * without the marker its rules read as binding. An ontology section has neither — it is a
57
+ * worldview, not a rule list — and an empty badge collapses its column.
39
58
  */
40
59
  function badgeFor(kind, data) {
60
+ if (kind === 'ontology') return '';
61
+ if (kind === 'doctrine') return `${data.klass ?? 'craft'}${data.active === false ? ' (off)' : ''}`;
41
62
  if (kind === 'law') return data.klass ?? 'craft';
42
63
  if (kind === 'skill') return `${data.klass ?? 'build'}/${data.status ?? 'unknown'}`;
43
64
  return data.status ?? 'unknown';
@@ -98,11 +119,15 @@ export function catalogLines(inv, section, width, showSource = false) {
98
119
  * validator here, and the entry point's `exitCode` arm carries the refusal out.
99
120
  */
100
121
  export function cmdCatalog(args) {
101
- const theme = args.theme || installedDefaults().theme || defaultTheme();
122
+ const inst = installedDefaults();
123
+ const theme = args.theme || inst.theme || defaultTheme();
124
+ // The install's own pack selection, so an inactive pack's rules are listed and MARKED
125
+ // rather than listed as though they bind. `null` — no carrier said — reads as every pack.
102
126
  // `helpWidth()` is `COLUMNS`, else the terminal, else 80 — minus the two columns argparse
103
127
  // subtracts for its own layout. This listing wants the whole terminal, so it adds them
104
128
  // back rather than owning a second copy of that precedence chain.
105
- const lines = catalogLines(tuiInventory(theme), args.section, helpWidth() + 2, args.source);
129
+ const lines = catalogLines(tuiInventory(theme, inst.doctrines), args.section,
130
+ helpWidth() + 2, args.source);
106
131
  if (!lines.length) {
107
132
  pyPrint(`[catalog] nothing to list${args.section ? ` under ${args.section}` : ''}.\n`);
108
133
  return 1;
package/js/checkout.mjs CHANGED
@@ -66,14 +66,36 @@ export function discoverNames(dir, first) {
66
66
  return names.length ? names : [first];
67
67
  }
68
68
 
69
+ /**
70
+ * The doctrine packs, in the order they are rendered into AGENT.md — the ONE owner.
71
+ *
72
+ * DELIBERATELY NOT `discoverNames('doctrines', 'craft')`. That helper `.sort()`s, so it
73
+ * answers `craft, ops, process, rigor`; the constitution's order is a reading order —
74
+ * write it (craft), prove it (rigor), run it (ops), ship it (process) — and no sort
75
+ * produces it. Discovery still runs, but as a GATE rather than as the order: `js/render.mjs`
76
+ * refuses to build when a pack file exists under `src/doctrines/` that is missing from this
77
+ * array, so a fifth pack cannot be silently dropped from every install.
78
+ *
79
+ * It lives here, beside `makeCfg` and `discoverNames`, because every consumer (the cfg
80
+ * default, the render loop, the `Active packs:` marker, the CLI flag, the wizard, the
81
+ * doctor) already imports this module and this module imports nothing of theirs — the one
82
+ * placement that cannot introduce a cycle.
83
+ */
84
+ export const PACK_ORDER = ['craft', 'rigor', 'ops', 'process'];
85
+
69
86
  /**
70
87
  * `_build_core.js_cfg()`, originated rather than received.
71
88
  *
72
89
  * `posture` and `mode` are `_build_core`'s module defaults (`peer` / `direct`) unless a
73
90
  * caller overrides them. `build.py`'s `main()` sets them from its flags; `rituals/harness.py`
74
91
  * never touches them, so every harness verb that renders renders at the defaults.
92
+ *
93
+ * `doctrines` is the third register and the first that is a SET rather than a scalar: all
94
+ * four packs unless a caller narrows it. Copied, never aliased — `cfg.doctrines` is handed
95
+ * out to renderers and a caller that sorted or spliced it in place would rewrite
96
+ * `PACK_ORDER` for the whole process.
75
97
  */
76
- export function makeCfg({ posture = 'peer', mode = 'direct' } = {}) {
98
+ export function makeCfg({ posture = 'peer', mode = 'direct', doctrines = PACK_ORDER } = {}) {
77
99
  return {
78
100
  root: ROOT,
79
101
  src: SRC,
@@ -84,5 +106,6 @@ export function makeCfg({ posture = 'peer', mode = 'direct' } = {}) {
84
106
  workflowSrc: WORKFLOW_SRC,
85
107
  posture,
86
108
  mode,
109
+ doctrines: Array.isArray(doctrines) ? [...doctrines] : [...PACK_ORDER],
87
110
  };
88
111
  }
package/js/cli-table.json CHANGED
@@ -78,18 +78,20 @@
78
78
  },
79
79
  {
80
80
  "name": "catalog",
81
- "help": "list what this harness ships: every agent, skill and law, with its one-line purpose and lifecycle status",
81
+ "help": "list what this harness ships: every agent, skill and constitutional rule, with its one-line purpose and lifecycle status",
82
82
  "description": "",
83
83
  "positionals": [
84
84
  {
85
85
  "names": [],
86
86
  "dest": "section",
87
87
  "metavar": null,
88
- "help": "limit the listing to one section (default: all three)",
88
+ "help": "limit the listing to one section (default: all five)",
89
89
  "choices": [
90
90
  "agents",
91
91
  "skills",
92
- "laws"
92
+ "ontology",
93
+ "laws",
94
+ "doctrines"
93
95
  ],
94
96
  "default": null,
95
97
  "required": false,
@@ -135,7 +137,7 @@
135
137
  },
136
138
  {
137
139
  "name": "context",
138
- "help": "print context.json eager entries for a SessionStart hook (Rule XVIII)",
140
+ "help": "print context.json eager entries for a SessionStart hook",
139
141
  "description": "",
140
142
  "positionals": [],
141
143
  "options": [
@@ -336,7 +338,7 @@
336
338
  },
337
339
  {
338
340
  "name": "git-gate",
339
- "help": "PreToolUse hook: force an ASK before every git commit/push (Law XX backstop)",
341
+ "help": "PreToolUse hook: force an ASK before every git commit/push (process 5 backstop)",
340
342
  "description": "",
341
343
  "positionals": [],
342
344
  "options": [
@@ -584,7 +586,7 @@
584
586
  },
585
587
  {
586
588
  "name": "rule-gate",
587
- "help": "PreToolUse hook: force an ASK before any write to user-rules.md or memory (Law VI backstop)",
589
+ "help": "PreToolUse hook: force an ASK before any write to user-rules.md or memory (process 1 backstop)",
588
590
  "description": "",
589
591
  "positionals": [],
590
592
  "options": [
package/js/diff.mjs CHANGED
@@ -41,8 +41,8 @@ import path from 'node:path';
41
41
  import { emitGlobalInto } from '../bin/geneseed.mjs';
42
42
  import { GLOBAL_MANIFEST, VERSION_MARKER, expanduser, opencodeConfigDir } from './hosts.mjs';
43
43
  import {
44
- EMIT_HOST_SCOPE, defaultTheme, footprintOfDir, modeOfDir, postureOfDir, readJsonMaybe,
45
- readMaybe, themeOfDir,
44
+ EMIT_HOST_SCOPE, defaultTheme, doctrinesForBuild, footprintOfDir, modeOfDir, postureOfDir,
45
+ readJsonMaybe, readMaybe, themeOfDir,
46
46
  } from './installs.mjs';
47
47
  import { unifiedDiff, pySplitLines } from './lib/udiff.mjs';
48
48
  import { pyPathStr, pyPrint, pyPrintErr, readText, writeText } from './lib/fs.mjs';
@@ -166,7 +166,12 @@ export function diffCollect({ target = null, theme = null, emit = null, footprin
166
166
  const expected = path.join(tmp, 'expected');
167
167
  withStdoutSwallowed(() => emitGlobalInto(host, {
168
168
  theme: themeName, out: path.join(tmp, 'bundle'), cfgDir: expected, footprint: fp,
169
- posture: postureOfDir(dir), mode: modeOfDir(dir),
169
+ // The third register read off the deployment, for the same reason as the other two: an
170
+ // install built with `--doctrines craft` compared against an `expected` rendered at all
171
+ // four reports its entire doctrines section — and its `Active packs:` line — as drift.
172
+ // `null` (no marker) means unknown and renders at all four, which `doctrinesForBuild`
173
+ // makes explicit rather than leaving to `makeCfg`'s parameter default two layers down.
174
+ posture: postureOfDir(dir), mode: modeOfDir(dir), doctrines: doctrinesForBuild(dir),
170
175
  }));
171
176
  const rels = [...new Set([...ownedSet(dir), ...ownedSet(expected)])].sort();
172
177
  for (const rel of rels) {