@rqml/cli (the rqml command)
The command-line interface, and the universal substrate every integration can
invoke. It is published as @rqml/cli; the installed command is rqml.
npm install -g @rqml/cli # then: rqml <command>
# or, no install:
npx @rqml/cli <command>
It bundles @rqml/core, so it runs fully offline and its verdicts match the
engine and the @rqml/mcp server.
Commands
rqml <command> [spec.rqml] [options]
init [path] Scaffold a starter spec and merge the RQML block into AGENTS.md
validate [path] XML well-formedness, XSD, and referential integrity
status [path] Spec summary: requirement count, coverage, lint findings
lint [path] Semantic lint findings; severity scales with --strictness (exit 1 on error)
check [path] Deterministic enforcement gate (validation + coverage + drift)
link <id> <uri> Record an implements/verifiedBy trace edge and its drift baseline
(--update repoints an existing edge; --refresh <edge-id>
re-records only the baseline for an intentional change)
show <id> One artifact: statement, acceptance criteria, trace neighborhood
impact <id> What is affected, transitively, if this artifact changes
overview [path] Readable spec projection (whole, or --section/--id scoped)
matrix [path] Traceability matrix: status, goals, code, tests, coverage gaps
approve <id> Transition a requirement's status (--status, default approved)
gate [paths...] Block implementation of non-approved requirements (exit 2)
skeleton <kind> Print a schema-valid snippet (--list names every kind)
migrate [path] Rewrite a 2.0.1/2.1.0 spec to the current schema version
(compact trace edges, RFC-0003; --dry-run to preview)
When no path is given, rqml resolves the governing spec by walking up from the
working directory to the nearest *.rqml (preferring requirements.rqml), stopping
at the repository root — so commands work from anywhere inside a project unit. A
directory with several *.rqml files and no requirements.rqml is reported as
ambiguous. In a repository with multiple specs, see the
Monorepo guide.
migrate is the one command that rewrites your spec rather than reporting on it;
what it changes, what it leaves byte-for-byte alone, and why it never touches the
drift baseline are covered in the Migration guide.
Options
| Flag | Meaning |
|---|---|
--json | Emit machine-readable JSON (for status, check, validate, link, show, impact, matrix) — for control loops and editor hooks |
--strictness <level> | relaxed · standard (default) · strict · certified — how aggressively check gates |
--base-dir <dir> | Where spec discovery starts (and the --workspace root); code links resolve against the spec's own directory |
--workspace, --all | Run validate / status / check across every spec in the repository, with one aggregated exit code (non-zero if any unit fails) — see the Monorepo guide |
--ignore <names> | Comma-separated directory names to skip during --workspace discovery |
--spec <path> | Explicit spec file, for any command. Required by link, show, and impact, whose positional argument is an artifact id rather than a path; for the commands that take a path positionally it is an equivalent spelling, and giving both a positional and a different --spec is an error rather than one silently winning |
--type <type> | Link type: implements (default) · verifiedBy |
--id <id> | Explicit edge id for link, or the root id for skeleton |
--kind, --title | Optional locator hints recorded on the edge by link (preserved on --update unless re-stated) |
--update | For link: replace the external locator of the existing edge — matched by --id or the derived id — instead of appending, and re-record its baseline entry |
--refresh <edge-id> | For link: re-record the drift baseline for one intentionally changed artifact; the spec file is not touched |
--dry-run | For migrate: report the version change, edge count, and size delta without writing anything |
The agent loop
validate and check guard the ends of a spec-first task. The loop commands
serve the middle — choosing work, reading one artifact, and recording what was
done — so an agent (or a human) never has to hold the whole document in view or
hand-edit trace XML. This is the Code and Verify half of the
five-stage development process:
rqml show REQ-PAY-001 # read the requirement: statement,
# acceptance criteria, trace neighborhood
rqml impact REQ-PAY-001 # blast radius before touching anything
# … implement …
rqml link REQ-PAY-001 src/payments/capture.ts#capture # record the implements edge
rqml link REQ-PAY-001 test/capture.test.ts --type verifiedBy
rqml check # the gate — must exit 0
link is the workhorse:
- It appends a schema-valid edge textually, before
</trace>— XML comments and hand formatting in the spec survive untouched. - It writes the file only if the edited document still validates; otherwise nothing changes.
- It derives a deterministic edge id (
REQ-PAY-001→E-IMPL-PAY-001); pass--idto override. - For
implementslinks it records a drift baseline: a content hash of the linked artifact, stored in.rqml/baseline.json(commit it — see below). - It also maintains links as they age:
--updaterepoints the existing edge in place — same id, same orientation, only the locator changes — and--refresh <edge-id>re-blesses one artifact's baseline without re-stating the URI (see Drift baselines).
skeleton exists so nobody hand-rolls invalid structure. It covers every
authorable element — requirements and trace edges, but equally goals, scenarios,
glossary terms, business rules and entities — so "never invent element shapes"
is advice an author can actually follow:
rqml skeleton --list # every kind, grouped by the section it belongs under
rqml skeleton req --id REQ-PAY-002 # a ready-to-fill <req> with acceptance criteria
rqml skeleton rule # a business rule with the boundary examples slot
Standard output is the snippet and nothing else, so redirecting it into a file
is safe; the section it belongs under goes to standard error as a hint, and
--json returns it as a section field alongside the snippet.
matrix is the spec-health view: one row per requirement with its status, the
goals it satisfies, the code that implements it, the tests that verify it, and
any coverage warnings — derived from the same coverage pass as check, as a
markdown table or --json, and filterable by --status / --type / --warning:
rqml matrix --warning unverified # requirements still lacking a test
The check gate
rqml check is the deterministic enforcement gate. It composes XSD + integrity
validation, trace coverage, and implementation drift into a single pass/fail
verdict, and exits non-zero only when the document is invalid or has blocking
drift/coverage. Coverage findings block at strict and certified — including
the lifecycle-aware ones: approved requirements with no implements link,
and implements edges that point at a requirement that is not yet approved
(premature implementation).
Integrity validation also covers state machines: an unresolved initial state,
a dangling transition endpoint, or an outgoing transition from a final state
fails validation at every strictness level.
Because it invokes no language model, the verdict is reproducible — which is what makes it safe to wire into a save hook, a pre-commit hook, or CI.
rqml check --strictness strict
echo $? # 0 = pass
Drift baselines
rqml link records a sha256 hash of each linked artifact in
.rqml/baseline.json. When that file exists, check reports a linked artifact
as changed — its content no longer matches the hash recorded at link time —
in addition to missing. Commit the baseline so CI catches both:
rqml link REQ-PAY-001 src/payments/capture.ts # writes the edge + the baseline entry
git add requirements.rqml .rqml/baseline.json
# later, someone edits capture.ts without touching the spec…
rqml check # ✗ changed-implementation, exit 2
When the failure is unintentional drift, fix the code or the spec. When the change is intentional — the implementation was legitimately revised, or it moved — bless it explicitly instead of hand-editing the trace XML or the baseline file:
rqml link --refresh E-IMPL-PAY-001 # content changed: re-record this edge's hash
rqml link REQ-PAY-001 src/payments/charge.ts --update # artifact moved: repoint the edge + baseline
rqml check # ✓ exit 0
Both forms are deliberately edge-scoped: nothing else is re-hashed, so unrelated drift is never silently blessed along the way.
Without a baseline, drift detection falls back to existence checks only.
Fragment scope
A locator may name a fragment: packages/cli/package.json#bin says the bin
entry is the evidence, not the whole manifest. rqml link records that
fragment's content alongside the file hash, so when the file later changes,
check can tell the two cases apart:
| Outcome | Means | Blocks |
|---|---|---|
changed-implementation | the evidence itself changed | yes |
context-changed-implementation | the file changed, the named fragment did not | only at certified |
That is what stops a routine version bump from failing the build on an edge
that was never about the version. Refresh it when convenient to clear the
notice; nothing is waiting on you.
Three rules keep this from weakening the gate:
- The whole-file hash is still the detector. Fragment scope can only ever downgrade an alarm it has already raised.
- Only
.jsonfragments are interpreted, as a member name (#bin) or an RFC 6901 pointer (#/scripts/build). TypeScript, JavaScript and XSD fragments are used to locate the file and nothing more, so those edges behave exactly as they always have. - Anything uncertain — a fragment that no longer resolves, a file that stops being valid JSON, a member declared twice — is reported as drift, not as a pass.
A locator with no fragment is never narrowed. That is the point: a requirement
like "no model SDK in the dependency tree" links the whole package.json, so
scripts, peerDependencies and every other channel stay in scope by
construction.
Existing baselines keep working untouched — a bare sha256 still means whole-file
scope — and an edge gains fragment scope the next time you link or
--refresh it. Do that after everything that runs the gate is on a version
that understands it: CI, editor hooks, and contributors' global installs. An
older rqml treats the newer entry as drift rather than trusting it, which is
the safe direction, but it will turn the gate red for everyone still on the old
version.
Exit codes
Stable and documented, so scripts can branch on them:
| Code | Meaning |
|---|---|
0 | success |
1 | validation failure (not well-formed, schema-invalid, or integrity error) |
2 | check-gate failure (blocking drift or coverage) |
64 | usage error |
Examples
rqml init # scaffold requirements.rqml + merge the RQML block into AGENTS.md
rqml validate # is the spec structurally valid?
rqml status --json | jq . # coverage/lint summary as JSON
rqml show REQ-PAY-001 # one requirement as markdown (add --json for data)
rqml impact GOAL-CHECKOUT # everything that traces to/from this goal, transitively
rqml link REQ-PAY-001 src/payments/capture.ts#capture
rqml link --refresh E-IMPL-PAY-001 # bless an intentional change to linked code
rqml skeleton stateMachine # a valid lifecycle snippet to fill in
rqml check --strictness strict # CI gate