cmv Command Reference

cmv verifies, deterministically, that a project holds the intents cmf compiled for it. It reads the compile manifest cmf install --local wrote, resolves each compiled intent's record in the atlas, runs the validators that match the workspace's ecosystems (detected by the atlas's own sensors), and exits nonzero when a required intent is not held. It never asks a model, never reads the clock, and never executes project code: given the same workspace, manifest, atlas, and cmv.toml, its output is byte-identical.

Run it from the project root, or pass --root <project>. check, status, and explain accept standalone schema-1 manifests and schema-2 local collections. Schema 1 also accepts the older knowledge_base block name. An unsupported schema exits 2 with the manifest path before cmv resolves the atlas or runs any validator. Default check verifies every artifact in a collection, each against its own pinned atlas revision, and returns nonzero if any artifact fails. JSON output contains an artifacts array with each artifact identity and its own check report; schema-1 output keeps its original shape. Default status reports every compilation at its own pin. explain requires --artifact <name> when a collection contains multiple compilations; add --surface agent|skill when the name is shared.

The repository's reference atlas contains representative records, sensors, validators, and source cases for testing this workflow. Production atlases are maintained separately.

Commands

cmv check            [--json] [--strict] [--root <project>] [--manifest <path>] [--atlas <path>] [--at-head]
cmv status           [--json] [--artifact <name> [--surface agent|skill]] [--root <project>] [--manifest <path>] [--atlas <path>] [--at-head]
cmv explain <intent> [--json] [--artifact <name> [--surface agent|skill]] [--root <project>] [--manifest <path>] [--atlas <path>] [--at-head]
CommandDescription
cmv checkRun every artifact’s compiled validators and report attributed verdicts
cmv check --strictAlso fail the run when any intent could not be checked
cmv check --jsonEmit the full per-intent report as JSON for CI
cmv statusSummarize the manifest, pin, ecosystems, and validator coverage without running any validator
cmv explain <intent>Show what check would do for one intent — record resolution, validators, argv, config, stale — without running anything
--at-headVerify the atlas's working tree even when the manifest pins a revision its HEAD has moved past

Defaults:

InputDefault
--rootthe current directory
--manifest<root>/.context-mixer/cmf-manifest.json, where cmf install --local --apply writes it
--atlasresolved through the cmx source registry, then the manifest (see below); --knowledge-base still parses as a hidden alias

A relative path — on the command line, in the registry, or in the manifest — is resolved against cmv's working directory.

Where the atlas comes from

The atlas is the registry (CMV.md, design decision 5): it is a git repository, so it is a cmx source, and cmv finds it the way cmx would. The resolution order is fixed, and every report says which step answered in its atlas.resolved_by field:

resolved_byStep
override--atlas <path> (or its hidden alias --knowledge-base) was given; nothing else is consulted
sourcethe manifest's atlas.source names a registered cmx source (cmx source list); its local directory or clone is used
paththe manifest's recorded atlas.path

A recorded source name the registry does not know falls through to path with a warning on stderr naming the source and suggesting cmx source add: the manifest still says where the records were when cmf read them, so the run can proceed.

The pinned revision

The manifest records the git revision cmf read. When the resolved atlas is a git checkout whose HEAD differs from that pin, cmv verifies against the pinned tree, not the working tree: it runs

git -C <atlas> archive --format=tar -o <scratch>/kb.tar <revision>
tar -xf <scratch>/kb.tar -C <scratch>/kb

and reads records from, and runs validators in, <scratch>/kb (executable bits survive git archive). Validators' run paths resolve inside it. The scratch directory is removed when the run ends and never appears in output.

When HEAD equals the pin, the manifest has no revision, or the root is not a git checkout, cmv uses the root directly. When the pinned revision cannot be archived — typically because the checkout has not fetched it — cmv exits 2 naming the revision and suggesting cmx source update <name> (or git fetch when the atlas is not a registered source).

--at-head bypasses the pin and verifies the working tree; the report's verified_against says head. This is for validator authors iterating on an atlas: edit the script, run cmv check --at-head against a project, repeat. It never re-pins anything.

Every check, status, and explain report carries an atlas block:

FieldMeaning
paththe atlas root as resolved
resolved_byoverride, source, or path
sourcethe cmx source name the manifest recorded, if any
pinned_revisionthe manifest's revision, if any
head_revisionthe working tree's HEAD, when it is a git checkout
verified_againstpinned when the verdicts came from the pinned revision (materialized, or checked out as HEAD); head otherwise
movedtrue when HEAD differs from the pin

moved is informational and never changes the exit code. In human output it adds one line after the summary:

atlas has moved: HEAD ffffffffffff vs pinned a1b2c3d4e5f6; 2 compiled records or validators changed; re-run cmf install to recompile

Recompiling is cmf's decision — a newer atlas may change selection — so cmv only reports it.

Ecosystem detection

cmv verifies as the ecosystems the atlas's sensors detect at the project root. The atlas declares them in ecosystems.toml at its root — one table per ecosystem, each with the signatures that recognize it and the ecosystems it implies (see the cmf reference for the schema). cmv has no built-in table of build files: the atlas knows which ecosystems it supports, and the names are its own vocabulary (the directories below intents/), so the sensors are read from the tree being verified — the pinned tree when one is materialized — and validated against its records before anything runs.

A validator runs only when its language is in the detected set. Setting ecosystems in cmv.toml replaces detection entirely.

An atlas with no sensor file (or one declaring nothing) detects nothing, and cmv says so rather than guessing: when cmv.toml gives no override, every validator-bearing intent is unchecked with the reason

atlas declares no sensors; set ecosystems in cmv.toml to override

cmv status reports Ecosystems: none (atlas declares no sensors; …), and cmv explain marks each validator skipped: with the same reason. The atlas.sensors field of every JSON report says whether the verified tree declared any.

When the manifest's profile.ecosystems names an ecosystem detection did not find, cmv check reports it as profile_mismatch and ends the human listing with one informational line:

manifest profile targets rust but the workspace shows python; the guidance may be for a different ecosystem

or … but no sensors detected anything when the detected set is empty. It never changes the exit code, and it is not computed when the atlas declares no sensors. A cmv.toml override counts as the workspace's word.

Project config: cmv.toml

Hand-authored, at the project root, entirely optional. It carries what neither the atlas nor the code can supply.

# Replace the atlas's sensor detection; an empty list runs no validators.
ecosystems = ["rust"]

# Seconds before a validator is killed and its intent reported unchecked.
# Default 60.
validator_timeout_seconds = 30

# Per-intent settings, keyed by catalog key. Each table is handed to that
# intent's validators verbatim as the --config JSON document; an intent
# without a table receives {}.
[intent."craftsperson/rust/isolate-functional-core"]
business_rule_pattern = "\\b10_?000\\b|\\b500\\b"
business_rule_minimum_matches = 2

[intent."craftsperson/python/nonblocking-async-io"]
blocking_symbols = ["time.sleep", "requests.get"]

Unknown top-level keys are rejected, so a misspelled ecosystems cannot silently fall back to detection.

How validators run

For each intent in the manifest, cmv resolves the record by its catalog key first: the key is the compile-time locator, and a record's id may intentionally recur across collections (one specialization per language), so an id on its own cannot locate a record. When no record sits at the key, cmv falls back to the id only if exactly one record carries it — a record that moved. When several do, the intent is reported unchecked with a reason naming those records; cmf install recompiles against the current keys. cmv then runs each static-check validator whose language matches:

<atlas-root>/<run> --workspace <project-root> --config <tempfile.json>

with the atlas root as the working directory. The validator writes one JSON document to stdout and exits 0:

{
  "applicable": true,
  "followed": false,
  "signals": { "effectful_modules": ["src/http.rs"] },
  "evidence": ["no gateway trait is declared"],
  "locations": [{ "path": "src/http.rs", "line": 14 }]
}

applicable and followed are required; signals (default {}), evidence (default []), and locations (default []; line optional) may be omitted.

When several validators match one intent (a record with one validator per language, in a workspace with several ecosystems) they combine all-must-pass: any failure fails the intent; otherwise any unchecked run leaves it unchecked; otherwise it passes when at least one run was applicable.

Verdict states

StateMeaningEffect on exit code
passValidator ran; applicable: true, followed: true—
failValidator ran; applicable: true, followed: false1 if the validator is required
not_applicableValidator ran; applicable: false — the condition never arose—
uncheckedNo validator for the workspace's ecosystems (or the atlas declares no sensors), record missing from the atlas, validator could not start, crashed, timed out, or wrote no parseable verdict — the reason is reported1 only with --strict
unguidedThe manifest lists the intent as dropped; the guidance never reached the artifact—

An intent is additionally marked stale when, at the working tree's HEAD, its record's bytes no longer match the checksum the manifest recorded at compile time, or — when validators ran from a materialized pinned tree — any of its validators' run files differ between HEAD and that tree. Stale is always computed against the working tree, never the pinned tree, so a moved atlas shows exactly which compiled intents it touched. Stale is informational and never changes the exit code; the remedy is to re-run cmf install, because a newer atlas may change selection, which is cmf's decision.

Exit codes

CodeMeaning
0Every required, applicable validator passed
1A required validator failed, or, with --strict, an intent was unchecked
2Missing or malformed manifest, unreadable atlas, or bad usage

An optional validator's failure is reported but never changes the exit code.

Human output

A linter-style listing, one line per intent, grouped by state with settled outcomes first and problems last, so they sit beside the summary:

PASS       craftsperson/rust/put-gateways-at-effect-boundaries
           every effectful call crosses a gateway trait
UNGUIDED   craftsperson/rust/name-for-intent
           budget
UNCHECKED  craftsperson/rust/compile-public-documentation
           no validator for ecosystems [rust]
FAIL       craftsperson/rust/isolate-functional-core  (required)  (stale: record changed since compile)
           business rules live beside I/O in src/main.rs
           src/main.rs:12

1 pass, 1 fail, 0 not applicable, 1 unchecked, 1 unguided; adherence 50.0%
1 record changed in the atlas since compile; re-run `cmf install` to recompile.

Under each intent come its evidence strings, then its locations as path:line, then the reason when unchecked or unguided. The adherence rate is pass / (pass + fail): the denominator is what the code had occasion to exhibit.

JSON report

cmv check --json writes one pretty-printed document. It carries no timestamp and no temporary path, so it is byte-stable across runs.

{
  "schema": 1,
  "manifest": {
    "profile": { "id": "rust-shipping", "version": "0.3.0" },
    "atlas": { "source": "guidelines", "path": "kb", "revision": "a1b2c3d4…" }
  },
  "atlas": {
    "path": "/home/me/guidelines",
    "resolved_by": "source",
    "source": "guidelines",
    "pinned_revision": "a1b2c3d4…",
    "head_revision": "ffffffff…",
    "verified_against": "pinned",
    "moved": true,
    "sensors": true
  },
  "ecosystems": ["rust"],
  "profile_mismatch": [],
  "intents": [
    {
      "id": "guidelines.intent.isolate-functional-core",
      "key": "craftsperson/rust/isolate-functional-core",
      "language": "rust",
      "required": true,
      "state": "fail",
      "description": "No module holding business rules references a gateway.",
      "signals": { "business_rule_minimum_matches": 2 },
      "evidence": ["business rules live beside I/O in src/main.rs"],
      "locations": [{ "path": "src/main.rs", "line": 12 }],
      "stale": true
    }
  ],
  "summary": {
    "pass": 1,
    "fail": 1,
    "not_applicable": 0,
    "unchecked": 1,
    "unguided": 1,
    "adherence_rate": 0.5,
    "exit_code": 1
  }
}
  • manifest echoes the manifest's profile and atlas as recorded at compile time (source and revision are omitted when the manifest has none).
  • atlas is where cmv actually read from and which tree it verified; see "The pinned revision" above for every field. sensors says whether that tree declares any ecosystem sensors.
  • ecosystems is the set the workspace was verified as (detected, or the cmv.toml override; [] when nothing was detected or nothing could be), and profile_mismatch lists the manifest profile's declared ecosystems that were not detected (see "Ecosystem detection").
  • intents lists every compiled intent in manifest order, then every dropped intent. state is one of pass, fail, not_applicable, unchecked, unguided; reason is present for the last two. language and description are null when no validator ran; id is null for a dropped intent whose record is no longer in the atlas. language and description join several validators' values with , and / respectively, and signals is then an object keyed by language.
  • summary.adherence_rate is pass / (pass + fail) rounded to four decimals, or null when nothing was applicable. summary.exit_code is the code cmv exits with.

cmv status --json emits schema, manifest_path, profile, artifact, atlas (the block above plus exists), ecosystems, intents, dropped, and coverage (with_validator, missing, stale), with coverage null when the atlas could not be scanned. The human form adds HEAD revision and Verified against lines after Pinned revision, and the atlas has moved line at the end when moved. For a schema-2 collection, default JSON wraps these per-artifact reports in { "schema": 2, "artifacts": [...] }. Use --artifact to get one report. Each artifact is scanned against its own pinned atlas revision.

Explaining one intent

cmv explain <intent> answers "what would check do with this one?" without running anything. The argument is a catalog key, or a record id when it contains a .. cmv exits 2 when the manifest neither compiled nor dropped the intent. For a collection with multiple artifacts, cmv exits 2 with the available identities until you select one with --artifact. If two surfaces share the name, also pass --surface.

Artifact: AGENTS (agent)
Intent: craftsperson/rust/isolate-functional-core
Id: guidelines.intent.isolate-functional-core
Record: resolved by key
Title: Isolate the functional core
Status: confirmed (informational; never gates)
Compiled: yes
Dropped: no
Stale: yes (record or validator changed at HEAD since compile)
Atlas: /home/me/guidelines (resolved by cmx source, verified against pinned revision)
Ecosystems: rust
Config: {"business_rule_minimum_matches":2,"business_rule_pattern":"\\b500\\b"}
Validators:
  rust  checks/rust/isolate_functional_core.py  (required)  would run
    No module holding business rules references a gateway.
    <pinned-tree>/checks/rust/isolate_functional_core.py --workspace /home/me/project --config <scratch>/1.json
  python  checks/python/isolate_functional_core.py  (required)  skipped: language python is not among the workspace's ecosystems [rust]
    No module holding business rules imports an I/O client.
    <pinned-tree>/checks/python/isolate_functional_core.py --workspace /home/me/project --config <scratch>/1.json
  • Record is resolved by key, resolved by id (no record at the manifest's key, but exactly one carries its id — a moved record), or not found in atlas, followed in parentheses by the records sharing the id when that is what stopped the fallback.
  • Config is the exact JSON document the validators would receive through --config: the intent's [intent."<key>"] table from cmv.toml, or {}.
  • Each validator line shows its language, run, whether it is required, and whether it would run here; below it, its description and the exact argv. <scratch> stands for the per-run temporary directory and <pinned-tree> for a materialized pinned revision — both are created at check time and never appear in output, so explain is byte-stable like everything else. When cmv verifies the checkout directly, the program path is the real one.
  • A dropped intent shows Dropped: yes (<reason>); its validators are listed but marked skipped, because the guidance never reached the artifact.

cmv explain <intent> --json emits schema, artifact, atlas, ecosystems, and intent (key, id, resolution, title, status, compiled, dropped, drop_reason, stale, config, and validators, each with language, run, required, description, would_run, skipped, and argv).