# Curated Toolchain Layer — Operator Guide

> Since v4.41.0. Opt-in, gated on `features.has_toolchain`. The **runtime**
> protocol (which command each gate runs) lives in
> [`framework/agents/toolchain-protocol.md`](../agents/toolchain-protocol.md);
> this document covers the *plumbing* — install, config, lifecycle, fallback.

## 1. Why this exists

BALDART has always been opinionated about *how* you work (workflows, review,
gates) but agnostic about the *tools* you work with. Every quality-gate flow
hard-coded `eslint` / `tsc` / `jest` / `npm run build`. This layer lets BALDART
also recommend and install a curated, best-in-class JS/TS toolchain — and, more
importantly, makes the agents **use it**: the gate flows read the literal
commands from `toolchain.commands.*` instead of guessing.

The curated set (JS/TS):

| Slot | Tool | Why |
| --- | --- | --- |
| Format + Lint + Imports | **Biome** | One fast Rust binary replacing ESLint + Prettier + import plugins |
| Test | **Vitest** | Fast, ESM-native test runner |
| Type-check | **tsc** | The TypeScript compiler in `--noEmit` mode |
| Pre-commit | **Lefthook** | Fast, parallel git-hook runner (owns `pre-commit`) |

Other languages (Ruff for Python, gofmt for Go, …) plug in by adding an adapter —
no other layer changes.

## 2. Principles (non-negotiable)

- **Opinionated but askable** — on a JS/TS project with no incumbent, `configure`
  PRESELECTS the tools (default Y); the user opts out.
- **Non-destructive** — config files are written only when absent; incumbent
  tools (ESLint/Prettier/Jest/husky) are detected, **never installed or removed**.
  A migration is only ever PROPOSED (with a preview), never automatic. Flipping
  `features.has_toolchain` true→false does NOT uninstall anything — it just stops
  agents from using the commands.
- **Never silent in CI** — `--non-interactive`/`--yes` installs nothing; it writes
  the flag and `baldart doctor` backfills interactively.
- **Silent fallback, never abort** — for each gate, an unset command falls back to
  the project-standard default; a missing tool is a doctor item, never a task
  blocker. (A configured command that EXITS NON-ZERO is a real failure — fallback
  applies only to *unset* commands, not failing ones.)

## 3. What BALDART adds vs what the tools ship

BALDART does not reimplement Biome/Vitest/tsc/Lefthook. It adds only:

- **Gating + config** (`features.has_toolchain` + the `toolchain:` block).
- **Opt-in install** (`configure` interactive branch, `/toolchain-bootstrap`,
  `doctor` backfill) via per-tool adapters.
- **A command-resolution protocol** telling BALDART's agents which command each
  gate runs.
- **Currency** — `baldart doctor` reports devDeps behind their npm latest
  (non-blocking; devDep upgrades are user-run).
- **Fallback discipline** — silent degrade to project-standard defaults.

## 4. The moving parts

| Part | Where | Role |
|------|-------|------|
| Config flag + block | `framework/templates/baldart.config.template.yml` | `features.has_toolchain` + `toolchain.{installed_tools,commands.*,auto_verify}` |
| Curated adapters | `src/utils/toolchain-adapters/{biome,vitest,tsc,lefthook}.js` | `installCommand/verifyCommand/commands()/initConfig/static replaces/static detect` |
| Incumbent detectors | `src/utils/toolchain-adapters/{eslint,prettier,jest,husky}.js` | detection only (migration proposal) |
| Dispatcher | `src/utils/toolchain-adapters/index.js` | `REGISTRY` + `INCUMBENTS` + `detectAll` + `detectIncumbents` |
| Installer wrapper | `src/utils/toolchain-installer.js` | `recommend/migrations/install/initConfigs/commandsFor/certify/activeTools` |
| Configure | `src/commands/configure.js` | autodetect default + prompt + interactive install/migrate/write |
| Update detector | `src/commands/update.js` | diffs the `toolchain:` block (incl. nested `commands.*`) |
| Doctor | `src/commands/doctor.js` | `toolchain-install` / `toolchain-init-config` backfill + currency |
| Currency | `src/utils/tool-currency.js` | `_toolchainRecords` — installed (node_modules) vs npm latest |
| Retrieval protocol | `framework/agents/toolchain-protocol.md` | which command each gate runs; fallback |
| Consumers | `qa-sentinel`, `coder`, `/qa`, `new-card-review.js`, `new2.js` | run `toolchain.commands.*` with fallback |
| Bootstrap skill | `/toolchain-bootstrap` | explicit install path (CI-safe backfill) |

## 5. Install lifecycle

```
features.has_toolchain: true
        │
        ├─ baldart configure (INTERACTIVE)
        │      → recommend() clean set → npm install -D -E (devDeps)
        │      → initConfigs() writes biome.json / lefthook.yml IF ABSENT
        │      → Lefthook registers its pre-commit hook
        │      → write toolchain.installed_tools + toolchain.commands.*
        │      → certify() (each tool resolves via npx + config present)
        │      └─ incumbent present → PROPOSE migration (never automatic)
        │
        ├─ baldart configure --yes / CI
        │      → writes the flag from autodetect; installs NOTHING
        │      → doctor backfills the install
        │
        ├─ /qa · /new · /new2 · qa-sentinel · coder
        │      → resolve each gate from toolchain.commands.* (fallback to default)
        │
        └─ baldart doctor
               → toolchain-install   (devDep missing)
               → toolchain-init-config (default config missing)
               → tool-upgrade:toolchain:<tool> (behind npm latest — non-blocking)
```

## 6. Fallback hierarchy (per gate)

1. **Explicit** — `toolchain.commands.<gate>`, run verbatim.
2. **Project-standard** — the flow's built-in default (`npx eslint`, `npx tsc
   --noEmit`, `npm test`, `npm run build`, `npm audit`).
3. **Skip** — when neither resolves (e.g. no build script), report `SKIP`.

## 7. Edge cases

- **Non-JS project** — no adapter `detect()` fires; nothing is proposed.
- **Monorepo** — Biome/Vitest are root-scoped (one `biome.json` covers the
  workspace); Lefthook is root-only (one `.git`).
- **Existing ESLint/Prettier/Jest/husky** — detected as incumbents; the matching
  curated tool routes to the migration proposal, never an automatic install. husky
  specifically: Lefthook is NOT installed over `.husky/` — the hook handoff is
  manual.
- **`biome.json` / `lefthook.yml` already present** — kept, never overwritten.
- **No `package.json`** — the JS toolchain is skipped (cannot install a devDep);
  the flag stays on so a later `configure`/`doctor` can complete it.

## 8. Adding a language / tool

1. Create `src/utils/toolchain-adapters/<tool>.js` shaped like `biome.js`
   (`installCommand`, `verifyCommand`, `commands()`, `initConfig`, `static
   replaces`, `static detect`). Add it to `REGISTRY` in `index.js`.
2. For an incumbent it supersedes, add a detection-only adapter to `INCUMBENTS`
   and list it in the curated tool's `static replaces`.
3. Everything else (configure, doctor, currency, the protocol) iterates the
   registry — no further wiring.

## See also

- `framework/agents/toolchain-protocol.md` — runtime command resolution.
- `framework/.claude/skills/toolchain-bootstrap/SKILL.md` — explicit install path.
- `src/utils/toolchain-adapters/` — per-tool install/verify recipes.
