@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.
- package/.claude/agents/coder.md +9 -3
- package/.claude/agents/grader.md +13 -5
- package/.claude/agents/merger.md +2 -0
- package/.claude/agents/planner.md +22 -1
- package/.claude/agents/researcher.md +3 -1
- package/.claude/agents/reviewer.md +9 -2
- package/.claude/agents/security-reviewer.md +15 -7
- package/.claude/agents/spec-reviewer.md +12 -3
- package/.claude/agents/tester.md +5 -2
- package/.claude/agents/uiux.md +10 -3
- package/.claude/agents/verifier.md +8 -3
- package/.claude/skills/bs/SKILL.md +119 -0
- package/.claude/skills/bs/audit.md +252 -0
- package/.claude/skills/bs/dispatch.md +394 -0
- package/.claude/skills/bs/lessons.md +73 -0
- package/.claude/skills/bs/mcp.md +29 -0
- package/.claude/skills/bs/new.md +35 -0
- package/.claude/skills/bs/plan.md +172 -0
- package/.claude/skills/bs/report.md +129 -0
- package/.claude/skills/bs/run.md +327 -0
- package/.claude/skills/bs/status.md +54 -0
- package/.claude/skills/bs/ui.md +19 -0
- package/.claude/skills/bs/waivers.md +13 -0
- package/.claude/skills/bs/wave.md +267 -0
- package/README.md +136 -79
- package/factory/orchestrator/dist/actors.js +4 -3
- package/factory/orchestrator/dist/agents-registry.js +96 -19
- package/factory/orchestrator/dist/artifacts.js +36 -4
- package/factory/orchestrator/dist/budgets.js +7 -5
- package/factory/orchestrator/dist/claims.js +27 -1
- package/factory/orchestrator/dist/cli.js +196 -27
- package/factory/orchestrator/dist/crosscheck.js +11 -0
- package/factory/orchestrator/dist/daemon.js +30 -5
- package/factory/orchestrator/dist/db/projector.js +272 -90
- package/factory/orchestrator/dist/db/queries.js +83 -14
- package/factory/orchestrator/dist/db/schema.js +7 -0
- package/factory/orchestrator/dist/events.js +88 -4
- package/factory/orchestrator/dist/harness.js +516 -0
- package/factory/orchestrator/dist/impact.js +76 -5
- package/factory/orchestrator/dist/judges.js +49 -8
- package/factory/orchestrator/dist/lessons.js +4 -4
- package/factory/orchestrator/dist/mcp.js +4 -3
- package/factory/orchestrator/dist/paths.js +169 -15
- package/factory/orchestrator/dist/plan.js +61 -1
- package/factory/orchestrator/dist/planQuorum.js +36 -8
- package/factory/orchestrator/dist/providers/api-transport.js +62 -5
- package/factory/orchestrator/dist/providers/cli-transport.js +7 -73
- package/factory/orchestrator/dist/providers/index.js +1 -0
- package/factory/orchestrator/dist/providers/schema-validate.js +58 -7
- package/factory/orchestrator/dist/providers/types.js +5 -0
- package/factory/orchestrator/dist/roadmap.js +3 -3
- package/factory/orchestrator/dist/run-cli.js +130 -0
- package/factory/orchestrator/dist/runner.js +264 -0
- package/factory/orchestrator/dist/scaffold.js +3 -2
- package/factory/orchestrator/dist/spawn.js +84 -0
- package/factory/orchestrator/dist/stack.js +10 -2
- package/factory/orchestrator/dist/templateFragments.js +178 -0
- package/factory/orchestrator/dist/usage.js +30 -9
- package/factory/orchestrator/dist/waveNext.js +42 -14
- package/factory/orchestrator/dist/waveSchedule.js +7 -1
- package/factory/orchestrator/dist/workroot.js +113 -0
- package/factory/orchestrator/drizzle/0011_findings_spec_ref.sql +3 -0
- package/factory/orchestrator/drizzle/meta/_journal.json +7 -0
- package/factory/policies/budgets.yml +7 -4
- package/factory/policies/crosscheck.yml +10 -8
- package/factory/policies/harness.yml +82 -0
- package/factory/policies/lessons.md +122 -0
- package/factory/policies/severity.yml +1 -1
- package/factory/policies/taxonomy.yml +6 -2
- package/factory/specs/roadmap.md +154 -0
- package/factory/specs/schema/task-spec.schema.json +5 -0
- package/package.json +10 -7
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
# across months of runs. Changing the taxonomy is a PR that bumps `version` —
|
|
10
10
|
# never a runtime write. Analytics may group only by taxonomy dimensions.
|
|
11
11
|
|
|
12
|
-
version:
|
|
12
|
+
version: 10
|
|
13
13
|
|
|
14
14
|
# ── Work classification ─────────────────────────────────────────────
|
|
15
15
|
case: [feature, bugfix, refactor, research, spec-review, recheck,
|
|
@@ -24,11 +24,15 @@ origin: [user, inferred, recheck, lesson, escalation]
|
|
|
24
24
|
# ── Actors ──────────────────────────────────────────────────────────
|
|
25
25
|
agent: [planner, spec-reviewer, researcher, coder, tester, grader,
|
|
26
26
|
reviewer, verifier, security-reviewer, merger, scribe, uiux,
|
|
27
|
-
wave-runner, auditor]
|
|
27
|
+
wave-runner, auditor, operator]
|
|
28
28
|
# wave-runner — the only role delegation.yml grants `Agent`: it
|
|
29
29
|
# runs one wave of .claude/skills/bs/wave.md in its own session
|
|
30
30
|
# auditor — one axis of `/bs audit` (performance, code-quality or
|
|
31
31
|
# architecture); the security axis dispatches security-reviewer
|
|
32
|
+
# operator — the human, as a `found_by`: a defect read off the code
|
|
33
|
+
# by a person. Never dispatched — no template, no budget, no
|
|
34
|
+
# delegation grant, no judge turn — so nothing that counts
|
|
35
|
+
# rounds or pairs roles ever sees it (dogfood-csb-audit-1 FD-21)
|
|
32
36
|
|
|
33
37
|
provider: [claude, codex, deepseek]
|
|
34
38
|
model_tier: [frontier, mid, small] # fable/opus · sonnet · haiku
|
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
# Blacksmith — Roadmap
|
|
2
|
+
|
|
3
|
+
<!-- PLANNED-NAMESPACE: loop -->
|
|
4
|
+
|
|
5
|
+
A milestone names the surface it will ship before it ships it; the marker
|
|
6
|
+
above is how `docCommands.test.ts` is told, and it fails once `loop` is a
|
|
7
|
+
namespace the CLI declares.
|
|
8
|
+
|
|
9
|
+
Source of truth for the Overview/Roadmap dashboard pages' milestone
|
|
10
|
+
progress (`docs/specs/black-smith-architecture.md` §10, §16 "Build order").
|
|
11
|
+
Parsed by `factory/orchestrator/src/roadmap.ts`; projected into the
|
|
12
|
+
`milestones` table by `factory/orchestrator/src/db/projector.ts` and joined
|
|
13
|
+
with task/token stats by `factory/orchestrator/src/db/queries.ts`'s
|
|
14
|
+
`roadmapPage()`/`overview()`.
|
|
15
|
+
|
|
16
|
+
Four `envkit` milestones — bootstrap, config loader, MCP surface, MCP
|
|
17
|
+
follow-up — were struck from this file 2026-09-04: this clone's
|
|
18
|
+
`workspaces/` is empty and the only envkit checkout lives in a sibling
|
|
19
|
+
clone, so a project declared here could not be reached from here. The
|
|
20
|
+
removed rows are preserved verbatim, not lost, in
|
|
21
|
+
`docs/specs/dogfood-4-findings.md` (D-271).
|
|
22
|
+
|
|
23
|
+
Each milestone is a `## <name>` heading followed by bullet fields:
|
|
24
|
+
`id` (required, stable), `status` (required — `planned` | `in-progress` |
|
|
25
|
+
`completed`), `goal` (optional, one sentence), `epics` (optional, `[]` when
|
|
26
|
+
no epic has been mapped to this phase yet — the join yields zero tasks
|
|
27
|
+
until an epic is tagged here), `project` (optional, defaults to
|
|
28
|
+
`black-smith` — this clone), `kind` (optional — `factory` | `dogfood` |
|
|
29
|
+
`product`), and `error_issues` (optional — `on` | `off`).
|
|
30
|
+
|
|
31
|
+
`kind` describes the *project*, not the milestone, so one bullet anywhere in
|
|
32
|
+
a project's milestones settles all of them; a second copy would only be a
|
|
33
|
+
copy that drifts. It defaults to `factory` for `black-smith` and `product`
|
|
34
|
+
for everything else, which is why a project registered by `smith new` needs
|
|
35
|
+
no bullet at all. `dogfood` is the one value that must be written by hand:
|
|
36
|
+
a project built to exercise the factory looks, in the data, exactly like a
|
|
37
|
+
project built for its own sake — the difference is intent. The Roadmap page
|
|
38
|
+
shows `product` by default and hides the other two, so an operator asking
|
|
39
|
+
"what has this factory built" is not reading past the factory's own phases.
|
|
40
|
+
|
|
41
|
+
`error_issues` says whether the factory may open issues on a project's own
|
|
42
|
+
tracker for its build-time errors. Like `kind`, it describes the *project*
|
|
43
|
+
while being written on a milestone, so one bullet settles every milestone
|
|
44
|
+
naming that project. It defaults to `on`, so no project needs the bullet at
|
|
45
|
+
all; write `- error_issues: off` by hand to opt a project's tracker out.
|
|
46
|
+
|
|
47
|
+
## Phase 1 — Interview + standards
|
|
48
|
+
- id: phase-1
|
|
49
|
+
- status: completed
|
|
50
|
+
- epics: []
|
|
51
|
+
- goal: Run the operator interview; compile stack.md and per-agent constraint blocks; pin the scaffold.
|
|
52
|
+
|
|
53
|
+
## Phase 2 — Skeleton + contracts
|
|
54
|
+
- id: phase-2
|
|
55
|
+
- status: completed
|
|
56
|
+
- epics: []
|
|
57
|
+
- goal: Repo layout, spec/result/finding/lesson JSON Schemas, taxonomy.yml, agent templates.
|
|
58
|
+
|
|
59
|
+
## Phase 3 — Loop runner + worktree engine
|
|
60
|
+
- id: phase-3
|
|
61
|
+
- status: completed
|
|
62
|
+
- epics: []
|
|
63
|
+
- goal: Dispatch from specs, path-claim validation, worktree lifecycle, serial merge queue, event log.
|
|
64
|
+
|
|
65
|
+
## Phase 4 — Gates
|
|
66
|
+
- id: phase-4
|
|
67
|
+
- status: completed
|
|
68
|
+
- epics: []
|
|
69
|
+
- goal: Test gate, reviewer/verifier chain, severity policy, waiver flow.
|
|
70
|
+
|
|
71
|
+
## Phase 5 — State + analytics
|
|
72
|
+
- id: phase-5
|
|
73
|
+
- status: completed
|
|
74
|
+
- epics: []
|
|
75
|
+
- goal: SQLite projections, timeline, live agent registry.
|
|
76
|
+
|
|
77
|
+
## Phase 6 — UI (HDS)
|
|
78
|
+
- id: phase-6
|
|
79
|
+
- status: completed
|
|
80
|
+
- epics: []
|
|
81
|
+
- goal: Overview + timeline + kanban first (6a); lessons/errors/analytics second (6b). Local-only shipped; Cloudflare port moved to Phase 9.
|
|
82
|
+
|
|
83
|
+
## Phase 7 — Self-extension
|
|
84
|
+
- id: phase-7
|
|
85
|
+
- status: completed
|
|
86
|
+
- epics: []
|
|
87
|
+
- goal: Inferred tasks + confidence policy, scheduler, rechecks, lessons compilation loop, /bs operator skill. Dispatch stays skill-guided — the always-on daemon is Phase 9.
|
|
88
|
+
|
|
89
|
+
## Phase 8 — Cross-provider judges
|
|
90
|
+
- id: phase-8
|
|
91
|
+
- status: completed
|
|
92
|
+
- epics: []
|
|
93
|
+
- goal: Provider adapters (codex CLI, deepseek API), quorum policy, disagreement analytics, shadow-mode calibration. All four crosscheck.yml quorum_triggers have a host: blocking-finding and same-mistake fire automatically from gate.ts; epic-final-verdict (`smith epic verdict`) and plan-quorum (`smith plan quorum`, critique-only) are operator-invoked. Neither external provider ships `enabled: false`. `providers.codex` ships `enabled: auto` with `mode: active`. `providers.deepseek` ships `enabled: auto` with `mode: active` — phase 8 shipped it in shadow, and the operator promoted it on 2026-09-14 after the calibration pass that mode exists for. `auto` means the transport decides — `codex` on PATH, or `DEEPSEEK_API_KEY` set — so on a box that has one, a quorum trigger reaches it with no further operator action. Promotion gates *power*, not invocation: a `shadow` verdict is recorded and decides nothing. And with two active external judges against `quorum_rule.min_providers: 2`, a box that resolves both still reaches quorum after `finder_ne_critic` excludes the finder, while a box that resolves one is a gating pool of one, so a blocking finding escalates to the operator with both rationales rather than being decided — which is what `accept_non_gating_actives: true` buys and says it buys. Promotion procedure: docs/runbooks/providers.md.
|
|
94
|
+
|
|
95
|
+
## Phase 9 — Hardening
|
|
96
|
+
- id: phase-9
|
|
97
|
+
- status: completed
|
|
98
|
+
- epics: []
|
|
99
|
+
- goal: Escalation ladders, budget alarms, same-mistake KPI, the MCP surface standard, and the enforcement gaps specced in `docs/specs/phase-9-punch-list.md` (P9-1..P9-37, all fixed — close-out and the deliberate leftovers are in that file's "Phase 9 close-out" section). P9-1..P9-7 came from the subagent interviews: lessons approve/reject verb, dispatch-time lesson injection, postRunCheck split, a host for sensitive-paths.yml, the judge worktree-immutability guard, prompt-injection hardening, cross-session event edges. P9-8..P9-30 came from running a real epic end to end (see `docs/specs/dogfood-envkit-findings.md`, D-14..D-48) — the highest-value three being producers for the five task-status events that have none (D-46/P9-29, which subsumes the task-id convention of D-28), checks that run at the integration root rather than only inside task worktrees (D-42/P9-26), and an epic close that is both a logged fact and a folded projection (D-43/D-44/P9-27). P9-31..P9-37 came from the fixes themselves: two of them colliding (P9-31), the goal line's own escalation ladder turning out to be policy prose nothing parsed (P9-32, now counted from the log by `smith escalation check`), `epic.alarm_ratio` having no consumer (P9-33, now `smith budget alarm`), the same-mistake KPI having no instrument (`smith kpi same-mistake`), the novelty gate having no hand-authored entry point and being an exact-duplicate detector at its defaults (P9-34/P9-35), the UI's lesson-edit route being a third ungated door into memory (P9-36), and the taxonomy being hand-copied into four files that had all drifted (P9-37). The MCP surface standard (`docs/standards/mcp.md`, `smith mcp init|check`, hard-gated at epic close) also landed here, from the operator decisions of 2026-08-07 rather than from a punch-list item. Moved to Phase 10, untouched: runbooks beyond `docs/runbooks/providers.md`, the Cloudflare port, and the dispatch daemon. `epics: []` is accurate rather than unfilled — the phase was driven as punch-list items on branches, not as a planned epic.
|
|
100
|
+
|
|
101
|
+
## Phase 10 — Deployment + ops
|
|
102
|
+
- id: phase-10
|
|
103
|
+
- status: completed
|
|
104
|
+
- epics: [phase-10]
|
|
105
|
+
- goal: The three items Phase 9 carried on its goal line. Two landed, one stays deferred. **Ops runbook** — `docs/runbooks/ops.md`, so the factory can be operated without reading the operator guide end to end. **The background process** (moved from Phase 7, then Phase 9) — shipped as `smith daemon`, and shipped deliberately narrower than the "always-on dispatch daemon" the earlier phases named: it is a *watcher*. It folds the event log on an interval and reports budgets, stale agents, due rechecks and due cadences, so that *knowing* what the factory needs no longer requires an open session; it never dispatches an agent, never enters the merge queue, and never writes outside `state/daemon/` and the derived SQLite read-model. Dispatch stays skill-guided through `/bs` — architecture §12, not a gap. **The Cloudflare port of the UI** (moved from Phase 6, then Phase 9) is no longer carried here: the operator struck it to its own `planned` milestone on 2026-09-04 (`cloudflare-port`, below), so this phase closes on what it built rather than on what it deferred for a fourth time. What remains of Phase 10 comes from the four-axis mandate and is specced in `docs/specs/phase-10-scope.md` — six items, and by operator decision of 2026-09-04 they run as a real epic on this repo rather than as branch-by-branch punch-list items, because exercising the factory on itself is the only thing that turns a built instrument into an observed one. P10-2 shipped ahead of that decision as `fix/a-value-nobody-read-back` (D-269), being a wrong operational fact in the first document an operator reads.
|
|
106
|
+
|
|
107
|
+
## Cloudflare port of the UI
|
|
108
|
+
- id: cloudflare-port
|
|
109
|
+
- status: planned
|
|
110
|
+
- epics: []
|
|
111
|
+
- goal: A Cloudflare port of the dashboard — Workers/Pages + D1 + Access. Carried on the goal line of Phase 6, then Phase 9, then Phase 10 without ever being specced, and struck to its own milestone by operator decision 2026-09-04 so that Phase 10 closes on what it built. Nothing is designed yet: the dashboard is local-only, the two Cloudflare release commands are deny-listed for agents by `.claude/settings.json`, and no upload path exists for the SQLite read-model every page reads. `docs/specs/black-smith-architecture.md` §16 files it under "Hardening" and never gave it a phase of its own, which is how it survived three moves — this milestone is the first place it is a thing to plan rather than a thing to postpone.
|
|
112
|
+
|
|
113
|
+
## Factory error log — GitHub issues
|
|
114
|
+
- id: factory-error-log
|
|
115
|
+
- status: planned
|
|
116
|
+
- epics: [factory-error-log]
|
|
117
|
+
- goal: When the factory fails while building a project, open a GitHub issue in that project's repo. Requested by the operator 2026-09-04, and scoped by their answer to the fork the request contained: the errors reported are **the factory's own build-time errors** — a gate that returns `blocked`, a task that reaches `task_status: failed`, and every `error-logged` event — not runtime errors of the shipped product. **No code is injected into a generated project**: a project this factory builds carries no reporter, no dependency and no trace of Blacksmith beyond the "Built by blacksmith" line in its README, which is the whole point of the factory contract, so the issue is opened by the factory's own side through `gh issue create` against the project's remote. **Default ON, with a per-project disable switch** — a project that does not want its issue tracker written to says so once and the mechanism stays silent for it. Deliberately not scoped here and left to the plan: which of the three sources deduplicates against an already-open issue, what the issue body may carry given that event payloads can quote logs and diffs (`docs/standards/guardrails.md` "Secrets, keys, tokens" governs, and nothing may reach an issue unredacted), and whether the daemon or the run itself is the producer. Runs as its own epic after `phase-10` closes, by operator decision — not folded into that phase's plan.
|
|
118
|
+
|
|
119
|
+
## Claude status bar — audit wave 1 (signing, hardening, Keychain ACL)
|
|
120
|
+
- id: csb-audit-1
|
|
121
|
+
- status: completed
|
|
122
|
+
- epics: [csb-audit-1]
|
|
123
|
+
- project: claude-status-bar-macos
|
|
124
|
+
- kind: product
|
|
125
|
+
- goal: The first epic cut from the four-axis audit of 2026-09-07 (45 findings, 0 S1, 9 S2, 29 S3, 7 S4; axes fixed by the operator as performance, code quality, architecture, security). Scope chosen by the operator: the security and build cluster only, because it is the one cluster that is already doing damage rather than only risking it, and because it touches no UI and no `AppState`, so it cannot regress the menu bar. Four items. **SEC-2 (S2)** `scripts/ensure-signing-identity.sh:56` calls `security set-key-partition-list -S apple-tool:,apple:,codesign: -s "$LOGIN_KEYCHAIN"`; `-s` is a predicate that takes no operand, so the keychain path is swallowed as a positional and the command rewrites the partition list of *every* signing private key in the login keychain, destroying `teamid:` partitions irreversibly — triggered by an ordinary `make app` on any machine that does not yet have the identity — the call sits inside the `find-certificate` creation branch opened at line 23 — which is every fresh machine, every new user account, and every keychain reset. The fix is to bound it with `-l "$SIGNING_IDENTITY_NAME"`. **SEC-3 (S2)** `scripts/make-app.sh:80` signs with neither hardened runtime nor entitlements, verified on the shipped artifact rather than inferred: `flags=0x0(none)`, `TeamIdentifier=not set`, `(no entitlements)`, and `DYLD_INSERT_LIBRARIES` honoured — which is what makes the Keychain ACL below borrowable by any process that can inject. **SEC-1 (S2)** `LiveCredentialWriter.swift:121-141` grants a Keychain ACL to a path fed to `SecTrustedApplicationCreateFromPath` with no signature check; two of three static candidates sit in user- or admin-writable locations, the dynamic fallback resolves the binary through an interactive login shell, and `LiveCredentialSelfHeal.swift:51-54` re-asserts the ACL on every launch, wake and unlock, so a bad grant is durable rather than a one-off. **ARCH-10 (S3)** is the same `make-app.sh` line read as a release concern — deprecated `--deep`, no `--timestamp`, no reproducibility — and lands here because `--options runtime --timestamp` plus dropping `--deep` closes it and SEC-3 in one change. Deliberately not in this epic and recorded so it is not lost: the "the bar lies to you" cluster (ARCH-1 hook read-modify-write with no lock, ARCH-2 the absolute path baked into settings.json, CQ-1 freshness never consulted on the menu bar, CQ-2 the 900s staleness applied to in-flight tool states) and the `AppState` extraction that ARCH-3/5/6 and CQ-3/8/9/11 and PERF-1 all reduce to. Also deferred here by operator decision: PERF-4's cheap variant — dropping the `PostToolUse` registration in `HookSettingsMerger.swift:8-9`, which halves the hook's per-tool-call cost but changes what the bar shows between tools, and is therefore a UI-visible change belonging with the UI cluster rather than with signing.
|
|
126
|
+
|
|
127
|
+
## Claude status bar — per-path-class signing policy (SEC-1 follow-up)
|
|
128
|
+
- id: csb-signing-policy-1
|
|
129
|
+
- status: completed
|
|
130
|
+
- epics: [csb-signing-policy-1]
|
|
131
|
+
- project: claude-status-bar-macos
|
|
132
|
+
- kind: product
|
|
133
|
+
- goal: The successor epic `csb-audit-1` named when it closed (ledger `csb-audit-1-2026-09-07#338`, `successor_epic`), carrying the one S2 that epic left standing. `csb-audit-1` task-2d added `TrustedApplicationGate` in front of the Keychain ACL grant, but its single `policyRequirement` string admits any Developer-ID-signed binary on the machine as a trusted application for the credential item — far weaker than "the `claude` binary or this app", which is what the grant is for. The operator confirmed the finding and chose to land the gate as it was (better than no gate: it still refuses ad-hoc and unsigned binaries) and to fix the policy here rather than amend that plan a seventh time, because criteria 6 and 12 of task-2d had just pinned the requirement string and a new one needs its own specimens and its own grading. Measured design direction: per-path-class policy — for the `claude` binary, `anchor apple generic and identifier "com.anthropic.claude-code"` plus `certificate leaf[subject.OU] = "Q6L2SF6YDW"`; for the app's own self-signed bundle, the running process's own designated requirement (a pinned leaf-certificate hash is the fallback if a self-signed DR does not validate without a trusted anchor); a path in neither class is refused. The same epic closes the empty-ACL hole at both `SecAccessCreate` sites (a rejected write must leave the old ACL alone, never write an item that names zero trusted applications) and fixes the signing test harness so it never deletes the operator's `dist/` and escapes what it prints. Scoped like its parent: no UI, no `AppState`, no self-heal or locator files, and every agent bound by the same prohibition on mutating `/usr/bin/security` subcommands — the blast radius is the operator's real login keychain.
|
|
134
|
+
|
|
135
|
+
## Continuous loop — self-improve and on-command audit
|
|
136
|
+
- id: continuous-loop
|
|
137
|
+
- status: planned
|
|
138
|
+
- epics: []
|
|
139
|
+
- goal: Remove the operator from the middle of a run without removing them from the decisions. Requested 2026-09-07 and scoped in `docs/specs/continuous-loop-scope.md`, which splits it the way the request did. **Mechanism A — the factory's own self-improvement**, unattended, this checkout only, budget unbounded by operator decision: a `smith loop` process, separate from `smith daemon` and leaving that daemon's "never dispatches" refusal intact, which reads what `smith scheduler admit` classifies `auto` and spawns a headless `claude -p` session to carry each one through `/bs run`. The headless session is the missing link and the only new idea here — dispatch is a playbook needing the `Agent` tool, `smith` is a Node CLI that cannot call it, and a print-mode session is a real dispatching node that can (probed 2026-09-07: `bs=yes Agent=yes`). Unbounded budget lands as a per-epic override of `epic.cap_tokens`, the follow-up `budgets.yml` already asks for in its own comment, so one loop's decision does not widen every epic the factory will ever run. Local-only is enforced by a gitignored `state/loop/enabled` marker rather than promised in prose, and the self-improve path is excluded from `plugin-port` by name. **Mechanism B — `/bs audit <project>` and `/bs maintain <project>`** for projects outside the factory, on four axes fixed by the operator (performance, code quality, architecture, security), consolidating across axes before ranking because convergence is the strongest signal an audit produces, then stopping to ask the operator which findings become an epic. Triggered by a command, never by a timer — the operator's own amendment to the option they chose, and it removes the unattended-timer risk at no cost to what they wanted. Three things stay where they were: a person merges the PR, growth-review scope never auto-classifies, and a security-keyword surface always waits. **"Self-improve" is read wide, by operator decision 2026-09-07**: mechanism A may run the audit on the factory itself, cut epics from what it finds, and run them, rather than being limited to epics a person planned. That makes the merge the only human checkpoint between noticing and changing, so the scope prices it with four bounds — a severity floor of S1/S2-or-cross-axis-convergence on what may be auto-cut, one epic per PR per human merge, growth-review still never auto, and a protected set of declarations (`scheduler.yml`, `autonomy.ts`, `budgets.yml`, `delegation.yml`, `.claude/settings.json`, the enable marker) that the loop may propose changes to but never auto-dispatch, because a process allowed to widen its own leash has no fixed point. Four forks stay open and none blocks the epic — the loop interval, what a failed child does, `--max-turns` for the headless session, and the format of the durable findings file that keeps a wide loop from re-cutting the same epic every run.
|
|
140
|
+
|
|
141
|
+
## Blacksmith as a Claude Code plugin
|
|
142
|
+
- id: plugin-port
|
|
143
|
+
- status: planned
|
|
144
|
+
- epics: []
|
|
145
|
+
- goal: Make Blacksmith installable without cloning it — a Claude Code plugin carrying `/bs`, the agent templates and the guard hook, driven by a `smith` CLI published to npm and invoked through `npx` at a pinned version. Requested by the operator 2026-09-07 and scoped, before any path is moved, in `docs/specs/plugin-port-scope.md`. Three decisions are already taken there: the CLI ships through npm rather than as a vendored build; writable state moves to `<project>/.blacksmith/` rather than to a per-slug directory under the user's home; and the spec is written and reviewed before code. The work the scope measures is mostly one change — `factory/orchestrator/src/paths.ts` anchors shipped assets, runtime state and operator declarations on a single `REPO_ROOT`, and a plugin has to tell those three apart across 32 call sites in 8 modules — plus its sharpest consequence, that `guardrails.yml`'s `write_roots` are repo-root-relative literals matched segment-wise by `policy.ts`, so relocating state removes every judge's permission to write its own verdict unless the policy, the matcher and the judge templates move together. Five forks stay open for the operator and are why no epic is cut yet: the npm name, one repo or two, whether this clone migrates its own state, where the deny-list lives once `.claude/settings.json` is no longer the delivery mechanism, and whether the dashboard is in the first release at all. Docker and exposing the factory as a service were asked for in the same conversation and answered no, with the argument recorded in that scope's "Out of scope": dispatch is a playbook an interactive session executes, not code a container could run.
|
|
146
|
+
|
|
147
|
+
## vam — audit wave 1 (error formatting, poll back-pressure, adapter boundary)
|
|
148
|
+
- id: vam-audit-1
|
|
149
|
+
- status: planned
|
|
150
|
+
- epics: [vam-audit-1]
|
|
151
|
+
- project: vam
|
|
152
|
+
- kind: product
|
|
153
|
+
- goal: Cut from audit 20260914-5fe9088c of `vam` (3 accepted findings: 3 S3-minor). Each finding below is one acceptance criterion; the plan decides the tasks. **6acbe3a3 (S3-minor, performance)** `src/adapter/useCanvas.ts` — The 4-second poll loop fires the next overview+timeline fetch on a fixed timer with no in-flight guard, so a slow or degraded black-smith backend causes concurrent request piles that never drain, and an explicit refresh() (fired on every write) stacks more on top instead of coalescing.. **4de3c5cb (S3-minor, architecture)** `src/panels/ReviewQueue.tsx` — ReviewQueue.tsx and canvas/actions.ts import ApiFinding/ApiLesson wire-format types directly from adapter/api.ts instead of a domain-layer abstraction, breaking the project's own consistently-applied rule that no UI component learns which system (black-smith) it is looking at.. **7d3536a4 (S3-minor, code-quality)** `src/canvas/Canvas.tsx` — The same error-unwrapping ternary (SmithApiError -> code:message, else Error -> message, else String(cause)) is written out verbatim twice in one file instead of being factored into a shared helper..
|
|
154
|
+
|
|
@@ -128,6 +128,11 @@
|
|
|
128
128
|
"project": {
|
|
129
129
|
"type": "string",
|
|
130
130
|
"description": "Optional plain-string project identifier (Phase 6b, architecture §8) — NOT a closed taxonomy.yml vocabulary value (projects open/close far more often than any §8 dimension). Absent tasks default to 'black-smith' in the projection layer."
|
|
131
|
+
},
|
|
132
|
+
"keeps_exports": {
|
|
133
|
+
"type": "array",
|
|
134
|
+
"items": { "type": "string" },
|
|
135
|
+
"description": "Repo-relative file paths, each inside one of this task's own claims, whose existing exports this task keeps: no export removed, no export's declaration changed; adding exports is allowed. A symbol crossing whose producer promised the exporting file does not serialize the wave (impact.ts waveImpact); the promise is verified post-run by `smith claims impact <worktree> <spec.json>` against the diff."
|
|
131
136
|
}
|
|
132
137
|
},
|
|
133
138
|
"additionalProperties": false
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@juzser/blacksmith",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Autonomous agent factory — loop runner and worktree engine.",
|
|
6
6
|
"keywords": [
|
|
@@ -33,7 +33,8 @@
|
|
|
33
33
|
},
|
|
34
34
|
"packageManager": "pnpm@9.3.0",
|
|
35
35
|
"bin": {
|
|
36
|
-
"smith": "factory/orchestrator/dist/cli.js"
|
|
36
|
+
"smith": "factory/orchestrator/dist/cli.js",
|
|
37
|
+
"smith-run": "factory/orchestrator/dist/run-cli.js"
|
|
37
38
|
},
|
|
38
39
|
"files": [
|
|
39
40
|
"factory/orchestrator/dist",
|
|
@@ -42,8 +43,10 @@
|
|
|
42
43
|
"!factory/orchestrator/drizzle/meta/*_snapshot.json",
|
|
43
44
|
"factory/policies",
|
|
44
45
|
"factory/specs/schema",
|
|
46
|
+
"factory/specs/roadmap.md",
|
|
45
47
|
"factory/scaffold",
|
|
46
|
-
".claude/agents"
|
|
48
|
+
".claude/agents",
|
|
49
|
+
".claude/skills"
|
|
47
50
|
],
|
|
48
51
|
"scripts": {
|
|
49
52
|
"prepare": "pnpm run build",
|
|
@@ -74,15 +77,15 @@
|
|
|
74
77
|
"better-sqlite3": "13.0.3",
|
|
75
78
|
"drizzle-orm": "0.45.2",
|
|
76
79
|
"picomatch": "4.0.7",
|
|
77
|
-
"yaml": "2.9.
|
|
80
|
+
"yaml": "2.9.1"
|
|
78
81
|
},
|
|
79
82
|
"devDependencies": {
|
|
80
|
-
"@biomejs/biome": "2.5.
|
|
83
|
+
"@biomejs/biome": "2.5.13",
|
|
81
84
|
"@hono/node-server": "2.1.1",
|
|
82
85
|
"@playwright/test": "1.63.0",
|
|
83
86
|
"@tailwindcss/vite": "4.3.3",
|
|
84
87
|
"@types/better-sqlite3": "9.6.0",
|
|
85
|
-
"@types/node": "26.
|
|
88
|
+
"@types/node": "26.5.1",
|
|
86
89
|
"@vitejs/plugin-vue": "6.0.8",
|
|
87
90
|
"@vitest/coverage-v8": "5.0.0",
|
|
88
91
|
"@vue-flow/core": "1.48.2",
|
|
@@ -90,7 +93,7 @@
|
|
|
90
93
|
"hono": "4.13.7",
|
|
91
94
|
"tailwindcss": "4.3.3",
|
|
92
95
|
"typescript": "7.0.2",
|
|
93
|
-
"vite": "8.
|
|
96
|
+
"vite": "8.3.0",
|
|
94
97
|
"vitest": "5.0.0",
|
|
95
98
|
"vue": "3.5.42",
|
|
96
99
|
"vue-router": "5.3.1"
|