@juzser/blacksmith 0.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 (172) hide show
  1. package/.claude/agents/auditor.md +146 -0
  2. package/.claude/agents/coder.md +164 -0
  3. package/.claude/agents/grader.md +110 -0
  4. package/.claude/agents/merger.md +107 -0
  5. package/.claude/agents/planner.md +92 -0
  6. package/.claude/agents/researcher.md +105 -0
  7. package/.claude/agents/reviewer.md +171 -0
  8. package/.claude/agents/scribe.md +72 -0
  9. package/.claude/agents/security-reviewer.md +130 -0
  10. package/.claude/agents/spec-reviewer.md +215 -0
  11. package/.claude/agents/tester.md +121 -0
  12. package/.claude/agents/uiux.md +126 -0
  13. package/.claude/agents/verifier.md +103 -0
  14. package/.claude/agents/wave-runner.md +74 -0
  15. package/LICENSE +21 -0
  16. package/README.md +389 -0
  17. package/factory/orchestrator/dist/actors.js +46 -0
  18. package/factory/orchestrator/dist/agents-registry.js +308 -0
  19. package/factory/orchestrator/dist/args.js +84 -0
  20. package/factory/orchestrator/dist/artifacts.js +111 -0
  21. package/factory/orchestrator/dist/attribution.js +160 -0
  22. package/factory/orchestrator/dist/audit.js +812 -0
  23. package/factory/orchestrator/dist/autonomy.js +151 -0
  24. package/factory/orchestrator/dist/budgetAlarm.js +366 -0
  25. package/factory/orchestrator/dist/budgets.js +196 -0
  26. package/factory/orchestrator/dist/claims.js +633 -0
  27. package/factory/orchestrator/dist/cli.js +3185 -0
  28. package/factory/orchestrator/dist/commit.js +152 -0
  29. package/factory/orchestrator/dist/coverage.js +188 -0
  30. package/factory/orchestrator/dist/crossFinding.js +479 -0
  31. package/factory/orchestrator/dist/crosscheck.js +396 -0
  32. package/factory/orchestrator/dist/daemon.js +707 -0
  33. package/factory/orchestrator/dist/db/projector.js +1317 -0
  34. package/factory/orchestrator/dist/db/queries.js +1714 -0
  35. package/factory/orchestrator/dist/db/schema.js +305 -0
  36. package/factory/orchestrator/dist/delegation.js +400 -0
  37. package/factory/orchestrator/dist/diffstat.js +164 -0
  38. package/factory/orchestrator/dist/dispatchAudit.js +275 -0
  39. package/factory/orchestrator/dist/dotenv.js +72 -0
  40. package/factory/orchestrator/dist/effort.js +202 -0
  41. package/factory/orchestrator/dist/epic.js +1018 -0
  42. package/factory/orchestrator/dist/epicWidth.js +238 -0
  43. package/factory/orchestrator/dist/errorIssues.js +249 -0
  44. package/factory/orchestrator/dist/errors.js +11 -0
  45. package/factory/orchestrator/dist/escalation.js +500 -0
  46. package/factory/orchestrator/dist/events.js +1015 -0
  47. package/factory/orchestrator/dist/findingAge.js +91 -0
  48. package/factory/orchestrator/dist/findingContext.js +103 -0
  49. package/factory/orchestrator/dist/findings.js +1156 -0
  50. package/factory/orchestrator/dist/gate.js +911 -0
  51. package/factory/orchestrator/dist/gh.js +146 -0
  52. package/factory/orchestrator/dist/git.js +87 -0
  53. package/factory/orchestrator/dist/goalCheck.js +380 -0
  54. package/factory/orchestrator/dist/graph.js +61 -0
  55. package/factory/orchestrator/dist/hookDecision.js +106 -0
  56. package/factory/orchestrator/dist/immutability.js +171 -0
  57. package/factory/orchestrator/dist/impact.js +280 -0
  58. package/factory/orchestrator/dist/integration.js +141 -0
  59. package/factory/orchestrator/dist/judgePreflight.js +155 -0
  60. package/factory/orchestrator/dist/judges.js +310 -0
  61. package/factory/orchestrator/dist/lessonAudit.js +399 -0
  62. package/factory/orchestrator/dist/lessons.js +1329 -0
  63. package/factory/orchestrator/dist/mcp.js +555 -0
  64. package/factory/orchestrator/dist/paths.js +82 -0
  65. package/factory/orchestrator/dist/plan.js +502 -0
  66. package/factory/orchestrator/dist/planQuorum.js +421 -0
  67. package/factory/orchestrator/dist/policy.js +1308 -0
  68. package/factory/orchestrator/dist/policyHook.js +28 -0
  69. package/factory/orchestrator/dist/preconditions.js +47 -0
  70. package/factory/orchestrator/dist/projects.js +134 -0
  71. package/factory/orchestrator/dist/prompts.js +57 -0
  72. package/factory/orchestrator/dist/provenance.js +201 -0
  73. package/factory/orchestrator/dist/providers/api-transport.js +117 -0
  74. package/factory/orchestrator/dist/providers/cli-transport.js +208 -0
  75. package/factory/orchestrator/dist/providers/index.js +54 -0
  76. package/factory/orchestrator/dist/providers/schema-validate.js +152 -0
  77. package/factory/orchestrator/dist/providers/types.js +49 -0
  78. package/factory/orchestrator/dist/queue.js +263 -0
  79. package/factory/orchestrator/dist/quorum.js +347 -0
  80. package/factory/orchestrator/dist/quorumEscalations.js +132 -0
  81. package/factory/orchestrator/dist/results.js +65 -0
  82. package/factory/orchestrator/dist/roadmap.js +437 -0
  83. package/factory/orchestrator/dist/runtime.js +86 -0
  84. package/factory/orchestrator/dist/sameMistakeKpi.js +243 -0
  85. package/factory/orchestrator/dist/sandbox.js +165 -0
  86. package/factory/orchestrator/dist/scaffold.js +373 -0
  87. package/factory/orchestrator/dist/scheduler.js +408 -0
  88. package/factory/orchestrator/dist/schemas.js +195 -0
  89. package/factory/orchestrator/dist/security.js +222 -0
  90. package/factory/orchestrator/dist/severity.js +293 -0
  91. package/factory/orchestrator/dist/spec.js +376 -0
  92. package/factory/orchestrator/dist/specChange.js +497 -0
  93. package/factory/orchestrator/dist/stack.js +324 -0
  94. package/factory/orchestrator/dist/symbols.js +966 -0
  95. package/factory/orchestrator/dist/taskEvents.js +399 -0
  96. package/factory/orchestrator/dist/taskId.js +126 -0
  97. package/factory/orchestrator/dist/taxonomy.js +113 -0
  98. package/factory/orchestrator/dist/testSelect.js +129 -0
  99. package/factory/orchestrator/dist/testerAudit.js +264 -0
  100. package/factory/orchestrator/dist/testgate.js +171 -0
  101. package/factory/orchestrator/dist/usage.js +874 -0
  102. package/factory/orchestrator/dist/waivers.js +228 -0
  103. package/factory/orchestrator/dist/waveBudget.js +223 -0
  104. package/factory/orchestrator/dist/waveConcurrency.js +250 -0
  105. package/factory/orchestrator/dist/waveNext.js +210 -0
  106. package/factory/orchestrator/dist/waveSchedule.js +146 -0
  107. package/factory/orchestrator/dist/worktree.js +207 -0
  108. package/factory/orchestrator/drizzle/0000_broken_rockslide.sql +183 -0
  109. package/factory/orchestrator/drizzle/0001_luxuriant_zaladane.sql +1 -0
  110. package/factory/orchestrator/drizzle/0002_yellow_wild_pack.sql +8 -0
  111. package/factory/orchestrator/drizzle/0003_damp_riptide.sql +12 -0
  112. package/factory/orchestrator/drizzle/0004_broad_lady_vermin.sql +1 -0
  113. package/factory/orchestrator/drizzle/0005_romantic_jocasta.sql +2 -0
  114. package/factory/orchestrator/drizzle/0006_bent_madelyne_pryor.sql +16 -0
  115. package/factory/orchestrator/drizzle/0007_overjoyed_goliath.sql +1 -0
  116. package/factory/orchestrator/drizzle/0008_smart_iron_patriot.sql +2 -0
  117. package/factory/orchestrator/drizzle/0009_agents_epic_id.sql +2 -0
  118. package/factory/orchestrator/drizzle/0010_milestone_kind.sql +1 -0
  119. package/factory/orchestrator/drizzle/meta/_journal.json +83 -0
  120. package/factory/policies/budgets.yml +262 -0
  121. package/factory/policies/crosscheck.yml +308 -0
  122. package/factory/policies/delegation.yml +44 -0
  123. package/factory/policies/effort.yml +142 -0
  124. package/factory/policies/guardrails.yml +306 -0
  125. package/factory/policies/lessons.md +239 -0
  126. package/factory/policies/scheduler.yml +90 -0
  127. package/factory/policies/sensitive-paths.yml +148 -0
  128. package/factory/policies/severity.yml +83 -0
  129. package/factory/policies/stack.yml +60 -0
  130. package/factory/policies/taxonomy.yml +340 -0
  131. package/factory/policies/worktree.yml +95 -0
  132. package/factory/scaffold/base/.github/workflows/ci.yml +34 -0
  133. package/factory/scaffold/base/.gitignore.tmpl +11 -0
  134. package/factory/scaffold/base/AGENTS.md +33 -0
  135. package/factory/scaffold/base/README.md +25 -0
  136. package/factory/scaffold/base/biome.json.tmpl +30 -0
  137. package/factory/scaffold/base/package.json +25 -0
  138. package/factory/scaffold/base/pnpm-workspace.yaml.tmpl +16 -0
  139. package/factory/scaffold/base/src/index.ts +4 -0
  140. package/factory/scaffold/base/test/index.test.ts +8 -0
  141. package/factory/scaffold/base/tsconfig.json +20 -0
  142. package/factory/scaffold/base/tsconfig.test.json +9 -0
  143. package/factory/scaffold/base/vitest.config.ts +29 -0
  144. package/factory/scaffold/mcp/mcp.manifest.json +22 -0
  145. package/factory/scaffold/mcp/package.fragment.json +9 -0
  146. package/factory/scaffold/mcp/src/mcp/README.md +63 -0
  147. package/factory/scaffold/mcp/src/mcp/guard.ts +110 -0
  148. package/factory/scaffold/mcp/src/mcp/redact.ts +69 -0
  149. package/factory/scaffold/mcp/src/mcp/server.ts +55 -0
  150. package/factory/scaffold/mcp/src/mcp/tools/health.ts +60 -0
  151. package/factory/scaffold/mcp/test/mcp/guard.test.ts +108 -0
  152. package/factory/scaffold/mcp/test/mcp/redact.test.ts +61 -0
  153. package/factory/scaffold/mcp/test/mcp/surface.test.ts +100 -0
  154. package/factory/scaffold/ui/index.html +12 -0
  155. package/factory/scaffold/ui/package.fragment.json +13 -0
  156. package/factory/scaffold/ui/src/App.vue +10 -0
  157. package/factory/scaffold/ui/src/main.ts +5 -0
  158. package/factory/scaffold/ui/src/shims.d.ts +11 -0
  159. package/factory/scaffold/ui/vite.config.ts +20 -0
  160. package/factory/scaffold/ui-tailwind/package.fragment.json +6 -0
  161. package/factory/scaffold/ui-tailwind/vite.config.ts +26 -0
  162. package/factory/specs/schema/event.schema.json +82 -0
  163. package/factory/specs/schema/finding-evidence.schema.json +45 -0
  164. package/factory/specs/schema/finding.schema.json +115 -0
  165. package/factory/specs/schema/grader-verdict.schema.json +50 -0
  166. package/factory/specs/schema/judge-verdict.schema.json +19 -0
  167. package/factory/specs/schema/lesson.schema.json +85 -0
  168. package/factory/specs/schema/mcp-manifest.schema.json +230 -0
  169. package/factory/specs/schema/result.schema.json +81 -0
  170. package/factory/specs/schema/spec-change-request.schema.json +46 -0
  171. package/factory/specs/schema/task-spec.schema.json +134 -0
  172. package/package.json +98 -0
