geneseed 4.0.0 → 4.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.
Files changed (63) hide show
  1. package/CHANGELOG.md +36 -0
  2. package/SHIPPED.md +1 -1
  3. package/adapters/opencode/HOW-OPENCODE-LOADS.md +35 -0
  4. package/adapters/opencode/plugins/geneseed-activity.js +105 -2
  5. package/adapters/opencode/plugins/geneseed-context.js +96 -1
  6. package/adapters/opencode/plugins/geneseed-guard.js +33 -1
  7. package/adapters/opencode/plugins/geneseed-learn.js +127 -14
  8. package/adapters/opencode/plugins/geneseed-notify.js +46 -1
  9. package/adapters/opencode/plugins/geneseed-ponytail.js +44 -2
  10. package/adapters/opencode/plugins/geneseed-workflow.js +124 -24
  11. package/docs/guides/mcp-filesystem.md +2 -2
  12. package/docs/guides/mcp-gitlab.md +2 -2
  13. package/docs/guides/mcp-markitdown.md +3 -3
  14. package/docs/guides/mcp.md +7 -7
  15. package/docs/guides/project-context.md +1 -1
  16. package/docs/reference/opencode-plugins.md +9 -0
  17. package/harness.config.json +1 -1
  18. package/js/cli-table.json +1 -1
  19. package/js/hosts/mcp.mjs +23 -152
  20. package/js/hosts/opencode.mjs +1 -1
  21. package/js/web/actions.mjs +15 -77
  22. package/js/web/api.mjs +8 -1
  23. package/js/web/handler.mjs +2 -2
  24. package/js/web/routes.mjs +1 -2
  25. package/package.json +1 -1
  26. package/src/agents/_template.md +2 -1
  27. package/src/agents/researcher.md +2 -1
  28. package/src/agents/reviewer.md +9 -4
  29. package/src/agents/tester.md +3 -3
  30. package/src/doctrines/rigor.md +8 -7
  31. package/src/skills/brainstorm/builder-check.md +16 -0
  32. package/src/skills/brainstorm.md +19 -11
  33. package/src/skills/daydream/SKILL.md +1 -1
  34. package/src/skills/daydream/VENDOR.md +4 -0
  35. package/src/skills/debug/ci.md +4 -4
  36. package/src/skills/debug.md +4 -4
  37. package/src/skills/develop.md +6 -4
  38. package/src/skills/fresh-eyes.md +1 -1
  39. package/src/skills/geneseed-code-review.md +8 -2
  40. package/src/skills/handoff.md +1 -1
  41. package/src/skills/parallel-agents.md +4 -4
  42. package/src/skills/pipeline.md +3 -3
  43. package/src/skills/plan.md +18 -6
  44. package/src/skills/review-response.md +5 -2
  45. package/src/skills/ship.md +2 -1
  46. package/src/skills/worktree.md +2 -0
  47. package/web/dist/assets/{Activity-BCtqxjfy.js → Activity-CqVt2u9s.js} +1 -1
  48. package/web/dist/assets/{ActivityDetail-Ba3Oo4dE.js → ActivityDetail-Bui5Gomc.js} +1 -1
  49. package/web/dist/assets/{Dashboard-DpHza68-.js → Dashboard-VlIx1-At.js} +2 -2
  50. package/web/dist/assets/{Docs-Bw_-UK0O.js → Docs-6cYYkVeA.js} +1 -1
  51. package/web/dist/assets/{GreenhouseView-DnJ1Ggp1.js → GreenhouseView-DgNY8QKU.js} +1 -1
  52. package/web/dist/assets/{Installs-CWoNKFBk.js → Installs-DZwZOUZJ.js} +1 -1
  53. package/web/dist/assets/{JournalView-g6-bw4c8.js → JournalView-DXpFbKOG.js} +1 -1
  54. package/web/dist/assets/{Laws-DkVWR1tb.js → Laws-Bh7ztekk.js} +1 -1
  55. package/web/dist/assets/{Library-CK9HZzjV.js → Library-DBLX-1SD.js} +1 -1
  56. package/web/dist/assets/{Loops-BP98SMOH.js → Loops-CvFMZ7_P.js} +1 -1
  57. package/web/dist/assets/{OperatorHudView-DI_n12M9.js → OperatorHudView-FPTUH1CB.js} +1 -1
  58. package/web/dist/assets/{Personal-Bk89f13a.js → Personal-DcVA502F.js} +1 -1
  59. package/web/dist/assets/{Tabs-3WuYIE1b.js → Tabs-DtyR4h75.js} +1 -1
  60. package/web/dist/assets/{api-CxgfYu18.js → api-CRqWld2H.js} +1 -1
  61. package/web/dist/assets/{drawable-oCUeq9e5.js → drawable-CNSPVZxX.js} +1 -1
  62. package/web/dist/assets/{index-CiXwChvf.js → index-BmjcLIOr.js} +2 -2
  63. package/web/dist/index.html +2 -2
@@ -42,7 +42,7 @@ import { setupBuildArgs } from '../build/generate.mjs';
42
42
  import { DEFAULT_PRESET, PRESETS } from '../loop/score.mjs';
43
43
  import { activeLoops, setLoopPreset } from '../loop/registry.mjs';
44
44
  import {
45
- CLAUDE_STYLE, HOSTS, bobConfigDir, claudeConfigDir, expanduser, openclaudeConfigDir,
45
+ HOSTS, bobConfigDir, claudeConfigDir, expanduser, openclaudeConfigDir,
46
46
  opencodeConfigDir, resolvePath,
47
47
  } from '../hosts/hosts.mjs';
