ways
Concepts

Doctor & trust

Honest environment validation, and why nothing runs before you approve it.

ways doctor answers one question before anyone runs a flow: is this environment actually ready? It resolves everything the way (and its bound slots) requires and checks it — CLIs, env vars, MCP servers, slot bindings, companion ways, pins.

Honest statuses, always

Every check reports exactly one of five statuses — and the CLI never pretends to know more than it does:

StatusMeaning
passverified present/valid
failrequired and missing/broken — comes with a copy-pasteable remediation
skippedoptional and absent — not an error
unknownpresent but unverifiable (e.g. a binding with no profile, an unrun check)
not-inspectableno inspector can see it (e.g. MCP config of an unsupported agent)

Exit code 0 when nothing failed; --strict (CI) also fails on unknown. MCP configuration is read through a pluggable agent inspector — the claude inspector ships first; other agents honestly report not-inspectable rather than guessing.

Project mode

With no arguments, doctor validates the whole repo:

  • Conflicts across installed ways (contract rule #14): the same slot id declared with incompatible contracts, or two ways colliding on a skill name.
  • Pins: every way declared in ways.yaml is installed, its content digest still matches ways.lock, and its versionPin matches the resolved ref. Drift = fail with the exact re-acquire command.
  • Then per-way checks for every declared way. ways doctor incu/dev scopes to one way — by installed name, no path needed.

Trust: approval is bound to content

The way's declared check commands (gh auth status, git --version) are executable content — so doctor only runs them for trusted ways:

  1. ways add shows the full plan — including every check command and the executable surface — and requires explicit approval.
  2. Approval records approvedDigest in ways.lock: trust is bound to the content digest, not the name.
  3. If the installed content changes in any way, the digest no longer matches: doctor drops back to presence-only checks (unknown), list flags the drift, and re-approval is required.

No shell is ever used to execute checks (argv-spawn only), nothing runs before approval, and secrets are never echoed in any check output.

Contracts a bound impl must satisfy

Once a slot is bound, doctor resolves the impl's Binding profile through the contract catalogs and checks it for real:

  • Coverage. A binding that doesn't cover all of its SlotContract's operations (coversOperations) is reported — advisory ⚠ by default, a failure under --strict — so that field stops being decorative.
  • Unresolvable contract → unknown. If a slot's contract can't be resolved (no catalog provides it), doctor reports that slot unknown with the real reason, and every other check still runs — one gap never masks the rest.

A catalog is executable surface, so it's trusted exactly like a way: its Bindings contribute check commands, ways add discloses each catalog in the approval plan (attributed to catalog + impl), a changed catalog digest forces re-approval, and read-only commands (doctor, bind, ways contracts) are cache-only — they never fetch. WAYS_NO_CATALOGS=1 turns resolution off.

On this page