geneseed 3.15.0 → 3.17.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 +35 -0
- package/SHIPPED.md +1 -1
- package/adapters/opencode/plugins/geneseed-context.js +36 -8
- package/adapters/opencode/plugins/geneseed-guard.js +28 -0
- package/bin/geneseed.mjs +17 -0
- package/docs/concepts/exclusions.md +21 -9
- package/docs/concepts/hooks.md +1 -0
- package/docs/concepts/loop-notes.md +3 -0
- package/docs/concepts/loops.md +11 -0
- package/docs/guides/headless.md +1 -1
- package/docs/guides/install-scripted.md +1 -1
- package/docs/guides/project-context.md +3 -3
- package/docs/guides/read-non-markdown.md +1 -1
- package/docs/reference/plugin-context.md +2 -2
- package/docs/reference/plugin-guard.md +1 -1
- package/docs/token-footprint.md +10 -7
- package/harness.config.json +1 -1
- package/js/build/args.mjs +34 -3
- package/js/build/driver.mjs +8 -7
- package/js/build/generate.mjs +11 -5
- package/js/build/render.mjs +33 -3
- package/js/build/source.mjs +37 -1
- package/js/cli-table.json +15 -0
- package/js/hosts/hooks-context.mjs +112 -56
- package/js/hosts/hooks.mjs +34 -1
- package/js/hosts/installs.mjs +25 -2
- package/js/hosts/opencode.mjs +2 -0
- package/js/hosts/settings.mjs +2 -1
- package/js/inspect/checks-constitution.mjs +2 -2
- package/js/inspect/diff.mjs +4 -1
- package/js/inspect/status.mjs +2 -1
- package/js/inspect/validate.mjs +3 -1
- package/js/loop/graph.mjs +2 -1
- package/js/loop/state.mjs +30 -1
- package/js/maintain/setup.mjs +11 -4
- package/js/maintain/update.mjs +1 -1
- package/js/web/actions.mjs +5 -3
- package/package.json +1 -1
- package/src/AGENT.md.tmpl +1 -1
- package/src/agents/docs.md +5 -0
- package/src/bricks/apply.md +3 -0
- package/src/bricks/docs-update.md +2 -0
- package/src/bricks/test.md +17 -7
- package/src/doctrines/process.md +9 -5
- package/src/loops/api-endpoint.json +1 -1
- package/src/loops/bugfix.json +1 -1
- package/src/loops/ci-repair.json +1 -1
- package/src/loops/deps-upgrade.json +1 -1
- package/src/loops/enforce-architecture-rule.json +1 -1
- package/src/loops/feature.json +1 -1
- package/src/loops/fix-flaky-tests.json +1 -1
- package/src/loops/legacy-refactor.json +1 -1
- package/src/loops/legacy-tests.json +1 -1
- package/src/loops/refactor.json +1 -1
- package/src/loops/remove-dead-code.json +1 -1
- package/src/loops/spec-first-feature.json +1 -1
- package/src/loops/tdd.json +1 -1
- package/src/loops/update-contract.json +1 -1
- package/src/skills/document-project.md +91 -22
- package/web/dist/assets/{Activity-kpWxd70F.js → Activity-DonKN1pi.js} +1 -1
- package/web/dist/assets/{ActivityDetail-Ccr942VL.js → ActivityDetail-e47a3cdE.js} +1 -1
- package/web/dist/assets/{Dashboard-D1lE7jcg.js → Dashboard-Cr7i0PsO.js} +2 -2
- package/web/dist/assets/{Docs-BHyaggFy.js → Docs-Lne3nuzD.js} +1 -1
- package/web/dist/assets/{GreenhouseView-Sc_UDMOE.js → GreenhouseView-4CbIuTpl.js} +1 -1
- package/web/dist/assets/{Installs-Gw-pJ3Zi.js → Installs-CIzbV1Ks.js} +1 -1
- package/web/dist/assets/{JournalView-_gxpsxXi.js → JournalView-BlBfuvzj.js} +1 -1
- package/web/dist/assets/{Laws-S9fq1r9T.js → Laws-B-pjcjHr.js} +1 -1
- package/web/dist/assets/{Library-MBxadRzn.js → Library-x8Nzg6yq.js} +1 -1
- package/web/dist/assets/{Loops-Da_JhlzM.js → Loops-DIOxW1xH.js} +1 -1
- package/web/dist/assets/{OperatorHudView--TkvDybH.js → OperatorHudView-D7S7z7CJ.js} +1 -1
- package/web/dist/assets/{Personal-CTXKHVbV.js → Personal-Ws3v35AB.js} +1 -1
- package/web/dist/assets/{Tabs-B0cdf8k6.js → Tabs-6Z1eziAq.js} +1 -1
- package/web/dist/assets/{drawable-BbWQxe82.js → drawable-ATNeYKbT.js} +1 -1
- package/web/dist/assets/{index-ujKG1ZNf.js → index-CDg5XUhG.js} +2 -2
- package/web/dist/index.html +1 -1
package/js/loop/graph.mjs
CHANGED
|
@@ -83,7 +83,8 @@ export function checkGraph(graph, bricks) {
|
|
|
83
83
|
if (!brick) continue;
|
|
84
84
|
for (const o of brick.outcomes) {
|
|
85
85
|
const count = edges.filter((e) => e.from === n && e.on === o).length;
|
|
86
|
-
|
|
86
|
+
// `error` is reserved: with no edge the engine routes it to $stop (`recordOutcome`).
|
|
87
|
+
if (count === 0 && o !== 'error') problems.push(`node ${n}: no edge for outcome ${o}`);
|
|
87
88
|
else if (count > 1) problems.push(`node ${n}: ${count} edges for outcome ${o}`);
|
|
88
89
|
}
|
|
89
90
|
}
|
package/js/loop/state.mjs
CHANGED
|
@@ -288,6 +288,22 @@ function allowedEntries(graph, v) {
|
|
|
288
288
|
return { allowed: widest ? 1 + widest.max : 1, loop: widest };
|
|
289
289
|
}
|
|
290
290
|
|
|
291
|
+
// The repair ring an edge closes: the smallest non-iteration loop whose FIRST node is the edge's
|
|
292
|
+
// target and which also holds its source (test -> apply is apply-test's repair, review -> apply
|
|
293
|
+
// review-fix's). Its own counter makes `max` the number of repairs that ring may spend, even when
|
|
294
|
+
// a wider ring sharing the node raises the node budget above it — `max: 1` is one repair, then
|
|
295
|
+
// `exhaust`'s fresh attempt, then a stop (arXiv 2607.24604: a second revision lowers accuracy).
|
|
296
|
+
// Its key lives in `counters`, so every reset of a unit resets it too.
|
|
297
|
+
function repairRing(graph, from, to) {
|
|
298
|
+
const iteration = iterationLoop(graph);
|
|
299
|
+
let ring = null;
|
|
300
|
+
for (const m of graph.loops) {
|
|
301
|
+
if (m === iteration || m.nodes[0] !== to || !m.nodes.includes(from)) continue;
|
|
302
|
+
if (!ring || m.nodes.length < ring.nodes.length) ring = m;
|
|
303
|
+
}
|
|
304
|
+
return ring;
|
|
305
|
+
}
|
|
306
|
+
|
|
291
307
|
// Porcelain lines are `XY <path>`; strip the 2-char status + space, slash-normalise, drop
|
|
292
308
|
// LOOP.md rows (the engine rewrites it on every action — it is never part of the scored work)
|
|
293
309
|
// and a lingering LOOP.md.tmp (the atomic writer's own sibling — see `writeLoopFile`'s docblock).
|
|
@@ -348,10 +364,17 @@ export function recordOutcome(state, bricks, outcome, { card = null, porcelain =
|
|
|
348
364
|
// this call closes the unit, re-splits, or stops the loop. `notes` is never reset mid-run
|
|
349
365
|
// (only `exhaust`'s own push and `decideAwaiting` add to it otherwise), so it survives
|
|
350
366
|
// `resetUnit`/`finishUnit` — which a card does not: `resetUnit` clears it.
|
|
367
|
+
// A fresh verdict: `test`'s latest report supersedes its earlier ones, so a repair never reads
|
|
368
|
+
// findings about code that has since changed (stale traces broke 34 of 135 correct attempts
|
|
369
|
+
// in arXiv 2607.24604, fresh ones 4). Every other brick's notes are a record and are kept.
|
|
370
|
+
if (from === 'test') state.notes = state.notes.filter((n) => !/^iteration \d+ \(test\): /.test(n));
|
|
351
371
|
if (note) state.notes.push(`iteration ${state.iteration} (${from}): ${note}`);
|
|
352
372
|
state.visited.push(from);
|
|
353
373
|
|
|
354
|
-
|
|
374
|
+
// `error` is reserved: a check that produced no verdict stops for a human, never a repair. A
|
|
375
|
+
// brick may declare it without an edge (`checkGraph` allows that); the engine routes it here.
|
|
376
|
+
const edge = state.graph.edges.find((e) => e.from === from && e.on === outcome)
|
|
377
|
+
?? (outcome === 'error' ? { from, on: 'error', to: '$stop' } : null);
|
|
355
378
|
if (!edge) throw new Error(`no edge from ${from} on ${outcome}`);
|
|
356
379
|
if (brick.gate === 'human' && (!brick.gateOn || brick.gateOn.includes(outcome))) {
|
|
357
380
|
state.status = 'awaiting';
|
|
@@ -385,6 +408,12 @@ function transition(state, bricks, from, edge) {
|
|
|
385
408
|
finishUnit(state, false);
|
|
386
409
|
return state.status === 'stopped' ? { stopped: state.reason } : { node: state.node };
|
|
387
410
|
}
|
|
411
|
+
const ring = repairRing(state.graph, from, edge.to);
|
|
412
|
+
if (ring) {
|
|
413
|
+
const key = `ring:${ring.name}`;
|
|
414
|
+
state.counters[key] = (state.counters[key] ?? 0) + 1;
|
|
415
|
+
if (state.counters[key] > ring.max) return exhaust(state, ring);
|
|
416
|
+
}
|
|
388
417
|
state.counters[edge.to] = (state.counters[edge.to] ?? 0) + 1;
|
|
389
418
|
const { allowed, loop } = allowedEntries(state.graph, edge.to);
|
|
390
419
|
if (state.counters[edge.to] > allowed) return exhaust(state, loop ?? { name: edge.to, max: 0 });
|
package/js/maintain/setup.mjs
CHANGED
|
@@ -277,11 +277,18 @@ export function collectSetupLines() {
|
|
|
277
277
|
// `setupBuildArgs` spell `--exclude-rules none`, and that string would land in the
|
|
278
278
|
// "About to run:" line every recorded wizard probe compares byte for byte.
|
|
279
279
|
const excludeRules = inst.excludeRules?.length ? inst.excludeRules : null;
|
|
280
|
+
// Skills left out are preserved the same way, and elide when there are none.
|
|
281
|
+
const excludeSkills = inst.excludeSkills?.length ? inst.excludeSkills : null;
|
|
280
282
|
printOut(`\nAbout to run: geneseed build ${
|
|
281
283
|
setupBuildArgs(theme, emit, out, root, footprint, posture, mode, doctrines, allPacks,
|
|
282
|
-
excludeRules).join(' ')}\n`);
|
|
284
|
+
excludeRules, undefined, excludeSkills).join(' ')}\n`);
|
|
283
285
|
if (!confirm('Proceed?', true)) return null;
|
|
284
|
-
|
|
286
|
+
// The key only when there is something to carry, so a selection that excludes no skill is
|
|
287
|
+
// the same object it was before the flag existed.
|
|
288
|
+
return {
|
|
289
|
+
theme, posture, mode, doctrines, excludeRules, ...(excludeSkills ? { excludeSkills } : {}),
|
|
290
|
+
emit, out, root, footprint,
|
|
291
|
+
};
|
|
285
292
|
}
|
|
286
293
|
|
|
287
294
|
// --------------------------------------------------------------------------------------
|
|
@@ -463,7 +470,7 @@ export function setupLines() {
|
|
|
463
470
|
}
|
|
464
471
|
const {
|
|
465
472
|
theme, emit, out, root, footprint = 'lean', posture = 'peer', mode = 'direct',
|
|
466
|
-
doctrines = null, excludeRules = null,
|
|
473
|
+
doctrines = null, excludeRules = null, excludeSkills = null,
|
|
467
474
|
} = sel;
|
|
468
475
|
if (emit === 'opencode-global') {
|
|
469
476
|
// The build below overwrites the deployed global harness, and the self-improvement loops
|
|
@@ -482,7 +489,7 @@ export function setupLines() {
|
|
|
482
489
|
// runs must carry the pack selection the plan line just previewed, or the wizard would print
|
|
483
490
|
// one command and run another.
|
|
484
491
|
const argv = setupBuildArgs(theme, emit, out, root, footprint, posture, mode, doctrines,
|
|
485
|
-
doctrineOptions().map(([n]) => n), excludeRules);
|
|
492
|
+
doctrineOptions().map(([n]) => n), excludeRules, undefined, excludeSkills);
|
|
486
493
|
printOut(`Running: geneseed build ${argv.join(' ')}\n`);
|
|
487
494
|
const rc = driverMain(argv);
|
|
488
495
|
if (rc !== 0) {
|
package/js/maintain/update.mjs
CHANGED
|
@@ -617,7 +617,7 @@ export async function installAxes(dir, { installProfile, setupBuildArgs }) {
|
|
|
617
617
|
if (!existsSync(path.join(String(dir), '.geneseed-emit'))) return [];
|
|
618
618
|
const p = installProfile('opencode', 'global', String(dir));
|
|
619
619
|
return setupBuildArgs('', 'files', null, null, p.footprint, p.posture, p.mode, p.doctrines,
|
|
620
|
-
undefined, p.excludeRules, p.trust).slice(4);
|
|
620
|
+
undefined, p.excludeRules, p.trust, p.excludeSkills).slice(4);
|
|
621
621
|
}
|
|
622
622
|
|
|
623
623
|
/**
|
package/js/web/actions.mjs
CHANGED
|
@@ -46,7 +46,8 @@ import {
|
|
|
46
46
|
opencodeConfigDir, resolvePath,
|
|
47
47
|
} from '../hosts/hosts.mjs';
|
|
48
48
|
import {
|
|
49
|
-
EMIT_HOST_SCOPE, doctrinesForBuild, excludedRulesOfDir,
|
|
49
|
+
EMIT_HOST_SCOPE, doctrinesForBuild, excludedRulesOfDir, excludedSkillsOfDir, footprintOfDir,
|
|
50
|
+
installState,
|
|
50
51
|
installTargets, modeOfDir, postureOfDir, trustOfDir,
|
|
51
52
|
} from '../hosts/installs.mjs';
|
|
52
53
|
import {
|
|
@@ -550,6 +551,7 @@ export function apiRestore(state, files) {
|
|
|
550
551
|
// The excluded rules for the same boundary reason: without them a restored AGENT.md
|
|
551
552
|
// re-states a rule whose hook gate the install deliberately left unwired.
|
|
552
553
|
excludeRules: excludedRulesOfDir(target),
|
|
554
|
+
excludeSkills: excludedSkillsOfDir(target),
|
|
553
555
|
}));
|
|
554
556
|
for (const raw of (isTruthy(files) ? files : [])) {
|
|
555
557
|
const rel = stripWhitespace(formatValue(raw).replace(/\\/g, '/')).replace(/^\/+/, '');
|
|
@@ -622,7 +624,7 @@ export function apiInstallCmd(state, body) {
|
|
|
622
624
|
const excludeRules = bodyExcludeRules(body) ?? excludedRulesOfDir(root);
|
|
623
625
|
const out = scope === 'global' ? null : String(root);
|
|
624
626
|
const argv = setupBuildArgs(theme || 'neutral', emit, out, out, fp, pos, mode, doctrines,
|
|
625
|
-
PACK_ORDER, excludeRules, trust);
|
|
627
|
+
PACK_ORDER, excludeRules, trust, excludedSkillsOfDir(root));
|
|
626
628
|
return { cmd: [process.execPath, path.join(ROOT, 'bin', 'build-driver.mjs'), ...argv] };
|
|
627
629
|
}
|
|
628
630
|
|
|
@@ -716,6 +718,6 @@ export function apiDeployCmd(state, body) {
|
|
|
716
718
|
const excludeRules = bodyExcludeRules(body) ?? excludedRulesOfDir(root);
|
|
717
719
|
// project-scope emit name == host name (opencode / claude / bob / openclaude)
|
|
718
720
|
const argv = setupBuildArgs(theme || 'neutral', host, root, root, fp, pos, mode, doctrines,
|
|
719
|
-
PACK_ORDER, excludeRules, trust);
|
|
721
|
+
PACK_ORDER, excludeRules, trust, excludedSkillsOfDir(root));
|
|
720
722
|
return { cmd: [process.execPath, path.join(ROOT, 'bin', 'build-driver.mjs'), ...argv] };
|
|
721
723
|
}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"//": "Every field here is argued and gated in tests/unit/package_manifest.test.mjs. `files`, `bin` and `engines` each have a test that fails when reality drifts from this file; `version` mirrors harness.config.json and is gated too. Read that docblock before editing this one.",
|
|
3
3
|
"name": "geneseed",
|
|
4
|
-
"version": "3.
|
|
4
|
+
"version": "3.17.0",
|
|
5
5
|
"description": "A portable, theme-able harness you implant once and use everywhere to grow a disciplined AI coding agent.",
|
|
6
6
|
"keywords": [
|
|
7
7
|
"ai",
|
package/src/AGENT.md.tmpl
CHANGED
|
@@ -295,7 +295,7 @@ inventory — that list is the catalogue and it is authoritative. Each written
|
|
|
295
295
|
procedure is in [`{{DIR_SKILLS}}/`]({{DIR_SKILLS}}/) and the host loads it on
|
|
296
296
|
demand.
|
|
297
297
|
<!-- CATALOG:end -->
|
|
298
|
-
|
|
298
|
+
{{EXCLUDED_SKILLS_LINE}}
|
|
299
299
|
When a task repeats and no {{SKILL}} covers it, forge one through the
|
|
300
300
|
[skill-forge]({{DIR_SKILLS}}/skill-forge.md) {{SKILL}}: copy
|
|
301
301
|
[`{{DIR_SKILLS}}/_template.md`]({{DIR_SKILLS}}/_template.md), keep it to one coherent
|
package/src/agents/docs.md
CHANGED
|
@@ -24,6 +24,11 @@
|
|
|
24
24
|
that the code does not implement ({{LAW:verify-before-asserting}}).
|
|
25
25
|
2. Write for the stated audience; lead with what the reader needs to do.
|
|
26
26
|
3. Keep examples runnable; update any example that the change broke.
|
|
27
|
+
4. Write each page in the format it is already in — Markdown or AsciiDoc; never convert one.
|
|
28
|
+
A new page follows the `Docs format:` line in the root `AGENTS.md`, else the format the
|
|
29
|
+
project's docs already use (only AsciiDoc when it has none yet). Agent-runtime files —
|
|
30
|
+
`AGENTS.md`, `CLAUDE.md`, specs, ADRs loops read — stay Markdown. In AsciiDoc, never add
|
|
31
|
+
an `include::` to a page agents read.
|
|
27
32
|
|
|
28
33
|
## Output contract
|
|
29
34
|
- The doc files written/updated, a one-line note of what changed and why,
|
package/src/bricks/apply.md
CHANGED
|
@@ -9,6 +9,9 @@ Implement the card's intent exactly, touching only the files in its `writeSet`.
|
|
|
9
9
|
carries an `amend`, that supersedes the original intent — follow the amendment, not the plan it
|
|
10
10
|
replaced.
|
|
11
11
|
|
|
12
|
+
When this is a repair after `test`, act on the latest `test` note only — it is the verdict on
|
|
13
|
+
the code as it stands. Fix every finding it lists in this one pass: there is no second repair.
|
|
14
|
+
|
|
12
15
|
Make no unrelated edits: no drive-by rename, no incidental cleanup, no touching a file the card
|
|
13
16
|
did not declare. If the change genuinely needs a file outside the write set, stop and report that
|
|
14
17
|
rather than widening scope unasked — the diff is scored against the declared set, not your
|
|
@@ -10,6 +10,8 @@ flag, a moved file, a behaviour the README or docs still describe the old way.
|
|
|
10
10
|
|
|
11
11
|
Update only those docs, only to match what the diff actually changed. Do not rewrite unrelated
|
|
12
12
|
prose, reorganize a page, or fix an unrelated staleness you happen to notice while in there.
|
|
13
|
+
Keep each doc in the format it is already in (Markdown or AsciiDoc) — never convert one; a new
|
|
14
|
+
page follows the `Docs format:` line in the root `AGENTS.md`.
|
|
13
15
|
|
|
14
16
|
Report `pass` once every doc the diff touched is back in sync, naming the files you changed — or
|
|
15
17
|
that none needed it, if the diff left nothing stale.
|
package/src/bricks/test.md
CHANGED
|
@@ -1,14 +1,24 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: test
|
|
3
|
-
description: Run the
|
|
3
|
+
description: Run the project's checks over this iteration's change, in order, and report every finding.
|
|
4
4
|
effect: read
|
|
5
5
|
agent: tester
|
|
6
|
-
outcomes: pass, fail
|
|
6
|
+
outcomes: pass, fail, error
|
|
7
7
|
---
|
|
8
|
-
Run this project's
|
|
9
|
-
|
|
8
|
+
Run this project's checks over the current change, in this order. Never edit any file — this
|
|
9
|
+
brick only observes; a fix belongs in `apply`, not here.
|
|
10
10
|
|
|
11
|
-
|
|
11
|
+
1. **Gate** — the build or compile step. If it fails, mark every check below `SKIPPED (gate
|
|
12
|
+
failed)` and report.
|
|
13
|
+
2. **Focused checks** — the linter and the tests the change can reach. Run every one even after a
|
|
14
|
+
failure: they check independent properties, and the one repair must see every finding at once.
|
|
15
|
+
3. **Full suite** — only when everything above passed; otherwise `SKIPPED (an earlier check failed)`.
|
|
12
16
|
|
|
13
|
-
|
|
14
|
-
|
|
17
|
+
List every check with `PASS`, `FAIL`, `ERROR` or `SKIPPED (reason)` — one that did not run is
|
|
18
|
+
never left out, and silence is never a pass. Write each failure as four lines: the check's
|
|
19
|
+
purpose, the property it guards, a one-line diagnostic (not the raw log), and the command that
|
|
20
|
+
reruns it alone. Keep full logs in a file, and write the list to the note file.
|
|
21
|
+
|
|
22
|
+
Report `pass` only if every check passed. Report `error` if a check crashed or could not be run —
|
|
23
|
+
no test runner, a missing tool, evidence never wired: that is a stop for a human, not a repair.
|
|
24
|
+
Report `fail` otherwise.
|
package/src/doctrines/process.md
CHANGED
|
@@ -114,9 +114,11 @@ legitimate rewrite). The host gates both at the tool boundary.
|
|
|
114
114
|
Every autonomous loop needs an exit you set before you enter it. Before iterating —
|
|
115
115
|
retrying, searching, generating-and-checking — fix the bounds: a cap on attempts, a
|
|
116
116
|
budget of time or tokens, and an explicit definition of success *and* of failure.
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
117
|
+
A check-and-repair loop gets one repair, then a fresh attempt or a hand-back — a second
|
|
118
|
+
revision lowers accuracy. Only a verdict on the final artifact counts: a pass from before
|
|
119
|
+
an edit is void, and old check output is never fed back. Then watch for the loop that has stopped progressing:
|
|
120
|
+
if you are issuing the same call, hitting the same error, or trying variations of one
|
|
121
|
+
approach with no new information, that is not persistence, it is thrashing — break out, change strategy,
|
|
120
122
|
gather different context, or stop. When a bound is reached or progress stalls, do
|
|
121
123
|
not grind on: halt and hand back a structured summary of what was tried, what was
|
|
122
124
|
learned, and what remains ({{LAW:surface-failures}}, {{DOCTRINE:plan-before-acting}}). {{DOCTRINE:context-economy}}
|
|
@@ -124,8 +126,10 @@ economises *within* a step; this bounds the *number* of steps. An agent that can
|
|
|
124
126
|
stop itself is a cost without a limit.
|
|
125
127
|
<!-- LEAN:else -->
|
|
126
128
|
Fix an autonomous loop's bounds before you enter it: an attempt cap, a time or token
|
|
127
|
-
budget, an explicit definition of success *and* failure.
|
|
128
|
-
|
|
129
|
+
budget, an explicit definition of success *and* failure. A check-and-repair loop spends
|
|
130
|
+
one repair, then a fresh attempt or a hand-back; accept only a verdict on the final
|
|
131
|
+
artifact — a pass from before an edit is void, old check output is never fed back.
|
|
132
|
+
Watch for the loop that has stopped progressing: the same call, the same error, variations with no new information are
|
|
129
133
|
thrashing; break out, change strategy, or stop. When a bound is reached or progress
|
|
130
134
|
stalls, halt with a structured summary of what was tried, learned, and remains ({{LAW:surface-failures}},
|
|
131
135
|
{{DOCTRINE:plan-before-acting}}).
|
|
@@ -24,7 +24,7 @@
|
|
|
24
24
|
],
|
|
25
25
|
"loops": [
|
|
26
26
|
{ "name": "iterations", "nodes": ["identify", "apply", "test", "bruno-test", "security-scan", "review"], "max": 20, "iteration": true },
|
|
27
|
-
{ "name": "apply-test", "nodes": ["apply", "test"], "max":
|
|
27
|
+
{ "name": "apply-test", "nodes": ["apply", "test"], "max": 1 },
|
|
28
28
|
{ "name": "review-fix", "nodes": ["apply", "test", "bruno-test", "security-scan", "review"], "max": 3 }
|
|
29
29
|
],
|
|
30
30
|
"contracts": ["**/openapi*.yaml", "**/openapi*.yml", "**/openapi*.json", "**/swagger*.yaml", "**/swagger*.yml", "**/swagger*.json"]
|
package/src/loops/bugfix.json
CHANGED
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
],
|
|
18
18
|
"loops": [
|
|
19
19
|
{ "name": "iterations", "nodes": ["identify", "apply", "test", "review"], "max": 20, "iteration": true },
|
|
20
|
-
{ "name": "apply-test", "nodes": ["apply", "test"], "max":
|
|
20
|
+
{ "name": "apply-test", "nodes": ["apply", "test"], "max": 1 },
|
|
21
21
|
{ "name": "review-fix", "nodes": ["apply", "test", "review"], "max": 3 }
|
|
22
22
|
]
|
|
23
23
|
}
|
package/src/loops/ci-repair.json
CHANGED
|
@@ -22,7 +22,7 @@
|
|
|
22
22
|
],
|
|
23
23
|
"loops": [
|
|
24
24
|
{ "name": "iterations", "nodes": ["upgrade-scout", "apply", "test", "deps-audit", "review"], "max": 20, "iteration": true },
|
|
25
|
-
{ "name": "apply-test", "nodes": ["apply", "test"], "max":
|
|
25
|
+
{ "name": "apply-test", "nodes": ["apply", "test"], "max": 1 },
|
|
26
26
|
{ "name": "review-fix", "nodes": ["apply", "test", "deps-audit", "review"], "max": 3 }
|
|
27
27
|
],
|
|
28
28
|
"ignoreDeletions": ["**/package-lock.json", "**/yarn.lock", "**/pnpm-lock.yaml", "**/*.lock", "**/gradle.lockfile"]
|
|
@@ -22,7 +22,7 @@
|
|
|
22
22
|
],
|
|
23
23
|
"loops": [
|
|
24
24
|
{ "name": "iterations", "nodes": ["identify", "apply", "test", "review"], "max": 20, "iteration": true },
|
|
25
|
-
{ "name": "apply-test", "nodes": ["apply", "test"], "max":
|
|
25
|
+
{ "name": "apply-test", "nodes": ["apply", "test"], "max": 1 },
|
|
26
26
|
{ "name": "review-fix", "nodes": ["apply", "test", "review"], "max": 3 }
|
|
27
27
|
]
|
|
28
28
|
}
|
package/src/loops/feature.json
CHANGED
|
@@ -18,7 +18,7 @@
|
|
|
18
18
|
],
|
|
19
19
|
"loops": [
|
|
20
20
|
{ "name": "iterations", "nodes": ["identify", "apply", "test", "review", "done-check"], "max": 20, "iteration": true },
|
|
21
|
-
{ "name": "apply-test", "nodes": ["apply", "test"], "max":
|
|
21
|
+
{ "name": "apply-test", "nodes": ["apply", "test"], "max": 1 },
|
|
22
22
|
{ "name": "review-fix", "nodes": ["apply", "test", "review"], "max": 3 }
|
|
23
23
|
]
|
|
24
24
|
}
|
|
@@ -24,7 +24,7 @@
|
|
|
24
24
|
],
|
|
25
25
|
"loops": [
|
|
26
26
|
{ "name": "iterations", "nodes": ["identify", "apply", "flake-check", "test", "review"], "max": 10, "iteration": true },
|
|
27
|
-
{ "name": "stabilise", "nodes": ["apply", "flake-check"], "max":
|
|
27
|
+
{ "name": "stabilise", "nodes": ["apply", "flake-check"], "max": 1 },
|
|
28
28
|
{ "name": "review-fix", "nodes": ["apply", "flake-check", "test", "review"], "max": 3 }
|
|
29
29
|
]
|
|
30
30
|
}
|
|
@@ -19,7 +19,7 @@
|
|
|
19
19
|
],
|
|
20
20
|
"loops": [
|
|
21
21
|
{ "name": "iterations", "nodes": ["identify", "apply", "test", "review"], "max": 20, "iteration": true },
|
|
22
|
-
{ "name": "apply-test", "nodes": ["apply", "test"], "max":
|
|
22
|
+
{ "name": "apply-test", "nodes": ["apply", "test"], "max": 1 },
|
|
23
23
|
{ "name": "review-fix", "nodes": ["apply", "test", "review"], "max": 3 }
|
|
24
24
|
],
|
|
25
25
|
"weights": { "logic": 0.6 }
|
|
@@ -22,7 +22,7 @@
|
|
|
22
22
|
],
|
|
23
23
|
"loops": [
|
|
24
24
|
{ "name": "iterations", "nodes": ["identify", "characterize", "test", "mutation-check"], "max": 20, "iteration": true },
|
|
25
|
-
{ "name": "write-run", "nodes": ["characterize", "test"], "max":
|
|
25
|
+
{ "name": "write-run", "nodes": ["characterize", "test"], "max": 1 },
|
|
26
26
|
{ "name": "kill-mutants", "nodes": ["characterize", "test", "mutation-check"], "max": 3 }
|
|
27
27
|
],
|
|
28
28
|
"weights": { "new-file": 0.2 }
|
package/src/loops/refactor.json
CHANGED
|
@@ -18,7 +18,7 @@
|
|
|
18
18
|
],
|
|
19
19
|
"loops": [
|
|
20
20
|
{ "name": "iterations", "nodes": ["identify", "apply", "test"], "max": 20, "iteration": true },
|
|
21
|
-
{ "name": "apply-test", "nodes": ["apply", "test"], "max":
|
|
21
|
+
{ "name": "apply-test", "nodes": ["apply", "test"], "max": 1 }
|
|
22
22
|
],
|
|
23
23
|
"weights": { "logic": 0.6 }
|
|
24
24
|
}
|
|
@@ -22,7 +22,7 @@
|
|
|
22
22
|
],
|
|
23
23
|
"loops": [
|
|
24
24
|
{ "name": "iterations", "nodes": ["identify", "apply", "test", "review"], "max": 20, "iteration": true },
|
|
25
|
-
{ "name": "apply-test", "nodes": ["apply", "test"], "max":
|
|
25
|
+
{ "name": "apply-test", "nodes": ["apply", "test"], "max": 1 },
|
|
26
26
|
{ "name": "review-fix", "nodes": ["apply", "test", "review"], "max": 3 }
|
|
27
27
|
],
|
|
28
28
|
"weights": { "delete": 0.5 },
|
|
@@ -23,7 +23,7 @@
|
|
|
23
23
|
],
|
|
24
24
|
"loops": [
|
|
25
25
|
{ "name": "iterations", "nodes": ["identify", "apply", "test", "review", "done-check"], "max": 20, "iteration": true },
|
|
26
|
-
{ "name": "apply-test", "nodes": ["apply", "test"], "max":
|
|
26
|
+
{ "name": "apply-test", "nodes": ["apply", "test"], "max": 1 },
|
|
27
27
|
{ "name": "review-fix", "nodes": ["apply", "test", "review"], "max": 3 }
|
|
28
28
|
]
|
|
29
29
|
}
|
package/src/loops/tdd.json
CHANGED
|
@@ -19,7 +19,7 @@
|
|
|
19
19
|
],
|
|
20
20
|
"loops": [
|
|
21
21
|
{ "name": "iterations", "nodes": ["identify", "red-test", "apply", "test", "review"], "max": 20, "iteration": true },
|
|
22
|
-
{ "name": "apply-test", "nodes": ["apply", "test"], "max":
|
|
22
|
+
{ "name": "apply-test", "nodes": ["apply", "test"], "max": 1 },
|
|
23
23
|
{ "name": "review-fix", "nodes": ["apply", "test", "review"], "max": 3 }
|
|
24
24
|
]
|
|
25
25
|
}
|
|
@@ -23,7 +23,7 @@
|
|
|
23
23
|
],
|
|
24
24
|
"loops": [
|
|
25
25
|
{ "name": "iterations", "nodes": ["identify", "apply", "test", "compat-check", "review"], "max": 20, "iteration": true },
|
|
26
|
-
{ "name": "apply-test", "nodes": ["apply", "test"], "max":
|
|
26
|
+
{ "name": "apply-test", "nodes": ["apply", "test"], "max": 1 },
|
|
27
27
|
{ "name": "review-fix", "nodes": ["apply", "test", "compat-check", "review"], "max": 3 }
|
|
28
28
|
],
|
|
29
29
|
"contracts": [
|
|
@@ -5,34 +5,57 @@
|
|
|
5
5
|
**Trigger:** the project's docs are missing or have drifted from the code, or it needs a PRD, a design system, an architecture document or an AGENTS.md. Existing codebases only — every document is extracted from the code, never written ahead of it.
|
|
6
6
|
|
|
7
7
|
**Argument:** `[prd|design|architecture|agents|all]` — optional. It names the doc-set members to
|
|
8
|
-
write; with none, step
|
|
8
|
+
write; with none, step 5 proposes them.
|
|
9
9
|
|
|
10
10
|
## Procedure
|
|
11
11
|
1. **Find the doc home.** Look for an existing `docs/`, `doc/`, `documentation/`, or
|
|
12
12
|
`wiki/` folder at the project root, or a `context.json` pointer to one (the same
|
|
13
13
|
convention [repo-map {{SKILL}}](repo-map.md) and the context loader use). Reuse the one
|
|
14
14
|
that exists — never create a second. If none exists, create `docs/` at the root.
|
|
15
|
-
2. **
|
|
15
|
+
2. **Pick the docs format** — Markdown or AsciiDoc, once per project. A `Docs format:
|
|
16
|
+
markdown|asciidoc` line in the root `AGENTS.md` decides; never re-decide it. Otherwise
|
|
17
|
+
look at the project's existing docs (the doc home and the root `README`), ignoring the
|
|
18
|
+
agent-runtime files below: only `.md` → Markdown; only `.adoc` → AsciiDoc; both → ask
|
|
19
|
+
the user; no docs yet → AsciiDoc. Record the result as that line under *Non-obvious
|
|
20
|
+
conventions* in `AGENTS.md`.
|
|
21
|
+
- **Agent-runtime files stay Markdown whatever the format:** `AGENTS.md`, `CLAUDE.md`,
|
|
22
|
+
`SKILL.md`, and the specs and ADR files that loops read — the tools need them so.
|
|
23
|
+
- **In a Markdown project, propose — never impose — a switch to AsciiDoc** when the docs
|
|
24
|
+
would gain from it: complex tables, many diagrams, content reused across pages,
|
|
25
|
+
several versions, or PDF output. Say which need you saw, once; the user decides, and a
|
|
26
|
+
yes rewrites the recorded line.
|
|
27
|
+
- **In AsciiDoc,** apply *AsciiDoc mode* below wherever this skill shows Markdown.
|
|
28
|
+
3. **Interview first when the project has no docs yet** — before writing anything. The code
|
|
29
|
+
gives the *what*; only the user gives the *why*. Ask one question at a time, offering
|
|
30
|
+
options where you can: the audience and what they need to do — which also sets the C4
|
|
31
|
+
levels: L1 and L2 always, L3 only for the containers the user calls complex; the project's purpose;
|
|
32
|
+
goals and non-goals; the key decisions and the reason for each; constraints; what is out
|
|
33
|
+
of scope. Read any spec, ADRs or design notes that exist, for facts. When an answer
|
|
34
|
+
explains a decision, offer to record it as an ADR (in `architecture`'s *Decisions*) —
|
|
35
|
+
accept or skip. Draft only once the user says the interview is done. Skip this step on a
|
|
36
|
+
re-run or when docs exist: their prose already carries the intent.
|
|
37
|
+
4. **Survey the code, not the intent.** Map entry points, the public API / modules,
|
|
16
38
|
commands, config, and key directories — read the actual behaviour ({{LAW:verify-before-asserting}},
|
|
17
39
|
{{DOCTRINE:read-the-docs-first}}). If there is no `ARCHITECTURE.md`, run [repo-map {{SKILL}}](repo-map.md)
|
|
18
40
|
first so you have the orientation map to build on.
|
|
19
|
-
|
|
41
|
+
5. **Select the doc set.** Unless the argument names the targets, propose which of the four
|
|
20
42
|
documents apply and wait for the user's go-ahead — e.g. "no UI detected (no stylesheet,
|
|
21
43
|
theme, or component tree) — skipping `DESIGN.md`". `AGENTS.md`, `PRD.md` and
|
|
22
44
|
`architecture.md` apply to every project; `DESIGN.md` only when a UI exists.
|
|
23
45
|
`all` still skips `DESIGN.md` when no UI exists, and says so in one line.
|
|
24
|
-
|
|
46
|
+
6. **Write or refresh each selected document** from its template in *The doc set* below,
|
|
25
47
|
under the rules in *Re-runs*. **Invent nothing**: every claim cites `path:line`, or carries
|
|
26
48
|
the marker `⚠ to confirm` (in the user's language). When drafting is done, put every `⚠` to
|
|
27
49
|
the user as **one** batch of questions — not one at a time — and fold the answers in as plain
|
|
28
50
|
text. A command you could not run is recorded as `⚠ fails: <error>`, never as working.
|
|
29
|
-
Every document follows the three page conventions in step
|
|
30
|
-
|
|
51
|
+
Every document follows the three page conventions in step 7.
|
|
52
|
+
7. **Reconcile the docs (whole tree).** Check every existing page against the current
|
|
31
53
|
implementation — renamed or removed APIs, changed flags, dead examples — and fix the
|
|
32
54
|
drift. Add pages for significant undocumented surfaces; remove docs for features that no
|
|
33
55
|
longer exist ({{LAW:deletion-is-deliberate}}). For substantial writing, dispatch
|
|
34
56
|
the [docs {{AGENT}}](../{{DIR_AGENTS}}/docs.md). Keep examples runnable — run them.
|
|
35
|
-
Every generated page follows three conventions
|
|
57
|
+
Every generated page follows three conventions (in AsciiDoc mode, their *AsciiDoc mode*
|
|
58
|
+
forms):
|
|
36
59
|
- **Typed frontmatter.** Open each page with YAML frontmatter carrying `type:` (one of
|
|
37
60
|
`overview`, `module`, `api`, `flow`, `how-to`, `prd`, `design-system`, `architecture`),
|
|
38
61
|
`mirrors-commit: <sha>`, and `generated: <date>` — so drift is auditable per page, not only
|
|
@@ -43,15 +66,15 @@ write; with none, step 3 proposes them.
|
|
|
43
66
|
`<!-- geneseed:doc:start -->` and `<!-- geneseed:doc:end -->` markers — one pair per
|
|
44
67
|
section, so prose a reader adds between sections survives — and on re-runs rewrite *only*
|
|
45
68
|
inside them; hand-authored prose outside the markers is never touched.
|
|
46
|
-
- **Diagrams as Mermaid, keyed by purpose.** In the
|
|
69
|
+
- **Diagrams as Mermaid, keyed by purpose.** In the doc pages, render diagrams as fenced
|
|
47
70
|
`mermaid` code blocks — they render natively on GitHub, Obsidian, and VS Code with no
|
|
48
71
|
dependency. Pick the kind by what you are showing: sequence for runtime/request flows,
|
|
49
72
|
ER for data models, state for lifecycles, flowchart for control flow and C4 views. Reserve
|
|
50
|
-
hand-authored inline SVG for the offline HTML only (step
|
|
51
|
-
|
|
73
|
+
hand-authored inline SVG for the offline HTML only (step 9).
|
|
74
|
+
8. **Keep an index.** Ensure the doc home has an index/README linking every page, the doc-set
|
|
52
75
|
members included, current with the set you just reconciled.
|
|
53
|
-
|
|
54
|
-
|
|
76
|
+
9. **Regenerate the HTML** — self-contained files at the doc home, a visual parallel to the
|
|
77
|
+
doc pages and never a source of truth: regenerate them whole from the pages each run
|
|
55
78
|
({{DOCTRINE:edit-the-source-not-the-surface}}).
|
|
56
79
|
Overwrite the previous ones, but confirm each is the generated artifact before clobbering
|
|
57
80
|
({{LAW:verify-before-asserting}}, {{LAW:deletion-is-deliberate}}). Both files:
|
|
@@ -65,7 +88,7 @@ write; with none, step 3 proposes them.
|
|
|
65
88
|
**`overview.html`** (always) must:
|
|
66
89
|
- **Carry the digest** — hero (project name + one-line purpose), a quick-facts strip
|
|
67
90
|
(language, entry point, build/test/run, license), an architecture section (component
|
|
68
|
-
cards and an inline-SVG or CSS directory tree), and links out to the
|
|
91
|
+
cards and an inline-SVG or CSS directory tree), and links out to the doc pages for
|
|
69
92
|
depth.
|
|
70
93
|
- **Go deep on the hard parts** — identify the few subsystems that carry the project's
|
|
71
94
|
essential complexity (the core engine, the load-bearing algorithms, the non-obvious
|
|
@@ -83,7 +106,7 @@ write; with none, step 3 proposes them.
|
|
|
83
106
|
sizes and weights; spacing, radius and shadow on sample squares; components as cards
|
|
84
107
|
(variants, states, path) — no live rendering, which would need the project's framework; and
|
|
85
108
|
the hard-coded-value drift in a separate callout.
|
|
86
|
-
|
|
109
|
+
10. **Do not auto-publish.** Leave the changes for the user to review; stage and commit only
|
|
87
110
|
on consent, via the [commit {{SKILL}}](commit.md) ({{DOCTRINE:consent-before-push}}).
|
|
88
111
|
|
|
89
112
|
## The doc set
|
|
@@ -121,26 +144,67 @@ The detailed architecture. Open with a link to the root `ARCHITECTURE.md` (repo-
|
|
|
121
144
|
map) and make sure the map links back — one fenced `geneseed:doc` line at its top, nothing else
|
|
122
145
|
in that file touched; repeat nothing between the two.
|
|
123
146
|
1. **Context (C4 L1)** — the system, its actors, and the external systems (APIs, SSO, shared
|
|
124
|
-
databases)
|
|
147
|
+
databases).
|
|
125
148
|
2. **Containers (C4 L2)** — the deployable units and the protocols between them.
|
|
126
|
-
3. **Components (C4 L3)** —
|
|
127
|
-
|
|
149
|
+
3. **Components (C4 L3)** — only for the containers the user called complex in the interview
|
|
150
|
+
(on a re-run, the ones already drawn), one diagram each. On a monorepo, work one container
|
|
151
|
+
or package at a time. Never draw L4 (code) — the code is its own diagram.
|
|
128
152
|
4. **Decisions** — lightweight inline ADRs, `ADR-001`, …, four lines each: *context · decision ·
|
|
129
153
|
consequences · evidence*. Structural choices only (framework, storage, architectural style,
|
|
130
154
|
decomposition) — not details.
|
|
131
155
|
|
|
156
|
+
**C4 notation.** Every diagram is a Mermaid `flowchart` styled as C4 — not the `C4Context` /
|
|
157
|
+
`C4Container` diagram types, which Mermaid still marks experimental and lays out by hand. Each
|
|
158
|
+
node reads `name [type · technology]` (type: person, software system, container, component,
|
|
159
|
+
database), each edge `intent · protocol`, and each diagram carries a `title:` and a `Legend`
|
|
160
|
+
subgraph keying its shapes (c4model.com notation). Each diagram sits inside its section's
|
|
161
|
+
`geneseed:doc` fences, so a re-run redraws it there and nowhere else.
|
|
162
|
+
|
|
163
|
+
```mermaid
|
|
164
|
+
---
|
|
165
|
+
title: Containers (C4 L2) — shop
|
|
166
|
+
---
|
|
167
|
+
flowchart LR
|
|
168
|
+
user(["Customer [person]"]) -->|"browses · HTTPS"| web["web [container · React SPA]"]
|
|
169
|
+
web -->|"reads orders · HTTPS/JSON"| api["api [container · Node/Express]"]
|
|
170
|
+
api -->|"reads/writes · SQL"| db[("orders [database · PostgreSQL]")]
|
|
171
|
+
subgraph Legend
|
|
172
|
+
l1(["person"]) ~~~ l2["container"] ~~~ l3[("database")]
|
|
173
|
+
end
|
|
174
|
+
```
|
|
175
|
+
|
|
132
176
|
### `AGENTS.md` — repo root, at most ~60 lines
|
|
133
177
|
The short manual an agent reads before touching the repo.
|
|
134
178
|
1. **Commands** — build, test, lint, run: exact, and verified by running each one.
|
|
135
|
-
2. **Non-obvious conventions
|
|
179
|
+
2. **Non-obvious conventions** — first, the `Docs format:` line from step 2.
|
|
136
180
|
3. **Do not touch** — generated files, vendored code, applied migrations.
|
|
137
|
-
4. **Before you change…** — targeted pointers: a UI → `docs/DESIGN.md`; a
|
|
138
|
-
|
|
181
|
+
4. **Before you change…** — targeted pointers: a UI → `docs/DESIGN.md`; a change that crosses
|
|
182
|
+
containers → read the L2 diagram in `docs/architecture.md` first; a new flow or container →
|
|
183
|
+
`docs/architecture.md`; a feature → `docs/PRD.md` (its FR ID) — with the extension the docs
|
|
184
|
+
format gives them.
|
|
139
185
|
|
|
140
186
|
Geneseed may own a block in this file, between `<!-- BEGIN GENESEED -->` and
|
|
141
187
|
`<!-- END GENESEED -->` — never write inside it. Create the file if it is absent; if it holds
|
|
142
188
|
only that block, add the project sections below it.
|
|
143
189
|
|
|
190
|
+
## AsciiDoc mode
|
|
191
|
+
When step 2 picks AsciiDoc, every doc page this skill writes is AsciiDoc; `AGENTS.md` and
|
|
192
|
+
the other agent-runtime files stay Markdown.
|
|
193
|
+
- **Page names:** `.adoc` for every page — `PRD.adoc`, `DESIGN.adoc`, `architecture.adoc`,
|
|
194
|
+
`index.adoc`. A `README.adoc` is fine: GitHub shows it as the repo homepage.
|
|
195
|
+
- **Typed header, not frontmatter:** the page title (`= Title`) followed by attributes —
|
|
196
|
+
`:geneseed-type: prd`, `:geneseed-mirrors-commit: <sha>`, `:geneseed-generated: <date>`.
|
|
197
|
+
`index.adoc` carries none.
|
|
198
|
+
- **Fences:** `// geneseed:doc:start` and `// geneseed:doc:end` comment lines, one pair per
|
|
199
|
+
section, with the same rewrite-only-inside rule.
|
|
200
|
+
- **Diagrams:** Mermaid in a `[source,mermaid]` listing block delimited by `----` — GitHub
|
|
201
|
+
renders it like a Markdown `mermaid` fence; the C4 notation is unchanged. Not `[mermaid]` blocks (asciidoctor-diagram)
|
|
202
|
+
and no STEM: GitHub renders neither.
|
|
203
|
+
- **No `include::`** in a generated page — GitHub does not resolve it, and an agent reading
|
|
204
|
+
the raw file would see the directive instead of the content. Each page reads whole on its
|
|
205
|
+
own, and no Markdown copy is kept beside it: two sources drift.
|
|
206
|
+
- **Tables** use `|===` blocks; the FR/NFR columns are unchanged.
|
|
207
|
+
|
|
144
208
|
## Re-runs
|
|
145
209
|
- **Reader prose is sacred.** Rewrite only inside a section's `geneseed:doc` fences. A
|
|
146
210
|
document that already exists **without** fences (a hand-written `PRD.md`, say) is never
|
|
@@ -159,12 +223,17 @@ only that block, add the project sections below it.
|
|
|
159
223
|
## Done when
|
|
160
224
|
- Every selected doc-set member exists, follows its template, and cites its evidence or
|
|
161
225
|
carries `⚠`; the batch of `⚠` questions has been put to the user.
|
|
162
|
-
- The doc home mirrors the current implementation: every
|
|
163
|
-
|
|
226
|
+
- The doc home mirrors the current implementation: every page carries typed frontmatter
|
|
227
|
+
(header attributes in AsciiDoc mode), wraps its generated sections in `geneseed:doc` markers, and is verified against
|
|
164
228
|
the code or flagged; examples run, Mermaid fences are well-formed, and the index links
|
|
165
229
|
them all.
|
|
166
230
|
- `overview.html` opens offline and shows the digest, the complex-core deep-dives, and the
|
|
167
231
|
doc set; `design.html` does too wherever `DESIGN.md` exists; and any surface left
|
|
168
232
|
undocumented is named explicitly.
|
|
233
|
+
- `AGENTS.md` records the `Docs format:` line.
|
|
234
|
+
- In AsciiDoc mode, every page written passes `asciidoctor --failure-level=WARN -o - <page>`
|
|
235
|
+
(output discarded) when `asciidoctor` is on PATH. Without it, the report says
|
|
236
|
+
`asciidoctor lint: SKIPPED — not installed` — never silently passed over, never installed
|
|
237
|
+
for the user.
|
|
169
238
|
|
|
170
239
|
<!-- INCLUDE: skills/_self-improvement.md -->
|