geneseed 2.1.0 → 3.1.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.
- package/CHANGELOG.md +155 -0
- package/DESIGN.md +112 -61
- package/QUICKSTART.md +1 -1
- package/README.md +24 -14
- package/SETUP.md +83 -17
- package/SHIPPED.md +5 -4
- package/adapters/bob/README.md +3 -3
- package/adapters/claude-code/README.md +6 -4
- package/adapters/claude-code/skills/geneseed/SKILL.md +10 -6
- package/adapters/copilot/README.md +5 -4
- package/adapters/opencode/GLOBAL-HARNESS-SPEC.md +11 -6
- package/adapters/opencode/HOW-OPENCODE-LOADS.md +1 -1
- package/adapters/opencode/README.md +15 -9
- package/adapters/opencode/agents/orchestrator.md +1 -1
- package/adapters/opencode/plugins/geneseed-context.js +7 -7
- package/adapters/opencode/plugins/geneseed-guard.js +6 -6
- package/adapters/opencode/workflows/dispatch.js +1 -1
- package/bin/geneseed.mjs +72 -6
- package/docs/extending.md +164 -55
- package/docs/limits.md +4 -4
- package/docs/token-footprint.md +15 -4
- package/docs/web/authoring.md +1 -1
- package/docs/web/claude-hooks.md +2 -2
- package/docs/web/collaboration.md +3 -3
- package/docs/web/first-session.md +2 -2
- package/docs/web/footprint.md +14 -7
- package/docs/web/foreman-mode.md +2 -2
- package/docs/web/harnesses.md +5 -3
- package/docs/web/install-quick.md +1 -1
- package/docs/web/model.md +3 -3
- package/docs/web/plugin-context.md +2 -2
- package/docs/web/plugin-guard.md +3 -3
- package/docs/web/plugin-ponytail.md +1 -1
- package/docs/web/rules.md +23 -3
- package/docs/web/setup-choices.md +20 -7
- package/docs/web/themes-author.md +13 -1
- package/docs/web-ui.md +36 -12
- package/harness.config.json +1 -1
- package/js/catalog.mjs +29 -4
- package/js/checkout.mjs +24 -1
- package/js/cli-table.json +8 -6
- package/js/diff.mjs +8 -3
- package/js/doctor.mjs +307 -4
- package/js/emit.mjs +48 -11
- package/js/generate.mjs +39 -5
- package/js/hooks.mjs +8 -7
- package/js/installs.mjs +101 -4
- package/js/inventory.mjs +150 -21
- package/js/migrate.mjs +10 -4
- package/js/render.mjs +110 -7
- package/js/settings.mjs +218 -27
- package/js/setup.mjs +95 -5
- package/js/status.mjs +45 -4
- package/js/tui.mjs +44 -1
- package/js/uninstall.mjs +25 -6
- package/js/web/actions.mjs +56 -5
- package/js/web/api.mjs +102 -16
- package/js/web/docs.mjs +33 -5
- package/js/web/jobs.mjs +12 -3
- package/js/web/server.mjs +6 -0
- package/package.json +1 -1
- package/src/AGENT.md.tmpl +75 -65
- package/src/agents/_template.md +4 -4
- package/src/agents/advocate.md +4 -4
- package/src/agents/architect.md +2 -2
- package/src/agents/developer.md +5 -5
- package/src/agents/docs.md +2 -2
- package/src/agents/empiricist.md +3 -3
- package/src/agents/explorer.md +3 -3
- package/src/agents/framer.md +3 -3
- package/src/agents/historian.md +3 -3
- package/src/agents/operator.md +3 -3
- package/src/agents/pragmatist.md +3 -3
- package/src/agents/reviewer.md +2 -2
- package/src/agents/security.md +2 -2
- package/src/agents/skeptic.md +4 -4
- package/src/agents/steward.md +3 -3
- package/src/agents/tester.md +2 -2
- package/src/agents/user-advocate.md +3 -3
- package/src/agents/visionary.md +3 -3
- package/src/doctrines/README.md +41 -0
- package/src/doctrines/craft.md +51 -0
- package/src/doctrines/ops.md +61 -0
- package/src/doctrines/process.md +87 -0
- package/src/doctrines/rigor.md +52 -0
- package/src/laws/universal.md +17 -336
- package/src/memory/README.md +2 -2
- package/src/modes/README.md +2 -2
- package/src/modes/foreman.md +1 -1
- package/src/notebook/README.md +2 -2
- package/src/ontology/universal.md +89 -0
- package/src/postures/README.md +3 -3
- package/src/postures/artisan.md +3 -3
- package/src/postures/assistant.md +1 -1
- package/src/postures/expert.md +1 -1
- package/src/postures/mentor.md +1 -1
- package/src/postures/peer.md +2 -2
- package/src/skills/_template.md +2 -2
- package/src/skills/brainstorm.md +2 -2
- package/src/skills/clarify.md +2 -2
- package/src/skills/codebase-design.md +1 -1
- package/src/skills/commit.md +5 -5
- package/src/skills/council.md +4 -4
- package/src/skills/crash-course.md +1 -1
- package/src/skills/daydream/SKILL.md +1 -1
- package/src/skills/debug.md +2 -2
- package/src/skills/decode.md +1 -1
- package/src/skills/develop.md +6 -6
- package/src/skills/document-project.md +4 -4
- package/src/skills/domain-modeling.md +1 -1
- package/src/skills/drill.md +1 -1
- package/src/skills/feynman.md +1 -1
- package/src/skills/forge-mcp.md +3 -3
- package/src/skills/fresh-eyes.md +4 -4
- package/src/skills/frontend-design.md +1 -1
- package/src/skills/gap-detector.md +1 -1
- package/src/skills/geneseed-code-review.md +1 -1
- package/src/skills/geneseed.md +4 -4
- package/src/skills/git-archaeology.md +1 -1
- package/src/skills/git-rescue.md +3 -3
- package/src/skills/handoff.md +4 -4
- package/src/skills/herdr.md +1 -1
- package/src/skills/ingest.md +3 -3
- package/src/skills/learning-path.md +1 -1
- package/src/skills/migrate.md +5 -5
- package/src/skills/opencode-theme.md +1 -1
- package/src/skills/parallel-agents.md +2 -2
- package/src/skills/pipeline.md +2 -2
- package/src/skills/plan.md +2 -2
- package/src/skills/ponytail.md +1 -1
- package/src/skills/profile.md +1 -1
- package/src/skills/prose.md +2 -2
- package/src/skills/prototype.md +2 -2
- package/src/skills/refactor.md +2 -2
- package/src/skills/release.md +4 -4
- package/src/skills/repo-map.md +5 -5
- package/src/skills/research.md +6 -6
- package/src/skills/review-response.md +3 -3
- package/src/skills/roast-me.md +1 -1
- package/src/skills/rule.md +5 -5
- package/src/skills/ship.md +3 -3
- package/src/skills/tdd.md +2 -2
- package/src/skills/tickets.md +1 -1
- package/src/skills/wayfinder.md +1 -1
- package/src/skills/wiki.md +4 -4
- package/src/skills/workflow.md +2 -2
- package/themes/README.md +17 -7
- package/themes/_TEMPLATE.json +37 -36
- package/themes/biker.json +37 -36
- package/themes/commentator.json +37 -36
- package/themes/cyberpunk.json +37 -36
- package/themes/gamer.json +37 -36
- package/themes/imperial.json +37 -36
- package/themes/joker.json +37 -36
- package/themes/marvin.json +37 -36
- package/themes/mean.json +37 -36
- package/themes/military.json +37 -36
- package/themes/neutral.json +37 -36
- package/themes/pirate.json +37 -36
- package/themes/sports.json +37 -36
- package/themes/verstappen.json +37 -36
- package/themes/wizard.json +37 -36
- package/web/dist/assets/{About-BYXlmbyo.js → About-_MnJcwb_.js} +1 -1
- package/web/dist/assets/{Activity-us5MPf4u.js → Activity-DpjqO-FR.js} +1 -1
- package/web/dist/assets/{ActivityDetail-CiaQXUk2.js → ActivityDetail-Bvrjv8oW.js} +1 -1
- package/web/dist/assets/{Diff-Bh0qbZ2s.js → Diff-DZ0IehBV.js} +1 -1
- package/web/dist/assets/{Doctor-BIlQME45.js → Doctor-cu4krooO.js} +1 -1
- package/web/dist/assets/{Graph-4dYD1dPG.js → Graph-DUOPY65j.js} +1 -1
- package/web/dist/assets/{Harnesses-PzYZ3LOC.js → Harnesses-B5Osg-BF.js} +1 -1
- package/web/dist/assets/Laws-D8DJgTBp.js +3 -0
- package/web/dist/assets/{Library-CjMbksJW.js → Library-8y69I3_z.js} +1 -1
- package/web/dist/assets/{Markdown-Bk81c3aZ.js → Markdown-Ds5GS1OD.js} +1 -1
- package/web/dist/assets/{Profile-Curui_-j.js → Profile-7Jxa7ZUX.js} +1 -1
- package/web/dist/assets/{Rules-Bm283wdv.js → Rules-UZ0jWkjg.js} +1 -1
- package/web/dist/assets/{Skills-gruqYuhl.js → Skills-Bgkl0xLd.js} +1 -1
- package/web/dist/assets/{StatusBadge-EiM_FPqv.js → StatusBadge-Cx4caF_2.js} +1 -1
- package/web/dist/assets/{Themes-DU99j4Hr.js → Themes-De8az7Sv.js} +1 -1
- package/web/dist/assets/{activity-0rvQ6Vra.js → activity-VDAdVQ3q.js} +1 -1
- package/web/dist/assets/index-1pPSz7Kl.css +1 -0
- package/web/dist/assets/{index-0b2hobOo.js → index-BKrjBRV4.js} +1 -1
- package/web/dist/assets/index-C-gb-q-r.js +12 -0
- package/web/dist/assets/{index-IiGFmCW_.js → index-wNiNzFFQ.js} +1 -1
- package/web/dist/index.html +2 -2
- package/web/src/pages/Laws.jsx +401 -93
- package/web/dist/assets/Laws-DtZweXal.js +0 -1
- package/web/dist/assets/index-D5VY3TY_.js +0 -12
- package/web/dist/assets/index-DUCsDv7z.css +0 -1
package/bin/geneseed.mjs
CHANGED
|
@@ -52,7 +52,7 @@ import {
|
|
|
52
52
|
// P5d moved these out of this file for the reason P5c moved the host resolvers: `harness
|
|
53
53
|
// status` renders to count, so `bin/geneseed-cli.mjs` needs the same checkout paths and the
|
|
54
54
|
// same cfg. golden.py's 259 cells all build one, which is what made the move safe.
|
|
55
|
-
import { ROOT, CONFIG, THEMES, discoverNames, makeCfg } from '../js/checkout.mjs';
|
|
55
|
+
import { ROOT, CONFIG, THEMES, discoverNames, makeCfg, PACK_ORDER } from '../js/checkout.mjs';
|
|
56
56
|
|
|
57
57
|
// P5f moved these, for the same arithmetic a third time: `harness rebuild-all` reads the
|
|
58
58
|
// registry to find every install it must re-emit, and a CLI verb may not reach into a driver
|
|
@@ -122,7 +122,9 @@ export function resolveOut(raw) {
|
|
|
122
122
|
* byte-for-byte by `tests/golden.py` (:316).
|
|
123
123
|
*/
|
|
124
124
|
function configDefaults() {
|
|
125
|
-
const d = {
|
|
125
|
+
const d = {
|
|
126
|
+
theme: 'neutral', posture: 'peer', mode: 'direct', doctrines: [...PACK_ORDER],
|
|
127
|
+
};
|
|
126
128
|
if (!existsSync(CONFIG)) return d;
|
|
127
129
|
try {
|
|
128
130
|
const data = JSON.parse(readFileSync(CONFIG, 'utf8'));
|
|
@@ -130,6 +132,20 @@ function configDefaults() {
|
|
|
130
132
|
if (data.theme !== undefined) d.theme = data.theme;
|
|
131
133
|
if (data.posture !== undefined) d.posture = data.posture;
|
|
132
134
|
if (data.mode !== undefined) d.mode = data.mode;
|
|
135
|
+
// `doctrines` is the only config key that is a LIST, so it is the only one that can be
|
|
136
|
+
// the right type and still nonsense. A bad value warns and falls back to all packs
|
|
137
|
+
// rather than dying: this file is hand-editable, and a typo here must not brick every
|
|
138
|
+
// rebuild of an install whose AGENT.md is otherwise fine. `[]` is a legitimate value
|
|
139
|
+
// (no packs) and must survive the check — hence an explicit Array test, not truthiness.
|
|
140
|
+
if (data.doctrines !== undefined) {
|
|
141
|
+
const known = discoverNames('doctrines', PACK_ORDER[0]);
|
|
142
|
+
if (Array.isArray(data.doctrines) && data.doctrines.every((x) => known.includes(x))) {
|
|
143
|
+
d.doctrines = PACK_ORDER.filter((p) => data.doctrines.includes(p));
|
|
144
|
+
} else {
|
|
145
|
+
process.stderr.write(`[geneseed] WARN: ${path.basename(CONFIG)} "doctrines" is not a `
|
|
146
|
+
+ 'list of known pack names — using all packs.\n');
|
|
147
|
+
}
|
|
148
|
+
}
|
|
133
149
|
}
|
|
134
150
|
} catch {
|
|
135
151
|
process.stderr.write(`[geneseed] WARN: ${path.basename(CONFIG)} is unreadable — `
|
|
@@ -146,6 +162,7 @@ function configDefaults() {
|
|
|
146
162
|
*/
|
|
147
163
|
const VALUED = {
|
|
148
164
|
'--theme': 'theme', '--posture': 'posture', '--mode': 'mode',
|
|
165
|
+
'--doctrines': 'doctrines',
|
|
149
166
|
'--out': 'out', '--target': 'out', '--emit': 'emit',
|
|
150
167
|
'--footprint': 'footprint', '--root': 'root',
|
|
151
168
|
};
|
|
@@ -160,6 +177,13 @@ const FLAGS = {
|
|
|
160
177
|
* A function and not a constant because two of the four read the checkout: `discoverNames`
|
|
161
178
|
* scans `postures/` and `modes/`, so the answer depends on the source tree this driver is
|
|
162
179
|
* standing in and cannot be frozen at import.
|
|
180
|
+
*
|
|
181
|
+
* `--doctrines` is DELIBERATELY not a fifth row. Every consumer of this table treats an
|
|
182
|
+
* entry as one value drawn from a closed list — `choice` refuses anything else, and
|
|
183
|
+
* `usage`'s metavar prints the list as the whole legal surface. `--doctrines` takes a comma
|
|
184
|
+
* LIST plus the sentinel `none`, so a row here would have refused `craft,rigor` outright and
|
|
185
|
+
* advertised a metavar that lies. It is validated by `parseDoctrines` instead and prints the
|
|
186
|
+
* plain `DOCTRINES` metavar, exactly as `--theme` (also open-ended) already does.
|
|
163
187
|
*/
|
|
164
188
|
function choicesFor() {
|
|
165
189
|
return {
|
|
@@ -170,6 +194,33 @@ function choicesFor() {
|
|
|
170
194
|
};
|
|
171
195
|
}
|
|
172
196
|
|
|
197
|
+
/**
|
|
198
|
+
* `--doctrines craft,rigor` / `--doctrines none` -> the cfg's pack array.
|
|
199
|
+
*
|
|
200
|
+
* Normalised into `PACK_ORDER` rather than kept in the order typed, which also dedupes: the
|
|
201
|
+
* rendered `Active packs:` line is a MARKER a later reader parses back out of a deployed
|
|
202
|
+
* carrier, and a marker whose contents depend on argument order is one that compares unequal
|
|
203
|
+
* to itself. Validation is against DISCOVERY, not `PACK_ORDER`, so the refusal names the
|
|
204
|
+
* packs the checkout actually has; a discovered pack missing from `PACK_ORDER` is a
|
|
205
|
+
* different fault and `js/render.mjs` refuses the whole build for it.
|
|
206
|
+
*/
|
|
207
|
+
function parseDoctrines(value) {
|
|
208
|
+
const s = value.trim();
|
|
209
|
+
const known = discoverNames('doctrines', PACK_ORDER[0]);
|
|
210
|
+
if (s === 'none') return [];
|
|
211
|
+
const names = s.split(',').map((x) => x.trim()).filter(Boolean);
|
|
212
|
+
if (!names.length) {
|
|
213
|
+
die(2, "argument --doctrines: expected a comma-separated list of packs, or 'none'");
|
|
214
|
+
}
|
|
215
|
+
for (const n of names) {
|
|
216
|
+
if (!known.includes(n)) {
|
|
217
|
+
die(2, `argument --doctrines: invalid choice: '${n}' (choose from `
|
|
218
|
+
+ `${known.map((c) => `'${c}'`).join(', ')}, or 'none')`);
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
return PACK_ORDER.filter((p) => names.includes(p));
|
|
222
|
+
}
|
|
223
|
+
|
|
173
224
|
/**
|
|
174
225
|
* `-h/--help` — the flag argparse handed the reference for free and this hand-rolled parser
|
|
175
226
|
* did not, so the two entry points disagreed: the reference printed usage and exited 0 while
|
|
@@ -212,6 +263,7 @@ function usage() {
|
|
|
212
263
|
function parseArgs(argv, defaults) {
|
|
213
264
|
const args = {
|
|
214
265
|
theme: defaults.theme, posture: defaults.posture, mode: defaults.mode,
|
|
266
|
+
doctrines: defaults.doctrines,
|
|
215
267
|
out: 'Harness', emit: 'files', footprint: 'lean', root: null,
|
|
216
268
|
syncThemes: false, validateOnly: false, verbose: false,
|
|
217
269
|
};
|
|
@@ -241,6 +293,9 @@ function parseArgs(argv, defaults) {
|
|
|
241
293
|
}
|
|
242
294
|
const choices = choicesFor();
|
|
243
295
|
for (const flag of Object.keys(choices)) choice(flag, args[VALUED[flag]], choices[flag]);
|
|
296
|
+
// Only when the flag was actually PASSED is this a string; left at its default it is
|
|
297
|
+
// already the array `configDefaults` built, and re-parsing an array would stringify it.
|
|
298
|
+
if (typeof args.doctrines === 'string') args.doctrines = parseDoctrines(args.doctrines);
|
|
244
299
|
return args;
|
|
245
300
|
}
|
|
246
301
|
|
|
@@ -897,9 +952,14 @@ const PROJECT_EMITS = {
|
|
|
897
952
|
opencode: emitOpencode,
|
|
898
953
|
};
|
|
899
954
|
|
|
900
|
-
export function emitProjectInto(host, { theme, out, root, footprint = 'full' }) {
|
|
955
|
+
export function emitProjectInto(host, { theme, out, root, footprint = 'full', doctrines = null }) {
|
|
901
956
|
const emit = PROJECT_EMITS[host];
|
|
902
|
-
|
|
957
|
+
// `doctrines` rides the same rail posture and mode ride into `emitGlobalInto`, and for the
|
|
958
|
+
// same reason: a drift reader that renders `expected` at the DEFAULT pack set reports the
|
|
959
|
+
// whole doctrines section as edited on every narrowed install. `null` means "no opinion" and
|
|
960
|
+
// `makeCfg` renders all four, which is what every validation caller wants.
|
|
961
|
+
return withPyNewlines(() => emit(makeCfg(doctrines ? { doctrines } : {}),
|
|
962
|
+
{ theme, footprint, root }, out));
|
|
903
963
|
}
|
|
904
964
|
|
|
905
965
|
/**
|
|
@@ -917,7 +977,7 @@ export function buildInto({ theme, out, footprint = 'lean' }) {
|
|
|
917
977
|
}
|
|
918
978
|
|
|
919
979
|
export function emitGlobalInto(host, {
|
|
920
|
-
theme, out, cfgDir, footprint, posture = null, mode = null,
|
|
980
|
+
theme, out, cfgDir, footprint, posture = null, mode = null, doctrines = null,
|
|
921
981
|
}) {
|
|
922
982
|
// `build.HOSTS.get(host, build.HOSTS["opencode"])` — an unknown host falls back rather than
|
|
923
983
|
// raising, because the host comes from a marker file a user can edit.
|
|
@@ -935,7 +995,13 @@ export function emitGlobalInto(host, {
|
|
|
935
995
|
// that chose a register — the same scar the footprint left in `diffCollect`, one axis over.
|
|
936
996
|
return withPyNewlines(
|
|
937
997
|
() => emit(
|
|
938
|
-
|
|
998
|
+
// THE PACK SELECTION RIDES THE SAME RAIL, with one difference: `doctrinesOfDir` answers
|
|
999
|
+
// `null` for "no marker / undetectable", and that must render at ALL packs rather than
|
|
1000
|
+
// at `[]`, so the key is OMITTED instead of passed through — `makeCfg`'s own default is
|
|
1001
|
+
// the fail-closed answer and an explicit `doctrines: null` would not reach it.
|
|
1002
|
+
makeCfg({
|
|
1003
|
+
posture: posture || 'peer', mode: mode || 'direct', ...(doctrines ? { doctrines } : {}),
|
|
1004
|
+
}),
|
|
939
1005
|
{ theme, footprint, root: null, cfgDir }, out,
|
|
940
1006
|
),
|
|
941
1007
|
);
|
package/docs/extending.md
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
# Extending — what it costs to change this tool
|
|
2
2
|
|
|
3
3
|
`docs/limits.md` is the standing answer to *"what does this tool not prove about itself?"*.
|
|
4
|
-
This file is its companion: **"what does it cost to add one thing?"** — one
|
|
5
|
-
plugin, one hook verb, one doc page, one theme, one screen.
|
|
4
|
+
This file is its companion: **"what does it cost to add one thing?"** — one invariant, one
|
|
5
|
+
doctrine rule, one skill, one plugin, one hook verb, one doc page, one theme, one screen.
|
|
6
6
|
|
|
7
7
|
It exists because the answer is never one file. Every user-visible noun in Geneseed has
|
|
8
8
|
*satellites* — a themed title in fourteen voices, a class in a hand-written map, a count in a
|
|
@@ -10,6 +10,11 @@ badge, a row in a ledger, a page in the console — and the gates that keep them
|
|
|
10
10
|
across `doctor`, the Node suite and four CI jobs. A contributor who knows the satellites ships in
|
|
11
11
|
one pass; one who does not discovers them one red gate at a time.
|
|
12
12
|
|
|
13
|
+
The governance surface is three tiers and they cost very different amounts. **Adding a doctrine
|
|
14
|
+
rule is the cheap, common case** (§2a); **amending an invariant** is next (§2b); **adding an
|
|
15
|
+
invariant** is the most expensive single edit in the repo after the CLI surface (§2c); **adding a
|
|
16
|
+
whole pack** is rare and mechanical (§2d).
|
|
17
|
+
|
|
13
18
|
Written after the Python migration completed (2026-08-18), against `main`. Verified: every
|
|
14
19
|
file:line below was opened, and the commands were run.
|
|
15
20
|
|
|
@@ -35,11 +40,22 @@ Two rules follow from the table and they cause most of the surprises:
|
|
|
35
40
|
|
|
36
41
|
### Counts are computed — never type one
|
|
37
42
|
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
`
|
|
41
|
-
`
|
|
42
|
-
|
|
43
|
+
Eight tokens are substituted at request time from the live inventory, by `docCounts` in
|
|
44
|
+
`js/web/docs.mjs`: `{N_LAWS}` `{N_AGENTS}` `{N_SKILLS}` `{N_PLUGINS}`, plus the four the
|
|
45
|
+
three-tier split added — `{N_ONTOLOGY}` (the ontology's sections), `{N_PACKS}` (packs that exist),
|
|
46
|
+
`{N_PACKS_ACTIVE}` (packs this install built in) and `{N_DOCTRINE_RULES}` (rules inside the active
|
|
47
|
+
packs). `{N_LAWS}` is the **invariant** count and nothing else; there is deliberately no token
|
|
48
|
+
meaning "the whole constitution", because `proseMirrorProblems` holds README and `SHIPPED.md`
|
|
49
|
+
prose to that same number and a token that quietly meant something wider would put the docs and
|
|
50
|
+
the gate at odds with no way to re-bless either.
|
|
51
|
+
|
|
52
|
+
⚠ **Only a `kind: "concept"` page is substituted.** A `markdown`-kind page renders `{N_PACKS}`
|
|
53
|
+
literally, on the screen, as those nine characters.
|
|
54
|
+
|
|
55
|
+
Typing a literal number into a `docs/web` page is caught by `proseMirrorProblems`. The README
|
|
56
|
+
badges and prose, and the `N laws, N agents, N skills` line in `SHIPPED.md`, are the hand-written
|
|
57
|
+
exceptions — and each has its own arm in `js/doctor.mjs` (`countTableProblems` walks the five
|
|
58
|
+
badge keys `agents`/`skills`/`laws`/`themes`/`plugins`; `proseMirrorProblems` holds the prose).
|
|
43
59
|
|
|
44
60
|
---
|
|
45
61
|
|
|
@@ -128,18 +144,38 @@ Notes that matter:
|
|
|
128
144
|
|
|
129
145
|
---
|
|
130
146
|
|
|
131
|
-
## 2 —
|
|
147
|
+
## 2 — Changing the constitution
|
|
132
148
|
|
|
133
|
-
|
|
134
|
-
|
|
149
|
+
Three tiers, four different costs. The addresses are `{{LAW}} <roman>` for an invariant and
|
|
150
|
+
`{{DOCTRINE}} <pack> <n>` for a doctrine rule; the ontology is cited by section name and adding a
|
|
151
|
+
section to it is not a checklist, it is a design change.
|
|
135
152
|
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
153
|
+
To count the cross-references either tier already carries, from the repo root:
|
|
154
|
+
|
|
155
|
+
```bash
|
|
156
|
+
grep -rhoE "\{\{LAW\}\} [IVXL]+" src/ | wc -l
|
|
157
|
+
grep -rhoE "\{\{DOCTRINE\}\} [a-z]+ [0-9]+" src/ | wc -l
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
On this checkout that reports 153 and 209. Both numbers move on every wave of editing, which is
|
|
161
|
+
why the commands are here and the answers are not load-bearing.
|
|
162
|
+
|
|
163
|
+
### 2a — Adding a DOCTRINE RULE (the common case)
|
|
164
|
+
|
|
165
|
+
Five files, none of them a count. This is the slot most new material belongs in, and it is cheap
|
|
166
|
+
on purpose so that the invariant slot stays scarce.
|
|
167
|
+
|
|
168
|
+
1. `src/doctrines/<pack>.md` — **append** `### {{DOCTRINE}} <pack> <n> — {{DOC_<PACK>_<n>}}` plus
|
|
169
|
+
the body. Two gates in `constitutionProblems` (`js/doctor.mjs`) sit on this: the pack named in
|
|
170
|
+
the *heading* is what addresses the rule (not the filename, so a rule filed in the wrong file is
|
|
171
|
+
reported rather than silently renamed), and ids must run **contiguously from 1**, so appending
|
|
172
|
+
at the end is the only place `n` is free. Packs are numbered independently — nothing outside
|
|
173
|
+
this file renumbers.
|
|
174
|
+
2. `themes/_TEMPLATE.json` — add `DOC_<PACK>_<n>`. ⚠ **This file *is* gated for this key family.**
|
|
175
|
+
`themeFiles()` filters `_`-prefixed names and theme parity never sees the template, but
|
|
176
|
+
`constitutionProblems` reads it alongside the fourteen voices for `DOC_*` and `LEX_*`
|
|
177
|
+
specifically — because it is what `--sync-themes` seeds the *next* voice from. Every other key
|
|
178
|
+
family in that file is still ungated.
|
|
143
179
|
3. Seed the fourteen themes:
|
|
144
180
|
|
|
145
181
|
```bash
|
|
@@ -147,37 +183,110 @@ touched 21 files, 14 of them themes.
|
|
|
147
183
|
```
|
|
148
184
|
|
|
149
185
|
⚠ Four spellings of this command are in circulation and two of them fail — `doctor`'s own tip
|
|
150
|
-
is one of the two. See §7.2 before you copy a command from anywhere else.
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
**
|
|
186
|
+
is one of the two. See §7.2 before you copy a command from anywhere else. Then restyle all
|
|
187
|
+
fourteen by hand: `--sync-themes` writes the template's placeholder and only *prints*
|
|
188
|
+
`RESTYLE these`; a shipped placeholder passes every gate.
|
|
189
|
+
4. `web/src/pages/Laws.jsx` — a `DOCTRINE_META` row keyed `'<pack>.<n>'`. Its first field is the
|
|
190
|
+
**pack**, not one of `LAW_CLASSES`' six; `doctrineMetaProblems` requires an *equality* between
|
|
191
|
+
that field and the key's own pack, which catches the copy error a six-way vocabulary cannot — a
|
|
192
|
+
row pasted from the pack above it, keeping the wrong pack. Its second field is the one-line
|
|
193
|
+
Principle, and **that copy exists nowhere else**; a rule absent here renders with a blank
|
|
194
|
+
description.
|
|
195
|
+
5. `CHANGELOG.md`, then rebuild and commit `web/dist` (step 4 touched `web/src`).
|
|
196
|
+
|
|
197
|
+
**What a doctrine rule does *not* cost**, and each of these is a deliberate asymmetry:
|
|
198
|
+
|
|
199
|
+
- **No class entry.** There is no `LAW_CLASS` analogue: a doctrine rule's class *is* its pack, and
|
|
200
|
+
there is no second taxonomy over it.
|
|
201
|
+
- **No count, anywhere.** No badge, no `SHIPPED.md` triple, no prose mirror. The console spends
|
|
202
|
+
`{N_PACKS}` / `{N_PACKS_ACTIVE}` / `{N_DOCTRINE_RULES}`, all computed at request time.
|
|
203
|
+
- **No test fixture to bump**, and no renumber risk.
|
|
204
|
+
|
|
205
|
+
⚠ **Cite only downward.** An always-on tier may never reference a toggleable one:
|
|
206
|
+
`constitutionProblems` refuses a `{{DOCTRINE}}` token anywhere under `src/ontology/` or
|
|
207
|
+
`src/laws/`, because a `--doctrines craft` build would then ship an invariant pointing at text its
|
|
208
|
+
`AGENT.md` does not contain. Doctrine→doctrine citations are fine and stay — every pack file ships
|
|
209
|
+
on disk whether or not it was built in. If the build's own default is narrowed,
|
|
210
|
+
`constitutionProblems` emits a `[note]` naming every citation that points at a shelved pack; notes
|
|
211
|
+
are printed and **not** counted, because a narrowed build is a configuration its owner chose, not
|
|
212
|
+
a defect.
|
|
213
|
+
|
|
214
|
+
### 2b — Amending an INVARIANT
|
|
215
|
+
|
|
216
|
+
Steps 1 and 9 of §2c, plus `LAW_META` if the Principle line moved. Two cautions:
|
|
164
217
|
|
|
165
218
|
- `--footprint` defaults to **lean**, and lean keeps only the heading plus the first sentence
|
|
166
|
-
(`js/render.mjs
|
|
167
|
-
Amend the first sentence, or the amendment does not exist for most installs.
|
|
168
|
-
|
|
169
|
-
|
|
219
|
+
(`terseBlocks` in `js/render.mjs`). A clause added to the second paragraph is invisible in the
|
|
220
|
+
default build. Amend the first sentence, or the amendment does not exist for most installs. The
|
|
221
|
+
same is true of a doctrine rule; it is **not** true of the ontology, which ships whole at both
|
|
222
|
+
footprints.
|
|
223
|
+
- ⚠ **Rule I is frozen.** `LEX_I` is one of seven theme keys recorded byte-for-byte in the
|
|
224
|
+
primitives corpus (§5.2). Retitling Rule I in any theme reddens a snapshot that cannot be
|
|
225
|
+
re-blessed.
|
|
226
|
+
|
|
227
|
+
### 2c — Adding an INVARIANT
|
|
228
|
+
|
|
229
|
+
Nine steps, and only the first is the rule itself. This is the expensive one, and it should be:
|
|
230
|
+
the bar is in `DESIGN.md` Decision 7, and most candidates belong in a doctrine pack instead.
|
|
170
231
|
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
232
|
+
1. `src/laws/universal.md` — **append** `### {{LAW}} <roman> — {{LEX_<roman>}}` plus the body.
|
|
233
|
+
Never insert: the `{{LAW}}` cross-references counted above live all over `src/`, plus hardcoded
|
|
234
|
+
citations in `js/hooks.mjs` and two OpenCode plugins, and **nothing resolves a cross-reference
|
|
235
|
+
against the canon**. Renumbering silently rewires every one of them.
|
|
236
|
+
2. `themes/_TEMPLATE.json` — add `LEX_<roman>` in template order. Gated, as in §2a step 2:
|
|
237
|
+
`constitutionProblems` holds `LEX_I..LEX_IX` as an **equality** across all fifteen files (the
|
|
238
|
+
fourteen voices and the template), so both a missing key *and* a leftover one are reported. That
|
|
239
|
+
arm exists because the renumber left `LEX_XXII`, `LEX_XXIII`, `LEX_XXIV` and `LEX_XXXVI` behind
|
|
240
|
+
in every file and parity was silent — they were absent from nowhere.
|
|
241
|
+
3. `--sync-themes`, then restyle all fourteen by hand (§2a step 3).
|
|
242
|
+
4. `LAW_CLASS` in `js/inventory.mjs` — one of the six in `LAW_CLASSES` beside it.
|
|
243
|
+
5. `LAW_META` in `web/src/pages/Laws.jsx` — same class, plus the one-line Principle. Note the map
|
|
244
|
+
is keyed by **arabic** number where `universal.md` heads with a Roman numeral. **This copy
|
|
245
|
+
exists nowhere else**; a rule absent here renders with a blank description. It is why that one
|
|
246
|
+
React file ships alone out of `web/src` in `package.json` — `doctor` regex-parses its literal.
|
|
247
|
+
6. `README.md` — badge `badge/laws-N` and the `N universal laws` sentence.
|
|
248
|
+
7. `SHIPPED.md` — the `N laws, N agents, N skills` triple.
|
|
249
|
+
8. `tests/unit/harness.test.mjs` — the negative fixture for the `LAW_CLASS` gate plants a rule at
|
|
250
|
+
the *first free numeral*, which is `X` now that the invariants are I..IX. Bump it, or it stops
|
|
251
|
+
being a fixture and starts being a duplicate.
|
|
252
|
+
9. `CHANGELOG.md`, then rebuild and commit `web/dist` (step 5 touched `web/src`).
|
|
253
|
+
|
|
254
|
+
⚠ While restyling, `{{LAW}}` must stay a **single word** in every theme (and so must
|
|
255
|
+
`{{DOCTRINE}}`). Both heading parsers match the tier noun with `\S+`, so a two-word value does not
|
|
256
|
+
error — the heading simply stops matching and the whole tier parses to nothing, in silence.
|
|
257
|
+
`constitutionProblems` refuses one, which is the only reason it is visible at all.
|
|
258
|
+
|
|
259
|
+
The carrier itself is gated: `tests/unit/emit_smoke.test.mjs` checks every rule reaches every one
|
|
260
|
+
of nine emit modes in order and themed, under both footprints, with a `CEILING` **and** a floor
|
|
261
|
+
(half the ceiling) on the rendered size. Its docblock carries the current measurement: headroom is
|
|
262
|
+
1,522 characters (2.8%) at full and 1,794 (4.8%) at lean, against the largest carrier — the
|
|
263
|
+
host-agnostic `files` bundle. Read that docblock before adding text to any tier; it is
|
|
264
|
+
re-measured, never nudged, and the ceiling is measured **with all four packs active**, which is
|
|
265
|
+
the only configuration it can speak for.
|
|
266
|
+
|
|
267
|
+
### 2d — Adding a whole PACK
|
|
268
|
+
|
|
269
|
+
Rare, and mechanical. On top of §2a for each rule the pack carries:
|
|
270
|
+
|
|
271
|
+
1. `src/doctrines/<pack>.md`, opening with its lead line — `**{{PACK_<NAME>}}** — how … .` A pack
|
|
272
|
+
file `PACK_ORDER` names but cannot read, or one carrying no `### {{DOCTRINE}} <pack> <n>`
|
|
273
|
+
heading at all, is a refusal.
|
|
274
|
+
2. `PACK_ORDER` in `js/checkout.mjs` — the registration, and the render order. It is **narrative,
|
|
275
|
+
not alphabetical** (craft → rigor → ops → process); discovery sorts alphabetically and the
|
|
276
|
+
renderer refuses a `.md` under `src/doctrines/` that `PACK_ORDER` does not name, rather than
|
|
277
|
+
skipping it.
|
|
278
|
+
3. `PACK_<NAME>` in `themes/_TEMPLATE.json` and all fourteen voices. Unlike `DOC_*`, this family is
|
|
279
|
+
held only by `themeParityProblems` — presence, across the voices, template excluded.
|
|
280
|
+
4. `DOCTRINE_BLURBS` in `js/setup.mjs` — the one-line description an installer sees in the wizard,
|
|
281
|
+
and the only place a pack is ever explained to them. Missing entries fall back to the bare name.
|
|
282
|
+
5. `harness.config.json` if the pack should be on by default; `constitutionProblems` refuses a
|
|
283
|
+
`doctrines` array naming a pack this checkout does not ship.
|
|
175
284
|
|
|
176
285
|
---
|
|
177
286
|
|
|
178
287
|
## 3 — Adding a SKILL or an AGENT
|
|
179
288
|
|
|
180
|
-
**Order matters at the first two steps.** `missingReferencedSpecs` (`js/emit.mjs
|
|
289
|
+
**Order matters at the first two steps.** `missingReferencedSpecs` (in `js/emit.mjs`) *aborts the
|
|
181
290
|
build* when `AGENT.md.tmpl` names a spec with no file — so the file comes before the table row, or
|
|
182
291
|
nothing builds at all. The refusal is clean: `tests/unit/emit_gates.test.mjs:265` proves a refused
|
|
183
292
|
emit leaves the prior install intact.
|
|
@@ -185,14 +294,14 @@ emit leaves the prior install intact.
|
|
|
185
294
|
1. `src/skills/<name>.md` or `src/agents/<name>.md`. The shape is load-bearing: `# {{SKILL}}: <name>`,
|
|
186
295
|
a blank line, then a `>` blockquote holding `{{DESC_<NAME>}}` — title, blockquote, nothing
|
|
187
296
|
between. `doctor` checks both the presence of the purpose line and that the blockquote is the
|
|
188
|
-
*first* block (`
|
|
297
|
+
*first* block (`authoringProblems`, via `firstBlockquote` and `descBlockProblem`).
|
|
189
298
|
2. One row in the hand-authored table in `src/AGENT.md.tmpl` (agents `125-141`, skills `183-229`).
|
|
190
299
|
Gated both ways: a row with no file, and a file with no row.
|
|
191
300
|
3. `DESC_<NAME>` in **all fourteen** themes. Theme parity catches a missing one; nothing catches
|
|
192
301
|
an unstyled placeholder.
|
|
193
|
-
4. **Skills only** — `SKILL_CLASS` in `js/inventory.mjs
|
|
194
|
-
|
|
195
|
-
skill renders as `build
|
|
302
|
+
4. **Skills only** — `SKILL_CLASS` in `js/inventory.mjs`. Gated both ways, inside
|
|
303
|
+
`countTableProblems`, which matters because the runtime fallback is silent: an unclassified
|
|
304
|
+
skill renders as `build`.
|
|
196
305
|
5. `registry.json` — a row keyed `skills/<name>` or `agents/<name>` with `status` ∈
|
|
197
306
|
{`experimental`, `approved`, `deprecated`}, a semver `version`, a non-blank `owner`, an ISO
|
|
198
307
|
`added`, and `last_verified: ""`. **This is the most forgettable step**: four hand-typed fields,
|
|
@@ -231,7 +340,7 @@ The `geneseed-` prefix and the `.js` suffix are mechanically load-bearing: the b
|
|
|
231
340
|
|
|
232
341
|
1. `adapters/opencode/plugins/geneseed-<name>.js` — ESM, zero dependencies. The factory-export
|
|
233
342
|
convention is real (OpenCode requires it) but **ungated**; the only generic gate on plugin
|
|
234
|
-
source is `node --check` (`
|
|
343
|
+
source is `node --check` (the one spawn in `authoringProblems`).
|
|
235
344
|
2. `docs/web/plugin-<name>.md` — `group: plugins`, `title: "geneseed-<name>"`, `kind: "concept"`.
|
|
236
345
|
3. `docs/web/plugins.md` — a bullet. The count above it renders from `{N_PLUGINS}`.
|
|
237
346
|
4. `docs/web/model.md` — a second `{N_PLUGINS}` sentence whose **enumeration of the capabilities
|
|
@@ -396,8 +505,9 @@ only, at best, on its presence.
|
|
|
396
505
|
|
|
397
506
|
| What | Where | Gated on |
|
|
398
507
|
|---|---|---|
|
|
508
|
+
| `§N` cross-references into `AGENT.md`'s anatomy | `src/skills/*`, `src/agents/*`, `adapters/**` | **range only.** `constitutionProblems` refuses a `§N` the template declares no section for — which catches a pointer past the end, the shape *removing* a section leaves. It cannot catch one that still resolves and now means something else, which is the shape *inserting* a section leaves, and is what actually happened when `## 2. Doctrines` pushed every later section down one. **Renumbering the anatomy means `grep -rn '§' src/ adapters/` and reading every hit.** Four satellites and a live OpenCode deny message shipped stale because the sweep stopped at `AGENT.md.tmpl` |
|
|
399
509
|
| Per-law Principle lines | `web/src/pages/Laws.jsx` | presence and class only, never accuracy |
|
|
400
|
-
|
|
|
510
|
+
| 504 themed constitution titles (36 keys × 14 voices) — `LEX_I..LEX_IX` (9), `DOC_<PACK>_<n>` (23), `PACK_<NAME>` (4) | `themes/*.json` | key presence only — a shipped placeholder is green. `LEX_*` and `DOC_*` are held across the template too, and in both directions; `PACK_*` only across the voices |
|
|
401
511
|
| The README keyword enumerations | `README.md`, `docs/web/rules.md` | nothing |
|
|
402
512
|
| The plugin capability enumeration | `docs/web/model.md` | nothing (the number substitutes; the list does not) |
|
|
403
513
|
| Section labels and page subtitles | `web/src/lib/sections.js`, `web/src/pages/Docs/index.jsx` | nothing |
|
|
@@ -540,20 +650,19 @@ to kill every pid on the port, then `geneseed web start`.
|
|
|
540
650
|
Ordered by what unblocks the most work per unit of effort. Each is small; none is urgent enough to
|
|
541
651
|
stop a change today, and all of them cost a contributor a wrong turn until they are done.
|
|
542
652
|
|
|
543
|
-
1. **
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
3. **Decide the hook-verb question (§5.1) before it is asked under pressure.** Either mirror the
|
|
653
|
+
1. **Extend the fenced-command gate to `DESIGN.md` and `docs/**/*.md` (§7.3).** One array literal.
|
|
654
|
+
Today it covers four documents, and both of the pointer-to-nothing defects §7 records — the
|
|
655
|
+
`DESIGN.md` authoring section and `doctor`'s theme-parity tip, since fixed — sat outside its
|
|
656
|
+
reach. It keeps catching them.
|
|
657
|
+
2. **Decide the hook-verb question (§5.1) before it is asked under pressure.** Either mirror the
|
|
549
658
|
CLI side's exemption list onto the hook half, or write down that the hook verb set is closed.
|
|
550
659
|
Either answer is fine; discovering the question mid-feature is not.
|
|
551
|
-
|
|
660
|
+
3. **Write down the frozen-key list (§5.2) where a theme author will see it** — `themes/README.md`
|
|
552
661
|
is the natural home. Seven keys × fifteen files is a small enough surface to name explicitly,
|
|
553
662
|
and today nothing warns you before the snapshot goes red.
|
|
554
|
-
|
|
663
|
+
4. **Gate `AGENT_LESSON_PROMPT` like its sibling (§7.7), and either gate or delete
|
|
555
664
|
`adapters/claude-code/settings.json` (§7.10).** Two silent failure modes, both cheap to close.
|
|
556
|
-
|
|
665
|
+
5. **Consider a `scripts` block in the root `package.json`.** There is currently no single command
|
|
557
666
|
that runs what CI runs; every contributor reassembles the five by hand from this file. A
|
|
558
667
|
`verify` script is three lines and makes §1 executable rather than descriptive.
|
|
559
668
|
|
package/docs/limits.md
CHANGED
|
@@ -78,10 +78,10 @@ nothing else — **M1, M2, M3, M4 and M8** (`EMIT`, `EMIT_IMPERIAL`, `EMIT_CLAUD
|
|
|
78
78
|
`CLI_CONTEXT`). All five are killed by `tests/unit/` alone, the control included, and each row now
|
|
79
79
|
**declares** the unit file that kills it rather than a replay that can no longer run — M1 and M3
|
|
80
80
|
`maintainer_tools`, M2 `node_driver`, M4 `hook_form`, M8 `hook_cli`. A gate a matrix names and
|
|
81
|
-
cannot run guards nothing, and is worse than none, because it is trusted (
|
|
82
|
-
defect the mutation matrix knows how to plant, the corpus was
|
|
83
|
-
argument, and it is the only one that licenses a deletion:
|
|
84
|
-
already proves the property, never because it is red.
|
|
81
|
+
cannot run guards nothing, and is worse than none, because it is trusted (Doctrine rigor 2,
|
|
82
|
+
Honest Tests). For every defect the mutation matrix knows how to plant, the corpus was
|
|
83
|
+
redundant. That is the whole argument, and it is the only one that licenses a deletion:
|
|
84
|
+
a test goes because a living gate already proves the property, never because it is red.
|
|
85
85
|
|
|
86
86
|
**What was knowingly LOST: byte-level regression detection on emit, cli and web output.** Nothing
|
|
87
87
|
now notices that a rendered bundle, a verb's stdout / stderr / exit code, or an HTTP response body
|
package/docs/token-footprint.md
CHANGED
|
@@ -30,10 +30,21 @@ every host the same way instead of one silently falling behind.
|
|
|
30
30
|
|
|
31
31
|
## Where the tokens go
|
|
32
32
|
|
|
33
|
-
- **The root file is ~76% of the bill**, and
|
|
34
|
-
of
|
|
35
|
-
|
|
36
|
-
|
|
33
|
+
- **The root file is ~76% of the bill**, and the constitution inside it is the
|
|
34
|
+
bulk of that — no longer one section but three: the Ontology, the nine Rules,
|
|
35
|
+
and the doctrine packs this install built in. **Two** levers move it, not one.
|
|
36
|
+
The [footprint dial](#/docs/footprint) (`lean`, the default, keeps each Rule
|
|
37
|
+
and each doctrine rule as its heading plus first line, and ships the Ontology
|
|
38
|
+
*whole*; `full` inlines every rationale). And the
|
|
39
|
+
[doctrine packs](#/docs/setup-choices) — `geneseed-build --doctrines craft,rigor`
|
|
40
|
+
drops whole blocks of §2 at build time, which removes far more than the
|
|
41
|
+
footprint dial trims. Anything else is noise.
|
|
42
|
+
|
|
43
|
+
The three-tier split grew the root file: measured on `neutral`, `AGENT.md`
|
|
44
|
+
went from 31,457 bytes to 36,882 at `lean` (+17.2%) and 53,378 to 54,810 at
|
|
45
|
+
`full` (+2.7%). The lean growth is the larger one *by design* — the Ontology
|
|
46
|
+
is prose, and truncating four flowing sections to four orphan sentences would
|
|
47
|
+
have shipped a worldview nobody could read.
|
|
37
48
|
- **Skill bodies (~53k) and agent bodies (~10k) are lazy** on every host —
|
|
38
49
|
loaded only when invoked. A typical skill costs ≤3k per invocation; the
|
|
39
50
|
heaviest (`react-view-transitions`, ~17.5k with its reference files) loads
|
package/docs/web/authoring.md
CHANGED
|
@@ -4,7 +4,7 @@ order: 0
|
|
|
4
4
|
title: "Edit the source"
|
|
5
5
|
kind: "concept"
|
|
6
6
|
---
|
|
7
|
-
Everything theme-independent lives under `src/` — laws, agents, skills, memory and notebook conventions, and the `AGENT.md.tmpl` entrypoint. Voice tokens live under `themes/` as one JSON file per theme. After editing, `geneseed build --emit opencode-global` (or `geneseed update`) re-renders the deployed bundle. The `doctor` action verifies the result: unresolved theme tokens, dead links, hermetic escapes, theme-key parity, and that the committed bundle matches a fresh render.
|
|
7
|
+
Everything theme-independent lives under `src/` — the constitution (`ontology/`, `laws/`, `doctrines/`), the `postures/` and `modes/` registers, agents, skills, memory and notebook conventions, and the `AGENT.md.tmpl` entrypoint. Voice tokens live under `themes/` as one JSON file per theme. After editing, `geneseed build --emit opencode-global` (or `geneseed update`) re-renders the deployed bundle. The `doctor` action verifies the result: unresolved theme tokens, dead links, hermetic escapes, theme-key parity, and that the committed bundle matches a fresh render.
|
|
8
8
|
|
|
9
9
|
Each agent and skill also carries a lifecycle status — `experimental`, `approved` or `deprecated` — recorded in `registry.json` at the repo root alongside its version, owner and add-date. The file is maintainer-side: it is never rendered into a bundle, so a status costs no session context. Adding a spec means adding its row; `doctor` fails on a spec with no row and on a row with no spec, and the catalog badges anything that is not `approved`. The same pass refuses to let a credential ship, and holds every vendored skill folder to an immutable upstream commit rather than a moving branch.
|
|
10
10
|
|
package/docs/web/claude-hooks.md
CHANGED
|
@@ -9,8 +9,8 @@ Claude Code has no `instructions` array and no JS plugin dir — the harness rea
|
|
|
9
9
|
### The four hooks
|
|
10
10
|
|
|
11
11
|
- **Context injection** — `SessionStart` (startup, clear, resume) runs `geneseed-hook context`: auto-discovers the repo's docs by convention and injects them before your first turn, plus your machine wiki. It honours the same `GENESEED_CONTEXT` manifest as the OpenCode context plugin.
|
|
12
|
-
- **Git gate** — `PreToolUse` on Bash runs `geneseed-hook git-gate`:
|
|
13
|
-
- **Rule gate** — `PreToolUse` on the write tools runs `geneseed-hook rule-gate`: a write to `user-rules.md` or to a memory file asks first, because whether something you want kept is a standing rule or a durable fact is *your* call, settled through the [rule skill](#/docs/skills) (**
|
|
12
|
+
- **Git gate** — `PreToolUse` on Bash runs `geneseed-hook git-gate`: a `git commit` or `git push` anywhere in the command line — a compound one-liner and a `-C <path>` form included — asks first, at the tool boundary and before the shell runs it (**Doctrine process 5**). It is the one hook that rides a doctrine pack: an install built without **process** never gets this group, because a boundary that keeps asking for a rule the install did not adopt is a gate arguing with its own harness.
|
|
13
|
+
- **Rule gate** — `PreToolUse` on the write tools runs `geneseed-hook rule-gate`: a write to `user-rules.md` or to a memory file asks first, because whether something you want kept is a standing rule or a durable fact is *your* call, settled through the [rule skill](#/docs/skills) (**Doctrine process 1**). Ordinary edits are untouched.
|
|
14
14
|
- **Learn** — `Stop` and `SubagentStop` run `geneseed-hook learn`: distils durable memories into the install's `memory/` store at session end; a subagent's stop routes to the per-agent lesson path (`memory/agents/<name>.md`).
|
|
15
15
|
|
|
16
16
|
### Where they live
|
|
@@ -4,7 +4,7 @@ order: 11
|
|
|
4
4
|
title: "The collaboration layer"
|
|
5
5
|
kind: "concept"
|
|
6
6
|
---
|
|
7
|
-
|
|
7
|
+
Beside the [constitution](#/docs/rules), a handful of mechanisms shape *how* the agent works with you — the two registers, the mutual contract, how memory binds, and who you are. All of them are plain content in `AGENT.md` and its neighbours, so they ride to every host (OpenCode, Claude, Bob, Copilot) unchanged.
|
|
8
8
|
|
|
9
9
|
### Postures — the register
|
|
10
10
|
|
|
@@ -16,7 +16,7 @@ A **mode** is the session's operating register — *how* work gets executed, as
|
|
|
16
16
|
|
|
17
17
|
### The Pact — a two-way contract
|
|
18
18
|
|
|
19
|
-
Where the
|
|
19
|
+
Where the Rules bind the agent, the **Pact** binds the collaboration — and it is not a layer beside them: it is stated inside the Ontology's **Telos**, the tier that is always in force, so it holds in every task and every repository. It carries three co-equal protections (you, the truth, the agent), never traded one for another, and — unusually — names what *you* owe back: don't punish candour that honours the pact, give context up front, decide when shown a fork. Your half is not enforceable against you; the agent's half is binding on it.
|
|
20
20
|
|
|
21
21
|
### Typed memory — binding force
|
|
22
22
|
|
|
@@ -24,4 +24,4 @@ A memory may carry an optional `force` — **constraint** (imposed, not the agen
|
|
|
24
24
|
|
|
25
25
|
### Your profile — identity
|
|
26
26
|
|
|
27
|
-
`PROFILE.md`, seeded once beside `AGENT.md` and never overwritten, holds *who you are*: role, habits, register preferences. It is identity, not rules — it colours how the agent works but never binds (precedence is
|
|
27
|
+
`PROFILE.md`, seeded once beside `AGENT.md` and never overwritten, holds *who you are*: role, habits, register preferences. It is identity, not rules — it colours how the agent works but never binds (precedence is the Ontology and the Rules, then `user-rules.md`, then the active Doctrines, then the profile). Edit it here under the **Profile** tab, or in the file directly — or let the agent draft it: the [[profile]] skill interviews you (who you are, how you work, how you like answers pitched) and writes the file only with your consent, routing anything that is really a standing rule to `user-rules.md` instead.
|
|
@@ -8,7 +8,7 @@ Once installed, the agent doesn't change *how* you talk to your tool — it chan
|
|
|
8
8
|
|
|
9
9
|
### What loaded automatically
|
|
10
10
|
|
|
11
|
-
- **`AGENT.md`** — {N_LAWS}
|
|
11
|
+
- **`AGENT.md`** — the [constitution](#/docs/rules): the Ontology's {N_ONTOLOGY} sections, {N_LAWS} always-on Rules, and the {N_DOCTRINE_RULES} doctrine rules from the packs this install built in.
|
|
12
12
|
- **Your repo's docs** — `README.md`, `CONTRIBUTING.md`, anything under `docs/` the harness discovers.
|
|
13
13
|
- **Your machine's wiki** (if you [set one up](#/docs/configure-wiki)) — eager entries and a lazy listing of the rest.
|
|
14
14
|
- **The skill and agent catalogue** — invokable by name.
|
|
@@ -25,4 +25,4 @@ Skills are repeatable workflows; agents are capability specialists. You invoke t
|
|
|
25
25
|
|
|
26
26
|
---
|
|
27
27
|
|
|
28
|
-
**Catalog:** [Skills](#/section/skills) · [Agents](#/section/agents) · [
|
|
28
|
+
**Catalog:** [Skills](#/section/skills) · [Agents](#/section/agents) · [Constitution](#/laws)
|