48
48
  import {
@@ -50,11 +50,10 @@ import {
50
50
  installState, installTargets, legacyProcessCarrierOfDir, modeOfDir, postureOfDir, trustOfDir,
51
51
  } from '../hosts/installs.mjs';
52
52
  import {
53
- MCP_PRESETS, isDict, mcpApply, mcpCommented, mcpInstallTargets, mcpKnownNames, mcpLoad,
54
- mcpMeta, mcpPresetBlock, mcpSave, mcpSetEnabled, mcpState,
53
+ isDict, mcpCommented, mcpInstallTargets, mcpLoad, mcpServerNames, mcpState,
55
54
  } from '../hosts/mcp.mjs';
56
- import { readText, isFile, isDir } from '../lib/fs.mjs';
57
- import { parseJson, formatRepr, formatValue, isTruthy } from '../lib/json.mjs';
55
+ import { isFile, isDir } from '../lib/fs.mjs';
56
+ import { formatRepr, formatValue, isTruthy } from '../lib/json.mjs';
58
57
  import { NO_WINDOW } from '../lib/proc.mjs';
59
58
  import { normcase, which, within } from '../lib/paths.mjs';
60
59
  import { stripWhitespace } from '../lib/text.mjs';
@@ -348,18 +347,20 @@ export function apiLoopsPresetMutate(state, body) {
348
347
 
349
348
  // ---- MCP ----------------------------------------------------------------------------------
350
349
 
350
+ /**
351
+ * The MCP servers each active install ALREADY has, and nothing it could have. Read-only by
352
+ * decision (2026-10): which servers to wire depends on the user and on the host, so the console
353
+ * shows what is in each config and where that file lives, and the user edits it. There is no
354
+ * preset to add and no toggle, so nothing here ever rewrites a config — including
355
+ * `~/.claude.json`, which holds far more than MCP wiring.
356
+ */
351
357
  export function apiMcp() {
352
358
  const out = [];
353
359
  for (const [label, p, host, scope, root] of mcpInstallTargets()) {
354
360
  if (installState(root, host, scope) !== 'active') continue;
355
361
  const cfg = mcpLoad(p, host);
356
- const servers = [];
357
- for (const name of mcpKnownNames(cfg, host)) {
358
- const [lbl, desc] = mcpMeta(name);
359
- servers.push({ name, label: lbl, desc,
360
- preset: Object.hasOwn(MCP_PRESETS, name),
361
- state: mcpState(cfg, name, host) });
362
- }
362
+ const servers = mcpServerNames(cfg, host)
363
+ .map((name) => ({ name, state: mcpState(cfg, name, host) }));
363
364
  out.push({ label, path: p, host, root, exists: isFile(p),
364
365
  commented: mcpCommented(p), servers });
365
366
  }
@@ -370,10 +371,8 @@ export function apiMcp() {
370
371
  /**
371
372
  * The MCP config paths a request body is allowed to name, as `path -> [path, host]`.
372
373
  *
373
- * LIFTED OUT OF `apiMcpToggle` BECAUSE IT NOW HAS A SECOND CALLER, not for tidiness. `/api/reveal`
374
- * hands a path to the desktop's file manager, and the allowlist is the whole security of that
375
- * endpoint exactly as it is of the toggle: an unlisted path must 404 before anything is opened.
376
- * Two copies of a security check drift, and the copy that drifts is the one nobody re-read.
374
+ * `/api/reveal` hands a path to the desktop's file manager, and this allowlist is the whole
375
+ * security of that endpoint: an unlisted path must 404 before anything is opened.
377
376
  *
378
377
  * It is rebuilt per call rather than cached: installs come and go while the daemon runs, and a
379
378
  * stale allowlist is wrong in both directions — refusing a real target, or naming a dead one.
@@ -386,67 +385,6 @@ export function mcpTargetPaths() {
386
385
  return known;
387
386
  }
388
387
 
389
- /**
390
- * Enable / disable / first-add one server.
391
- *
392
- * THE PATH COMES OUT OF THE REQUEST BODY, so the allowlist is the whole security of this
393
- * endpoint: `known` is built from the detected install targets and an unlisted path is a 404
394
- * before anything is read or written. Without it this is "write arbitrary JSON to an
395
- * arbitrary file", behind a CSRF token and nothing else.
396
- *
397
- * The Claude-shaped hosts are parsed ONCE, STRICTLY, and that exact object is what gets
398
- * rewritten — so the safety check and the value saved come from the same read, with no
399
- * time-of-check/time-of-use gap and no comment-stripper touching a string that contains
400
- * `,]`. A file that will not parse is refused rather than clobbered: it may be
401
- * `~/.claude.json`, which holds projects and history far beyond MCP wiring.
402
- */
403
- export function apiMcpToggle(state, body) {
404
- const name = strOr(bget(body, 'name'));
405
- const want = isTruthy(bget(body, 'enabled'));
406
- const pathArg = strOr(bget(body, 'path'));
407
- const known = mcpTargetPaths();
408
- const hit = known.get(pathArg);
409
- if (hit === undefined || !name) {
410
- throw new NotFound(`mcp target ${pathArg || '(none)'}`);
411
- }
412
- const [p, host] = hit;
413
- if (mcpCommented(p)) {
414
- return { ok: false, error: 'config holds comments — edit it by hand to keep them' };
415
- }
416
- let cfg;
417
- if (CLAUDE_STYLE.includes(host)) {
418
- if (isFile(p)) {
419
- let parsed;
420
- try {
421
- parsed = parseJson(readText(p));
422
- } catch {
423
- parsed = null;
424
- }
425
- if (!isDict(parsed)) {
426
- return { ok: false,
427
- error: "couldn't parse this config — edit it by hand to avoid data loss" };
428
- }
429
- cfg = parsed;
430
- } else {
431
- cfg = {};
432
- }
433
- } else {
434
- cfg = mcpLoad(p);
435
- }
436
- if (mcpState(cfg, name, host) === 'absent') {
437
- if (!Object.hasOwn(MCP_PRESETS, name)) {
438
- return { ok: false, error: `unknown server '${name}'` };
439
- }
440
- if (!want) return { ok: false, error: `'${name}' is not configured` };
441
- cfg = mcpApply(cfg, name, mcpPresetBlock(name, host), host);
442
- cfg = mcpSetEnabled(cfg, name, true, host);
443
- } else {
444
- cfg = mcpSetEnabled(cfg, name, want, host);
445
- }
446
- mcpSave(p, cfg);
447
- return { ok: true, name, state: mcpState(cfg, name, host) };
448
- }
449
-
450
388
  // ---- the harness selector ------------------------------------------------------------------
451
389
 
452
390
  /**
package/js/web/api.mjs CHANGED
@@ -113,11 +113,18 @@ export function viewCfg(host, scope, root) {
113
113
  return root;
114
114
  }
115
115
 
116
+ /**
117
+ * The row `id` carries the ROOT, not only `host:scope`: two project installs of one host (two
118
+ * repos on Bob, say) are both `bob:project`, and the console keys its selection, its React rows
119
+ * and its per-install picks on this id — with a shared one, both rows read as selected and every
120
+ * pick resolved to whichever came first. `installTargets()` de-duplicates on (host, root), so
121
+ * this is unique by construction.
122
+ */
116
123
  export function apiInstalls(state) {
117
124
  const out = [];
118
125
  for (const [host, scope, root] of installTargets()) {
119
126
  out.push({
120
- id: `${host}:${scope}`, host, scope, path: root,
127
+ id: `${host}:${scope}:${root}`, host, scope, path: root,
121
128
  state: installState(root, host, scope),
122
129
  // Narrowed to this row's own host (host-compat B1): a shared repo otherwise answers
123
130
  // every row with whichever host's carrier the host-agnostic scan favours.
@@ -371,8 +371,8 @@ export function makeHandler(state, jm, token, dist, holder = null) {
371
371
  try {
372
372
  return doPost(req, res, path, ae, buf);
373
373
  } catch (e) {
374
- // `apiMcpToggle`, `apiSelectView`, `apiMemoryDelete`, `apiRulesMutate` and
375
- // `apiRulesPromote` all raise `NotFound` for an unknown target, mapped to 404
374
+ // `apiSelectView`, `apiMemoryDelete`, `apiRulesMutate` and `apiRulesPromote` all
375
+ // raise `NotFound` for an unknown target, mapped to 404
376
376
  // here; anything else falls to the 500 arm below, carrying its own message.
377
377
  if (e instanceof NotFound) {
378
378
  return sendJson(res, { error: `not found: ${e.message}` }, 404, ae);
package/js/web/routes.mjs CHANGED
@@ -18,7 +18,7 @@
18
18
  */
19
19
  import { formatValue, isTruthy, parseJson } from '../lib/json.mjs';
20
20
  import { percentDecode } from '../lib/text.mjs';
21
- import { apiExcludesMutate, apiInstallToggle, apiLoopsPresetMutate, apiMcp, apiMcpToggle, apiMemoryDelete, apiSelectView } from './actions.mjs';
21
+ import { apiExcludesMutate, apiInstallToggle, apiLoopsPresetMutate, apiMcp, apiMemoryDelete, apiSelectView } from './actions.mjs';
22
22
  import { apiActivity, apiActivityDetail, apiActivityToggle } from './activity.mjs';
23
23
  import {
24
24
  apiDiff, apiDoctor, apiExcludes, apiInstalls, apiLoops, apiLoopsActive, apiOverview,
@@ -43,7 +43,6 @@ import { apiProfile, apiProfileSave, apiRules, apiRulesMutate, apiRulesPromote }
43
43
  */
44
44
  /** @type {Map<string, [(state: any, body: any) => any, boolean]>} */
45
45
  export const POST_ROUTES = new Map([
46
- ['/api/mcp', [apiMcpToggle, true]],
47
46
  ['/api/install', [apiInstallToggle, true]],
48
47
  ['/api/excludes', [apiExcludesMutate, true]],
49
48
  ['/api/view', [apiSelectView, true]],
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": "4.0.0",
4
+ "version": "4.1.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",
@@ -28,7 +28,8 @@
28
28
  ## Inputs
29
29
  - What the caller must provide (files, diff, scope, acceptance criteria).
30
30
  - Dispatches arrive as an envelope: goal, inputs, output contract, inherited
31
- constraints (never commit/push; report gaps instead of inventing). When an
31
+ constraints (never commit/push; dispatch no sub-agents — review comes from the caller;
32
+ report gaps instead of inventing). When an
32
33
  envelope arrives incomplete, hold the caller to it via `spec-feedback:`.
33
34
 
34
35
  ## Allowed tools
@@ -21,7 +21,8 @@
21
21
  - The question, what a complete answer must contain, and any source the caller
22
22
  already trusts or distrusts.
23
23
  - Dispatches arrive as an envelope: goal, inputs, output contract, inherited
24
- constraints (never commit/push; report gaps instead of inventing). When an
24
+ constraints (never commit/push; dispatch no sub-agents — review comes from the caller;
25
+ report gaps instead of inventing). When an
25
26
  envelope arrives incomplete, hold the caller to it via `spec-feedback:`.
26
27
 
27
28
  ## Allowed tools
@@ -11,16 +11,19 @@
11
11
  - Pure design questions — use [architect](architect.md).
12
12
 
13
13
  ## Inputs
14
- - The diff or list of changed files, and the task the change was meant to satisfy.
14
+ - The base..head range (or the diff), and the task the change was meant to satisfy.
15
15
 
16
16
  ## Allowed tools
17
17
  - **Read-only.** May read code, run the test suite and linters, inspect history.
18
- - Does not edit code; it reports.
18
+ - Does not edit code; it reports. Never moves HEAD, the index or the working tree — to see
19
+ another revision, use `git show` or a separate worktree. Never dispatches another reviewer.
19
20
  <!-- bash: allow -->
20
21
 
21
22
  ## Procedure
22
23
  0. If `{{DIR_MEMORY}}/agents/<your-name>.md` exists, read it first — your durable lessons from prior dispatches ({{DOCTRINE:persist-insight}}).
23
- 1. Confirm the change actually does what the task required (read the spec/issue).
24
+ 1. Confirm the change actually does what the task required (read the spec/issue). Where
25
+ the spec is silent, judge by what a reasonable user would expect: a crash, hang or data
26
+ loss on an input the spec implies but never names is blocking, not a nitpick.
24
27
  Then read, for each changed file, the nearest `REVIEW.md` above it — a deeper one
25
28
  overrides a shallower one, and they override this procedure and the output contract,
26
29
  never a {{LAW}}.
@@ -31,7 +34,9 @@
31
34
  ## Output contract
32
35
  - A list of findings, each a Conventional Comment, `label (decoration): file:line — problem
33
36
  — suggested fix`, ordered correctness-first. Labels: issue, suggestion, question, todo,
34
- nitpick, thought, note, praise; decorations: blocking, non-blocking, if-minor. End with a
37
+ nitpick, thought, note, praise; decorations: blocking, non-blocking, if-minor. Then a
38
+ **Set aside:** list — each behaviour considered and left out of scope, one line with the
39
+ reason, or `none` — for the caller to rule on. End with a
35
40
  one-line verdict that follows from the decorations: any blocking → block, any if-minor
36
41
  and nothing blocking → fix-then-ship, otherwise ship.
37
42
  - If a check was impossible — no diff, no task statement, a suite that will not
@@ -42,11 +42,11 @@ to recruit; it changes nothing about how this {{AGENT}} behaves when dispatched
42
42
  independently.)*
43
43
 
44
44
  - **Seat(s):** tester — the development floor's validator, the other half of
45
- the dev↔tester loop (capped at 5 iterations).
45
+ the dev↔tester loop (two repairs, then one fresh developer).
46
46
  - **Receives:** the developer's changed worktree.
47
47
  - **Delivers:** raw test + lint output with exit codes — the mechanical proof.
48
- On failure, findings go back to the developer seat; on the 5th failure, the
49
- pipeline stops and reports instead of looping again.
48
+ On failure, findings go back to the developer seat; when the fresh
49
+ developer fails too, the pipeline stops and reports instead of looping again.
50
50
 
51
51
  ## Self-improvement
52
52
 
@@ -44,7 +44,8 @@ Code you author is not done until its behaviour is covered by a test you wrote
44
44
  and the affected tests run green. New behaviour ships with the test that pins it,
45
45
  a bug fix with the test that reproduces it first (the develop {{SKILL}} drives this).
46
46
  After each change run the tests that change could affect — the ones you touched,
47
- not the whole suite ({{DOCTRINE:context-economy}}) — and read the output before moving on.
47
+ not the whole suite ({{DOCTRINE:context-economy}}) — and read the output before moving on;
48
+ once at the end, run the whole suite and name every failure, even one you did not cause.
48
49
  Verify against the project's real runner and show the result as evidence ({{LAW:verify-before-asserting}});
49
50
  assert on observable behaviour, deterministically ({{DOCTRINE:honest-tests}}). Where the
50
51
  project has no suite or the change is genuinely untestable — a doc, a constant, a
@@ -52,12 +53,12 @@ config — say so rather than invent a test; where a real test is out of scope,
52
53
  the gap and stop rather than ship untested behaviour in silence ({{LAW:one-intent-one-act}},
53
54
  {{LAW:cure-the-cause}}).
54
55
  <!-- LEAN:else -->
55
- Code is not done until its behaviour is covered by a test you wrote and the affected tests
56
- run green. New behaviour ships with its test, a bug fix with the reproducing test first
57
- (run the develop {{SKILL}}). Run them on the real runner, read the output, show it as
58
- evidence ({{LAW:verify-before-asserting}}). Where the change is untestable, say so and name the gap rather than
59
- invent a test; where a real test is out of scope, stop rather than ship untested behaviour in
60
- silence ({{LAW:one-intent-one-act}}, {{LAW:cure-the-cause}}).
56
+ Code is done when a test you wrote covers its behaviour and the affected tests run green.
57
+ New behaviour ships with its test, a bug fix with the reproducing test first (run the
58
+ develop {{SKILL}}). Run them on the real runner, the whole suite once at the end, and show
59
+ the output, every failure named ({{LAW:verify-before-asserting}}). Untestable: name the gap,
60
+ never invent a test; a real test out of scope: stop rather than ship untested behaviour
61
+ silently ({{LAW:one-intent-one-act}}, {{LAW:cure-the-cause}}).
61
62
  <!-- LEAN:end -->
62
63
 
63
64
  ### {{DOCTRINE:prove-the-gate}} Prove the Gate
@@ -0,0 +1,16 @@
1
+ # {{SKILL}}: brainstorm — builder check
2
+
3
+ The spec's author cannot read it cold: a re-read inherits the framing that wrote it. So a
4
+ fresh reader does.
5
+
6
+ 1. **Dispatch one fresh subagent** — never resume one; isolation and the no-subagent
7
+ fallback are as in [fresh-eyes](../fresh-eyes.md) step 3. Brief it with the spec file
8
+ alone: *"You are a capable builder in this domain who must plan the work from this
9
+ document and cannot reach its author. List, most important first, the questions where a
10
+ wrong guess would cost real rework. Skip what a builder may rightly decide."*
11
+ 2. **Sort its questions into three piles.** *Answered* — the answer exists (the code, the
12
+ chat, the docs): write it into the spec. *Minor* — settle it yourself and mark it
13
+ **your call** in the ledger ({{DOCTRINE:declare-the-judgment-calls}}). *Theirs* — only the
14
+ user can decide: ask ONE numbered round, most important first, then update the spec.
15
+ 3. **One round only.** Do not re-run the check on the updated spec; what is still open
16
+ after the user's answers stays in the ledger as open.
@@ -15,12 +15,15 @@ the design is skipped.
15
15
  several goals or systems, separate them and take one at a time.
16
16
  2. **Interpret charitably, then interview.** Read the request in its strongest
17
17
  reasonable form — do not manufacture ambiguity from a fair ask. If goal, scope and
18
- success criteria are already unambiguous, restate them in one line and go to step
19
- 4. Otherwise ask ONE numbered round of every question answerable now, each with your
20
- recommended answer so "yes" accepts it; dependent questions wait a round. Drive at
21
- *why* (the outcome wanted), *scope* (in and out) and *done* (how success is judged) —
22
- not *how* yet. Stop when each is unambiguous. Facts are yours to find (read the code,
23
- dispatch a subagent), never the user's. A decision someone else owns gets a drafted
18
+ success criteria are already unambiguous, restate them in one line (naming any
19
+ platform or language choice) and go to step 4. Otherwise ask ONE numbered round of
20
+ every question answerable now, each with your recommended answer so "yes" accepts it;
21
+ dependent questions wait a round. Drive at *why* (the outcome wanted), *scope* (in and
22
+ out), *done* (how success is judged) and which build choices (platform, language, key
23
+ libraries) the user wants to own. Existing work decides by default
24
+ ({{DOCTRINE:respect-conventions}}); a choice you take goes in the ledger as **your
25
+ call**, never as agreed. Stop when each is unambiguous. Facts are yours to find (read
26
+ the code, dispatch a subagent), never the user's. A decision someone else owns gets a drafted
24
27
  `questionnaire-<slug>.md` for them — ask the user only who and what they need back.
25
28
  3. **Ledger the decisions.** Name every KEY DECISION the answers imply or leave open —
26
29
  direction chosen, trade-offs accepted, load-bearing constraints, assumptions,
@@ -28,15 +31,18 @@ the design is skipped.
28
31
  fact. Read the ledger back as a numbered list and get an EXPLICIT confirmation
29
32
  ({{LAW:echo-the-intent}} — an inferred intent is not ground truth until echoed and agreed);
30
33
  scope the read-back to what is consequential, irreversible or genuinely uncertain.
31
- 4. **Design — only when there is something to design.** Propose 2–3 approaches with
34
+ 4. **Size it, then design.** Say the size; the user may override. *Quick* — exit and do
35
+ it, no spec. *Small* — the confirmed ledger in chat is the spec; go to step 6.
36
+ *Project* — design, spec file, builder check. If it grows mid-work, stop and step up.
37
+ Design only when there is something to design: propose 2–3 approaches with
32
38
  trade-offs, leading with your recommendation. Present the chosen design in
33
39
  sections (purpose → components → data flow → failure modes → testing), getting an
34
40
  explicit "looks right" after each; cut anything YAGNI. For a non-design ask, skip
35
41
  this step.
36
42
  5. **Write the spec.** One file the next session can find — `SPEC.md` beside the work,
37
43
  or the project's own spec home (e.g. `docs/specs/`): the goal in one line, the
38
- confirmed decision ledger, then the design (when there is one). Re-read it cold for
39
- ambiguity and fix what a stranger could misread.
44
+ confirmed decision ledger, then the design (when there is one). Then run the builder
45
+ check: read [brainstorm/builder-check.md](brainstorm/builder-check.md) and follow it.
40
46
  6. **Exit — route, don't build.** Hand the spec to the {{SKILL}} the work now needs:
41
47
  [plan](plan.md) for a multi-step build whose route is known (sliced if too big for a
42
48
  session), [wayfinder](wayfinder.md) only when the route itself is still in the fog,
@@ -44,7 +50,9 @@ the design is skipped.
44
50
 
45
51
  ## Done when
46
52
  - A confirmed, ambiguity-free goal with its ratified decision ledger — and, where
47
- the ask was a design, an approved design — sits in one spec file, and the work has
48
- been handed to the next {{SKILL}} with no code written beforehand.
53
+ the ask was a design, an approved design that passed the builder check — sits in one
54
+ spec file (or, for a small change, in the confirmed chat ledger), and the work has
55
+ been handed to the next {{SKILL}} with no code written beforehand — or, sized quick,
56
+ the brainstorm was exited to do the work.
49
57
 
50
58
  <!-- INCLUDE: skills/_self-improvement.md -->
@@ -79,4 +79,4 @@ No external dependencies -- pure Claude Code tools (Glob, Read, Write, Bash, Tas
79
79
 
80
80
  ## Cost
81
81
 
82
- Per run (~50 pairs): approximately $0.40-0.50 via Claude Code usage.
82
+ Per run (~50 pairs): approximately 0.40-0.50 USD via Claude Code usage.
@@ -37,3 +37,7 @@ bump the commit above.
37
37
  `SKILL.md`'s frontmatter also carries `disable-model-invocation: true`, which upstream lacks: the
38
38
  skill is user-only (`/daydream`), so its description stays out of the model's always-on catalogue —
39
39
  it is personal to one vault. Re-apply it on update.
40
+
41
+ The cost line in `SKILL.md` reads "0.40-0.50 USD" where upstream writes a dollar sign before the
42
+ number: Claude Code substitutes a dollar sign followed by a digit with the skill's arguments, so
43
+ upstream's text renders mangled. Re-apply it on update.
@@ -1,10 +1,10 @@
1
1
  # {{SKILL}}: debug — CI branch, a red run
2
2
 
3
3
  Needs the CI log: the host's CI tool, `gh run view --log-failed` or equivalent, or the log pasted by the user.
4
- 1. **Read the log, not the badge.** Find the first failing job and its first failing step. Read the error and the command that produced it in full ({{LAW:verify-before-asserting}}); note the runner's OS, toolchain versions and exact invocation.
5
- 2. **Classify before touching anything:** a *real failure* (code or test wrong), an *environment difference* (a version, path, line endings, missing binary, a test skipped locally but not in CI), an *infra flake* (network, runner, cache, timeout), or a *gate on the report itself* (a coverage or count threshold, a lint the local hook skips).
6
- 3. **Reproduce under CI's own conditions** — the workflow's script, flags and a matching toolchain. Green locally and red in CI has not reproduced yet: close the gap (the env var, `--frozen-lockfile`, the reporter, the binary not on PATH) until it fails the same way. Never retry a run blindly.
7
- 4. **Fix at the cause** through steps 2–6 of the debug procedure. For an environment difference, make the *repo* deterministic (pin, normalise, declare) rather than CI more permissive. A flake is fixed at its source — the race, the timeout, the unpinned resource — or quarantined *with an issue and an owner*, never silently skipped ({{LAW:cure-the-cause}}). A fix to CI config itself is its own commit ({{LAW:one-intent-one-act}}), noted in the PR.
4
+ 1. **Read the log, not the badge.** Measure a log before reading it and grep a large one rather than loading it whole ({{DOCTRINE:context-economy}}). Find the first failing job and its first failing step. Read the error and the command that produced it in full ({{LAW:verify-before-asserting}}); note the runner's OS, toolchain versions and exact invocation.
5
+ 2. **Classify before touching anything.** First diff against the last green run: commit range, lockfile, runner image, toolchain. Then name the class: a *real failure* (code or test wrong), an *environment difference* (a version, path, line endings, missing binary, a test skipped locally but not in CI), an *infra flake* (network, runner, cache, timeout), or a *gate on the report itself* (a coverage or count threshold, a lint the local hook skips).
6
+ 3. **Reproduce under CI's own conditions** — the workflow's script, flags and a matching toolchain. Green locally and red in CI has not reproduced yet: close the gap (the env var, `--frozen-lockfile`, the reporter, the binary not on PATH) until it fails the same way. Never retry a run blindly. CI logs are shared: probe a secret's presence, never its value (`[ -n "$TOKEN" ] && echo set || echo unset`).
7
+ 4. **Fix at the cause** through steps 2–6 of the debug procedure. For an environment difference, make the *repo* deterministic (pin, normalise, declare) rather than CI more permissive. A flake is fixed at its source — the race, the timeout, the unpinned resource — or quarantined *with an issue and an owner*, never silently skipped ({{LAW:cure-the-cause}}). A sleep that guesses at timing becomes a wait on the actual condition with a bounded timeout; a fixed delay that remains says why ({{DOCTRINE:honest-tests}}). A fix to CI config itself is its own commit ({{LAW:one-intent-one-act}}), noted in the PR.
8
8
  5. **Prove it the way CI will:** run CI's command locally once more and read the output, push with the user's per-push consent ({{DOCTRINE:consent-before-push}}), and watch the re-run to green; the gate that reported it verifies the fix. Report what failed, its class, what changed, and the green run.
9
9
 
10
10
  ## Done when
@@ -13,13 +13,13 @@ faster than thrashing; do not trade it away under pressure.
13
13
 
14
14
  ## Procedure
15
15
  1. **Build one command that goes red on *this* bug** before reading code for a theory. It asserts the user's exact symptom (not "didn't crash"), gives the same verdict every run, takes seconds and runs unattended; run it and show the output. Read the error and stack trace in full. For a flaky bug, raise the reproduction rate until it is debuggable. If you cannot build it, say so, list what you tried and ask for access or a captured artifact — no command, no hypothesis. Read `GLOSSARY.md` (or `CONTEXT.md`) and the ADRs in the area for the domain's vocabulary.
16
- 2. **Minimise, then isolate.** Cut inputs and steps one at a time until every remaining element is load-bearing. Then binary-search the cause — the code path, or for a regression the commit range with `git bisect` (the [git-history {{SKILL}}](git-history.md) carries the method). Change one variable at a time. In a multi-layer system (CI → build → sign, API → service → DB), instrument each boundary once to see *which* layer breaks before investigating inside it. For a performance regression, take a baseline measurement and bisect; don't log.
17
- 3. **Rank 3–5 falsifiable hypotheses** ("if X is the cause, changing Y removes the bug") — list them in your reply, then test the top one without waiting. Proceed only on one that explains ALL the evidence — else gather more evidence, don't guess.
16
+ 2. **Minimise, then isolate.** Cut inputs and steps one at a time until every remaining element is load-bearing. Then binary-search the cause — the code path, or for a regression the commit range with `git bisect` (the [git-history {{SKILL}}](git-history.md) carries the method). Change one variable at a time. Find the nearest working twin (a passing sibling test, the last green commit, the same call elsewhere) and list every difference, however small. For a bad value deep in the stack, trace it back caller by caller to where it was born, and fix there. In a multi-layer system (CI → build → sign, API → service → DB), instrument each boundary once to see *which* layer breaks before investigating inside it. For a performance regression, take a baseline measurement and bisect; don't log.
17
+ 3. **Rank 3–5 falsifiable hypotheses** ("if X is the cause, changing Y removes the bug") — list them in your reply, then test the top one without waiting. Cite the evidence for each as `file:line` or the exact log line. Proceed only on one that explains ALL the evidence — else gather more evidence, don't guess.
18
18
  4. Apply the smallest fix that addresses the root cause, not the symptom; resist fixing things the evidence doesn't implicate ({{LAW:one-intent-one-act}}). One change at a time — no bundled "while I'm here" edits.
19
19
  5. Verify: run the project's checks and read the actual output ({{LAW:verify-before-asserting}}) — the step-1 command now passes and nothing nearby broke. Where a test can pin the bug at a seam that reproduces the real call chain, add a regression test that fails before the fix and passes after. If no such seam exists, record that as a finding rather than writing a shallow test. Name the confirmed hypothesis in the commit message. Dispatch the [tester {{AGENT}}](../{{DIR_AGENTS}}/tester.md) for a focused regression check when the blast radius is unclear.
20
- 6. If a fix doesn't work, return to step 1 with what you learned — don't stack a second fix on top. **After three failed fixes, stop fixing:** when each attempt only shifts the symptom elsewhere, the architecture, not the line, is likely wrong. Surface that to the user and decide the approach together before trying again ({{LAW:one-intent-one-act}}).
20
+ 6. If a fix doesn't work, return to step 1 with what you learned — don't stack a second fix on top. **After three failed fixes, stop fixing:** when each attempt only shifts the symptom elsewhere, the architecture, not the line, is likely wrong. Surface that to the user and decide the approach together before trying again ({{LAW:one-intent-one-act}}). If the evidence puts the cause outside the repo, show it; a retry or timeout is then a named workaround, taken with consent ({{LAW:cure-the-cause}}).
21
21
 
22
- **Diagnostic logging is scaffolding.** When you add logging to isolate a bug, use the project's real logger at a DEBUG level rather than scattered `print`/`console.log`, and **never log secrets, tokens, or PII** ({{LAW:sealed-secrets}}). Tag every probe with one unique prefix (`[DEBUG-a4f2]`) so cleanup is a single grep, and remove or downgrade each probe, `print`/`console.log`/`debugger` before the change ships ({{LAW:cure-the-cause}}).
22
+ **Diagnostic logging is scaffolding.** When you add logging to isolate a bug, use the project's real logger at a DEBUG level rather than scattered `print`/`console.log`, and **never log secrets, tokens, or PII** ({{LAW:sealed-secrets}}) — probe a secret's presence, never its value: `[ -n "$TOKEN" ] && echo set || echo unset`. Tag every probe with one unique prefix (`[DEBUG-a4f2]`) so cleanup is a single grep, and remove or downgrade each probe, `print`/`console.log`/`debugger` before the change ships ({{LAW:cure-the-cause}}).
23
23
 
24
24
  **CI branch (a red run)** → read [debug/ci.md](debug/ci.md) and follow it.
25
25
 
@@ -38,15 +38,17 @@ case where the seam is only known once the change is made.
38
38
  6. With the slice green, tidy through the [refactor {{SKILL}}](refactor.md) — the tests
39
39
  are the safety net — then commit the slice through the [commit {{SKILL}}](commit.md)
40
40
  ({{DOCTRINE:consent-before-push}}). Loop from step 3, one slice at a time.
41
- 7. **Exit.** When the last slice is in: run the whole affected suite once more, state
42
- what was run and its result, and hand over — to the [ship {{SKILL}}](ship.md) when
41
+ 7. **Exit.** When the last slice is in: run the whole suite once, state what was run and
42
+ its result, and name every failure in it — including one this change did not cause
43
+ ({{DOCTRINE:cover-and-verify}}) — then hand over to the [ship {{SKILL}}](ship.md) when
43
44
  the change is ready for a PR, or to the [handoff {{SKILL}}](handoff.md) if the
44
45
  session ends mid-task. Leave no slice uncommitted and no test you could not make
45
46
  fail.
46
47
 
47
48
  ## Done when
48
49
  - Every behaviour changed is covered by a test written this session that was seen
49
- to fail before it passed, the affected suite is green with its output shown, each
50
- slice was committed on its own, and the work has been handed to ship or handoff.
50
+ to fail before it passed, the whole suite ran at exit with its output shown and every
51
+ failure named, each slice was committed on its own, and the work has been handed to
52
+ ship or handoff.
51
53
 
52
54
  <!-- INCLUDE: skills/_self-improvement.md -->
@@ -9,7 +9,7 @@
9
9
  2. Deliberately WITHHOLD everything else and say so in the brief: the diff and changed-files list, the chat transcript, the solver's rationale and commit messages, prior test output, and every "it works because…" claim. Each is a vector for confirmation bias — they transmit the author's conviction, and a validator that inherits it cannot judge independently ({{ONTOLOGY}}: {{ONT_CONDUCT}}). The validator must re-confront the artifact cold, the way an external recipient would.
10
10
  3. Dispatch ONE fresh-context validator whose context starts empty — isolation is structural, not promised — using the [reviewer {{AGENT}}](../{{DIR_AGENTS}}/reviewer.md) (read-only, runs the suite, casts a verdict; NOT the [skeptic](../{{DIR_AGENTS}}/skeptic.md), whose charter forbids running commands and casting verdicts), via the dispatch pattern in [parallel-agents {{SKILL}}](parallel-agents.md), keeping the heavy reading out of the main context ({{DOCTRINE:context-economy}}); a cheaper model suffices for the validator unless the spec is subtle. Dispatch **fresh** — never resume a prior subagent session, which re-inherits its context and breaches the firewall. Where the host has no subagent capability, degrade: write the brief to a file and have the user run it in a separate fresh process; only as a last resort run the persona in-session and **stamp the verdict "SOFT ISOLATION — context bleed possible"** so the user discounts it. Never silently pretend a persona equals a fresh agent.
11
11
  4. Inside the fresh context, FIRST derive the rubric blind: from the task ALONE — before looking at the artifact — write a numbered list of observable acceptance criteria, each a yes/no test with a stated check method (a command to run, an output to see, a behaviour to exercise), tagged must-have or nice-to-have. FREEZE this list. Deriving it inside the firewall, from the task and not the solution, is what prevents criteria-fitting — the rubric cannot be bent to match what the artifact happens to do.
12
- 5. THEN reveal the artifact and rule each criterion against it under an inverted burden of proof: actively check it — run the command, exercise the behaviour, read the named output ({{LAW:verify-before-asserting}} — verify by running, never assume) — and record `Cn: PASS | FAIL | UNVERIFIABLE — <evidence: the exact output/behaviour checked>`. Default is NOT-PASS: mark PASS only after actively confirming; a criterion that cannot be checked is UNVERIFIABLE (a finding, not a pass — name the missing evidence). Flag any **Extra** the artifact added beyond the spec, but cut gold-plating both ways — never FAIL the artifact for a requirement the task never asked for. The validator does NOT fix, refactor, or polish; it only rules.
12
+ 5. THEN reveal the artifact and rule each criterion against it under an inverted burden of proof: actively check it — run the command, exercise the behaviour, read the named output ({{LAW:verify-before-asserting}} — verify by running, never assume) — and record `Cn: PASS | FAIL | UNVERIFIABLE — <evidence: the exact output/behaviour checked>`. Default is NOT-PASS: mark PASS only after actively confirming; a criterion that cannot be checked is UNVERIFIABLE (a finding, not a pass — name the missing evidence). Flag any **Extra** the artifact added beyond the spec, but cut gold-plating both ways — never FAIL the artifact for a requirement the task never asked for (a reasonable user's expectation that it not crash or lose data is not gold-plating). The validator does NOT fix, refactor, or polish; it only rules.
13
13
  6. Return the independent verdict: the per-criterion table, then the overall gate — **SATISFIES** (every must-have PASS, no FAIL), **SATISFIES-WITH-GAPS** (must-haves pass, a nice-to-have fails), or **DOES-NOT-SATISFY** (any must-have FAIL or UNVERIFIABLE), listing the failing criteria with evidence. Report "could not find a fault" as not-proven-false, never as "proven correct". Surface it for the user to decide; the gate advises and applies no changes — write no code, push nothing ({{LAW:deletion-is-deliberate}}, {{DOCTRINE:consent-before-push}}). On DOES-NOT-SATISFY, hand the failures to the solver (optionally via [review-response](review-response.md)) and re-run fresh-eyes after the fix rather than letting the original context relitigate the ruling.
14
14
 
15
15
  ## Done when
@@ -6,7 +6,8 @@
6
6
 
7
7
  ## Procedure
8
8
  1. Pin the diff: `git diff <base>...HEAD` for committed work, `git diff <base>`
9
- for uncommitted, or the PR the user names. Confirm the base resolves and the
9
+ for uncommitted, or the PR the user names. `<base>` is `origin/<default branch>` after a
10
+ `git fetch`, never a local branch that may be stale. Confirm the base resolves and the
10
11
  diff is non-empty.
11
12
  2. Find the spec: issue refs in the commits, a path the user gave, a match under
12
13
  `docs/`, `specs/` or `.scratch/`. None → ask once; still none → skip pass 3 and say so.
@@ -21,7 +22,9 @@
21
22
  `CONTRIBUTING.md`) override. Then, as judgement calls and skipping what tooling enforces:
22
23
  mysterious name, duplication, feature envy, data clumps, primitive obsession, repeated switches, shotgun surgery, divergent change, speculative generality, middle man, dead code, units that do too much.
23
24
  7. Pass 3 — spec fidelity: flag anything asked for but missing, present but never
24
- asked for, or implemented wrong — quoting the spec line for each. Architecture drift too: when
25
+ asked for, or implemented wrong — quoting the spec line for each. Where the spec is silent,
26
+ judge by what a reasonable user would expect: a crash, hang or data loss on an input the
27
+ spec implies but never names is `issue (blocking)`, not a nitpick. Architecture drift too: when
25
28
  `docs/architecture.md` draws C4 and the diff adds, removes or rewires a container — a Dockerfile,
26
29
  a compose service, a deployable module, a datastore, a new client of another container — but
27
30
  leaves the diagram alone, raise `issue (non-blocking)` and point at
@@ -30,6 +33,9 @@
30
33
  correctness first. Labels: issue, suggestion, question, todo, nitpick, thought, note,
31
34
  praise. Decorations: blocking, non-blocking, if-minor. The line pastes straight into a
32
35
  merge-request comment, and a reader can filter on the label without reading the prose.
36
+ Before the verdict, a **Set aside:** list — each behaviour you considered and left out of
37
+ scope, one line with the reason, or `none` — for the caller to rule on
38
+ ({{DOCTRINE:declare-the-judgment-calls}}).
33
39
 
34
40
  ## Done when
35
41
  - Findings are reported with a verdict that follows from the decorations: any `blocking`
@@ -5,7 +5,7 @@
5
5
  **Trigger:** the context window is filling, a session is ending mid-task, or work is passing to another agent or developer.
6
6
 
7
7
  ## Procedure
8
- 1. Capture the state in the worklog (`WORKLOG.md` or the task's plan file): the goal, what's done, the step in progress, and the exact next step.
8
+ 1. Capture the state in the worklog (`WORKLOG.md` or the task's plan file), whose first line names its task or branch so a stale one is never resumed: the goal, what's done, the step in progress, and the exact next step.
9
9
  2. Record open decisions, dead ends already ruled out, blockers, and any irreversible changes already made ({{DOCTRINE:plan-before-acting}}) — so the next agent neither re-derives nor repeats them.
10
10
  3. Promote any durable fact or correction learned this session into {{MEMORY}} (§5), not just the worklog.
11
11
  4. Point to the live artifacts: branch name, changed files, how to run the tests, and where any failure reproduces. Link specs, plans, ADRs, issues and commits by path or URL — never copy them in.
@@ -6,11 +6,11 @@
6
6
 
7
7
  ## Procedure
8
8
  1. Confirm independence: the subtasks must not depend on each other's output or write the same files ({{DOCTRINE:one-writer-per-file}}). Write down each unit's **write set** — the files or globs it may change — and intersect them; an overlap runs in sequence or goes to one owner, and shared append files (registries, index tables, lockfiles, generated bundles) stay with you. If they're sequential or share state, use [plan](plan.md) instead.
9
- 2. Split the work into self-contained units, each with one clear goal and a defined output contract — what it must return.
10
- 3. Dispatch each unit to its own subagent in one batch, each under a handoff envelope: the unit's goal, the inputs it needs, its **write set** (edit nothing outside it; return rows for a shared file instead of writing it), the observable check that proves it done, its output contract — naming every file it changed — and the inherited constraints (no commit/push — {{DOCTRINE:consent-before-push}} stays with you; gaps reported, never invented). Hand each unit only the access its goal needs ({{LAW:least-privilege}}). Prefer the read-only [explorer {{AGENT}}](../{{DIR_AGENTS}}/explorer.md) for investigation so the heavy reading stays out of the main context ({{DOCTRINE:context-economy}}). Where no subagent capability exists, run the units sequentially as personas instead, converging the same way.
9
+ 2. Split the work into self-contained units, each with one clear goal and a defined output contract — what it must return. Several small edits of one kind (the same fix, constant or field across files) form ONE unit with the union write set and get one review.
10
+ 3. Dispatch each unit to its own subagent in one batch, each under a handoff envelope: the unit's goal, the inputs it needs, its **write set** (edit nothing outside it; return rows for a shared file instead of writing it), the observable check that proves it done, its output contract — naming every file it changed — and the inherited constraints (no commit/push — {{DOCTRINE:consent-before-push}} stays with you; no sub-agents of its own — review comes from you; gaps reported, never invented). Hand each unit only the access its goal needs ({{LAW:least-privilege}}). Prefer the read-only [explorer {{AGENT}}](../{{DIR_AGENTS}}/explorer.md) for investigation so the heavy reading stays out of the main context ({{DOCTRINE:context-economy}}). Where no subagent capability exists, run the units sequentially as personas instead, converging the same way.
11
11
  4. Keep the main context lean: collect each subagent's distilled result, not its working transcript.
12
- 5. Converge: compare each unit's changed files against its write set and against its siblings' — an edit outside the set or a file two units touched is a conflict you resolve before anything else — apply the shared-file rows yourself, then verify the combined outcome.
13
- 6. **A plan with blocking edges.** To build a [plan](plan.md) file's slices — each with its `Blocked by:` line — in one run, dispatch every unblocked slice on its own branch off one integration branch, merge each into it as it returns (each merge is a commit — {{DOCTRINE:consent-before-push}} stays with you), and recompute the unblocked set from the plan after every merge — newly freed slices go out at once.
12
+ 5. Converge: compare each unit's changed files against its write set and against its siblings' — an edit outside the set, a file two units touched, or a file in a batch's set that never changed is a conflict you resolve before anything else — apply the shared-file rows yourself, then verify the combined outcome. A conflict or ambiguity between the plan, the findings and the code is yours to decide: decide it, record `Ruling: <choice> — <why> — <cost if wrong>` in the worklog, and continue. Stop only for what {{LAW:echo-the-intent}}, {{LAW:deletion-is-deliberate}} or {{DOCTRINE:consent-before-push}} names; every ruling goes in the final report ({{DOCTRINE:declare-the-judgment-calls}}).
13
+ 6. **A plan with blocking edges.** To build a [plan](plan.md) file's slices — each with its `Blocked by:` line — in one run, dispatch every unblocked slice on its own branch off one integration branch, merge each into it as it returns (each merge is a commit — {{DOCTRINE:consent-before-push}} stays with you), and recompute the unblocked set from the plan after every merge — newly freed slices go out at once. When the plan names a `Spec:`, every slice reads it once; the spec outranks the plan where they conflict. Record BASE before dispatch; before re-running the proof, confirm the branch descends from BASE and the diff is non-empty — an empty diff is a failure, not a clean result. Never diff against `HEAD~1`.
14
14
 
15
15
  ## Done when
16
16
  - Independent units ran concurrently, each returned a distilled result, and the reconciled outcome is verified.
@@ -24,11 +24,11 @@ The minimum roster per task type. The parent may add specialists on top — secu
24
24
  1. Confirm the task is genuinely substantial — a trivial one-file tweak or a question does not warrant a crew; do it directly instead.
25
25
  2. Compose the crew from the floor above, adding specialists only where the task demands them.
26
26
  3. Isolate the crew's work in its own git worktree/branch. Where worktrees are unavailable, fall back to a single tree, one pipeline at a time, and say so. Give the crew a **write set** and check it against every other pipeline in flight ({{DOCTRINE:one-writer-per-file}}): two crews whose sets overlap do not run at once, and shared append files (registries, index tables, lockfiles, generated bundles) are the parent's to apply, never a crew's.
27
- 4. **The dev↔tester loop:** the developer implements, the tester validates — runs the tests and lint, produces raw logs. On failure, the findings go back to the developer. Cap at **5** iterations; on exhaustion, stop, do not merge, and report the failure with the branch left in place for inspection.
27
+ 4. **The dev↔tester loop:** the developer implements, the tester validates — runs the tests and lint, produces raw logs. On failure, the findings go back to the developer — two repair rounds at most, then one fresh developer (a higher model tier where the host offers one) carrying the tester's findings ({{DOCTRINE:bound-the-loop}}); if that fails too, stop, do not merge, and report the failure with the branch left in place for inspection. A conflict or ambiguity between the plan, the findings and the code is yours to decide: decide it, record `Ruling: <choice> — <why> — <cost if wrong>` in the worklog, and continue. Stop only for what {{LAW:echo-the-intent}}, {{LAW:deletion-is-deliberate}} or {{DOCTRINE:consent-before-push}} names; every ruling goes in the final report ({{DOCTRINE:declare-the-judgment-calls}}). When the plan names a `Spec:`, the analyst reads it once; the spec outranks the plan.
28
28
  5. **Two execution shapes**, chosen by host capability (same pattern as the [workflow {{SKILL}}](workflow.md)):
29
- - *Deterministic:* where the host exposes a `workflow` tool, run a saved script encoding analyst → developer → (tester ⇄ developer)×≤5 → proof.
29
+ - *Deterministic:* where the host exposes a `workflow` tool, run a saved script encoding analyst → developer → (tester ⇄ developer)×≤2 → fresh developer → proof.
30
30
  - *Model-driven fallback:* everywhere else, run the same stages via the [parallel-agents {{SKILL}}](parallel-agents.md) or sequential personas, with the same handoff envelopes and the same delivery contract.
31
- 6. On success, hand the worktree back to the parent uncommitted, with the mechanical proof (test + lint output, exit codes) and the list of files it changed in the result envelope, rebased on the current base so a conflict with a sibling resolves on the crew's branch. The pipeline never commits, pushes, or merges ({{DOCTRINE:consent-before-push}}): the parent re-runs the proof commands itself, shows the user the diff and the output, and commits and merges once the user accepts.
31
+ 6. On success, hand the worktree back to the parent uncommitted, with the mechanical proof (test + lint output, exit codes) and the list of files it changed in the result envelope, rebased on the current base so a conflict with a sibling resolves on the crew's branch. The pipeline never commits, pushes, or merges ({{DOCTRINE:consent-before-push}}): the parent records BASE before dispatch and, before re-running the proof, confirms the branch descends from it and the diff is non-empty (an empty diff is a failure; never `HEAD~1`); it re-runs the proof commands itself, shows the user the diff and the output, and commits and merges once the user accepts.
32
32
 
33
33
  ## Delivery contract
34
34
 
@@ -17,17 +17,29 @@
17
17
  thin end-to-end pieces, each green and verifiable on its own, never one horizontal
18
18
  layer at a time — and give each a `Blocked by:` line naming the slices it waits on
19
19
  (`none` when it can start now). Sequence a wide refactor as expand → migrate
20
- callers in batches → contract, so every slice leaves the build green.
21
- 3. Execute one step at a time. After each, update the worklog — mark it done, note
22
- the current step, the next step, and any blockers.
20
+ callers in batches → contract, so every slice leaves the build green. A step records
21
+ decisions, not code: the files, the exact signatures and the spec's values, the test
22
+ that proves it, and the check command. Write a body only for an algorithm those leave
23
+ open; a plan longer than the code it describes has written the code, and "TBD",
24
+ "handle edge cases" or "add tests" decide nothing. The file's first line names the
25
+ task or branch, then `Spec: <path>` when a spec exists — the spec outranks the plan
26
+ where they conflict, and a worklog naming another task is stale, never resumed.
27
+ 3. Execute one step at a time. After each, update the worklog — mark it done only after
28
+ its check ran green in this session, with the command and result on the line — and
29
+ note the current step, the next step, and any blockers. After a compaction, trust the
30
+ worklog and `git log` over memory.
23
31
  4. At each milestone, stop and verify before continuing — run the project's checks
24
- and read the output ({{LAW:verify-before-asserting}}); on a consequential or ambiguous
25
- direction, surface the result for review before pressing on.
32
+ and read the output ({{LAW:verify-before-asserting}}). Decide forks yourself; stop
33
+ only for what {{LAW:echo-the-intent}} or {{DOCTRINE:consent-before-push}} names.
26
34
  5. If the plan proves wrong, revise the file *before* continuing. The file, not
27
- your memory, is the source of truth for where you are.
35
+ your memory, is the source of truth for where you are. A deviation you decide without
36
+ asking gets a worklog line `Ruling: <what> — <why> — <cost if wrong>`; those lines feed
37
+ {{DOCTRINE:declare-the-judgment-calls}} at the end.
28
38
  6. On finishing, clear or archive the worklog.
29
39
 
30
40
  ## Done when
41
+ - The plan was re-read against the spec before step 1: every requirement has a step,
42
+ names match across steps, and it is not several times the spec's length.
31
43
  - Every plan step is checked off, each milestone was verified, and the goal's
32
44
  done-condition is confirmed.
33
45