@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.
- package/.claude/agents/auditor.md +146 -0
- package/.claude/agents/coder.md +164 -0
- package/.claude/agents/grader.md +110 -0
- package/.claude/agents/merger.md +107 -0
- package/.claude/agents/planner.md +92 -0
- package/.claude/agents/researcher.md +105 -0
- package/.claude/agents/reviewer.md +171 -0
- package/.claude/agents/scribe.md +72 -0
- package/.claude/agents/security-reviewer.md +130 -0
- package/.claude/agents/spec-reviewer.md +215 -0
- package/.claude/agents/tester.md +121 -0
- package/.claude/agents/uiux.md +126 -0
- package/.claude/agents/verifier.md +103 -0
- package/.claude/agents/wave-runner.md +74 -0
- package/LICENSE +21 -0
- package/README.md +389 -0
- package/factory/orchestrator/dist/actors.js +46 -0
- package/factory/orchestrator/dist/agents-registry.js +308 -0
- package/factory/orchestrator/dist/args.js +84 -0
- package/factory/orchestrator/dist/artifacts.js +111 -0
- package/factory/orchestrator/dist/attribution.js +160 -0
- package/factory/orchestrator/dist/audit.js +812 -0
- package/factory/orchestrator/dist/autonomy.js +151 -0
- package/factory/orchestrator/dist/budgetAlarm.js +366 -0
- package/factory/orchestrator/dist/budgets.js +196 -0
- package/factory/orchestrator/dist/claims.js +633 -0
- package/factory/orchestrator/dist/cli.js +3185 -0
- package/factory/orchestrator/dist/commit.js +152 -0
- package/factory/orchestrator/dist/coverage.js +188 -0
- package/factory/orchestrator/dist/crossFinding.js +479 -0
- package/factory/orchestrator/dist/crosscheck.js +396 -0
- package/factory/orchestrator/dist/daemon.js +707 -0
- package/factory/orchestrator/dist/db/projector.js +1317 -0
- package/factory/orchestrator/dist/db/queries.js +1714 -0
- package/factory/orchestrator/dist/db/schema.js +305 -0
- package/factory/orchestrator/dist/delegation.js +400 -0
- package/factory/orchestrator/dist/diffstat.js +164 -0
- package/factory/orchestrator/dist/dispatchAudit.js +275 -0
- package/factory/orchestrator/dist/dotenv.js +72 -0
- package/factory/orchestrator/dist/effort.js +202 -0
- package/factory/orchestrator/dist/epic.js +1018 -0
- package/factory/orchestrator/dist/epicWidth.js +238 -0
- package/factory/orchestrator/dist/errorIssues.js +249 -0
- package/factory/orchestrator/dist/errors.js +11 -0
- package/factory/orchestrator/dist/escalation.js +500 -0
- package/factory/orchestrator/dist/events.js +1015 -0
- package/factory/orchestrator/dist/findingAge.js +91 -0
- package/factory/orchestrator/dist/findingContext.js +103 -0
- package/factory/orchestrator/dist/findings.js +1156 -0
- package/factory/orchestrator/dist/gate.js +911 -0
- package/factory/orchestrator/dist/gh.js +146 -0
- package/factory/orchestrator/dist/git.js +87 -0
- package/factory/orchestrator/dist/goalCheck.js +380 -0
- package/factory/orchestrator/dist/graph.js +61 -0
- package/factory/orchestrator/dist/hookDecision.js +106 -0
- package/factory/orchestrator/dist/immutability.js +171 -0
- package/factory/orchestrator/dist/impact.js +280 -0
- package/factory/orchestrator/dist/integration.js +141 -0
- package/factory/orchestrator/dist/judgePreflight.js +155 -0
- package/factory/orchestrator/dist/judges.js +310 -0
- package/factory/orchestrator/dist/lessonAudit.js +399 -0
- package/factory/orchestrator/dist/lessons.js +1329 -0
- package/factory/orchestrator/dist/mcp.js +555 -0
- package/factory/orchestrator/dist/paths.js +82 -0
- package/factory/orchestrator/dist/plan.js +502 -0
- package/factory/orchestrator/dist/planQuorum.js +421 -0
- package/factory/orchestrator/dist/policy.js +1308 -0
- package/factory/orchestrator/dist/policyHook.js +28 -0
- package/factory/orchestrator/dist/preconditions.js +47 -0
- package/factory/orchestrator/dist/projects.js +134 -0
- package/factory/orchestrator/dist/prompts.js +57 -0
- package/factory/orchestrator/dist/provenance.js +201 -0
- package/factory/orchestrator/dist/providers/api-transport.js +117 -0
- package/factory/orchestrator/dist/providers/cli-transport.js +208 -0
- package/factory/orchestrator/dist/providers/index.js +54 -0
- package/factory/orchestrator/dist/providers/schema-validate.js +152 -0
- package/factory/orchestrator/dist/providers/types.js +49 -0
- package/factory/orchestrator/dist/queue.js +263 -0
- package/factory/orchestrator/dist/quorum.js +347 -0
- package/factory/orchestrator/dist/quorumEscalations.js +132 -0
- package/factory/orchestrator/dist/results.js +65 -0
- package/factory/orchestrator/dist/roadmap.js +437 -0
- package/factory/orchestrator/dist/runtime.js +86 -0
- package/factory/orchestrator/dist/sameMistakeKpi.js +243 -0
- package/factory/orchestrator/dist/sandbox.js +165 -0
- package/factory/orchestrator/dist/scaffold.js +373 -0
- package/factory/orchestrator/dist/scheduler.js +408 -0
- package/factory/orchestrator/dist/schemas.js +195 -0
- package/factory/orchestrator/dist/security.js +222 -0
- package/factory/orchestrator/dist/severity.js +293 -0
- package/factory/orchestrator/dist/spec.js +376 -0
- package/factory/orchestrator/dist/specChange.js +497 -0
- package/factory/orchestrator/dist/stack.js +324 -0
- package/factory/orchestrator/dist/symbols.js +966 -0
- package/factory/orchestrator/dist/taskEvents.js +399 -0
- package/factory/orchestrator/dist/taskId.js +126 -0
- package/factory/orchestrator/dist/taxonomy.js +113 -0
- package/factory/orchestrator/dist/testSelect.js +129 -0
- package/factory/orchestrator/dist/testerAudit.js +264 -0
- package/factory/orchestrator/dist/testgate.js +171 -0
- package/factory/orchestrator/dist/usage.js +874 -0
- package/factory/orchestrator/dist/waivers.js +228 -0
- package/factory/orchestrator/dist/waveBudget.js +223 -0
- package/factory/orchestrator/dist/waveConcurrency.js +250 -0
- package/factory/orchestrator/dist/waveNext.js +210 -0
- package/factory/orchestrator/dist/waveSchedule.js +146 -0
- package/factory/orchestrator/dist/worktree.js +207 -0
- package/factory/orchestrator/drizzle/0000_broken_rockslide.sql +183 -0
- package/factory/orchestrator/drizzle/0001_luxuriant_zaladane.sql +1 -0
- package/factory/orchestrator/drizzle/0002_yellow_wild_pack.sql +8 -0
- package/factory/orchestrator/drizzle/0003_damp_riptide.sql +12 -0
- package/factory/orchestrator/drizzle/0004_broad_lady_vermin.sql +1 -0
- package/factory/orchestrator/drizzle/0005_romantic_jocasta.sql +2 -0
- package/factory/orchestrator/drizzle/0006_bent_madelyne_pryor.sql +16 -0
- package/factory/orchestrator/drizzle/0007_overjoyed_goliath.sql +1 -0
- package/factory/orchestrator/drizzle/0008_smart_iron_patriot.sql +2 -0
- package/factory/orchestrator/drizzle/0009_agents_epic_id.sql +2 -0
- package/factory/orchestrator/drizzle/0010_milestone_kind.sql +1 -0
- package/factory/orchestrator/drizzle/meta/_journal.json +83 -0
- package/factory/policies/budgets.yml +262 -0
- package/factory/policies/crosscheck.yml +308 -0
- package/factory/policies/delegation.yml +44 -0
- package/factory/policies/effort.yml +142 -0
- package/factory/policies/guardrails.yml +306 -0
- package/factory/policies/lessons.md +239 -0
- package/factory/policies/scheduler.yml +90 -0
- package/factory/policies/sensitive-paths.yml +148 -0
- package/factory/policies/severity.yml +83 -0
- package/factory/policies/stack.yml +60 -0
- package/factory/policies/taxonomy.yml +340 -0
- package/factory/policies/worktree.yml +95 -0
- package/factory/scaffold/base/.github/workflows/ci.yml +34 -0
- package/factory/scaffold/base/.gitignore.tmpl +11 -0
- package/factory/scaffold/base/AGENTS.md +33 -0
- package/factory/scaffold/base/README.md +25 -0
- package/factory/scaffold/base/biome.json.tmpl +30 -0
- package/factory/scaffold/base/package.json +25 -0
- package/factory/scaffold/base/pnpm-workspace.yaml.tmpl +16 -0
- package/factory/scaffold/base/src/index.ts +4 -0
- package/factory/scaffold/base/test/index.test.ts +8 -0
- package/factory/scaffold/base/tsconfig.json +20 -0
- package/factory/scaffold/base/tsconfig.test.json +9 -0
- package/factory/scaffold/base/vitest.config.ts +29 -0
- package/factory/scaffold/mcp/mcp.manifest.json +22 -0
- package/factory/scaffold/mcp/package.fragment.json +9 -0
- package/factory/scaffold/mcp/src/mcp/README.md +63 -0
- package/factory/scaffold/mcp/src/mcp/guard.ts +110 -0
- package/factory/scaffold/mcp/src/mcp/redact.ts +69 -0
- package/factory/scaffold/mcp/src/mcp/server.ts +55 -0
- package/factory/scaffold/mcp/src/mcp/tools/health.ts +60 -0
- package/factory/scaffold/mcp/test/mcp/guard.test.ts +108 -0
- package/factory/scaffold/mcp/test/mcp/redact.test.ts +61 -0
- package/factory/scaffold/mcp/test/mcp/surface.test.ts +100 -0
- package/factory/scaffold/ui/index.html +12 -0
- package/factory/scaffold/ui/package.fragment.json +13 -0
- package/factory/scaffold/ui/src/App.vue +10 -0
- package/factory/scaffold/ui/src/main.ts +5 -0
- package/factory/scaffold/ui/src/shims.d.ts +11 -0
- package/factory/scaffold/ui/vite.config.ts +20 -0
- package/factory/scaffold/ui-tailwind/package.fragment.json +6 -0
- package/factory/scaffold/ui-tailwind/vite.config.ts +26 -0
- package/factory/specs/schema/event.schema.json +82 -0
- package/factory/specs/schema/finding-evidence.schema.json +45 -0
- package/factory/specs/schema/finding.schema.json +115 -0
- package/factory/specs/schema/grader-verdict.schema.json +50 -0
- package/factory/specs/schema/judge-verdict.schema.json +19 -0
- package/factory/specs/schema/lesson.schema.json +85 -0
- package/factory/specs/schema/mcp-manifest.schema.json +230 -0
- package/factory/specs/schema/result.schema.json +81 -0
- package/factory/specs/schema/spec-change-request.schema.json +46 -0
- package/factory/specs/schema/task-spec.schema.json +134 -0
- 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
|
+
[](https://github.com/juzser/blacksmith/actions/workflows/ci.yml)
|
|
13
|
+

|
|
14
|
+

|
|
15
|
+

|
|
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
|
+
}
|