@juzser/blacksmith 0.1.0 → 0.2.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 (72) hide show
  1. package/.claude/agents/coder.md +9 -3
  2. package/.claude/agents/grader.md +13 -5
  3. package/.claude/agents/merger.md +2 -0
  4. package/.claude/agents/planner.md +22 -1
  5. package/.claude/agents/researcher.md +3 -1
  6. package/.claude/agents/reviewer.md +9 -2
  7. package/.claude/agents/security-reviewer.md +15 -7
  8. package/.claude/agents/spec-reviewer.md +12 -3
  9. package/.claude/agents/tester.md +5 -2
  10. package/.claude/agents/uiux.md +10 -3
  11. package/.claude/agents/verifier.md +8 -3
  12. package/.claude/skills/bs/SKILL.md +119 -0
  13. package/.claude/skills/bs/audit.md +252 -0
  14. package/.claude/skills/bs/dispatch.md +394 -0
  15. package/.claude/skills/bs/lessons.md +73 -0
  16. package/.claude/skills/bs/mcp.md +29 -0
  17. package/.claude/skills/bs/new.md +35 -0
  18. package/.claude/skills/bs/plan.md +172 -0
  19. package/.claude/skills/bs/report.md +129 -0
  20. package/.claude/skills/bs/run.md +327 -0
  21. package/.claude/skills/bs/status.md +54 -0
  22. package/.claude/skills/bs/ui.md +19 -0
  23. package/.claude/skills/bs/waivers.md +13 -0
  24. package/.claude/skills/bs/wave.md +267 -0
  25. package/README.md +136 -79
  26. package/factory/orchestrator/dist/actors.js +4 -3
  27. package/factory/orchestrator/dist/agents-registry.js +96 -19
  28. package/factory/orchestrator/dist/artifacts.js +36 -4
  29. package/factory/orchestrator/dist/budgets.js +7 -5
  30. package/factory/orchestrator/dist/claims.js +27 -1
  31. package/factory/orchestrator/dist/cli.js +196 -27
  32. package/factory/orchestrator/dist/crosscheck.js +11 -0
  33. package/factory/orchestrator/dist/daemon.js +30 -5
  34. package/factory/orchestrator/dist/db/projector.js +272 -90
  35. package/factory/orchestrator/dist/db/queries.js +83 -14
  36. package/factory/orchestrator/dist/db/schema.js +7 -0
  37. package/factory/orchestrator/dist/events.js +88 -4
  38. package/factory/orchestrator/dist/harness.js +516 -0
  39. package/factory/orchestrator/dist/impact.js +76 -5
  40. package/factory/orchestrator/dist/judges.js +49 -8
  41. package/factory/orchestrator/dist/lessons.js +4 -4
  42. package/factory/orchestrator/dist/mcp.js +4 -3
  43. package/factory/orchestrator/dist/paths.js +169 -15
  44. package/factory/orchestrator/dist/plan.js +61 -1
  45. package/factory/orchestrator/dist/planQuorum.js +36 -8
  46. package/factory/orchestrator/dist/providers/api-transport.js +62 -5
  47. package/factory/orchestrator/dist/providers/cli-transport.js +7 -73
  48. package/factory/orchestrator/dist/providers/index.js +1 -0
  49. package/factory/orchestrator/dist/providers/schema-validate.js +58 -7
  50. package/factory/orchestrator/dist/providers/types.js +5 -0
  51. package/factory/orchestrator/dist/roadmap.js +3 -3
  52. package/factory/orchestrator/dist/run-cli.js +130 -0
  53. package/factory/orchestrator/dist/runner.js +264 -0
  54. package/factory/orchestrator/dist/scaffold.js +3 -2
  55. package/factory/orchestrator/dist/spawn.js +84 -0
  56. package/factory/orchestrator/dist/stack.js +10 -2
  57. package/factory/orchestrator/dist/templateFragments.js +178 -0
  58. package/factory/orchestrator/dist/usage.js +30 -9
  59. package/factory/orchestrator/dist/waveNext.js +42 -14
  60. package/factory/orchestrator/dist/waveSchedule.js +7 -1
  61. package/factory/orchestrator/dist/workroot.js +113 -0
  62. package/factory/orchestrator/drizzle/0011_findings_spec_ref.sql +3 -0
  63. package/factory/orchestrator/drizzle/meta/_journal.json +7 -0
  64. package/factory/policies/budgets.yml +7 -4
  65. package/factory/policies/crosscheck.yml +10 -8
  66. package/factory/policies/harness.yml +82 -0
  67. package/factory/policies/lessons.md +122 -0
  68. package/factory/policies/severity.yml +1 -1
  69. package/factory/policies/taxonomy.yml +6 -2
  70. package/factory/specs/roadmap.md +154 -0
  71. package/factory/specs/schema/task-spec.schema.json +5 -0
  72. package/package.json +10 -7