package/README.md ADDED
@@ -0,0 +1,389 @@
1
+ <div align="center">
2
+
3
+ <img src="ui/src/assets/brand/black-smith.png" alt="Blacksmith" width="170" />
4
+
5
+ # Blacksmith
6
+
7
+ **An autonomous agent factory.**
8
+
9
+ You co-plan the spec. It decomposes, codes, tests, reviews, refutes itself —<br />
10
+ and hands you exactly one pull request.
11
+
12
+ [![CI](https://github.com/juzser/blacksmith/actions/workflows/ci.yml/badge.svg)](https://github.com/juzser/blacksmith/actions/workflows/ci.yml)
13
+ ![License](https://img.shields.io/badge/license-MIT-1f1f1f)
14
+ ![Node](https://img.shields.io/badge/node-%E2%89%A5%2022-1f1f1f)
15
+ ![TypeScript](https://img.shields.io/badge/TypeScript-1f1f1f)
16
+
17
+ **[Features](#features) · [Install](#install) · [Using it](#using-it) ·
18
+ [How it works](#how-it-works) · [Safety](#safety) · [Status](#status) ·
19
+ [Docs](#docs)**
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" />
22
+
23
+ <sub>The one screen that asks something of you. The rest is the factory reporting in.</sub>
24
+
25
+ </div>
26
+
27
+ ## Why Blacksmith
28
+
29
+ Handing a whole feature to an agent tends to fail in the same place, and it is
30
+ rarely the code. Two workers edit the same file. One quietly renegotiates the
31
+ goal it was given. A third reports itself done, and you find out in review. The
32
+ usual remedy is to watch it work — which costs exactly what the automation was
33
+ supposed to buy.
34
+
35
+ Blacksmith removes the watching instead. A goal becomes a set of immutable spec
36
+ contracts. Each contract runs in its own git worktree, under a token budget,
37
+ over paths no other worker is allowed to touch. What merges is decided by gates
38
+ — a schema check, tests, a reviewer that never saw the coder's session, and a
39
+ verifier whose only job is to refute the reviewer.
40
+
41
+ Your job shrinks to two touchpoints: **agree on the spec**, then **review one
42
+ pull request**. Everything in between runs unattended.
43
+
44
+ ## Features
45
+
46
+ <table>
47
+ <tr valign="top">
48
+ <td width="50%">
49
+
50
+ **Nothing is dispatched without a contract**
51
+
52
+ Every task carries an objective, an output schema, acceptance criteria, a tool
53
+ allowlist, the exact paths it may touch and a token budget. The plan is frozen
54
+ the moment you sign it and versioned in the event log, so a worker cannot
55
+ quietly reinterpret the job. No contract, no dispatch.
56
+
57
+ </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>
64
+
65
+ **Workers that cannot collide**
66
+
67
+ Path claims come from static analysis, not from epic prose. A wave is admitted
68
+ only once its tasks' claims are pairwise disjoint, which is what lets a whole
69
+ column run at the same time in separate worktrees; overlapping work serializes
70
+ instead. An edit outside a claim fails the gate rather than reaching the queue.
71
+
72
+ </td>
73
+ </tr>
74
+
75
+ <tr valign="top">
76
+ <td>
77
+
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
+ **Gates decide what merges, not confidence**
94
+
95
+ Schema check → tests → coverage evidence → a fresh-context reviewer that never
96
+ sees the coder's session → an adversarial verifier whose only job is to refute
97
+ the reviewer. S1 stops the line, S2 bounces back to the same branch, S3 batches
98
+ into one waiver question per epic. Only S3 and S4 are ever waivable.
99
+
100
+ </td>
101
+ </tr>
102
+
103
+ <tr valign="top">
104
+ <td>
105
+
106
+ **A second opinion from another vendor**
107
+
108
+ The factory grades its own judgment calls against models from a different
109
+ 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.
115
+
116
+ </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
+ </tr>
119
+
120
+ <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
+ <td>
123
+
124
+ **It learns from its own errors**
125
+
126
+ Errors are classified against a taxonomy, and a scribe distills them into
127
+ 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.
130
+
131
+ </td>
132
+ </tr>
133
+
134
+ <tr valign="top">
135
+ <td>
136
+
137
+ **The log is the source of truth**
138
+
139
+ Every prompt, dispatch, gate result and error is an append-only event on disk.
140
+ The dashboard is a projection of that log, and `smith db rebuild` reconstructs
141
+ the entire database from the log alone. Nothing the factory did exists only in
142
+ a chat transcript.
143
+
144
+ </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
+ </tr>
147
+ </table>
148
+
149
+ **Also in the box**
150
+
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
+ - **Project scaffolding.** `/bs new <project>` generates a target project from
156
+ the stack you answered for at install time; `/bs mcp` layers an MCP surface
157
+ onto it.
158
+ - **A factory that extends itself.** New agent roles, policies and taxonomy
159
+ values are data files, not code — see
160
+ [extending](docs/guide/extending.md).
161
+ - **One integration branch per epic**, one pull request at the end, merged by
162
+ you.
163
+
164
+ ## Install
165
+
166
+ ```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
171
+ ```
172
+
173
+ Verify it with the same gate CI runs (this one also needs `python3` + PyYAML):
174
+
175
+ ```bash
176
+ bash scripts/check.sh # ends in `== PASS ==` on a good install
177
+ ```
178
+
179
+ Driving a real epic additionally needs the **Claude Code CLI** — the planner and
180
+ every worker run as Claude Code sessions.
181
+
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.
187
+
188
+ ### From npm
189
+
190
+ The CLI alone is also on the registry as
191
+ [`@juzser/blacksmith`](https://www.npmjs.com/package/@juzser/blacksmith):
192
+
193
+ ```bash
194
+ npx @juzser/blacksmith --help # one-off
195
+ npm i -g @juzser/blacksmith && smith --help
196
+ ```
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.
206
+
207
+ ## Using it
208
+
209
+ ### Starting a new project
210
+
211
+ Blacksmith never builds inside itself. It builds a **separate project**, in
212
+ its own directory, with its own git history — and what comes out is not a
213
+ Blacksmith dependency. No config pointing back here, no docs about the
214
+ factory; one `Built by Blacksmith` line in its README is the whole trace.
215
+
216
+ Open a Claude Code session in this clone and say **`/bs new my-app`**. If you
217
+ would rather drive it yourself, it is three commands:
218
+
219
+ ```bash
220
+ $EDITOR factory/policies/stack.yml # your stack answers: language, frontend,
221
+ # database, deploy target. `none` is fine.
222
+ smith stack check # which answers the templates honour,
223
+ # which they only record, which they refuse
224
+ smith new my-app --target-dir ~/code/my-app # add --ui for a frontend
225
+ ```
226
+
227
+ The last call scaffolds (TS strict, Biome, Vitest, CI), installs, runs the
228
+ project's own gates, commits it on a `setup` branch, and registers a bootstrap
229
+ milestone. Read `toolchain` in the JSON it prints: `verified` means you may
230
+ plan against it. An answer the templates cannot build stops it **before
231
+ anything is created** rather than handing you something else.
232
+
233
+ Creating the remote and the first push are printed, not run — that is an
234
+ operator action, and no agent session here will do it for you:
235
+
236
+ ```bash
237
+ gh repo create my-app --private --source ~/code/my-app
238
+ git -C ~/code/my-app push -u origin setup
239
+ ```
240
+
241
+ Then `/bs plan <goal>` against it, and you are in the loop below. The MCP
242
+ surface comes later, at its own milestone (`/bs mcp my-app`), once there are
243
+ tools worth declaring.
244
+
245
+ → **[Step 0 of the operator loop](docs/guide/operator-loop.md)** has the same
246
+ ground with the failure modes spelled out.
247
+
248
+ ### Auditing an existing project
249
+
250
+ The other way in. A project that already exists — built here or not — is
251
+ audited, not scaffolded: say **`/bs audit <project-dir>`** and four judges read
252
+ it at `HEAD` on four fixed axes — performance, code quality, architecture,
253
+ security — from a detached, read-only worktree the command cuts and verifies
254
+ against its opening fingerprint before it removes it. The project's working
255
+ tree is never touched; the one thing the audit leaves behind is
256
+ `<project-dir>/.blacksmith/`, state rather than source, where the findings
257
+ accumulate across runs, so a second audit does not re-ask what the first one
258
+ settled — though a finding that comes back after its fix does, as a regression.
259
+
260
+ The returns are folded into one ranked list and **the command stops**. You
261
+ accept or decline each finding — a decline is remembered for 90 days — and
262
+ the accepted ones become one roadmap milestone and one epic spec. From there
263
+ it is the ordinary loop: `/bs plan` against that epic, then `/bs run`, and
264
+ closing the epic marks its findings fixed. There is no audit-specific run
265
+ path; the command's value is the insight and the ranking.
266
+
267
+ Underneath it is the `smith audit` family — `open`, `record`, `consolidate`,
268
+ `decide`, `cut`, `resolve`, `close` — and
269
+ [`docs/specs/audit-command-scope.md`](docs/specs/audit-command-scope.md) is the
270
+ contract each of them keeps.
271
+
272
+ ### The loop
273
+
274
+ Day to day, from a Claude Code session opened in this repo:
275
+
276
+ | Command | What it does |
277
+ |---|---|
278
+ | `/bs new <project> [--ui]` | Scaffold a new target project from your stack answers |
279
+ | `/bs mcp <project>` | Layer the MCP surface on and make its milestone due |
280
+ | `/bs audit <project-dir>` | Audit an existing project on four axes, rank, decide at a hard stop, cut one epic |
281
+ | `/bs plan <goal>` | Draft or re-plan an epic with the planner + spec-reviewer |
282
+ | `/bs run <epic>` | Admit a wave and drive it through the loop to merge |
283
+ | `/bs status` | Live agent count, budget burn, epic phase |
284
+ | `/bs ui` | Serve the local dashboard |
285
+ | `/bs waivers` | Answer the pending S3/S4 waiver batch for an epic |
286
+ | `/bs lessons` | Review pending lesson candidates |
287
+ | `/bs report` | Render the scribe's progress digest |
288
+
289
+ Underneath, every one of those is a `smith` command you can run yourself —
290
+ `smith --help` lists them all.
291
+
292
+ → **[The operator loop](docs/guide/operator-loop.md)** — the six steps, in the
293
+ order you meet them.<br />
294
+ → **[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.
298
+
299
+ ## How it works
300
+
301
+ You describe a goal. A planner on a frontier model turns it into spec contracts
302
+ and a spec-reviewer hunts holes in them *before* you sign; signing freezes plan
303
+ v1. From there the loop admits a wave whose path claims do not overlap, sends
304
+ researcher and UI/UX work ahead of code where the epic needs it, runs a coder
305
+ and a tester in a worktree, grades the result against its own acceptance
306
+ criteria, then puts it through the gates and a serial merge queue into
307
+ `smith/<epic>/integration`. One epic, one integration PR, merged by you.
308
+
309
+ → The pipeline diagram and the reasoning behind each stage:
310
+ **[architecture §3 — The loop](docs/specs/black-smith-architecture.md#3-the-loop)**.
311
+
312
+ ## Safety
313
+
314
+ Enforced mechanically — a `PreToolUse` policy layer on every command an agent
315
+ runs, plus branch protection — not by trust. Full rules:
316
+ **[`docs/standards/guardrails.md`](docs/standards/guardrails.md)**.
317
+
318
+ - **Secrets are environment-only.** `.env.example` is the only committed env
319
+ file (variable names, never values), and the event logger redacts
320
+ credential-shaped strings before write.
321
+ - **Only you merge to `main`.** No agent may push or merge to a protected
322
+ branch, and force-push is refused on every branch, protected or not — an
323
+ agent's pushed branch is append-only. Task branches reach the integration
324
+ branch solely through the serial merge queue.
325
+ - **No autonomous deploy or outbound sends.** Deploys, publishes and message
326
+ sends each need per-invocation approval.
327
+ - **Budgets are declared per role.** 4M tokens per epic with an alarm at 70%;
328
+ 150K tokens and 400 diff lines per coder task. Fan-out is bounded by the
329
+ claim graph, and `max_in_flight_tasks` is available on top of it, off by
330
+ default. Which of these *block* versus *report* is spelled out in
331
+ [`factory/policies/budgets.yml`](factory/policies/budgets.yml) — the task cap
332
+ reports on purpose.
333
+
334
+ Found a vulnerability? [`SECURITY.md`](SECURITY.md) — report privately, not in
335
+ a public issue.
336
+
337
+ ## Status
338
+
339
+ Phases 1–9 are built and merged: loop runner, worktree engine, gates, state and
340
+ analytics, dashboard, self-extension, cross-provider judges, hardening. Phase 10
341
+ is half in: `smith daemon` watches the factory in the background and its ops
342
+ runbook is written; the hosted UI stays deferred. Beside the phases, `/bs audit`
343
+ 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.
346
+
347
+ The one thing to know up front: **the daemon watches, it does not drive.** It
348
+ tells you what the factory needs — budget alarms, agents that never came back,
349
+ rechecks and cadences that are due — without an open session. Doing the work is
350
+ still `/bs run`, a playbook your Claude Code session follows; close the session
351
+ and nothing advances.
352
+
353
+ → **[What is built, what is not](docs/guide/status.md)**, and the unflinching
354
+ version in
355
+ [Limitations today](docs/guide/operator-guide.md#limitations-today).
356
+
357
+ ## Docs
358
+
359
+ | Doc | For |
360
+ |---|---|
361
+ | [`INSTALL.md`](INSTALL.md) | Getting it running, per platform |
362
+ | [`docs/guide/operator-loop.md`](docs/guide/operator-loop.md) | The six steps you actually do |
363
+ | [`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
+ | [`docs/guide/status.md`](docs/guide/status.md) | What is real today |
366
+ | [`docs/guide/extending.md`](docs/guide/extending.md) | Adding agents, policies, taxonomy values |
367
+ | [`docs/specs/black-smith-architecture.md`](docs/specs/black-smith-architecture.md) | Why it is shaped this way |
368
+ | [`docs/specs/audit-command-scope.md`](docs/specs/audit-command-scope.md) | What `/bs audit` promises an audited project, and why |
369
+ | [`docs/runbooks/providers.md`](docs/runbooks/providers.md) | Setting up the cross-provider judges |
370
+ | [`docs/runbooks/ops.md`](docs/runbooks/ops.md) | Running `smith daemon` unattended |
371
+ | [`docs/README.md`](docs/README.md) | Everything else, one line each |
372
+
373
+ Agents read [`AGENTS.md`](AGENTS.md) and [`CLAUDE.md`](CLAUDE.md) instead — this
374
+ repo is self-governing, and the rules it runs under live there.
375
+
376
+ ## Contributing
377
+
378
+ [`CONTRIBUTING.md`](CONTRIBUTING.md) has the details. Two things up front: the
379
+ gate is `bash scripts/check.sh` and it is the same script CI runs, so red
380
+ locally is red there; and several artifacts here are *generated* — see
381
+ [extending](docs/guide/extending.md) for which files you may hand-edit.
382
+
383
+ [`CODE_OF_CONDUCT.md`](CODE_OF_CONDUCT.md) ·
384
+ [`SECURITY.md`](SECURITY.md) ·
385
+ [`CHANGELOG.md`](CHANGELOG.md)
386
+
387
+ ## License
388
+
389
+ [MIT](LICENSE)
@@ -0,0 +1,46 @@
1
+ // Who counts as the operator.
2
+ //
3
+ // `actor` is a free string by schema (factory/specs/schema/event.schema.json:
4
+ // "Who emitted the event: 'user', 'system', an agent role, or a concrete
5
+ // agent_id"). Nothing validates it at write time and nothing enumerated it at
6
+ // read time, so every reader that needed to ask "did a person decide this?"
7
+ // answered it with a literal of its own. Two did, and they disagreed:
8
+ // `db/queries.ts`'s Decisions lens accepted only `'user'`, `lessons.ts`'s plan
9
+ // sign-off accepted only `'operator'`. Over the 668 events in the factory's own
10
+ // store, `'user'` appears zero times — so the lens was empty on every session
11
+ // ever recorded, while its sibling reader worked. This module is the one list
12
+ // both of them now read.
13
+ //
14
+ // Each entry says why it is here, because the set is a judgement about people
15
+ // and not a fact about the code:
16
+ //
17
+ // - 'user' — what waivers.ts, lessons.ts and prompts.ts default to when no
18
+ // actor is supplied, which is how every decision made through the UI is
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.
23
+ // - 'operator-skill' — what the operator's own console passes; 467 of the 668
24
+ // recorded events carry it. It is a skill rather than a person, and it is
25
+ // here anyway: it acts only on a turn the operator took, and the decision
26
+ // events it writes (11 waivers, 15 lesson transitions) are that person's.
27
+ //
28
+ // What stays out is the point of the guard: 'system' and the agent roles
29
+ // (planner, scribe, coder, …) keep writing events of decision-shaped types,
30
+ // and a lens that showed those would be reporting the factory's own traffic
31
+ // back to the operator as their own choices.
32
+ const OPERATOR_ACTORS = new Set(['user', 'operator', 'operator-skill']);
33
+ /**
34
+ * Was this event authored by the operator rather than by the factory?
35
+ *
36
+ * Ask this instead of comparing `actor` to a string. A new spelling belongs in
37
+ * OPERATOR_ACTORS above with its reason, where every reader picks it up at
38
+ * once — which is the whole difference between this and what it replaced.
39
+ */
40
+ export function isOperatorActor(actor) {
41
+ return actor !== null && actor !== undefined && OPERATOR_ACTORS.has(actor);
42
+ }
43
+ /** The vocabulary itself, for tests and for anything that needs to show it. */
44
+ export function operatorActors() {
45
+ return [...OPERATOR_ACTORS];
46
+ }