# Toolchain Protocol

## Purpose

Define how agents/skills run the **mechanical quality gates** — lint, format,
type-check, test, build, audit — when a project has opted into the curated
toolchain. The commands are read from `toolchain.commands.*` in
`baldart.config.yml` and run **verbatim**, instead of each gate hard-coding
`eslint` / `tsc` / `jest` / `npm run build`. This lets a project standardize on
the best-in-class tools (Biome for format+lint+import, Vitest, tsc, Lefthook)
and have every gate flow use them consistently.

## Scope

**In**: which command to invoke for each gate; the resolution order; the silent
fallback. **Out**: code review for correctness/quality (that is the reviewer
agents' job, not a mechanical gate); installing the tools (that is
`baldart configure` / `/toolchain-bootstrap` / `baldart doctor`, see
`framework/docs/TOOLCHAIN-LAYER.md`).

## Gating

Conditional on `features.has_toolchain: true` in `baldart.config.yml`. The layer
degrades **silently and per-command**: for each gate, if
`toolchain.commands.<gate>` is a non-empty string, run it **exactly**; otherwise
fall back to the flow's built-in project-standard default (`npx eslint`,
`npx tsc --noEmit`, `npm test`, `npm run build`, `npm audit`, …). When the flag
is `false`/missing, every gate uses its default — identical to pre-toolchain
behavior. **Never block a task** because a command is unset or a tool is missing;
surface install gaps through `baldart doctor` (`toolchain-install` /
`toolchain-init-config` actions), not mid-task.

## Resolution hierarchy (per gate)

1. **Explicit config** — `toolchain.commands.<gate>` from `baldart.config.yml`,
   run verbatim. This is the source of truth when set.
2. **Project-standard fallback** — the gate's existing default command, inferred
   from the stack (eslint/tsc/jest/npm scripts). Used when the config key is
   empty/absent.
3. **Skip** — when neither resolves (e.g. no build script in a library), report
   `SKIP`, never fail.

## Command map

| Gate | Config key | Curated default (Biome/Vitest/tsc) | Fallback |
| --- | --- | --- | --- |
| Lint | `toolchain.commands.lint` | `npx biome check .` | `npx eslint --max-warnings=0 <files>` |
| Format | `toolchain.commands.format` | `npx biome format --write .` | `npx prettier --write <files>` |
| Type-check | `toolchain.commands.typecheck` | `npx tsc --noEmit` | `npx tsc --noEmit` |
| Test | `toolchain.commands.test` | `npx vitest run` | `npm test` |
| Test (related) | `toolchain.commands.test_related` | `npx vitest related --run <files>` | `npx jest --findRelatedTests <files>` |
| Build | `toolchain.commands.build` | `npm run build` | `npm run build` |
| Audit | `toolchain.commands.audit` | `npm audit --audit-level=high` | `npm audit` |

Biome's `check` runs lint + format-check + import-organize in one pass, so the
`lint` gate alone covers what a separate ESLint+Prettier+import-plugin trio
would; the `format` command only `--write`s.

## Consumers

`qa-sentinel` (gate runner), `/qa`, `/check`, the `coder` post-fix re-verify,
and the `/new` + `/new2` review workflows resolve gate commands through this
protocol. The `/new` workflow scripts receive the resolved config via their
`args.config` payload (the consuming skill passes `baldart.config.yml`) — they
must never hard-code project facts (see the workflows contamination contract).

## Fallback rules

- A configured command that EXITS NON-ZERO is a genuine gate **FAIL** — do not
  silently fall back to the default (that would mask a real failure). Fallback
  applies only when the command is **unset**, not when it fails.
- A configured command whose binary is missing (`command not found`) is a setup
  gap → report it and fall back to the default for that single run, then let
  `baldart doctor` repair the install. Never abort the task.

## See also

- `framework/docs/TOOLCHAIN-LAYER.md` — install lifecycle, adapters, plumbing.
- `agents/testing.md` — scope-aware, profile-driven test selection (the `test` /
  `test_related` gates compose with it).