@@ -0,0 +1,267 @@
1
+ # `/bs run` — the wave playbook
2
+
3
+ Steps 2-10 of the loop [`run.md`](run.md) opens at step 1. That file is
4
+ the epic tier: it admits one wave and closes the epic. This file is the
5
+ wave tier — worktrees to merge queue, one wave — and it is meant to be
6
+ thrown away when the wave lands.
7
+
8
+ **Read the console first.** `SKILL.md` and [`dispatch.md`](dispatch.md)
9
+ bind every dispatch below: the project directory is an answer you ask for
10
+ rather than a path anything here knows, every write carries
11
+ `--session <id> --plan-version <n> --causal-parent <event-id>`, every
12
+ dispatch carries the compiled lessons block and that task's open-findings
13
+ block, and fetched text is wrapped before it is quoted. None of it is
14
+ restated here; a second copy is a copy that drifts.
15
+
16
+ The step numbers are the loop's own. They start at 2 because step 1 — which
17
+ tasks, and how wide — was answered before you were handed anything, and they
18
+ stop at 10 because the epic's own gates resume there. Nothing in this file
19
+ decides what the next wave is, and nothing in it closes an epic.
20
+
21
+ ## You own the log for what you dispatch
22
+
23
+ This playbook runs in one of two shapes, and is written to be correct in
24
+ both:
25
+
26
+ - **Inline**, in the epic session, when the wave is small enough that the
27
+ epic's window can carry it. Nothing changes: the session id you were
28
+ handed is the one you write to.
29
+ - **In a session of its own** when it is not. Open one with `smith session
30
+ start <wave-id> --continues <event-id>` and write every dispatch below
31
+ there. The epic session then carries the admission and the result rather
32
+ than every turn in between — which is the point, because an epic outlives
33
+ its waves, and a window spent on this wave's dispatches is a window the
34
+ epic does not have for the wave after next (D13).
35
+
36
+ Which `<event-id>` depends on how you were started, and the difference is
37
+ not cosmetic — it is the edge an audit walks:
38
+
39
+ - **The epic ran you** and you opened a wave session yourself: continue from
40
+ the epic event that admitted this wave.
41
+ - **You were dispatched as a `wave-runner`**: continue from the
42
+ `dispatch_decision` that dispatched you, the event id handed to you with
43
+ the wave. `smith delegation check` resolves your session by matching a
44
+ `session-start`'s `causal_parent` against that dispatch, and it is the
45
+ only thing that proves the dispatches you are about to write are your
46
+ own log's rather than an agent talking about itself. Continue from
47
+ anything else and the check reports you as `unverifiable` — not as a
48
+ pass — however well the wave ran. Open it **before** your first dispatch,
49
+ for the same reason: a grant is earned by owning the log first.
50
+
51
+ Either way, one rule holds: **the log you write is the log the epic reads**,
52
+ and `--continues` is the whole of what makes that true. Every deciding read
53
+ at the epic tier folds the lineage rather than one session — `wave audit`,
54
+ `budget alarm`, `tester check`, `judge outstanding`, `escalation check`,
55
+ `dispatch check`, `delegation check` — so a dispatch recorded in a wave
56
+ session is visible from the epic session that admitted it, and is *not*
57
+ visible from a sibling wave's. Open a wave session without `--continues` and
58
+ none of those verbs can see your work: they will not error, they will answer
59
+ about a wave that appears never to have run.
60
+
61
+ **What you are handed**, and carry through every command below: the project
62
+ directory, the epic id, the live plan path, the admitted task ids, the
63
+ effort `profile` the epic resolved once at the top of its run, the session
64
+ id you write to, and the event id to hang the first dispatch off as
65
+ `--causal-parent`.
66
+
67
+ **What you hand back** when the wave lands: each task's terminal state, the
68
+ merge-queue outcome, every finding raised with its severity, any escalation
69
+ that reached the operator, and — if you opened one — the wave session id and
70
+ its last event id, so the epic session goes on chaining from where you
71
+ stopped.
72
+
73
+ ## Run the whole wave at once
74
+
75
+ The wave is the unit of work, not the task. Three rules follow, and they are
76
+ the difference between a factory and a queue with extra steps:
77
+
78
+ - **One message, many dispatches.** When steps 3–7 reach a phase, issue
79
+ that phase for *every* task in the wave as parallel tool calls in a
80
+ single message. Five coders in one message is five agents working; five
81
+ messages of one coder is five agents waiting. The worktrees are
82
+ disjoint by construction — that is what step 1's `wave check` certified
83
+ before you were handed the wave — so there is nothing for them to
84
+ collide over.
85
+ - **No lockstep barrier.** Each task walks 3 → 7 at its own pace. Do not
86
+ hold a finished coder until its neighbours finish theirs; dispatch its
87
+ tester the moment it returns. Waiting for the slowest task at every
88
+ phase boundary costs the wave the difference between its longest task
89
+ and the sum of its phases, which is most of what parallelism buys.
90
+ - **A blocked task blocks itself.** Gate outcome `blocked` bounces to
91
+ *that* task's coder (step 9) while its neighbours carry on. One task
92
+ escalating to the operator does not stop the other four; report it and
93
+ keep the wave moving.
94
+
95
+ The single place the wave rejoins is step 10's merge queue, which is
96
+ serial on purpose — `smith queue run` rebases one task at a time onto
97
+ `smith/<epic>/integration` and runs the cumulative tests between. Merging
98
+ is the one thing that cannot be done in parallel, and it is already the
99
+ one thing this playbook never asks you to.
100
+
101
+ ## The steps
102
+
103
+ 2. Per admitted task, and for all of them together: `smith worktree create
104
+ <project-dir> <epic> <task-id>`.
105
+ 3. Pre-code, if the task needs it: dispatch `researcher` for an unknown, or
106
+ `uiux` (`.claude/agents/uiux.md`) for any UI-affecting acceptance
107
+ criterion — before the coder starts, not after.
108
+ - `profile.preCodeResearch` gates the researcher: `when-needed` is the
109
+ line above, `never` (`small`) means the coder reading the repo *is* the
110
+ brief. An epic that genuinely cannot start without a research brief is
111
+ not a `small` epic — raise the tier rather than dispatching anyway.
112
+ - `profile.preCodeUiux` gates the uiux spec, and is `when-ui-criterion` at
113
+ every tier: no tier ships a UI change without a spec to review it
114
+ against. It is listed as a knob so the answer is asked for rather than
115
+ assumed, not because a tier can turn it off.
116
+ - A returned brief goes through `smith research check --brief <path>`
117
+ before it is attached to a task spec ("Fetched and quoted text goes into
118
+ a prompt fenced" above). Exit 1 sends it back; on exit 0, carry
119
+ `recommendation.provenance` into the coder's prompt so the task knows
120
+ whether its research rests on this repo or on a fetched page. Any raw
121
+ fetched text you quote alongside it is wrapped with `smith prompt wrap`.
122
+ 4. Dispatch **`coder`** (`.claude/agents/coder.md`) in that worktree.
123
+ Token/diff caps (`budgets.yml`: 150k tokens, 400 diff lines) and YAGNI
124
+ are the coder's own constraints — don't restate them here, the template
125
+ does. What the template does not read is the schema, so when the spec
126
+ carries `keeps_exports`, restate the promise in the dispatch in one line:
127
+ the file list, and "keep every existing export's name and declaration;
128
+ adding is fine".
129
+ 5. Dispatch **`tester`** (`.claude/agents/tester.md`) for missing unit
130
+ coverage and epic-level e2e/screenshots.
131
+ - Then the **uiux visual pass**, but only when all three hold: the task
132
+ is UI-affecting, the tester actually returned screenshot artifacts, and
133
+ step 3 wrote a uiux spec for this task (agent-interviews.md N-6). Miss
134
+ any one and skip it — say so; a "visual pass" over screenshots that do
135
+ not exist is worse than no pass. Dispatch it with the spec path and the
136
+ image paths and **nothing else**: no diff, no components, no test code.
137
+ The pass is a judgment about the rendered screen, and a uiux session
138
+ that reads the diff ends up reviewing intent, which the reviewer
139
+ already covers.
140
+ 6. Dispatch **`grader`** (`.claude/agents/grader.md`) — bounded rubric
141
+ loop, `profile.graderRounds` rounds (2 at `huge`, 1 below; never more
142
+ than 2, agent-constraints.md "grader (v3)"), before any gate
143
+ runs; it never decides pass/fail itself. At one round the grader scores
144
+ once and a failed criterion is the coder's bounce, not a re-grade. Its result file is an **input to
145
+ step 7**, not a note to the operator: pass it as `--grader` or the rubric
146
+ gates nothing (D-34).
147
+ 7. Run the gate pipeline:
148
+ `smith gate run <task-id> --worktree <dir> --checks checks.json --result
149
+ result.json --grader state/results/<task-id>.grader-r<round>.json
150
+ --findings findings.json --session ... --plan-version N
151
+ --causal-parent ...` (schema check → grader verdict → tests → coverage
152
+ evidence → findings intake → severity decision,
153
+ `docs/guide/operator-guide/queue-and-gate.md` §5).
154
+ - `--grader` takes step 6's file, latest round. A criterion that came back
155
+ `fail` or `partial` blocks before any check command runs — the outcome is
156
+ `blocked` with `reason: "grader-fail"`, and the payload's
157
+ `failed_criteria` is what you hand back to the coder.
158
+ - Name a check `coverage` and the gate reads
159
+ `coverage/coverage-summary.json` instead of scraping the text table,
160
+ which hides every file at 100% — including the file the task exists to
161
+ add (D-40). `blocked` with `reason: "coverage-evidence"` means the run
162
+ produced no per-file number for a file this task's claims name; fix the
163
+ reporter or the include glob, not the code. Ask the same question
164
+ outside a gate run with `smith coverage check <worktree-dir> --plan
165
+ <plan.json> --task <task-id>` (§5c).
166
+ - Findings come from dispatching **`reviewer`**
167
+ (`.claude/agents/reviewer.md`, fresh context, read-only) then
168
+ **`verifier`** (`.claude/agents/verifier.md`, adversarial refute
169
+ mandate) — never skip the adversarial stage on an S1/S2 finding
170
+ (`crosscheck.yml` `asymmetric_roles`). Which findings that covers is
171
+ `profile.verifierSeverities`, plus a
172
+ `profile.verifierS3SpotCheckRatio` sample of S3-minor: `[S1, S2]` + 0.2
173
+ at `huge`, `[S1, S2]` + 0 at `medium`, `[S1]` + 0 at `small`. The S3
174
+ sample is a calibration measurement on the reviewer, so it is the first
175
+ thing a cheaper tier drops; `S1-stop-the-line` is in every tier's list
176
+ and no tier may remove it. A finding outside the tier's list still goes
177
+ to the coder — it is verified by the coder's fix, not waived.
178
+ - Dispatch **`security-reviewer`** only when its conditional triggers
179
+ fire — never per-task by default. Ask, do not recall:
180
+ `smith security triggers --task <spec.json>` and dispatch iff
181
+ `dispatchSecurityReviewer` is true ("Dispatching the security-reviewer"
182
+ above).
183
+ - Every judge dispatched in steps 5–7 — uiux visual pass, grader,
184
+ reviewer, verifier, security-reviewer — is bracketed by
185
+ `smith worktree fingerprint` / `smith worktree verify`
186
+ ("Fingerprint the worktree around every judge" above). Exit 1 discards
187
+ that judge's result; it does not become a finding against the coder.
188
+ - Each of those is also bracketed by `smith judge dispatch` /
189
+ `smith judge report` ("Declare each judge's artifact before you dispatch
190
+ it" above). `smith judge outstanding --task <task-id>` exits 1 while any
191
+ judge still owes its file — re-poke it and report before running the
192
+ gate, because the gate now refuses to score with a non-empty outstanding
193
+ set (`reason: judges-outstanding`) rather than reading a silent judge as
194
+ zero findings.
195
+ - The gate scores tests it did not write, so once it has run, make the log
196
+ say who did: `smith tester check <session-id> --task <task-id>`
197
+ (`crosscheck.yml` `role_isolation`, operator-guide/dispatch-audits.md §2d). Exit 1
198
+ means no `tester` dispatch precedes this task's `testgate-result`, the
199
+ coder and tester dispatches share one `agent_id`, or the answer is
200
+ unknowable. A
201
+ coder that writes and runs its own tests grades itself and every gate
202
+ downstream still goes green — step 5 is what prevents that, and this is
203
+ the log checking that step 5 happened.
204
+ 8. Every dispatch in steps 3–7 carries the compiled lessons block for that
205
+ role (`smith lessons for-dispatch <role> --plan … --task …`), every
206
+ worktree dispatch also carries the open-findings block for that task
207
+ (`smith findings for-dispatch --plan … --task …`) — both under "Dispatch
208
+ contract" above — and each is a `dispatch_decision` event with a `causal_parent`
209
+ chaining back to the prompt/decision that caused it (architecture §7) —
210
+ this is the timeline, not optional bookkeeping.
211
+ 9. Gate outcome `blocked` → bounce to the coder on the **same branch**.
212
+ After 2 failed rounds on the same task, escalate model tier
213
+ automatically (mid → frontier, logged — `budgets.yml`
214
+ `escalation_ladder`); after 3, escalate to the operator. Never skip a
215
+ rung, never loop past one. Count the rounds from this task's
216
+ `dispatch_decision` events, not from the agent's own account of itself
217
+ — see "Round counting and escalation" above. Then have the log check
218
+ you: `smith escalation check <session-id> --task <task-id>`, which
219
+ exits 1 if the rung you just climbed is not evidenced.
220
+ 10. Gate outcome `pass`/`pass-with-waivers-pending` → before admitting,
221
+ ask what the diff did to everyone outside the claims, and whether it
222
+ kept what the spec promised:
223
+ `smith claims impact <worktree-dir> <spec.json>`. Exit 1 means a
224
+ `proven` break — this task removed an export a file outside its claims
225
+ still imports — **or a broken promise**: a file the spec's
226
+ `keeps_exports` names lost an export or changed one's declaration.
227
+ Either is a bounce to the coder, not a merge; quote the `promises`
228
+ entries in the bounce. A `possible` / `signature-changed` entry in
229
+ `breaks` exits 0 and is a note: the scanner reads text, not types
230
+ (operator-guide/wave.md §2). Then admit into the
231
+ merge queue: `smith queue run <epic> --project <project-dir>
232
+ --test-cmd "<cumulative test command>" --tasks tasks.json`. On a
233
+ `rebase-conflict` outcome, dispatch **`merger`**
234
+ (`.claude/agents/merger.md`) with both diffs + specs, and note three
235
+ things the queue's own behaviour forces (agent-interviews.md N-12):
236
+ - **Into the failing task's existing worktree** — a fresh one would not
237
+ reproduce the conflict. The result gives you only `taskId` and
238
+ `conflictingFiles`, so the path is the `worktreeDir` you wrote for
239
+ that task in `tasks.json`; carry it into the prompt yourself.
240
+ - **Claims = the queue's `conflictingFiles`**, verbatim. Anything else
241
+ the merger touches is a claim violation like any other.
242
+ - The queue already ran `git rebase --abort` (`queue.ts`), so the
243
+ merger arrives at a clean tree and **replays** the rebase rather than
244
+ resuming it — and it **never lands the merge**. When it returns
245
+ `resolution: "mechanical"`, re-run `smith queue run`; the queue stays
246
+ the single place a merge can happen.
247
+
248
+ `resolution: "escalated"` — low confidence, or both sides changed the
249
+ same logic — goes to the operator with the side-by-side. Never
250
+ auto-resolve a semantic conflict silently (`worktree.yml`
251
+ `conflict_resolution_ladder`).
252
+
253
+ Once the wave is merged, check the epic's spend — `smith budget alarm
254
+ <session-id> [--epic <epic>]`. Exit 1 means either the epic crossed
255
+ `alarm_ratio` (re-plan the remaining work to fit, or ask the operator —
256
+ extension is always an operator question) **or** the log is too holey to
257
+ rule a crossing out. Read the two numbers as what they are:
258
+ `measuredTokens` is a floor, never the bill (judges return findings, not
259
+ Results, so their tokens are in no event), and `projectedTokens` prices
260
+ every unmeasured dispatch at its `budgets.yml` cap. `unverifiable` with
261
+ `rolesWithoutCap` non-empty is a policy gap, not a spend problem: that
262
+ role has no cap to price it with. `unverifiable` with `tasksOverPrice`
263
+ non-empty means this epic has already been measured spending more on one
264
+ task than the projection charges an unmeasured dispatch, so its caps are
265
+ bounding nothing here (D-188) — the fix is to record the missing spend,
266
+ never to raise the cap until the number fits. Do not report an epic as
267
+ under budget on the strength of `measuredTokens` alone.
package/README.md CHANGED
@@ -15,12 +15,15 @@ and hands you exactly one pull request.
15
15
  ![TypeScript](https://img.shields.io/badge/TypeScript-1f1f1f)
16
16
 
17
17
  **[Features](#features) · [Install](#install) · [Using it](#using-it) ·
18
- [How it works](#how-it-works) · [Safety](#safety) · [Status](#status) ·
19
- [Docs](#docs)**
18
+ [How it works](#how-it-works) · [Safety](#safety) ·
19
+ [Dashboard](#the-dashboard) · [Status](#status) · [Docs](#docs)**
20
20
 
21
- <img src="ui/e2e/__screenshots__/phase-6b/overview-desktop-dark.png" width="900" alt="Blacksmith Overview page: a 'Needs you' banner reading '1 waiver pending, 1 task escalated', counters for active agents, budget used, epics in flight and alerts, and a 'Now running' list of two live sessions" />
21
+ <pre>
22
+ goal → contracts you sign → one worktree per contract, run in parallel
23
+ → schema · tests · reviewer · verifier → one pull request you merge
24
+ </pre>
22
25
 
23
- <sub>The one screen that asks something of you. The rest is the factory reporting in.</sub>
26
+ <sub>Two touchpoints. Everything between them runs unattended.</sub>
24
27
 
25
28
  </div>
26
29
 
@@ -55,12 +58,7 @@ the moment you sign it and versioned in the event log, so a worker cannot
55
58
  quietly reinterpret the job. No contract, no dispatch.
56
59
 
57
60
  </td>
58
- <td width="50%"><img src="ui/e2e/__screenshots__/phase-6b/task-detail-desktop-dark.png" width="100%" alt="Task detail page for epic-9/task-3 showing a Spec contract card with case, origin, epic, plan version and claims, and an Attempts list naming each agent, provider and outcome" /></td>
59
- </tr>
60
-
61
- <tr valign="top">
62
- <td><img src="ui/e2e/__screenshots__/phase-6b/flow-desktop-dark.png" width="100%" alt="Flow page: task cards arranged in three columns labelled Wave 0 (6 tasks), Wave 1 (2 tasks) and Wave 2 (1 task), joined by dashed dependency edges" /></td>
63
- <td>
61
+ <td width="50%">
64
62
 
65
63
  **Workers that cannot collide**
66
64
 
@@ -75,21 +73,6 @@ instead. An edit outside a claim fails the gate rather than reaching the queue.
75
73
  <tr valign="top">
76
74
  <td>
77
75
 
78
- **A frontier planner, cheap workers**
79
-
80
- Planning and judgment go to a frontier model; the bulk of the work goes to
81
- small, fast tiers, many at once. Every session and every live agent is visible
82
- with the tier that drew it, and analytics breaks cost down per task, per tier
83
- and per provider.
84
-
85
- </td>
86
- <td><img src="ui/e2e/__screenshots__/phase-6b/sessions-desktop-dark.png" width="100%" alt="Sessions page: two session cards, sess-fixture and sess-multiproject-fixture, joined by dashed edges to six live agent cards labelled coder - small, coder - mid and planner - frontier, each marked working" /></td>
87
- </tr>
88
-
89
- <tr valign="top">
90
- <td><img src="ui/e2e/__screenshots__/phase-6b/kanban-desktop-dark.png" width="100%" alt="Kanban board with Todo, In progress, Reviewing and Blocked columns; cards carry severity chips such as S2-major and agent chips such as coder - mid" /></td>
91
- <td>
92
-
93
76
  **Gates decide what merges, not confidence**
94
77
 
95
78
  Schema check → tests → coverage evidence → a fresh-context reviewer that never
@@ -98,41 +81,46 @@ the reviewer. S1 stops the line, S2 bounces back to the same branch, S3 batches
98
81
  into one waiver question per epic. Only S3 and S4 are ever waivable.
99
82
 
100
83
  </td>
101
- </tr>
102
-
103
- <tr valign="top">
104
84
  <td>
105
85
 
106
86
  **A second opinion from another vendor**
107
87
 
108
88
  The factory grades its own judgment calls against models from a different
109
89
  vendor — Codex over its CLI, DeepSeek over its API, beside the native Claude
110
- judge. They ship switched off — which of them a machine can actually
111
- call is a fact about that machine, not about this repo — and the one you
112
- switch on arrives in **shadow mode**: every verdict recorded, none of them
113
- gating anything, until you have read the numbers and promoted it
114
- deliberately.
90
+ judge. Both external judges ship `enabled: auto`: they join the quorum on a
91
+ machine that holds the credentials and are skipped on one that does not, so
92
+ which of them you get is a fact about your machine, not about this repo. A
93
+ judge earns its vote in **shadow mode** first — every verdict recorded, none
94
+ of them gating anything — and is promoted only once you have read the numbers.
115
95
 
116
96
  </td>
117
- <td><img src="ui/e2e/__screenshots__/phase-6b/analytics-desktop-dark.png" width="100%" alt="Analytics page with throughput, cost-per-task, same-mistake-rate and recheck-pass-rate cards, bar charts of cost by model tier and by provider, and a cross-check quorum panel" /></td>
118
97
  </tr>
119
98
 
120
99
  <tr valign="top">
121
- <td><img src="ui/e2e/__screenshots__/phase-6b/lessons-desktop-dark.png" width="100%" alt="Lessons page listing lesson candidates with scope and status chips, each with approve and reject actions" /></td>
122
100
  <td>
123
101
 
124
102
  **It learns from its own errors**
125
103
 
126
104
  Errors are classified against a taxonomy, and a scribe distills them into
127
105
  lesson candidates you approve or reject. Approved lessons splice into later
128
- prompts — and the same-mistake rate on the analytics page tells you whether
129
- that is actually working. A loop you can audit, not a memory you have to trust.
106
+ prompts — and the same-mistake rate tells you whether that is actually
107
+ working. A loop you can audit, not a memory you have to trust.
108
+
109
+ </td>
110
+ <td>
111
+
112
+ **A frontier planner, cheap workers**
113
+
114
+ Planning and judgment go to a frontier model; the bulk of the work goes to
115
+ small, fast tiers, many at once. Every session and every live agent is visible
116
+ with the tier that drew it, and cost breaks down per task, per tier and per
117
+ provider.
130
118
 
131
119
  </td>
132
120
  </tr>
133
121
 
134
122
  <tr valign="top">
135
- <td>
123
+ <td colspan="2">
136
124
 
137
125
  **The log is the source of truth**
138
126
 
@@ -142,67 +130,93 @@ the entire database from the log alone. Nothing the factory did exists only in
142
130
  a chat transcript.
143
131
 
144
132
  </td>
145
- <td><img src="ui/e2e/__screenshots__/phase-6b/timeline-desktop-dark.png" width="100%" alt="Timeline page: an event list filtered by Prompts, Dispatches, Gate events, Scheduler and Errors chips, showing task-added, user_prompt and session-start entries with timestamps and task ids" /></td>
146
133
  </tr>
147
134
  </table>
148
135
 
149
136
  **Also in the box**
150
137
 
151
- - **Eleven dashboard pages**, dark and light, desktop and mobile: errors by
152
- taxonomy category, roadmap progress joined to real task and token counts, and
153
- per-project scoping. It binds to `127.0.0.1` and is read-only — clicking
154
- nothing there dispatches an agent.
155
138
  - **Project scaffolding.** `/bs new <project>` generates a target project from
156
139
  the stack you answered for at install time; `/bs mcp` layers an MCP surface
157
140
  onto it.
141
+ - **An audit that ends in an epic.** `/bs audit <project-dir>` reads a project
142
+ that already exists on four axes, ranks what it finds, and cuts one epic from
143
+ what you accept.
158
144
  - **A factory that extends itself.** New agent roles, policies and taxonomy
159
145
  values are data files, not code — see
160
146
  [extending](docs/guide/extending.md).
161
147
  - **One integration branch per epic**, one pull request at the end, merged by
162
148
  you.
149
+ - **A local dashboard**, eleven read-only pages over the same event log —
150
+ optional, and [further down](#the-dashboard).
163
151
 
164
152
  ## Install
165
153
 
154
+ Say **"install Blacksmith"** to a Claude Code session and it does the whole
155
+ thing: [`INSTALL.md`](INSTALL.md) is an executable runbook, and it stops to ask
156
+ before anything that touches your machine.
157
+
158
+ By hand it is one command in a shell:
159
+
166
160
  ```bash
167
- git clone https://github.com/juzser/blacksmith.git && cd blacksmith
168
- pnpm install --frozen-lockfile
169
- pnpm run build # tsc -> factory/orchestrator/dist/
170
- node factory/orchestrator/dist/cli.js --help
161
+ npm i -g @juzser/blacksmith
171
162
  ```
172
163
 
173
- Verify it with the same gate CI runs (this one also needs `python3` + PyYAML):
164
+ and two inside Claude Code:
174
165
 
175
- ```bash
176
- bash scripts/check.sh # ends in `== PASS ==` on a good install
166
+ ```
167
+ /plugin marketplace add juzser/blacksmith
168
+ /plugin install blacksmith@blacksmith
177
169
  ```
178
170
 
179
- Driving a real epic additionally needs the **Claude Code CLI** — the planner and
180
- every worker run as Claude Code sessions.
171
+ Then `smith init` in the project you want it to work on. That creates
172
+ `.blacksmith/` beside your code — the event log, your epic plans, a roadmap and
173
+ a `stack.yml` to answer — and writes nothing anywhere else; `SMITH_HOME` moves
174
+ that root if you want one home for several projects. You now have `/bs`.
181
175
 
182
- **Rather not do this by hand?** Open a Claude Code session in the clone and say
183
- *"install Blacksmith"*. [`INSTALL.md`](INSTALL.md) is an executable runbook: it
184
- asks before touching anything outside the clone, and it doubles as the human
185
- version — per-platform setup (macOS, Debian/Ubuntu, Fedora, Alpine, WSL2),
186
- troubleshooting, and the known platform gaps stated rather than papered over.
176
+ **Both halves are required.** The package
177
+ ([`@juzser/blacksmith`](https://www.npmjs.com/package/@juzser/blacksmith)) is the
178
+ deterministic `smith` CLI; the plugin is `/bs` and the fourteen agent roles it
179
+ dispatches. `smith` alone never gives you `/bs`, because Claude Code loads
180
+ skills from a project's `.claude/`, your `~/.claude/`, or a plugin — never from
181
+ `node_modules` — and a `/bs` with no `smith` on PATH can run nothing. Take
182
+ `latest`: `0.1.0` predates `smith init` and keeps state inside its own install
183
+ directory, which the next `npm i` replaces.
187
184
 
188
- ### From npm
185
+ <details>
186
+ <summary><b>A clone instead — the whole factory</b></summary>
189
187
 
190
- The CLI alone is also on the registry as
191
- [`@juzser/blacksmith`](https://www.npmjs.com/package/@juzser/blacksmith):
188
+ A clone is for hacking on Blacksmith itself, and for the two things an install
189
+ does not carry: the dashboard and this repo's own enforcement.
192
190
 
193
191
  ```bash
194
- npx @juzser/blacksmith --help # one-off
195
- npm i -g @juzser/blacksmith && smith --help
192
+ git clone https://github.com/juzser/blacksmith.git && cd blacksmith
193
+ pnpm install --frozen-lockfile
194
+ pnpm run build # tsc -> factory/orchestrator/dist/
195
+ bash scripts/check.sh # the gate CI runs; ends in `== PASS ==`
196
196
  ```
197
197
 
198
- That package is the `smith` binary plus everything it reads at runtime — the
199
- policies, the JSON Schemas, the scaffold templates, the agent role files, the
200
- database migrations. It is **not** the whole factory: the `/bs` console, the
201
- dashboard, the docs and the roadmap stay in the clone, and a registry install
202
- keeps its state (`state/`, `factory/specs/active/`) under its own install
203
- directory rather than beside the project it is working on. Driving an epic
204
- still means a Claude Code session opened in a clone. Take the package when you
205
- want `smith` on a machine without a clone; take the clone for everything else.
198
+ Open a Claude Code session in the clone and you have `/bs` already, from the
199
+ checkout's own `.claude/` — **do not also install the plugin there.** You would
200
+ get two of everything (`bs` and `blacksmith:bs`, `auditor` and
201
+ `blacksmith:auditor`, once per role), pay the always-on cost twice, and the two
202
+ copies are free to disagree: the plugin's is a pinned checkout of `main`, the
203
+ project's is whatever branch you have out. `claude plugin disable blacksmith`
204
+ settles it.
205
+
206
+ The dashboard is clone-only because `ui/` is in neither the tarball nor the
207
+ plugin, so `smith ui serve` answers `ui.not-built` in an install and means it.
208
+ Enforcement is clone-only because this repo's `.claude/settings.json` deny
209
+ rules and its policy hook resolve paths against a checkout; the plugin ships no
210
+ `hooks/hooks.json` and loads neither (`Hooks (0)`), since a `/bs` that asked
211
+ you about every Bash command would be worse than one that asks about none. The
212
+ rest of that port is scoped in
213
+ [`docs/specs/plugin-port-scope.md`](docs/specs/plugin-port-scope.md).
214
+
215
+ `INSTALL.md` Part 2 is the long form of the clone above: per-platform
216
+ setup (macOS, Debian/Ubuntu, Fedora, Alpine, WSL2), the stack interview,
217
+ troubleshooting, and the known platform gaps stated rather than papered over.
218
+
219
+ </details>
206
220
 
207
221
  ## Using it
208
222
 
@@ -286,15 +300,16 @@ Day to day, from a Claude Code session opened in this repo:
286
300
  | `/bs lessons` | Review pending lesson candidates |
287
301
  | `/bs report` | Render the scribe's progress digest |
288
302
 
289
- Underneath, every one of those is a `smith` command you can run yourself —
290
- `smith --help` lists them all.
303
+ Each of those is a playbook, not a script: the deterministic half is a `smith`
304
+ command you can run yourself — `smith --help` lists all of them — and the
305
+ judgment half is a Claude Code session the playbook dispatches. That is also
306
+ the line between the two installs: the `smith` half travels in the package, the
307
+ playbooks are read from a clone.
291
308
 
292
309
  → **[The operator loop](docs/guide/operator-loop.md)** — the six steps, in the
293
310
  order you meet them.<br />
294
311
  → **[Operator guide](docs/guide/operator-guide.md)** — the same ground with real
295
- commands and real output.<br />
296
- → **[The dashboard](docs/guide/dashboard.md)** — what each of the eleven pages
297
- shows you.
312
+ commands and real output.
298
313
 
299
314
  ## How it works
300
315
 
@@ -334,6 +349,39 @@ runs, plus branch protection — not by trust. Full rules:
334
349
  Found a vulnerability? [`SECURITY.md`](SECURITY.md) — report privately, not in
335
350
  a public issue.
336
351
 
352
+ ## The dashboard
353
+
354
+ Optional, and deliberately small: `/bs ui` (or `smith ui serve`) binds eleven
355
+ read-only pages to `127.0.0.1`. They are a projection of the event log and
356
+ nothing else — `smith db rebuild` reconstructs them from it, `smith stats`
357
+ prints the same facts in a terminal, and nothing you click there dispatches an
358
+ agent. The factory runs without ever opening it.
359
+
360
+ <table>
361
+ <tr valign="top">
362
+ <td width="50%"><img src="ui/e2e/__screenshots__/phase-6b/overview-desktop-dark.png" width="100%" alt="Blacksmith Overview page: a 'Needs you' banner reading '1 waiver pending, 1 task escalated', counters for active agents, budget used, epics in flight and alerts, and a 'Now running' list of two live sessions" /><br /><sub><b>Overview</b> — the one screen that asks something of you.</sub></td>
363
+ <td width="50%"><img src="ui/e2e/__screenshots__/phase-6b/task-detail-desktop-dark.png" width="100%" alt="Task detail page for epic-9/task-3 showing a Spec contract card with case, origin, epic, plan version and claims, and an Attempts list naming each agent, provider and outcome" /><br /><sub><b>Task detail</b> — the contract, and every attempt against it.</sub></td>
364
+ </tr>
365
+ <tr valign="top">
366
+ <td><img src="ui/e2e/__screenshots__/phase-6b/flow-desktop-dark.png" width="100%" alt="Flow page: task cards arranged in three columns labelled Wave 0 (6 tasks), Wave 1 (2 tasks) and Wave 2 (1 task), joined by dashed dependency edges" /><br /><sub><b>Flow</b> — waves and the dependency edges that shaped them.</sub></td>
367
+ <td><img src="ui/e2e/__screenshots__/phase-6b/kanban-desktop-dark.png" width="100%" alt="Kanban board with Todo, In progress, Reviewing and Blocked columns; cards carry severity chips such as S2-major and agent chips such as coder - mid" /><br /><sub><b>Kanban</b> — what is moving, and what is stuck and why.</sub></td>
368
+ </tr>
369
+ <tr valign="top">
370
+ <td><img src="ui/e2e/__screenshots__/phase-6b/sessions-desktop-dark.png" width="100%" alt="Sessions page: two session cards, sess-fixture and sess-multiproject-fixture, joined by dashed edges to six live agent cards labelled coder - small, coder - mid and planner - frontier, each marked working" /><br /><sub><b>Sessions</b> — every live agent and the tier that drew it.</sub></td>
371
+ <td><img src="ui/e2e/__screenshots__/phase-6b/analytics-desktop-dark.png" width="100%" alt="Analytics page with throughput, cost-per-task, same-mistake-rate and recheck-pass-rate cards, bar charts of cost by model tier and by provider, and a cross-check quorum panel" /><br /><sub><b>Analytics</b> — cost per task, per tier, per provider, and the same-mistake rate.</sub></td>
372
+ </tr>
373
+ <tr valign="top">
374
+ <td><img src="ui/e2e/__screenshots__/phase-6b/lessons-desktop-dark.png" width="100%" alt="Lessons page listing lesson candidates with scope and status chips, each with approve and reject actions" /><br /><sub><b>Lessons</b> — candidates waiting on your approve or reject.</sub></td>
375
+ <td><img src="ui/e2e/__screenshots__/phase-6b/timeline-desktop-dark.png" width="100%" alt="Timeline page: an event list filtered by Prompts, Dispatches, Gate events, Scheduler and Errors chips, showing task-added, user_prompt and session-start entries with timestamps and task ids" /><br /><sub><b>Timeline</b> — the append-only log itself, filtered.</sub></td>
376
+ </tr>
377
+ </table>
378
+
379
+ Dark and light, desktop and mobile; errors by taxonomy category, roadmap
380
+ progress joined to real task and token counts, and per-project scoping.
381
+
382
+ → **[The dashboard](docs/guide/dashboard.md)** — what each of the eleven pages
383
+ shows you. It is part of the clone, not of the package.
384
+
337
385
  ## Status
338
386
 
339
387
  Phases 1–9 are built and merged: loop runner, worktree engine, gates, state and
@@ -341,8 +389,16 @@ analytics, dashboard, self-extension, cross-provider judges, hardening. Phase 10
341
389
  is half in: `smith daemon` watches the factory in the background and its ops
342
390
  runbook is written; the hosted UI stays deferred. Beside the phases, `/bs audit`
343
391
  is built: an existing project can be read on four axes and one epic cut from
344
- what you accept. And the CLI is on npm as `@juzser/blacksmith` — the binary and
345
- what it reads, not the console or the dashboard, which still run from a clone.
392
+ what you accept.
393
+
394
+ The CLI is on npm as `@juzser/blacksmith`, at `0.2.0` — two binaries now,
395
+ `smith` and `smith-run`, the second being what runs a rendered turn on a
396
+ `cli` harness such as Codex. `0.1.1` was the first version that ran beside
397
+ you and knew it was a package, rather than out of the clone-shaped install
398
+ `0.1.0` was. The package is the binaries and what they
399
+ read. The dashboard, the docs, the test suite and `/bs` itself come from a
400
+ clone; a plugin is what would move `/bs`, and it is
401
+ [scoped, not cut](docs/specs/plugin-port-scope.md).
346
402
 
347
403
  The one thing to know up front: **the daemon watches, it does not drive.** It
348
404
  tells you what the factory needs — budget alarms, agents that never came back,
@@ -352,7 +408,7 @@ and nothing advances.
352
408
 
353
409
  → **[What is built, what is not](docs/guide/status.md)**, and the unflinching
354
410
  version in
355
- [Limitations today](docs/guide/operator-guide.md#limitations-today).
411
+ [Limitations today](docs/guide/operator-guide/limitations.md#limitations-today).
356
412
 
357
413
  ## Docs
358
414
 
@@ -361,11 +417,12 @@ version in
361
417
  | [`INSTALL.md`](INSTALL.md) | Getting it running, per platform |
362
418
  | [`docs/guide/operator-loop.md`](docs/guide/operator-loop.md) | The six steps you actually do |
363
419
  | [`docs/guide/operator-guide.md`](docs/guide/operator-guide.md) | Every command, end to end, with output |
364
- | [`docs/guide/dashboard.md`](docs/guide/dashboard.md) | The dashboard tour |
365
420
  | [`docs/guide/status.md`](docs/guide/status.md) | What is real today |
366
421
  | [`docs/guide/extending.md`](docs/guide/extending.md) | Adding agents, policies, taxonomy values |
367
422
  | [`docs/specs/black-smith-architecture.md`](docs/specs/black-smith-architecture.md) | Why it is shaped this way |
368
423
  | [`docs/specs/audit-command-scope.md`](docs/specs/audit-command-scope.md) | What `/bs audit` promises an audited project, and why |
424
+ | [`docs/specs/plugin-port-scope.md`](docs/specs/plugin-port-scope.md) | How `/bs` runs without a clone, and what the plugin leaves behind |
425
+ | [`docs/guide/dashboard.md`](docs/guide/dashboard.md) | The dashboard tour |
369
426
  | [`docs/runbooks/providers.md`](docs/runbooks/providers.md) | Setting up the cross-provider judges |
370
427
  | [`docs/runbooks/ops.md`](docs/runbooks/ops.md) | Running `smith daemon` unattended |
371
428
  | [`docs/README.md`](docs/README.md) | Everything else, one line each |
@@ -17,9 +17,10 @@
17
17
  // - 'user' — what waivers.ts, lessons.ts and prompts.ts default to when no
18
18
  // actor is supplied, which is how every decision made through the UI is
19
19
  // attributed (ui/server never passes one).
20
- // - 'operator' — what docs/guide/operator-guide.md and .claude/skills/bs/
21
- // SKILL.md hand the operator, in all six of their `--actor` examples,
22
- // including the `smith waivers apply` line that writes waiver-granted.
20
+ // - 'operator' — what docs/guide/operator-guide/*.md and .claude/skills/bs/
21
+ // SKILL.md hand the operator, in every `--actor` example they carry (three
22
+ // today), including the `smith waivers apply` line in
23
+ // severity-and-budget.md that writes waiver-granted.
23
24
  // - 'operator-skill' — what the operator's own console passes; 467 of the 668
24
25
  // recorded events carry it. It is a skill rather than a person, and it is
25
26
  // here anyway: it acts only on a turn the operator took, and the decision