baldart 4.40.0 → 4.41.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/CHANGELOG.md CHANGED
@@ -5,6 +5,27 @@ All notable changes to BALDART will be documented in this file.
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6
6
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
+ ## [4.41.0] - 2026-06-15
9
+
10
+ **BALDART becomes opinionated about the *tools*, not just the workflow: a new curated toolchain layer installs best-in-class JS/TS dev tools at first install and makes the agents actually use them.** Until now BALDART shipped agents and workflows but was agnostic about linters/formatters/test-runners — every quality gate hard-coded `eslint`/`tsc`/`jest`. This release adds an opt-in toolchain layer (`features.has_toolchain`) that, on a JS/TS project, PRESELECTS and installs a curated set as devDependencies — **Biome** (format + lint + import organizer), **Vitest**, **tsc**, **Lefthook** (pre-commit) — then records literal gate commands in `toolchain.commands.*` that the gate flows (`/new`, `/new2`, `/qa`, `qa-sentinel`, `coder`) run verbatim instead of guessing. The design is the fourth member of the install-adapter family (alongside routine-/tool-/lsp-adapters) and inherits their invariants: **opinionated but askable** (default Y, opt-out), **non-destructive** (configs written only when absent; existing ESLint/Prettier/Jest/husky are detected and a migration is only ever PROPOSED, never automatic — `.husky/` is never overwritten), **never silent in CI** (`--non-interactive` writes the flag only; `baldart doctor` backfills), and **silent fallback** (an unset command degrades to the project-standard default; the layer is invisible to non-JS projects and consumers with their own toolchain). **MINOR** (additive capability + new `features.has_toolchain` + `toolchain.*` config keys, propagated end-to-end per the schema-change propagation rule; backwards-compatible — flag defaults `false`, every gate falls back to today's behavior when unset).
11
+
12
+ ### Added
13
+
14
+ - **`src/utils/toolchain-adapters/`** — new adapter family (same dispatcher pattern as `lsp-adapters/`). Curated installers `biome.js` / `vitest.js` / `tsc.js` / `lefthook.js` (each: `installCommand`/`verifyCommand`/`commands()`/`initConfig`/`static replaces`/`static detect`) + incumbent **detectors** `eslint.js` / `prettier.js` / `jest.js` / `husky.js` (detection-only, drive the migration proposal). `index.js` exposes `REGISTRY` + `INCUMBENTS` + `detectAll` + `detectIncumbents`.
15
+ - **`src/utils/toolchain-installer.js`** — orchestrator (modeled on `graphify-installer.js`): `recommend()` (clean installs), `migrations()` (incumbent-blocked tools → manual migration), `install()` (devDeps; writes a tool's config BEFORE the package's own postinstall so Lefthook registers our Biome pre-commit, not its commented-out example), `initConfigs()` (non-destructive), `commandsFor()`, `activeTools()`, `certify()`. Never throws.
16
+ - **`framework/agents/toolchain-protocol.md`** — runtime protocol: per-gate resolution (explicit `toolchain.commands.*` → project-standard fallback → skip), the command map, and the rule that a configured command which FAILS is a real failure (fallback applies only to *unset* commands). Routed from `framework/agents/index.md`.
17
+ - **`framework/docs/TOOLCHAIN-LAYER.md`** — operator guide (plumbing, lifecycle, edge cases, how to add a language/tool).
18
+ - **`framework/.claude/skills/toolchain-bootstrap/SKILL.md`** — explicit install path (`/toolchain-bootstrap`), CI-safe; mirrors `/lsp-bootstrap`.
19
+ - **`framework/templates/baldart.config.template.yml`** — `features.has_toolchain` + the `toolchain:` block (`installed_tools`, `commands.{lint,format,typecheck,test,test_related,build,audit}`, `auto_verify`).
20
+
21
+ ### Changed
22
+
23
+ - **`src/commands/configure.js`** — autodetects the prompt default (JS/TS project AND no incumbent → Y), and on enable runs the install/migrate/write/certify flow (clean set preselected; incumbents → migration proposal, never automatic).
24
+ - **`src/commands/update.js`** — the schema-drift detector now diffs the `toolchain:` block including its nested `commands.*` map (same nested-block contract as `graph:`), so a future gate key surfaces for pre-existing consumers.
25
+ - **`src/commands/doctor.js`** — backfill actions `toolchain-install` (devDeps missing) and `toolchain-init-config` (default config missing), gated on `features.has_toolchain`, never blocking.
26
+ - **`src/utils/tool-currency.js`** — `_toolchainRecords` reports curated devDeps behind their npm `latest` (installed version read from `node_modules`, not a global binary); `autoUpgradable:false` (devDep upgrades touch `package.json` — surfaced as a command, user-run). Honest `unknown` offline.
27
+ - **Consumers wired to read `toolchain.commands.*` with silent fallback** — `framework/.claude/agents/qa-sentinel.md`, `framework/.claude/agents/coder.md`, `framework/.claude/commands/qa.md`, `framework/.claude/workflows/new-card-review.js` (post-fix re-verify + qa gate brief), `framework/.claude/workflows/new2.js` (pre-flight baseline config facts).
28
+
8
29
  ## [4.40.0] - 2026-06-15
9
30
 
10
31
  **The classic `/new` now slims its single-card final review the same way `new2` already does — closing an asymmetry that made an N=1 batch re-run review finders it had already run.** `new-final-review.js` has carried an F-041 single-card slim since v4.17.x (keep the unique-value cross-model Codex pass + the qa-sentinel merge gate; drop the duplicate Claude breadth finders that already ran per-card), but it only ever fired for **`new2`**, which passes `singleCard`. The classic `/new` final-review delegation (`final-review.md` Step F.1.5) **never passed the flag**, so `slim` was always false and a one-card `/new` batch ran the full breadth set in the final review even though the per-card pass had already covered the same files — a duplicate cross-model Codex + redundant doc review on every single-card run. The user's framing ("for one card, skip the per-card review") was the wrong lever (it would drop Simplify, break the fail-fast ordering that runs review *before* E2E + doc-sync, and lose the early security pass — and was already litigated: v3.35.0 introduced an N=1 final-review skip, v3.37.0 reverted it precisely because the per-card pass can run shallow under `light`). The right lever, already chosen for `new2`, is the inverse: keep the per-card pass, slim the *final*. This release extends that slim to classic `/new` — but **per-finder, coverage-gated**, because classic `/new` differs from `new2`: its `doc-reviewer` runs in the skill's Phase 3 (and can defer to Final under `light`), and its `api-perf-cost-auditor` is deferred-to-final *by design* (never runs per-card). **MINOR** (changes the N=1 merge-gate composition; no new surface, no `baldart.config.yml` key — `singleCard`/`slimDoc`/`slimApi` are workflow args ⇒ schema-propagation rule N/A).
package/README.md CHANGED
@@ -208,13 +208,13 @@ Skills always-ask when required keys are missing — never silently default.
208
208
  never overwrites your file. Full guide:
209
209
  [`framework/docs/PROJECT-CONFIGURATION.md`](framework/docs/PROJECT-CONFIGURATION.md).
210
210
 
211
- ### Skills (32 portable skills)
211
+ ### Skills (33 portable skills)
212
212
 
213
213
  Skills live under `.claude/skills/` and are auto-discovered by Claude Code.
214
214
  Bundled skills:
215
215
 
216
216
  - **Workflow**: `new`, `new2` (v4.16.0 — EXPERIMENTAL workflow-hosted `/new`, Claude-only, for A/B testing context economy), `prd`, `prd-add`, `bug`, `simplify`, `worktree-manager`, `issue-review`, `context-primer`
217
- - **Code quality**: `skill-creator`, `find-skills`, `webapp-testing`, `playwright-skill`, `lsp-bootstrap` (v3.10.0), `graphify-bootstrap` (v4.21.0 — code knowledge graph), `graph-align` (v4.21.0 — doc↔graph alignment), `e2e-review` (v3.18.0)
217
+ - **Code quality**: `skill-creator`, `find-skills`, `webapp-testing`, `playwright-skill`, `lsp-bootstrap` (v3.10.0), `graphify-bootstrap` (v4.21.0 — code knowledge graph), `graph-align` (v4.21.0 — doc↔graph alignment), `toolchain-bootstrap` (v4.41.0 — curated dev toolchain), `e2e-review` (v3.18.0)
218
218
  - **Design**: `frontend-design`, `ui-design`, `motion-design`, `gamification-design`, `design-system-init` (v3.11.0)
219
219
  - **Product**: `seo-audit`, `copywriting`, `api-design-principles`
220
220
  - **Knowledge**: `doc-writing-for-rag`, `capture` (LLM wiki overlay)
@@ -245,6 +245,10 @@ When `features.has_lsp_layer: true`, `codebase-architect` and the code-explorati
245
245
 
246
246
  When `features.has_code_graph: true`, agents prefer the [Graphify](https://github.com/safishamsi/graphify) code knowledge graph (tree-sitter, local/offline, native Leiden communities) for **structural / relational** queries — "what connects X to Y", blast-radius of a change, which modules cluster — via `graphify query`/`path`/`explain`/`affected`. The same graph **re-activates the LLM-wiki auto-learning loop** (dormant since the RAG removal in v4.20.0): `wiki-curator`, `/capture`, and the nightly `doc-graph-align` routine feed synthesis candidates from Graphify's native `GRAPH_REPORT.md` (god nodes, communities, suggested questions) — entirely offline. Graphify is a single language-agnostic tool (`pipx install graphifyy`); install via `baldart configure` or `/graphify-bootstrap` (never silent in CI — `baldart doctor` backfills). Falls back silently to LSP→Grep→Git. See [`framework/agents/code-graph-protocol.md`](framework/agents/code-graph-protocol.md) and [`framework/docs/CODE-GRAPH-LAYER.md`](framework/docs/CODE-GRAPH-LAYER.md).
247
247
 
248
+ ### Curated Toolchain Layer (new in v4.41.0)
249
+
250
+ When `features.has_toolchain: true`, BALDART becomes opinionated about the *tools* you build with, not just the workflow. On a JS/TS project `baldart configure` PRESELECTS and installs a curated set as devDependencies — **Biome** (format + lint + import organizer), **Vitest**, **tsc**, **Lefthook** (pre-commit) — and records literal gate commands in `toolchain.commands.*`. The quality-gate flows (`/new`, `/new2`, `/qa`, `qa-sentinel`, `coder`) then run those commands verbatim instead of hard-coding `eslint`/`tsc`/`jest`. Opinionated **but askable** (default Y, opt-out) and **non-destructive**: existing ESLint/Prettier/Jest/husky setups are detected and a migration is only ever PROPOSED, never automatic (`.husky/` is never overwritten). Never silent in CI (`baldart doctor` backfills); each gate falls back silently to the project-standard default when its command is unset, so non-JS projects and consumers with their own toolchain are unaffected. Install via `baldart configure` or `/toolchain-bootstrap`. See [`framework/agents/toolchain-protocol.md`](framework/agents/toolchain-protocol.md) and [`framework/docs/TOOLCHAIN-LAYER.md`](framework/docs/TOOLCHAIN-LAYER.md).
251
+
248
252
  ### Commands
249
253
 
250
254
  - **/new**: Batch orchestrator with QA validation, production readiness checklist, and context recovery (also available as a skill)
package/VERSION CHANGED
@@ -1 +1 @@
1
- 4.40.0
1
+ 4.41.0
@@ -226,9 +226,11 @@ persistence code while `stack.database` is empty, surface a warning suggesting
226
226
 
227
227
  Do NOT wait until the end to verify your work. After each sub-task that changes types, interfaces, or function signatures:
228
228
 
229
- 1. **When `stack.language` includes `typescript`**: run `npx tsc --noEmit` fix ALL errors before proceeding to the next sub-task. On non-TypeScript stacks, run the project's equivalent type/static check instead (e.g. `mypy` / `pyright` for Python, `go vet` for Go) when one is configured.
229
+ > **Toolchain (since v4.41.0):** when `features.has_toolchain: true`, use the commands in `toolchain.commands.*` (`typecheck`, `lint`, `test`/`test_related`) verbatim for the steps below per `agents/toolchain-protocol.md` falling back to the defaults shown when a key is unset.
230
+
231
+ 1. **When `stack.language` includes `typescript`**: run `toolchain.commands.typecheck` if set, else `npx tsc --noEmit` — fix ALL errors before proceeding to the next sub-task. On non-TypeScript stacks, run the project's equivalent type/static check instead (e.g. `mypy` / `pyright` for Python, `go vet` for Go) when one is configured.
230
232
  2. If the type check fails: **STOP**. Fix the errors first. Do NOT continue writing new files on top of broken types.
231
- 3. After the final sub-task, run the project's linter on your changed files (e.g. `npx eslint --max-warnings=0 <files>` for a JS/TS stack, or the configured equivalent).
233
+ 3. After the final sub-task, run the linter on your changed files: `toolchain.commands.lint` if set, else the project default (e.g. `npx eslint --max-warnings=0 <files>` for a JS/TS stack, or the configured equivalent).
232
234
  4. **Unit tests**: run ONLY the specific test file, not the full suite. `npm run test` is slow (minutes). Run the single file with the project's actual runner — check `package.json` scripts / devDependencies and use whichever is present (e.g. `npx vitest run <file>`, `npx jest <file>`, `node --import tsx <file>`, or `pytest <file>` / `go test ./<pkg>` on non-JS stacks). Do NOT assume `tsx` is installed: if the chosen command fails with a missing-loader/module error, that means the runner is wrong — try the next candidate, do NOT treat the failure as "no related tests". If the task doesn't involve a known test file, skip the test run.
233
235
 
234
236
  **Error Recovery — three-branch state machine (cap: 3 attempts)**: If a build breaks mid-implementation:
@@ -23,7 +23,16 @@ Run mechanical quality gates fast, return a PASS/FAIL verdict, and get out of th
23
23
  > patterns. Pre-commit gates below are the typical defaults — adjust the toolchain to
24
24
  > match your project (e.g. `ruff` instead of `eslint`, `pytest` instead of `npm test`).
25
25
 
26
- Default pre-commit gates (MUST pass before any commit verdict):
26
+ **Toolchain commands (since v4.41.0):** when `features.has_toolchain: true` in
27
+ `baldart.config.yml`, run the command from `toolchain.commands.<gate>` (lint,
28
+ typecheck, test, test_related, build, audit) **verbatim** instead of the default
29
+ below — per `agents/toolchain-protocol.md`. Resolve per gate: a non-empty config
30
+ command wins; an empty/absent one falls back to the default below. A configured
31
+ command that EXITS NON-ZERO is a real FAIL (do not fall back). Example: a project
32
+ on Biome runs `npx biome check .` for lint; a Vitest project runs `npx vitest run`.
33
+
34
+ Default pre-commit gates (MUST pass before any commit verdict) — used when no
35
+ `toolchain.commands.*` is configured:
27
36
  1. Lint: `npx eslint --max-warnings=0 <changed source files>` (or project equivalent)
28
37
  2. Type-check: `npx tsc --noEmit` (or project equivalent)
29
38
  3. Markdown lint: `npx markdownlint-cli2 <changed .md files>` (if .md files changed)
@@ -98,6 +98,8 @@ Write the initial file:
98
98
 
99
99
  ## Step 3 — Execute Profile
100
100
 
101
+ > **Toolchain (since v4.41.0):** when `features.has_toolchain: true` in `baldart.config.yml`, run the gate commands from `toolchain.commands.*` (lint, typecheck, test, test_related, build, audit) verbatim — per `agents/toolchain-protocol.md` — instead of the generic examples below. A configured command that fails is a real FAIL.
102
+
101
103
  ### LIGHT — Fast confidence (<3 min target [DESIGN-CHOICE: scoped to lint + type-check + related tests only; sufficient for low-risk or doc-only diffs])
102
104
 
103
105
  Run directly in this session (no sub-agents):
@@ -0,0 +1,127 @@
1
+ ---
2
+ name: toolchain-bootstrap
3
+ effort: medium
4
+ description: >
5
+ Install, verify, and wire the curated dev toolchain for this project. Detects
6
+ the JS/TS stack, installs the best-in-class tools as devDependencies (Biome for
7
+ format+lint+import, Vitest, tsc, Lefthook), writes their default config only
8
+ when absent, records toolchain.installed_tools + toolchain.commands.* in
9
+ baldart.config.yml, and proposes (never forces) a migration off any existing
10
+ ESLint/Prettier/Jest/husky. Use when the user says /toolchain-bootstrap,
11
+ "install the toolchain", "set up biome", or after enabling
12
+ features.has_toolchain for the first time. Idempotent — re-running re-verifies
13
+ and reports drift, never overwriting existing configs.
14
+ ---
15
+
16
+ # Toolchain Bootstrap
17
+
18
+ Set up the curated dev toolchain so the quality gates (`/new`, `/qa`, `/check`,
19
+ `qa-sentinel`) run best-in-class tools instead of whatever the project happened
20
+ to have. Non-destructive throughout: configs are written only when absent and
21
+ incumbent tools are never installed over or removed.
22
+
23
+ ## Project Context
24
+
25
+ **Reads from `baldart.config.yml`:** `features.has_toolchain`, `toolchain.installed_tools`, `toolchain.commands.*`, `toolchain.auto_verify`.
26
+ **Gated by features:** `features.has_toolchain` — this skill refuses to run when the flag is `false`, prompting the user to flip it via `npx baldart configure` first.
27
+ **Overlay:** loads `.baldart/overlays/toolchain-bootstrap.md` if present — project-specific tool choices or install commands.
28
+ **On missing keys:** ask the user; do not assume defaults. See `framework/agents/project-context.md` § 3.
29
+
30
+ ## Effort
31
+
32
+ **Baseline:** `effort: medium` (frontmatter). **Inline override:** pass
33
+ `effort=<low|medium|high|xhigh|max>` anywhere in the invocation to scale
34
+ reasoning depth for this run — detect it once at kickoff and strip the token
35
+ before consuming user input. Level→behavior mapping, parsing contract, and
36
+ precedence caveats: `framework/agents/effort-protocol.md`.
37
+
38
+ ## What This Skill Does
39
+
40
+ 1. Reads `baldart.config.yml` and confirms `features.has_toolchain: true`.
41
+ 2. Probes the cwd via `src/utils/toolchain-installer.js` to compute the clean
42
+ recommendation (`recommend()`) and any incumbent-blocked migrations
43
+ (`migrations()`).
44
+ 3. Installs the recommended tools as **devDependencies** (`npm install -D -E`) —
45
+ never global (these are project tools invoked via `npx`, unlike LSP servers).
46
+ 4. Writes each tool's default config **only when absent** (`biome.json`,
47
+ `lefthook.yml`) and registers Lefthook's `pre-commit` hook.
48
+ 5. For incumbents (ESLint/Prettier/Jest/husky), PROPOSES a migration with a
49
+ preview — never automatic, never touching the existing config (`.husky/` is
50
+ never overwritten).
51
+ 6. Writes `toolchain.installed_tools` + `toolchain.commands.*` to
52
+ `baldart.config.yml`, then `certify()`s the set.
53
+ 7. Prints a compact status and points to
54
+ `framework/agents/toolchain-protocol.md` for runtime behavior.
55
+
56
+ ## Workflow
57
+
58
+ 1. **Refusal check.** If `features.has_toolchain: false` (or missing):
59
+ ```
60
+ This project hasn't opted in to the curated toolchain yet.
61
+ Run `npx baldart configure` and answer YES to "Enable curated dev toolchain?"
62
+ then re-run /toolchain-bootstrap.
63
+ ```
64
+ Stop here. Do not proceed.
65
+
66
+ 2. **Probe.** Call the installer:
67
+ ```
68
+ node -e 'const T=require("./.framework/src/utils/toolchain-installer"); const t=new T(); console.log(JSON.stringify({hasPkg:t.hasPackageJson(),recommend:t.recommend(),migrations:t.migrations()},null,2))'
69
+ ```
70
+ If `hasPkg` is false, report "no package.json — JS toolchain not applicable"
71
+ and stop. Otherwise show the recommended tools and any migrations.
72
+
73
+ 3. **Confirm.** For the clean recommendation, default YES. For each migration,
74
+ show what it replaces (and for Biome, the `npx biome migrate eslint/prettier
75
+ --write` preview) and default NO.
76
+
77
+ 4. **Install + config + commands.** Run the installer's `install`, `initConfigs`,
78
+ then read back `commandsFor(activeTools())`. Capture failures into a "Skipped"
79
+ bucket — never abort the whole skill on one failure.
80
+
81
+ 5. **Persist.** Update `baldart.config.yml`:
82
+ ```yaml
83
+ toolchain:
84
+ installed_tools: [biome, vitest, tsc, lefthook]
85
+ commands:
86
+ lint: npx biome check .
87
+ format: npx biome format --write .
88
+ typecheck: npx tsc --noEmit
89
+ test: npx vitest run
90
+ test_related: npx vitest related --run
91
+ auto_verify: true
92
+ ```
93
+
94
+ 6. **Output.** A compact one-line-per-tool status, in the project's
95
+ `identity.language` from `baldart.config.yml` (English default).
96
+
97
+ ## Output Contract
98
+
99
+ A single short status block — never a multi-page report. Format:
100
+
101
+ ```
102
+ Toolchain bootstrap:
103
+ ✓ biome (devDep 2.x, biome.json written, lint+format wired)
104
+ ✓ vitest (devDep, test + test_related wired)
105
+ ✓ tsc (typescript present, typecheck wired)
106
+ ✓ lefthook (devDep, lefthook.yml + pre-commit hook installed)
107
+ · eslint → migration available (declined): npx biome migrate eslint --write
108
+ Config updated: baldart.config.yml toolchain.installed_tools = [biome, vitest, tsc, lefthook]
109
+ Next: /qa, /new, qa-sentinel will now run these commands instead of the defaults.
110
+ ```
111
+
112
+ ## Notes
113
+
114
+ - This skill never edits source code. Its only side effects are devDependency
115
+ installs, writing absent default configs, registering the Lefthook hook, and a
116
+ YAML write to `baldart.config.yml`.
117
+ - Re-run safely. `recommend()`/`migrations()` are recomputed each time, configs
118
+ are skipped when present, and already-usable tools are left untouched —
119
+ additions / repairs are idempotent.
120
+ - `baldart doctor` is the unattended backfill: it installs missing tools
121
+ (`toolchain-install`) and restores missing default config (`toolchain-init-config`).
122
+
123
+ ## See Also
124
+
125
+ - `framework/agents/toolchain-protocol.md` — runtime command resolution + fallback.
126
+ - `framework/docs/TOOLCHAIN-LAYER.md` — full plumbing + lifecycle.
127
+ - `src/utils/toolchain-adapters/` — per-tool install/verify recipes.
@@ -38,6 +38,14 @@ const cfg = a.config || {}
38
38
  const highRisk = (cfg.paths && cfg.paths.high_risk_modules) || [] // security-domain hint
39
39
  const protocolRef = '.claude/skills/new/references/review-cycle.md'
40
40
 
41
+ // Curated toolchain (since v4.41.0): when features.has_toolchain is on, the
42
+ // consumer records LITERAL gate commands in toolchain.commands.* — agents run
43
+ // THOSE instead of guessing (e.g. `npx biome check .` not `npm run lint`). Empty
44
+ // / absent → silent fallback to the project-standard default. Read from the
45
+ // config the skill already passes via args.config (never hardcoded project facts).
46
+ const tcCmds = (cfg.toolchain && cfg.toolchain.commands) || {}
47
+ const tc = (key, fallback) => (tcCmds[key] && String(tcCmds[key]).trim()) || fallback
48
+
41
49
  // Per-card result accumulator — built up-front (so the early-return guards can return it) and
42
50
  // populated with fixesApplied/residual in the Fix phase.
43
51
  const perCard = {}
@@ -193,8 +201,15 @@ const codexPrompt =
193
201
  `For each finding return: finding_id, title, severity (BLOCKER|HIGH|MEDIUM|LOW), confidence (0-100), evidence (exact file:line + code quote), minimal_fix_direction, and domain (doc|security|migration|code|perf|test). ` +
194
202
  `Run the mandatory false-positive check on every finding and suppress the unconvincing ones (your findings are treated as already FP-validated). Set codexAvailable:true when the review ran.`
195
203
 
204
+ const tcGateLines = [
205
+ ['lint', tcCmds.lint], ['typecheck', tcCmds.typecheck], ['test', tcCmds.test],
206
+ ['build', tcCmds.build], ['audit', tcCmds.audit],
207
+ ].filter(([, v]) => v && String(v).trim());
196
208
  const qaPrompt =
197
- `Run MECHANICAL GATES ONLY over the wave scope, per ${protocolRef} (Phase 3.5 qa-sentinel contract): lint, type-check (when stack uses typescript), the full test suite, build, dependency audit, and markdownlint as applicable. You are a GATE RUNNER: do NOT read source for code findings, do NOT emit severities — return only a PASS/FAIL/SKIP gate table.\n\nWorktree: ${a.worktreePath || '(cwd)'} — cd into it first.\nChanged files:\n${unionScope.join('\n')}`
209
+ `Run MECHANICAL GATES ONLY over the wave scope, per ${protocolRef} (Phase 3.5 qa-sentinel contract): lint, type-check (when stack uses typescript), the full test suite, build, dependency audit, and markdownlint as applicable. You are a GATE RUNNER: do NOT read source for code findings, do NOT emit severities — return only a PASS/FAIL/SKIP gate table.\n\nWorktree: ${a.worktreePath || '(cwd)'} — cd into it first.\nChanged files:\n${unionScope.join('\n')}` +
210
+ (tcGateLines.length
211
+ ? `\n\nThis project configures a curated toolchain — run THESE EXACT commands for the corresponding gates (do not substitute):\n${tcGateLines.map(([k, v]) => ` • ${k}: ${String(v).trim()}`).join('\n')}`
212
+ : '')
198
213
 
199
214
  function simplifyPrompt(c) {
200
215
  return `Simplify analysis (read-only — you do NOT edit, the workflow applies fixes afterward) over ONE card's committed diff, per ${protocolRef} (Phase 2.55). Cover all THREE lenses and return findings:\n` +
@@ -342,7 +357,7 @@ async function applyFixPass(findings, writer, label, role) {
342
357
  `You MAY edit ONLY these files (ownership map — touching anything else is a violation):\n${unionEditable.join('\n')}\n\n` +
343
358
  `Findings to fix (fix the code, not the tests unless a test itself is wrong; do NOT expand scope beyond the finding):\n` +
344
359
  findings.map((f) => `- [${f.finding_id}] (${f.card || '?'} / ${f.domain} / ${f.severity}) ${f.title}\n evidence: ${f.evidence}\n direction: ${f.minimal_fix_direction}`).join('\n') +
345
- `\n\nAfter applying: run \`npm run lint\` and (when the project uses typescript) \`npx tsc --noEmit\` and \`npm run build\` in the worktree. If a check fails because of an edit you made, fix the regression — at most 2 retries — staying within the allowed files. ` +
360
+ `\n\nAfter applying: run \`${tc('lint', 'npm run lint')}\` and (when the project uses typescript) \`${tc('typecheck', 'npx tsc --noEmit')}\` and \`${tc('build', 'npm run build')}\` in the worktree. If a check fails because of an edit you made, fix the regression — at most 2 retries — staying within the allowed files. ` +
346
361
  `Do NOT commit. Do NOT git stash (refs/stash is shared across worktrees). ` +
347
362
  `Return: applied (finding_ids you fixed), unresolved (finding_ids you could NOT fix within the allowed files / 2 retries), and checks (PASS/FAIL/SKIP for lint, tsc, build).`
348
363
  const r = await agent(fixBrief, { label, phase: 'Fix', agentType: writer, schema: FIX_SCHEMA })
@@ -215,6 +215,9 @@ const projectBrief = [
215
215
  `Trunk: ${TRUNK}`,
216
216
  `Reference modules (Read these for the EXACT /new semantics — this workflow only sequences them): ${REF}/`,
217
217
  `Config facts: stack=${JSON.stringify(cfg.stack || {})}; features=${JSON.stringify(features)}; high_risk_modules=${JSON.stringify(highRisk)}; paths.backlog_dir=${paths.backlog_dir || '?'}; paths.references_dir=${paths.references_dir || '?'}.`,
218
+ (features.has_toolchain && cfg.toolchain && cfg.toolchain.commands)
219
+ ? `Toolchain commands (run THESE verbatim for the baseline + any gate, per agents/toolchain-protocol.md; empty → project default): ${JSON.stringify(cfg.toolchain.commands)}.`
220
+ : '',
218
221
  FLAGS.effort ? `Reasoning effort for this run: ${FLAGS.effort}.` : '',
219
222
  ].filter(Boolean).join('\n')
220
223
 
@@ -24,6 +24,7 @@ Route agents to the right module with minimal reading.
24
24
  - If touching architecture, auth, or tech stack -> read `agents/architecture.md`.
25
25
  - If touching workflow/process/commits/backlog -> read `agents/workflows.md`.
26
26
  - If CREATING or MUTATING a backlog card (any prefix — `FEAT`/`CHORE`/`BUG`/`DOC`/`PERF`/`UI`), or consuming one type-blind (`/new`, `/new2`) -> read `agents/card-schema.md` (the universal, profile-aware baseline) before writing/validating fields.
27
+ - If running MECHANICAL GATES (lint, format, type-check, test, build, audit) and `features.has_toolchain: true` -> read `agents/toolchain-protocol.md` and run the command from `toolchain.commands.<gate>` verbatim, falling back to the project-standard default when a key is unset. A configured command that FAILS is a real gate failure (do not fall back).
27
28
  - If touching testing or QA issues -> read `agents/testing.md` (also documents the scope-aware,
28
29
  profile-driven test-selection strategy consumed by `qa-sentinel`).
29
30
  - If touching GitHub issues or issue workflow -> read `agents/github-issue-subagent.md`.
@@ -65,6 +66,7 @@ When adding or updating agents, update REGISTRY.md — not this file.
65
66
  - `agents/project-context.md` — Project context protocol: `baldart.config.yml` + overlays + missing-key handling (since v3.0.0)
66
67
  - `agents/code-search-protocol.md` — Retrieval hierarchy for code search: LSP → Grep → Git (since v3.10.0, gated on `features.has_lsp_layer`)
67
68
  - `agents/code-graph-protocol.md` — Structural/relational retrieval via the Graphify code knowledge graph (since v4.21.0, gated on `features.has_code_graph`)
69
+ - `agents/toolchain-protocol.md` — Mechanical-gate command resolution (lint/format/typecheck/test/build/audit) from `toolchain.commands.*` with silent project-standard fallback (since v4.41.0, gated on `features.has_toolchain`)
68
70
  - `agents/design-system-protocol.md` — Registry-first discipline for UI work: BLOCKING cascade on `INDEX.md` + `tokens-reference.md` + `components/<Name>.md` (since v3.11.0, gated on `features.has_design_system`)
69
71
  - `agents/card-schema.md` — Atomic Card Baseline Schema: the universal, profile-aware (epic/child/standalone) field contract every backlog card satisfies, plus the consumer HALT/BACK-FILL/WARN contract (since v4.35.0)
70
72
 
@@ -0,0 +1,80 @@
1
+ # Toolchain Protocol
2
+
3
+ ## Purpose
4
+
5
+ Define how agents/skills run the **mechanical quality gates** — lint, format,
6
+ type-check, test, build, audit — when a project has opted into the curated
7
+ toolchain. The commands are read from `toolchain.commands.*` in
8
+ `baldart.config.yml` and run **verbatim**, instead of each gate hard-coding
9
+ `eslint` / `tsc` / `jest` / `npm run build`. This lets a project standardize on
10
+ the best-in-class tools (Biome for format+lint+import, Vitest, tsc, Lefthook)
11
+ and have every gate flow use them consistently.
12
+
13
+ ## Scope
14
+
15
+ **In**: which command to invoke for each gate; the resolution order; the silent
16
+ fallback. **Out**: code review for correctness/quality (that is the reviewer
17
+ agents' job, not a mechanical gate); installing the tools (that is
18
+ `baldart configure` / `/toolchain-bootstrap` / `baldart doctor`, see
19
+ `framework/docs/TOOLCHAIN-LAYER.md`).
20
+
21
+ ## Gating
22
+
23
+ Conditional on `features.has_toolchain: true` in `baldart.config.yml`. The layer
24
+ degrades **silently and per-command**: for each gate, if
25
+ `toolchain.commands.<gate>` is a non-empty string, run it **exactly**; otherwise
26
+ fall back to the flow's built-in project-standard default (`npx eslint`,
27
+ `npx tsc --noEmit`, `npm test`, `npm run build`, `npm audit`, …). When the flag
28
+ is `false`/missing, every gate uses its default — identical to pre-toolchain
29
+ behavior. **Never block a task** because a command is unset or a tool is missing;
30
+ surface install gaps through `baldart doctor` (`toolchain-install` /
31
+ `toolchain-init-config` actions), not mid-task.
32
+
33
+ ## Resolution hierarchy (per gate)
34
+
35
+ 1. **Explicit config** — `toolchain.commands.<gate>` from `baldart.config.yml`,
36
+ run verbatim. This is the source of truth when set.
37
+ 2. **Project-standard fallback** — the gate's existing default command, inferred
38
+ from the stack (eslint/tsc/jest/npm scripts). Used when the config key is
39
+ empty/absent.
40
+ 3. **Skip** — when neither resolves (e.g. no build script in a library), report
41
+ `SKIP`, never fail.
42
+
43
+ ## Command map
44
+
45
+ | Gate | Config key | Curated default (Biome/Vitest/tsc) | Fallback |
46
+ | --- | --- | --- | --- |
47
+ | Lint | `toolchain.commands.lint` | `npx biome check .` | `npx eslint --max-warnings=0 <files>` |
48
+ | Format | `toolchain.commands.format` | `npx biome format --write .` | `npx prettier --write <files>` |
49
+ | Type-check | `toolchain.commands.typecheck` | `npx tsc --noEmit` | `npx tsc --noEmit` |
50
+ | Test | `toolchain.commands.test` | `npx vitest run` | `npm test` |
51
+ | Test (related) | `toolchain.commands.test_related` | `npx vitest related --run <files>` | `npx jest --findRelatedTests <files>` |
52
+ | Build | `toolchain.commands.build` | `npm run build` | `npm run build` |
53
+ | Audit | `toolchain.commands.audit` | `npm audit --audit-level=high` | `npm audit` |
54
+
55
+ Biome's `check` runs lint + format-check + import-organize in one pass, so the
56
+ `lint` gate alone covers what a separate ESLint+Prettier+import-plugin trio
57
+ would; the `format` command only `--write`s.
58
+
59
+ ## Consumers
60
+
61
+ `qa-sentinel` (gate runner), `/qa`, `/check`, the `coder` post-fix re-verify,
62
+ and the `/new` + `/new2` review workflows resolve gate commands through this
63
+ protocol. The `/new` workflow scripts receive the resolved config via their
64
+ `args.config` payload (the consuming skill passes `baldart.config.yml`) — they
65
+ must never hard-code project facts (see the workflows contamination contract).
66
+
67
+ ## Fallback rules
68
+
69
+ - A configured command that EXITS NON-ZERO is a genuine gate **FAIL** — do not
70
+ silently fall back to the default (that would mask a real failure). Fallback
71
+ applies only when the command is **unset**, not when it fails.
72
+ - A configured command whose binary is missing (`command not found`) is a setup
73
+ gap → report it and fall back to the default for that single run, then let
74
+ `baldart doctor` repair the install. Never abort the task.
75
+
76
+ ## See also
77
+
78
+ - `framework/docs/TOOLCHAIN-LAYER.md` — install lifecycle, adapters, plumbing.
79
+ - `agents/testing.md` — scope-aware, profile-driven test selection (the `test` /
80
+ `test_related` gates compose with it).
@@ -0,0 +1,135 @@
1
+ # Curated Toolchain Layer — Operator Guide
2
+
3
+ > Since v4.41.0. Opt-in, gated on `features.has_toolchain`. The **runtime**
4
+ > protocol (which command each gate runs) lives in
5
+ > [`framework/agents/toolchain-protocol.md`](../agents/toolchain-protocol.md);
6
+ > this document covers the *plumbing* — install, config, lifecycle, fallback.
7
+
8
+ ## 1. Why this exists
9
+
10
+ BALDART has always been opinionated about *how* you work (workflows, review,
11
+ gates) but agnostic about the *tools* you work with. Every quality-gate flow
12
+ hard-coded `eslint` / `tsc` / `jest` / `npm run build`. This layer lets BALDART
13
+ also recommend and install a curated, best-in-class JS/TS toolchain — and, more
14
+ importantly, makes the agents **use it**: the gate flows read the literal
15
+ commands from `toolchain.commands.*` instead of guessing.
16
+
17
+ The curated set (JS/TS):
18
+
19
+ | Slot | Tool | Why |
20
+ | --- | --- | --- |
21
+ | Format + Lint + Imports | **Biome** | One fast Rust binary replacing ESLint + Prettier + import plugins |
22
+ | Test | **Vitest** | Fast, ESM-native test runner |
23
+ | Type-check | **tsc** | The TypeScript compiler in `--noEmit` mode |
24
+ | Pre-commit | **Lefthook** | Fast, parallel git-hook runner (owns `pre-commit`) |
25
+
26
+ Other languages (Ruff for Python, gofmt for Go, …) plug in by adding an adapter —
27
+ no other layer changes.
28
+
29
+ ## 2. Principles (non-negotiable)
30
+
31
+ - **Opinionated but askable** — on a JS/TS project with no incumbent, `configure`
32
+ PRESELECTS the tools (default Y); the user opts out.
33
+ - **Non-destructive** — config files are written only when absent; incumbent
34
+ tools (ESLint/Prettier/Jest/husky) are detected, **never installed or removed**.
35
+ A migration is only ever PROPOSED (with a preview), never automatic. Flipping
36
+ `features.has_toolchain` true→false does NOT uninstall anything — it just stops
37
+ agents from using the commands.
38
+ - **Never silent in CI** — `--non-interactive`/`--yes` installs nothing; it writes
39
+ the flag and `baldart doctor` backfills interactively.
40
+ - **Silent fallback, never abort** — for each gate, an unset command falls back to
41
+ the project-standard default; a missing tool is a doctor item, never a task
42
+ blocker. (A configured command that EXITS NON-ZERO is a real failure — fallback
43
+ applies only to *unset* commands, not failing ones.)
44
+
45
+ ## 3. What BALDART adds vs what the tools ship
46
+
47
+ BALDART does not reimplement Biome/Vitest/tsc/Lefthook. It adds only:
48
+
49
+ - **Gating + config** (`features.has_toolchain` + the `toolchain:` block).
50
+ - **Opt-in install** (`configure` interactive branch, `/toolchain-bootstrap`,
51
+ `doctor` backfill) via per-tool adapters.
52
+ - **A command-resolution protocol** telling BALDART's agents which command each
53
+ gate runs.
54
+ - **Currency** — `baldart doctor` reports devDeps behind their npm latest
55
+ (non-blocking; devDep upgrades are user-run).
56
+ - **Fallback discipline** — silent degrade to project-standard defaults.
57
+
58
+ ## 4. The moving parts
59
+
60
+ | Part | Where | Role |
61
+ |------|-------|------|
62
+ | Config flag + block | `framework/templates/baldart.config.template.yml` | `features.has_toolchain` + `toolchain.{installed_tools,commands.*,auto_verify}` |
63
+ | Curated adapters | `src/utils/toolchain-adapters/{biome,vitest,tsc,lefthook}.js` | `installCommand/verifyCommand/commands()/initConfig/static replaces/static detect` |
64
+ | Incumbent detectors | `src/utils/toolchain-adapters/{eslint,prettier,jest,husky}.js` | detection only (migration proposal) |
65
+ | Dispatcher | `src/utils/toolchain-adapters/index.js` | `REGISTRY` + `INCUMBENTS` + `detectAll` + `detectIncumbents` |
66
+ | Installer wrapper | `src/utils/toolchain-installer.js` | `recommend/migrations/install/initConfigs/commandsFor/certify/activeTools` |
67
+ | Configure | `src/commands/configure.js` | autodetect default + prompt + interactive install/migrate/write |
68
+ | Update detector | `src/commands/update.js` | diffs the `toolchain:` block (incl. nested `commands.*`) |
69
+ | Doctor | `src/commands/doctor.js` | `toolchain-install` / `toolchain-init-config` backfill + currency |
70
+ | Currency | `src/utils/tool-currency.js` | `_toolchainRecords` — installed (node_modules) vs npm latest |
71
+ | Retrieval protocol | `framework/agents/toolchain-protocol.md` | which command each gate runs; fallback |
72
+ | Consumers | `qa-sentinel`, `coder`, `/qa`, `new-card-review.js`, `new2.js` | run `toolchain.commands.*` with fallback |
73
+ | Bootstrap skill | `/toolchain-bootstrap` | explicit install path (CI-safe backfill) |
74
+
75
+ ## 5. Install lifecycle
76
+
77
+ ```
78
+ features.has_toolchain: true
79
+
80
+ ├─ baldart configure (INTERACTIVE)
81
+ │ → recommend() clean set → npm install -D -E (devDeps)
82
+ │ → initConfigs() writes biome.json / lefthook.yml IF ABSENT
83
+ │ → Lefthook registers its pre-commit hook
84
+ │ → write toolchain.installed_tools + toolchain.commands.*
85
+ │ → certify() (each tool resolves via npx + config present)
86
+ │ └─ incumbent present → PROPOSE migration (never automatic)
87
+
88
+ ├─ baldart configure --yes / CI
89
+ │ → writes the flag from autodetect; installs NOTHING
90
+ │ → doctor backfills the install
91
+
92
+ ├─ /qa · /new · /new2 · qa-sentinel · coder
93
+ │ → resolve each gate from toolchain.commands.* (fallback to default)
94
+
95
+ └─ baldart doctor
96
+ → toolchain-install (devDep missing)
97
+ → toolchain-init-config (default config missing)
98
+ → tool-upgrade:toolchain:<tool> (behind npm latest — non-blocking)
99
+ ```
100
+
101
+ ## 6. Fallback hierarchy (per gate)
102
+
103
+ 1. **Explicit** — `toolchain.commands.<gate>`, run verbatim.
104
+ 2. **Project-standard** — the flow's built-in default (`npx eslint`, `npx tsc
105
+ --noEmit`, `npm test`, `npm run build`, `npm audit`).
106
+ 3. **Skip** — when neither resolves (e.g. no build script), report `SKIP`.
107
+
108
+ ## 7. Edge cases
109
+
110
+ - **Non-JS project** — no adapter `detect()` fires; nothing is proposed.
111
+ - **Monorepo** — Biome/Vitest are root-scoped (one `biome.json` covers the
112
+ workspace); Lefthook is root-only (one `.git`).
113
+ - **Existing ESLint/Prettier/Jest/husky** — detected as incumbents; the matching
114
+ curated tool routes to the migration proposal, never an automatic install. husky
115
+ specifically: Lefthook is NOT installed over `.husky/` — the hook handoff is
116
+ manual.
117
+ - **`biome.json` / `lefthook.yml` already present** — kept, never overwritten.
118
+ - **No `package.json`** — the JS toolchain is skipped (cannot install a devDep);
119
+ the flag stays on so a later `configure`/`doctor` can complete it.
120
+
121
+ ## 8. Adding a language / tool
122
+
123
+ 1. Create `src/utils/toolchain-adapters/<tool>.js` shaped like `biome.js`
124
+ (`installCommand`, `verifyCommand`, `commands()`, `initConfig`, `static
125
+ replaces`, `static detect`). Add it to `REGISTRY` in `index.js`.
126
+ 2. For an incumbent it supersedes, add a detection-only adapter to `INCUMBENTS`
127
+ and list it in the curated tool's `static replaces`.
128
+ 3. Everything else (configure, doctor, currency, the protocol) iterates the
129
+ registry — no further wiring.
130
+
131
+ ## See also
132
+
133
+ - `framework/agents/toolchain-protocol.md` — runtime command resolution.
134
+ - `framework/.claude/skills/toolchain-bootstrap/SKILL.md` — explicit install path.
135
+ - `src/utils/toolchain-adapters/` — per-tool install/verify recipes.
@@ -202,6 +202,19 @@ features:
202
202
  # changed. See framework/.claude/skills/e2e-review/SKILL.md.
203
203
  has_e2e_review: false
204
204
 
205
+ # Curated dev toolchain (since v4.41.0). When true, BALDART installs and
206
+ # enables an opinionated set of best-in-class JS/TS dev tools (Biome for
207
+ # format+lint+import; later Vitest, tsc, Lefthook) and the quality-gate flows
208
+ # (/new, /qa, /check, qa-sentinel) run the commands recorded in
209
+ # `toolchain.commands.*` below instead of hardcoding eslint/tsc/jest. Falls
210
+ # back SILENTLY to the project-standard defaults when a command is unset, so a
211
+ # consumer with its own toolchain (or a non-JS project) is unaffected.
212
+ # `baldart configure` / `/toolchain-bootstrap` install the tools; `baldart
213
+ # doctor` backfills. Existing ESLint/Prettier setups are never touched — a
214
+ # migration is only ever PROPOSED. See framework/agents/toolchain-protocol.md
215
+ # and framework/docs/TOOLCHAIN-LAYER.md.
216
+ has_toolchain: false
217
+
205
218
  # ─── E2E REVIEW ──────────────────────────────────────────────────────────
206
219
  # Tuning for the /e2e-review skill (only consulted when has_e2e_review: true).
207
220
  e2e_review:
@@ -263,6 +276,33 @@ graph:
263
276
  # without it, so this is an enhancement, not a requirement.
264
277
  register_mcp: false
265
278
 
279
+ # ─── TOOLCHAIN ─────────────────────────────────────────────────────────────
280
+ # State of the curated dev toolchain. Populated by `baldart configure` / the
281
+ # `/toolchain-bootstrap` skill. Only meaningful when `features.has_toolchain:
282
+ # true`. The commands are LITERAL (run verbatim by agents) — an empty string
283
+ # means "fall back to the project-standard default for this gate".
284
+ toolchain:
285
+ # Curated tools BALDART has installed/verified locally. Identifiers map to
286
+ # adapters under src/utils/toolchain-adapters/ (biome — extend with vitest,
287
+ # tsc, lefthook, …).
288
+ installed_tools: []
289
+
290
+ # Literal gate commands read by the quality-gate flows (/new, /qa, /check,
291
+ # qa-sentinel). Empty string → the flow uses its built-in fallback (eslint /
292
+ # tsc / jest / npm run build / npm audit), so the layer degrades cleanly.
293
+ commands:
294
+ lint: "" # e.g. npx biome check .
295
+ format: "" # e.g. npx biome format --write .
296
+ typecheck: "" # e.g. npx tsc --noEmit
297
+ test: "" # e.g. npx vitest run
298
+ test_related: "" # e.g. npx vitest related --run
299
+ build: "" # e.g. npm run build
300
+ audit: "" # e.g. npm audit --audit-level=high
301
+
302
+ # When true, `baldart doctor` re-verifies the installed tools resolve and
303
+ # restores any missing default config. Disable on CI if too noisy.
304
+ auto_verify: true
305
+
266
306
  # ─── GIT ─────────────────────────────────────────────────────────────────
267
307
  # Controls how worktree-manager (`/mw`) integrates a worktree's feature
268
308
  # branch back into the integration trunk.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "baldart",
3
- "version": "4.40.0",
3
+ "version": "4.41.0",
4
4
  "description": "Claude Agent Framework - Reusable framework for coordinating AI agents and humans in software projects",
5
5
  "bin": {
6
6
  "baldart": "./bin/baldart.js"