@dougharness/cli 1.0.1
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/LICENSE +21 -0
- package/dist/ablate.d.ts +96 -0
- package/dist/ablate.js +440 -0
- package/dist/ablate.js.map +1 -0
- package/dist/apply.d.ts +2 -0
- package/dist/apply.js +19 -0
- package/dist/apply.js.map +1 -0
- package/dist/bin.d.ts +2 -0
- package/dist/bin.js +80 -0
- package/dist/bin.js.map +1 -0
- package/dist/board-page.d.ts +15 -0
- package/dist/board-page.js +27 -0
- package/dist/board-page.js.map +1 -0
- package/dist/board-serve-process.d.ts +24 -0
- package/dist/board-serve-process.js +227 -0
- package/dist/board-serve-process.js.map +1 -0
- package/dist/board-serve.d.ts +9 -0
- package/dist/board-serve.js +302 -0
- package/dist/board-serve.js.map +1 -0
- package/dist/board.d.ts +6 -0
- package/dist/board.js +515 -0
- package/dist/board.js.map +1 -0
- package/dist/detect/fs.d.ts +6 -0
- package/dist/detect/fs.js +50 -0
- package/dist/detect/fs.js.map +1 -0
- package/dist/detect/index.d.ts +3 -0
- package/dist/detect/index.js +13 -0
- package/dist/detect/index.js.map +1 -0
- package/dist/detect/node.d.ts +3 -0
- package/dist/detect/node.js +179 -0
- package/dist/detect/node.js.map +1 -0
- package/dist/detect/python.d.ts +2 -0
- package/dist/detect/python.js +388 -0
- package/dist/detect/python.js.map +1 -0
- package/dist/detect/repo.d.ts +2 -0
- package/dist/detect/repo.js +102 -0
- package/dist/detect/repo.js.map +1 -0
- package/dist/detect/types.d.ts +98 -0
- package/dist/detect/types.js +2 -0
- package/dist/detect/types.js.map +1 -0
- package/dist/diff.d.ts +12 -0
- package/dist/diff.js +105 -0
- package/dist/diff.js.map +1 -0
- package/dist/generate/agents.d.ts +19 -0
- package/dist/generate/agents.js +184 -0
- package/dist/generate/agents.js.map +1 -0
- package/dist/generate/claude-md.d.ts +9 -0
- package/dist/generate/claude-md.js +111 -0
- package/dist/generate/claude-md.js.map +1 -0
- package/dist/generate/config.d.ts +51 -0
- package/dist/generate/config.js +155 -0
- package/dist/generate/config.js.map +1 -0
- package/dist/generate/proposal.d.ts +11 -0
- package/dist/generate/proposal.js +175 -0
- package/dist/generate/proposal.js.map +1 -0
- package/dist/generate/settings.d.ts +35 -0
- package/dist/generate/settings.js +213 -0
- package/dist/generate/settings.js.map +1 -0
- package/dist/generate/skills.d.ts +8 -0
- package/dist/generate/skills.js +264 -0
- package/dist/generate/skills.js.map +1 -0
- package/dist/init.d.ts +10 -0
- package/dist/init.js +69 -0
- package/dist/init.js.map +1 -0
- package/dist/trace.d.ts +9 -0
- package/dist/trace.js +106 -0
- package/dist/trace.js.map +1 -0
- package/node_modules/@dougharness/flow/.claude-plugin/plugin.json +10 -0
- package/node_modules/@dougharness/flow/LICENSE +21 -0
- package/node_modules/@dougharness/flow/agents/adversary-claude.md +33 -0
- package/node_modules/@dougharness/flow/agents/adversary.md +29 -0
- package/node_modules/@dougharness/flow/agents/implementer.md +23 -0
- package/node_modules/@dougharness/flow/agents/lead.md +35 -0
- package/node_modules/@dougharness/flow/agents/planner.md +70 -0
- package/node_modules/@dougharness/flow/agents/researcher.md +31 -0
- package/node_modules/@dougharness/flow/agents/reviewer.md +26 -0
- package/node_modules/@dougharness/flow/agents/verifier.md +24 -0
- package/node_modules/@dougharness/flow/lib/board.mjs +840 -0
- package/node_modules/@dougharness/flow/lib/code-index.mjs +629 -0
- package/node_modules/@dougharness/flow/lib/cost.mjs +392 -0
- package/node_modules/@dougharness/flow/lib/decisions.mjs +314 -0
- package/node_modules/@dougharness/flow/lib/embeddings.mjs +539 -0
- package/node_modules/@dougharness/flow/lib/land.mjs +219 -0
- package/node_modules/@dougharness/flow/lib/learn.mjs +742 -0
- package/node_modules/@dougharness/flow/lib/memory-import.mjs +145 -0
- package/node_modules/@dougharness/flow/lib/memory.mjs +1641 -0
- package/node_modules/@dougharness/flow/lib/models.mjs +148 -0
- package/node_modules/@dougharness/flow/lib/plan.mjs +773 -0
- package/node_modules/@dougharness/flow/lib/rehearse.mjs +825 -0
- package/node_modules/@dougharness/flow/lib/worktrees.mjs +215 -0
- package/node_modules/@dougharness/flow/package.json +19 -0
- package/node_modules/@dougharness/flow/scripts/board.mjs +260 -0
- package/node_modules/@dougharness/flow/scripts/cost.mjs +66 -0
- package/node_modules/@dougharness/flow/scripts/learn.mjs +161 -0
- package/node_modules/@dougharness/flow/scripts/memory.mjs +1274 -0
- package/node_modules/@dougharness/flow/scripts/plan.mjs +547 -0
- package/node_modules/@dougharness/flow/scripts/rehearse.mjs +129 -0
- package/node_modules/@dougharness/flow/skills/core-next/SKILL.md +92 -0
- package/node_modules/@dougharness/flow/skills/doug-approve/SKILL.md +15 -0
- package/node_modules/@dougharness/flow/skills/doug-decide/SKILL.md +26 -0
- package/node_modules/@dougharness/flow/skills/doug-implement/SKILL.md +22 -0
- package/node_modules/@dougharness/flow/skills/doug-learn/SKILL.md +20 -0
- package/node_modules/@dougharness/flow/skills/doug-next/SKILL.md +87 -0
- package/node_modules/@dougharness/flow/skills/doug-plan/SKILL.md +22 -0
- package/node_modules/@dougharness/flow/skills/doug-swarm/SKILL.md +55 -0
- package/node_modules/@dougharness/flow/skills/harness-fix/SKILL.md +85 -0
- package/node_modules/@dougharness/flow/skills/research/SKILL.md +41 -0
- package/node_modules/@dougharness/flow/skills/run-report/SKILL.md +51 -0
- package/node_modules/@dougharness/flow/skills/swarm-launch/SKILL.md +27 -0
- package/node_modules/@dougharness/flow/workflows/doug-implement.js +2687 -0
- package/node_modules/@dougharness/gates/.claude-plugin/plugin.json +10 -0
- package/node_modules/@dougharness/gates/LICENSE +21 -0
- package/node_modules/@dougharness/gates/hooks/hooks.json +184 -0
- package/node_modules/@dougharness/gates/lib/agent-context.mjs +111 -0
- package/node_modules/@dougharness/gates/lib/anchor.mjs +110 -0
- package/node_modules/@dougharness/gates/lib/baseline.mjs +160 -0
- package/node_modules/@dougharness/gates/lib/bash-rules.mjs +1522 -0
- package/node_modules/@dougharness/gates/lib/block-ledger.mjs +127 -0
- package/node_modules/@dougharness/gates/lib/checkpoint.mjs +97 -0
- package/node_modules/@dougharness/gates/lib/config.mjs +168 -0
- package/node_modules/@dougharness/gates/lib/evidence.mjs +59 -0
- package/node_modules/@dougharness/gates/lib/glob.mjs +86 -0
- package/node_modules/@dougharness/gates/lib/io.mjs +91 -0
- package/node_modules/@dougharness/gates/lib/paths.mjs +101 -0
- package/node_modules/@dougharness/gates/lib/proposals.mjs +201 -0
- package/node_modules/@dougharness/gates/lib/run.mjs +147 -0
- package/node_modules/@dougharness/gates/lib/scope.mjs +117 -0
- package/node_modules/@dougharness/gates/lib/secret-rules.mjs +268 -0
- package/node_modules/@dougharness/gates/lib/state.mjs +114 -0
- package/node_modules/@dougharness/gates/lib/trace.mjs +196 -0
- package/node_modules/@dougharness/gates/package.json +17 -0
- package/node_modules/@dougharness/gates/scripts/edit-loop.mjs +39 -0
- package/node_modules/@dougharness/gates/scripts/format-on-edit.mjs +45 -0
- package/node_modules/@dougharness/gates/scripts/guard-bash.mjs +32 -0
- package/node_modules/@dougharness/gates/scripts/protect-paths.mjs +49 -0
- package/node_modules/@dougharness/gates/scripts/reanchor.mjs +81 -0
- package/node_modules/@dougharness/gates/scripts/research-cap.mjs +295 -0
- package/node_modules/@dougharness/gates/scripts/secret-scan.mjs +26 -0
- package/node_modules/@dougharness/gates/scripts/session-start-baseline.mjs +57 -0
- package/node_modules/@dougharness/gates/scripts/statusline.mjs +133 -0
- package/node_modules/@dougharness/gates/scripts/stop-gate.mjs +1422 -0
- package/node_modules/@dougharness/gates/scripts/trace.mjs +75 -0
- package/package.json +33 -0
- package/templates/board-app.js +533 -0
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: harness-fix
|
|
3
|
+
description: The by-hand procedure for changing Doug's own harness code (plugins/doug-flow, plugins/doug-gates, packages/doug-codex, packages/doug-cli, evals) without running it through the flow (decision 0005). Which test file covers which module, a single test file while iterating, the full gate before a commit, gate scripts copied into .doug/hooks/scripts, no attribution trailers, and a docs/live-runs.md line when a measurement changes. Use it for any edit under those directories, and from /core-next.
|
|
4
|
+
allowed-tools: Read, Edit, Write, Grep, Glob, Bash
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# harness-fix
|
|
8
|
+
|
|
9
|
+
Harness code is built directly in the checkout: tests first, the full gate, a plain commit. This is the procedure; `/core-next` follows it for every hand-track card, and it applies just as well to a one-line fix made outside a card.
|
|
10
|
+
|
|
11
|
+
## 0. Who does the work
|
|
12
|
+
|
|
13
|
+
The lead briefs and gates; it never implements, verifies, or reviews the change itself. Before the coder, the `tester` agent (`.claude/agents/tester.md`), spawned with the Agent tool on the `implement` row of the CLAUDE.md Models table, writes or extends the test file first, from the goal; the coder implements against it. A tester that leaves tests red by design ends with its tests_red_by_design claim, in its final plain-text message or its hand-back call; the SubagentStop gate reads both. The `coder` agent, on the same row, may not edit a test except with a stated reason in its report. The `reviewer` agent, on the `review` row, reviews, and checks that rule. Verification on the hand track is the gate itself (`pnpm typecheck` and `pnpm test:unit`), which the reviewer runs and the lead re-runs before the commit. This holds on both tracks, swarm or not; a hand-track lead is the session model. For a card whose acceptance is that a mechanism exists, the reviewer is expected to mutate the mechanism and rerun the test rather than only read the diff (rule 7), rerunning the brief's mutation list and adding its own; the flow track's `plugins/doug-flow/agents/reviewer.md` does not carry this instruction — it is read-only by tool policy, and its verifier and adversary stages run the code afterward instead. On a tests-only card (the goal says tests only, no production change) there is no coder: the tester runs the brief's mutation list itself in a scratch copy or git worktree under `.doug/.state`, never editing a production file in the live checkout, and reports each result.
|
|
14
|
+
|
|
15
|
+
## 1. Find the test that covers the module
|
|
16
|
+
|
|
17
|
+
Under a card, the tester writes or extends the test before the change, in the file that already covers the module, and the coder runs only that file while iterating: `pnpm exec vitest run <path/to/file.test>`. For a one-line fix outside a card there is no tester: its author writes the test first, in the same file, and runs only that file.
|
|
18
|
+
|
|
19
|
+
| Module | Test file |
|
|
20
|
+
|---|---|
|
|
21
|
+
| `plugins/doug-flow/workflows/doug-implement.js` (the loop, the ledger, the prompts), `agents/*.md`, `skills/*/SKILL.md`, the plugin manifest | `plugins/doug-flow/tests/template.test.mjs` |
|
|
22
|
+
| `plugins/doug-flow/lib/board.mjs`, `scripts/board.mjs` | `plugins/doug-flow/tests/board.test.mjs` |
|
|
23
|
+
| `plugins/doug-flow/lib/plan.mjs` validation, levels, rendering, `mergePlans` | `plugins/doug-flow/tests/plan.test.mjs` |
|
|
24
|
+
| `scripts/plan.mjs set`, `plan.mjs merge` (several cards in one plan) and `--file`, config defaults for install and adversary | `plugins/doug-flow/tests/plan-set.test.mjs` |
|
|
25
|
+
| `lib/plan.mjs` specHash, reusePlan, `plan.mjs replan` | `plugins/doug-flow/tests/replan.test.mjs` |
|
|
26
|
+
| `plugins/doug-flow/lib/land.mjs`, `plan.mjs land`, worktree pruning | `plugins/doug-flow/tests/land.test.mjs` |
|
|
27
|
+
| `plugins/doug-flow/lib/worktrees.mjs` (worktree removal, used by `land.mjs`; branch retirement, used by `scripts/plan.mjs`) | `plugins/doug-flow/tests/land.test.mjs` (removal), `plugins/doug-flow/tests/replan.test.mjs` (retirement) |
|
|
28
|
+
| `plugins/doug-flow/lib/models.mjs` (the CLAUDE.md Models table) | `plugins/doug-flow/tests/models.test.mjs` |
|
|
29
|
+
| `plugins/doug-flow/lib/cost.mjs`, `scripts/cost.mjs` (a run's cost from local transcripts; the price table) | `plugins/doug-flow/tests/cost.test.mjs` |
|
|
30
|
+
| `plugins/doug-flow/lib/embeddings.mjs` (the embedding provider layer: openai-compatible and voyage adapters, probeProvider, doctorReport) | `plugins/doug-flow/tests/embeddings.test.mjs` |
|
|
31
|
+
| `plugins/doug-flow/lib/code-index.mjs` (the opt-in semantic code index: file listing, chunking, incremental build, status, search) | `plugins/doug-flow/tests/code-index.test.mjs` |
|
|
32
|
+
| `plugins/doug-flow/lib/learn.mjs`, `scripts/learn.mjs` (deterministic proposals from outcomes/lessons signals and the run trace; card learn-signals) | `plugins/doug-flow/tests/learn.test.mjs` |
|
|
33
|
+
| `plugins/doug-flow/lib/decisions.mjs` (proposal diffs for docs/decisions/ ADRs and .claude/rules/ conventions; card memory-decisions), `scripts/memory.mjs`'s `decision`/`rule` cases | `plugins/doug-flow/tests/decisions.test.mjs` |
|
|
34
|
+
| `plugins/doug-flow/lib/memory.mjs`, `scripts/memory.mjs` (the outcome log and lesson store: recall, the outcome record, reflect, and the memory.mjs CLI's index dispatch; card memory-lib) | `plugins/doug-flow/tests/memory.test.mjs`, `plugins/doug-flow/tests/memory-cli.test.mjs` |
|
|
35
|
+
| `plugins/doug-flow/lib/memory-import.mjs` (the `memory.mjs import` command; card memory-import) | `plugins/doug-flow/tests/memory-import.test.mjs` |
|
|
36
|
+
| `plugins/doug-gates/scripts/*.mjs` end to end (protect-paths, guard-bash, format-on-edit, edit-loop, stop-gate, reanchor, checkpoint) | `plugins/doug-gates/tests/hooks.test.mjs` |
|
|
37
|
+
| `plugins/doug-gates/lib/bash-rules.mjs` | `plugins/doug-gates/tests/bash-rules.test.mjs` |
|
|
38
|
+
| `plugins/doug-gates/lib/scope.mjs` (plan scope) | `plugins/doug-gates/tests/scope.test.mjs` |
|
|
39
|
+
| `plugins/doug-gates/lib/secret-rules.mjs`, `scripts/secret-scan.mjs` | `plugins/doug-gates/tests/secret-scan.test.mjs` |
|
|
40
|
+
| `plugins/doug-gates/lib/checkpoint.mjs` | `plugins/doug-gates/tests/checkpoint.test.mjs` |
|
|
41
|
+
| `plugins/doug-gates/lib/config.mjs`, state and paths | `plugins/doug-gates/tests/config-state.test.mjs` |
|
|
42
|
+
| `plugins/doug-gates/lib/proposals.mjs` (the applied-proposal ledger reader; card memory-decisions) | `plugins/doug-gates/tests/hooks.test.mjs` (protect-paths/stop-gate proposal-path blocks) |
|
|
43
|
+
| `plugins/doug-gates/lib/glob.mjs` | `plugins/doug-gates/tests/glob.test.mjs` |
|
|
44
|
+
| `plugins/doug-gates/lib/anchor.mjs` (the PreCompact snapshot in the anchor) | `plugins/doug-gates/tests/hooks.test.mjs` (reanchor on PreCompact) |
|
|
45
|
+
| `plugins/doug-gates/lib/evidence.mjs` (verification evidence: which recorded commands count) | `plugins/doug-gates/tests/evidence.test.mjs`; the stop-gate and guard-bash sides in `hooks.test.mjs` |
|
|
46
|
+
| `plugins/doug-gates/lib/trace.mjs` (the run trace: line shape, transcript usage, replay, attribution) | `plugins/doug-gates/tests/trace.test.mjs`; the `trace` script end to end in `hooks.test.mjs` |
|
|
47
|
+
| `plugins/doug-gates/scripts/statusline.mjs` | `plugins/doug-gates/tests/statusline.test.mjs` |
|
|
48
|
+
| the checked-in pre-commit hook | `plugins/doug-gates/tests/git-hooks.test.mjs` |
|
|
49
|
+
| `packages/doug-cli/src/board.ts` (`doug board`) | `packages/doug-cli/tests/board.test.ts` |
|
|
50
|
+
| `packages/doug-cli/src/board-page.ts`, `board-serve.ts`, `templates/board-app.js` | `packages/doug-cli/tests/board-page.test.ts` (serve tests skip with a reason where a local listener is denied: `board-page-skip.test.ts`) |
|
|
51
|
+
| `packages/doug-cli/src/detect/*` | `packages/doug-cli/tests/detect.test.ts` |
|
|
52
|
+
| `packages/doug-cli/src/generate/*` (config, CLAUDE.md, settings, proposal, apply) | `packages/doug-cli/tests/proposal.test.ts` |
|
|
53
|
+
| `packages/doug-cli/src/diff.ts` | `packages/doug-cli/tests/diff.test.ts` |
|
|
54
|
+
| `packages/doug-cli/src/ablate.ts` (`doug ablate`: eval results per condition, the runner pass-through) | `packages/doug-cli/tests/ablate.test.ts` |
|
|
55
|
+
| `packages/doug-cli/src/trace.ts` (`doug trace`: replay and per-agent attribution of a run trace) | `packages/doug-cli/tests/trace.test.ts` |
|
|
56
|
+
| `packages/doug-codex/src/prompt.ts` | `packages/doug-codex/tests/prompt.test.ts` |
|
|
57
|
+
| `packages/doug-codex/src/parse.ts` (Codex JSONL, verdict, exit codes) | `packages/doug-codex/tests/parse.test.ts` |
|
|
58
|
+
| `packages/doug-codex/src/run.ts` (spawning codex, timeout, worktree check) | `packages/doug-codex/tests/run.test.ts` |
|
|
59
|
+
| `packages/doug-codex/src/contract.ts` and `docs/worker-contract.md` | `packages/doug-codex/tests/contract.test.ts` |
|
|
60
|
+
| `packages/doug-codex/src/bin.ts` (`codex-review`) | `packages/doug-codex/tests/cli.test.ts` |
|
|
61
|
+
| `evals/run.mjs` (the scorer: tool calls from stream-json, leaks, must-run commands) and `evals/tasks/*.json` | `evals/tests/run.test.mjs` |
|
|
62
|
+
| `plugins/doug-flow/scripts/rehearse.mjs`, `lib/rehearse.mjs` (the on-demand live rehearsal runner: estimates, fixture, stream assertions, recording) | `plugins/doug-flow/tests/rehearse.test.mjs` |
|
|
63
|
+
| the `reviewIssues` report key (doug-implement.js) round-tripping into `lib/memory.mjs`'s `review_issue_count`/`review_issues`, through `board.mjs record`, `board.mjs summary`, and `plan.mjs replan` (card seam-contracts) | `plugins/doug-flow/tests/seams.test.mjs` |
|
|
64
|
+
| every `board.mjs`/`plan.mjs`/`memory.mjs` subcommand a `skills/*/SKILL.md`, `CLAUDE.md`, or `docs/worker-contract.md` names being a real dispatch case (card seam-contracts) | `plugins/doug-flow/tests/seams.test.mjs` |
|
|
65
|
+
| `claude plugin validate` actually catching a broken plugin manifest (card seam-contracts) | `plugins/doug-flow/tests/seams.test.mjs` |
|
|
66
|
+
| `doug init`'s PreToolUse wiring firing for real (protect-paths.mjs deny/allow, not just a string comparison of the wiring) (card seam-contracts) | `packages/doug-cli/tests/init-hooks.test.ts` |
|
|
67
|
+
|
|
68
|
+
`packages/doug-codex/tests/codex-live.test.ts` spawns the real Codex and is excluded from the gate; leave it out of iteration.
|
|
69
|
+
|
|
70
|
+
## 2. Rules while changing harness code
|
|
71
|
+
|
|
72
|
+
1. The workflow file `doug-implement.js` may not import, call `Date.now` or `Math.random`, or name a model; its template tests assert that, and it must parse when wrapped the way the Workflow runtime wraps it. A top-level `return` in it is expected, so `node --check` fails on it by design.
|
|
73
|
+
2. The Workflow tool runs the plugin copy loaded at session start. An edited workflow is launched with `scriptPath` pointing at the file, or the session is restarted.
|
|
74
|
+
3. After editing a gate script under `plugins/doug-gates/scripts/`, copy it to `.doug/hooks/scripts/` too: this repository has Doug installed on itself and its hooks run from there.
|
|
75
|
+
4. A change to `plugins/doug-flow/lib/board.mjs` or `lib/plan.mjs` reaches `packages/doug-cli` through the `@dougharness/flow` workspace dependency; the CLI's `src/flow-board.d.ts` declares the shapes, so a new field or option is added there as well or `pnpm typecheck` fails.
|
|
76
|
+
5. Keep the change to what the card or fix asks. A defect found on the way becomes its own hand-track card.
|
|
77
|
+
6. If a hook blocks a step, report it; do not work around it.
|
|
78
|
+
7. When the card's acceptance is that a mechanism exists, prove it before reporting done: mutate or remove the mechanism, run the new test file, confirm it fails, then revert the mutation and report which assertion failed. That is the line: a card whose acceptance is that a mechanism exists needs it; a card that only changes prose, a message, or a docs line does not. To prove it, the brief lists one mutation per case the card's goal names, each with the test that must fail; the coder runs every listed mutation and reports each result; the reviewer reruns the list and adds its own. Apply each mutation in a scratch copy or git worktree under `.doug/.state`, run the one test file there, and remove the copy.
|
|
79
|
+
8. A card that changes a workflow's or a skill's user-visible behaviour runs the live scenario that covers it before landing: `node plugins/doug-flow/scripts/rehearse.mjs <flow|swarm|hand> --card <id> --spend`, and its landing note quotes the outcome. The swarm scenario is the one that proves plugin loading and agent-name resolution in the real runtime. `docs/rehearsals.md` says what each scenario proves, how to read a result, and how to add one.
|
|
80
|
+
|
|
81
|
+
## 3. The gate, the commit, the record
|
|
82
|
+
|
|
83
|
+
1. Before the commit run the full gate: `pnpm typecheck` and `pnpm test:unit`. Never `pnpm test`, which spawns Codex. Say what ran and the counts.
|
|
84
|
+
2. Commit without attribution trailers, one commit per coherent change, with a message that says what changed and why. Leave `.doug/plan.json` and `.doug/anchor.md` out unless the change is about them.
|
|
85
|
+
3. When the change alters a measurement (a run's cost, wall clock, pass count, or what a stage does), add a line to `docs/live-runs.md`; a change to the board record shows on the served page (`doug board serve`).
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: research
|
|
3
|
+
description: The research step before a plan, for a card whose goal depends on facts outside the repository (a Claude Code hook contract, a CLI's output format, a third-party API). One researcher, or several in parallel with distinct questions, write one cited note the planner and the builder work from; uncertainty is stated, never guessed. Invoked by /core-next, /doug-plan, and /doug-next before planning, or on its own.
|
|
4
|
+
allowed-tools: Agent, Read, Write, Bash(mkdir *), Bash(cat *), Bash(node *plan.mjs *)
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# research
|
|
8
|
+
|
|
9
|
+
Facts first. A plan built on a guessed contract becomes a task the verifier cannot pass and an adversary blocker nobody can fix; on 2026-09-06 the run-trace and precompact-anchor cards each needed the claude-code-guide agent ad hoc before their plans were right. This is the procedure that was missing.
|
|
10
|
+
|
|
11
|
+
## When to take it
|
|
12
|
+
|
|
13
|
+
Take the step when the card's goal (or the request) depends on a fact that is not in the repository and not in the conversation: the exact shape of a Claude Code hook input, the fields of a CLI's JSON output, a third-party API's behavior, a package's version constraints. Skip it when every fact the plan needs can be read from the checkout. When in doubt, take it: one researcher costs less than one blocked pass.
|
|
14
|
+
|
|
15
|
+
## Who runs it
|
|
16
|
+
|
|
17
|
+
- Questions about Claude Code itself (hooks, skills, agents, the Workflow tool, the SDK, the API): `Agent({ subagent_type: "claude-code-guide", prompt: "<the question>" })`. Reuse a guide agent already running in the session with SendMessage rather than spawning another. The fetch budget (research.maxFetches) counts per agent, so a reused guide shares one budget across every question sent to it; when a question needs its own budget, spawn a fresh guide instead. This agent keeps its own model.
|
|
18
|
+
- Anything else: the plugin's `researcher` agent, read-only with WebFetch and WebSearch, which answers one question from primary sources, quotes each source with its URL or the command and its output, never installs or writes, and marks what it could not confirm. It runs on the `plan` row, the same row the planner uses: read it with the `plan.mjs models` command, `node "${CLAUDE_PLUGIN_ROOT}/scripts/plan.mjs" models`, which prints the parsed table as JSON (`roles.plan.model`), and pass that row's model (omit `model` when the row says `inherit`): `Agent({ subagent_type: "doug-flow:researcher", model: "<the plan row's model>", prompt: "<the question>. Other researchers are answering: <their questions, if any>." })`. It returns findings, not a file; this skill writes the note. The Agent tool carries no effort parameter, so the row's effort applies through the researcher agent's own frontmatter (`effort: high`, the plan row's default); a repository whose plan row sets another effort changes that frontmatter line.
|
|
19
|
+
|
|
20
|
+
The session model never researches itself; it asks the questions and writes the note from the answers.
|
|
21
|
+
|
|
22
|
+
## One researcher or several
|
|
23
|
+
|
|
24
|
+
One question, one researcher. Several independent questions get several researchers in the same message, in parallel, each with one distinct question and told not to answer the others'; their answers merge into one note. A request or card that names a crew of researchers (`crew: { "researchers": 2 }` in the plan's terms) gets that many, each with its own question. Do not give two researchers the same question: a disagreement between two guesses is not a check. Each question names the budget (at most 6 WebSearch plus WebFetch calls, research.maxFetches) and lists the raw URLs to try, in priority order.
|
|
25
|
+
|
|
26
|
+
## The note
|
|
27
|
+
|
|
28
|
+
Write the findings to `.doug/.state/research/<card-id>.md` (session state, ignored by git; `mkdir -p` the directory first), one section per question:
|
|
29
|
+
|
|
30
|
+
- the fact, in one or two sentences, as the plan will use it;
|
|
31
|
+
- the sources: a URL, a file path with a line, or a command and its output, one per fact;
|
|
32
|
+
- what stayed unverified, marked `unverified`, with what was tried. Never guess a fact into the note; an unverified line is what keeps the planner from building on it.
|
|
33
|
+
|
|
34
|
+
The note is written under the card's id, not the question's, because the id is also the promotion key: a note for a card that lands is promoted to `docs/research/<card-id>.md`, `board.mjs record` copying it there when it records the landing so a commit that cites the note has something to read afterward. A note for a card that never lands (dropped, replanned under another id) stays in state and is eventually swept with the rest of `.doug/.state/`.
|
|
35
|
+
|
|
36
|
+
Then hand it on:
|
|
37
|
+
|
|
38
|
+
- Flow track (`/doug-plan`, `/doug-next`): give the planner the note's path in its prompt. The planner writes the facts it relied on into the plan's goal with their sources and marks any unverified one.
|
|
39
|
+
- Hand track (`/core-next`): the builder reads the note before the test, cites the sources in the commit message where a fact decided the design, and names the note in the landing's `--note`.
|
|
40
|
+
|
|
41
|
+
The step spends agents only when invoked and publishes nothing.
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: run-report
|
|
3
|
+
description: End a card's run with one command: append the docs/live-runs.md entry for a workflow report (or a hand-track landing), and print the three-line summary that goes in the chat. Called by /doug-next after land and by /core-next after the commit; usable on any saved report.
|
|
4
|
+
allowed-tools: Agent, Read, Bash
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# run-report
|
|
8
|
+
|
|
9
|
+
One card's landing, recorded and summarized. The entry and the summary are rendered by `scripts/board.mjs`, never written by hand, so every run is recorded in the same shape.
|
|
10
|
+
|
|
11
|
+
## A workflow run (flow track)
|
|
12
|
+
|
|
13
|
+
With the card id, the report (`.doug/.state/last-report.json` unless another path is given), the run id the Workflow tool printed (`wf_...`), the wall clock, and the landing commit:
|
|
14
|
+
|
|
15
|
+
1. `node "${CLAUDE_PLUGIN_ROOT}/scripts/cost.mjs" <run-id>`: the run's real cost, summed from the local Claude Code transcripts of every agent in the run and priced from the dated table in the script (no network). Its last lines are the run total and any agent it could not price. The number after `Run total:` is the cost; when the run cannot be found or every agent is unpriced, there is no cost. The workflow itself does not report cost; never estimate one. The Codex line after it, when present, is the Codex adversary's cost: pass its USD as --codex-cost <usd> to record and summary; it is never added to --cost.
|
|
16
|
+
2. Classify every adversary block in the report. A block is a finding the adversary raised as a blocker (its ledger id, `F1`; for a report from before the ledger, `pass-<n>`); `board.mjs record` refuses an id the report does not have and lists the ones it has. This is judgment work and runs on the `review` row: read it with the `plan.mjs models` command, `node "${CLAUDE_PLUGIN_ROOT}/scripts/plan.mjs" models` (`roles.review.model`, `roles.review.effort`), and spawn `Agent({ subagent_type: "doug-flow:reviewer", model: "<review row model>", prompt: "There is no worktree and no diff for this job: read the report at <report path> (repository root, read-only) and classify every adversary block in it as real (a defect a user would hit), marginal (true to the spec, no user impact), or false (wrong), each with a one-line reason drawn from the fix passes and the checks in the report, not from the adversary's summary. Return exactly one line per block, nothing else: F1=<real|marginal|false>: <one-line reason> (pass-<n>=... for a pre-ledger report). Edit nothing." })`. The lead passes each returned line into `--adversary` verbatim and never reclassifies.
|
|
17
|
+
3. `node "${CLAUDE_PLUGIN_ROOT}/scripts/board.mjs" record <id> <report.json> --wall "<m> min" --commit <sha> --cost <usd> [--codex-cost <usd>] --adversary "F1=<class>: <reason>"` with `--adversary` repeated once per block, leaving `--cost` out when step 1 gave no number and `--codex-cost` out when step 1 showed no Codex line. This appends the entry to `docs/live-runs.md`: the measures table with the precision line (n real / n marginal / n false), the per-level, per-task table, and one line per classified block. It also promotes `.doug/.state/research/<id>.md` to `docs/research/<id>.md` when that note exists, printing one line saying so; add that path to the landing commit alongside `docs/live-runs.md`.
|
|
18
|
+
4. `node "${CLAUDE_PLUGIN_ROOT}/scripts/memory.mjs" import`: rolls any auto-memory file written since the last import into the lessons store — it is idempotent, a rewritten file supersedes its old row, and it never writes under the auto-memory directory. Its one-line output goes in the chat; an exit 1 naming Node is said in the chat and the landing goes on, the same as record below.
|
|
19
|
+
5. `node "${CLAUDE_PLUGIN_ROOT}/scripts/memory.mjs" record <report.json> --run <run-id> --card <id> --commit <sha> --adversary "F1=<class>: <reason>"` with `--adversary` repeated once per block, the same values step 3 used, and `--commit` left out for a run that stopped. It appends one row per task of the report to the local outcome log `.doug/.state/memory/memory.db` (uncommitted; run id, card, spec hash, owned files from the plan, size, shape, models, verify and review results, the classified adversary blocks, fix passes, budget, tokens and USD measured from the same transcripts `cost.mjs` read, or null where nothing was measured). It needs Node >=22.16 (node:sqlite). When it exits 1 naming Node, say so in the chat and go on, since the record is a log, not a gate.
|
|
20
|
+
6. `node "${CLAUDE_PLUGIN_ROOT}/scripts/memory.mjs" reflect <report.json> --run <run-id> --card <id> --commit <sha> --adversary "F1=<class>: <reason>"` with `--adversary` repeated once per block, the same values step 5 used. It applies deterministic helpful/harmful counters to any lesson a task's `memoryUsed` names, then runs a cheap-row `claude -p --json-schema` pass that proposes and appends at most three lessons from the report, filtered in code. Its one-line summary (with the measured cost) goes in the chat. An exit 1 naming the LLM pass is said in the chat and the landing goes on regardless — reflect is a log, not a gate, the same as record.
|
|
21
|
+
7. `node "${CLAUDE_PLUGIN_ROOT}/scripts/board.mjs" summary <report.json> --wall "<m> min" --commit <sha> [--codex-cost <usd>]` (same `--cost` rule) and put its three lines in the chat verbatim, in a fenced code block: the outcome, the tasks, and what stopped or was not met.
|
|
22
|
+
|
|
23
|
+
A run that stopped is recorded the same way, without `--commit`; the summary's third line quotes each task's stop reason.
|
|
24
|
+
|
|
25
|
+
## A batch (several cards in one plan)
|
|
26
|
+
|
|
27
|
+
When `.doug/plan.json` carries `cards` (made by `plan.mjs merge`), the run is recorded once per card:
|
|
28
|
+
|
|
29
|
+
1. `node "${CLAUDE_PLUGIN_ROOT}/scripts/cost.mjs" <run-id> --by-card`: after the usual tables, a per-card table with each card's tasks' agents summed for that card and one row for the shared integration agents (the integrate and level-adversary agents, task `level-<n>`). The card rows are each card's `--cost`; the shared row is `--shared-cost`, the same number for every card. Pass the Codex line's USD as --codex-cost to the first card's record only.
|
|
30
|
+
2. Classify the adversary blocks per card: `board.mjs record` lists only that card's tasks' blocks and refuses the others' ids.
|
|
31
|
+
3. For each card, in the plan's `cards` order: `node "${CLAUDE_PLUGIN_ROOT}/scripts/board.mjs" record <id> <report.json> --wall "<m> min" --commit <sha> --cost <that card's usd> --shared-cost <shared usd> [--codex-cost <usd>, first card only] --adversary ...`. Record reads the batch from the plan file: the entry names the other cards, shows only that card's tasks and the integration rows of their levels, and counts the shared cost once, under the first card.
|
|
32
|
+
4. `node "${CLAUDE_PLUGIN_ROOT}/scripts/memory.mjs" import` once for the whole report, the same as the workflow-run form's step 4: its one-line output goes in the chat, an exit 1 naming Node is said in the chat and the landing goes on, and it is idempotent, a rewritten file supersedes its old row, and it never writes under the auto-memory directory.
|
|
33
|
+
5. `node "${CLAUDE_PLUGIN_ROOT}/scripts/memory.mjs" record <report.json> --run <run-id> --commit <sha> --adversary ...` once for the whole report, with every card's block classes (each task carries its card in a batch report; no `--card`).
|
|
34
|
+
6. `node "${CLAUDE_PLUGIN_ROOT}/scripts/memory.mjs" reflect <report.json> --run <run-id> --commit <sha> --adversary ...` once for the whole report, no `--card` (each appended lesson's card comes from its own task).
|
|
35
|
+
7. `node "${CLAUDE_PLUGIN_ROOT}/scripts/board.mjs" summary <report.json> --card <id> --wall "<m> min" --commit <sha>` per card (same `--cost` rule), and put each card's three lines in the chat. Its "Acceptance not met" line reads only that card's own tasks by their `[<card>] ` tag (or the final integration level's acceptance, when the report carries it), so another card's failing command, or a command that depends on a level not yet run, never shows as this card's; the line names which source it used.
|
|
36
|
+
|
|
37
|
+
## A hand-track landing
|
|
38
|
+
|
|
39
|
+
With the card id, the landing commit, the wall clock, and the gate line (`typecheck 0; unit <n> passed`):
|
|
40
|
+
|
|
41
|
+
1. `node "${CLAUDE_PLUGIN_ROOT}/scripts/board.mjs" record <id> --hand --commit <sha> --wall "<m> min" --gate "typecheck 0; unit <n> passed"`, with `--note "<one line>"` when something about the build is worth keeping. This appends the hand-track entry to `docs/live-runs.md`; its table is the summary. It also promotes `.doug/.state/research/<id>.md` to `docs/research/<id>.md` when that note exists, printing one line saying so; add that path to the landing commit alongside `docs/live-runs.md`.
|
|
42
|
+
2. `node "${CLAUDE_PLUGIN_ROOT}/scripts/memory.mjs" import`, the same as above: its one-line output goes in the chat, an exit 1 naming Node is said in the chat and the landing goes on, and it is idempotent, supersedes a rewritten file, and never writes under the auto-memory directory.
|
|
43
|
+
3. `node "${CLAUDE_PLUGIN_ROOT}/scripts/memory.mjs" record <id> --hand --commit <sha> --wall "<m> min" --gate "typecheck 0; unit <n> passed" [--note "<one line>"]`, the same values step 1 used. It records one row in the local outcome log `.doug/.state/memory/memory.db` (uncommitted), keyed `hand:<sha>` so re-recording the same commit updates that row and track `hand`; a card that lands twice, in two commits, gets two rows. Its workflow-only columns (verified, review counts, adversary verdict, blocks, fix passes, budget, tokens, USD, the report itself) are null because they do not exist on this track, never because they measured zero: no independent verifier ran, and the gate's own text is the `gate` column instead. It needs Node >=22.16 (node:sqlite). When it exits 1 naming Node, say so in the chat and go on, since the record is a log, not a gate.
|
|
44
|
+
|
|
45
|
+
`memory.mjs reflect` does not run on a hand-track landing: there is no report for the cheap-row pass to read.
|
|
46
|
+
|
|
47
|
+
Say the commit, the wall clock, and the gate line in the chat.
|
|
48
|
+
|
|
49
|
+
## Then
|
|
50
|
+
|
|
51
|
+
Moving the card and committing the record and the log belong to the calling skill (`/doug-next` step 5, `/core-next` step 4); a record change shows on the served page (`doug board serve`).
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: swarm-launch
|
|
3
|
+
description: Run an approved plan that opts into the swarm (plan.mjs set swarm on) through the doug-implement workflow, where a lead agent splits each full-shape task into worker briefs, workers implement them in parallel on the worker row, and the lead merges before the usual verify, review, adversary, and integrate stages. The launch step /doug-implement and /doug-swarm share; a swarm never runs without an approved plan.
|
|
4
|
+
allowed-tools: Bash(node *plan.mjs *), Workflow, Read
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# swarm-launch
|
|
8
|
+
|
|
9
|
+
The swarm lives inside a plan task (decision 0001 as amended 2026-09-06): the plan is the contract, the task's owned files are the workers' boundary, and the same gates read the merged result. This skill is the one launch step every caller shares, so the rules live in one place.
|
|
10
|
+
|
|
11
|
+
## Preconditions
|
|
12
|
+
|
|
13
|
+
1. `node "${CLAUDE_PLUGIN_ROOT}/scripts/plan.mjs" validate`: the plan must be `approved`. Nothing runs on a draft; approval is the user's act (`/doug-approve`), never this skill's.
|
|
14
|
+
2. `node "${CLAUDE_PLUGIN_ROOT}/scripts/plan.mjs" show` prints `Swarm: on` when the plan opted in with `plan.mjs set swarm on`. Without it the same workflow runs the fixed pipeline; do not set it here on your own, because the opt-in is the user's (each swarm task spends a lead, N workers, and a merge instead of one implementer). The swarm pays on a task with independent deliverables that share no new symbol; a plan of small coupled tasks runs as the pipeline (`docs/decisions/0001-hierarchical-swarms.md`, Amendment 2026-09-20: one brief per task at +2.67 USD and +6.1 min against the pipeline on 2026-09-11; five briefs, 8/8 hidden tests, 8.31 USD, 8.5 min on 2026-09-19).
|
|
15
|
+
3. The caller is a user-invoked skill or command (`/doug-implement`, `/doug-next`, `/doug-swarm`, `/core-next` for a size M or L hand-track card the user chose to swarm): that invocation is the opt-in the Workflow tool requires. No swarm runs in the background or on a schedule.
|
|
16
|
+
|
|
17
|
+
## Launch
|
|
18
|
+
|
|
19
|
+
`node "${CLAUDE_PLUGIN_ROOT}/scripts/plan.mjs" json`, then `Workflow({ name: "doug-flow:doug-implement", args: <plan object> })` (or `scriptPath: "${CLAUDE_PLUGIN_ROOT}/workflows/doug-implement.js"` when the name is not found). The plan object is passed verbatim; `swarm` travels in it.
|
|
20
|
+
|
|
21
|
+
## What happens per task
|
|
22
|
+
|
|
23
|
+
A size-S task keeps its single implementer. For every other task: the `lead` agent (the `lead` row of the Models table) creates the task branch and splits the task into briefs, each owning a disjoint subset of the task's files; a brief that names any other file blocks the task before a worker runs. The workers (`implementer` agents on the `worker` row, one worktree each, labels `worker:<task>:<n>`) implement their briefs in parallel and commit on `doug/task-<id>-w<n>`. The lead merges the branches into `doug/task-<id>`, runs the task's verify command, and returns an implementer result; verify, review, the adversary, the ledger, the budget, and integration run on it unchanged, and a fix pass is one implementer in the lead's worktree. The report records `workers` per task (brief, files, branch, commit, block) and the lead and worker tiers under `models`; `cost.mjs` shows each worker's cost. A deterministic shape gate keeps a full-shape task whose owned files are one source file plus its tests off the lead as well, and the lead's split always carries a required `splitReason` the report can read to tell an unsplittable task from one nobody tried to split. A worker that blocks gets the lead back once to re-brief the unfinished pieces (label `lead-rebrief:<task>`) before the task blocks; a worker still partial after its resume, or a second block, ends the task as before. `plan.mjs set workerCheck on` (off by default) adds a deterministic check after each round, before the merge: a worker whose filesTouched strayed outside its brief, or who never committed, is blocked the same way, with `checkFailed: true`.
|
|
24
|
+
|
|
25
|
+
## Report
|
|
26
|
+
|
|
27
|
+
Read the report as `/doug-implement` does. Name each task's briefs and which worker blocked when one did; a lead block says `lead brief <id> names a file the task does not own` when the split tried to widen, and the fix is a wider task at approval, never a wider brief.
|