Command line: rr¶
rr is installed by pip install rules-requirements, and available in Bazel as
bazel run @rules_requirements//python:rr -- <command> ... (or
bazel run @rules_requirements -- <command> ...). Under bazel run, relative
paths resolve against the directory Bazel was invoked from.
Command |
Purpose |
Guide |
|---|---|---|
|
Check the model’s shape, references and coverage rules. |
|
|
Check that source annotations name defined ids; list them. |
|
|
Join the model with evidence; write HTML/JSON/Markdown and the gap queue. |
|
|
Export the trace graph as DOT, Mermaid, SVG or JSON. |
|
|
Print the test cases parsed from evidence files (debugging). |
|
|
List every test case key in the evidence, with status, declared ids and flags. |
|
|
Print each case’s one owner (or none), how it got it and its declared ids; |
|
|
Write the verification-set lock from the evidence, check the lock against it, or print one entity’s set. |
|
|
Re-prove from a JSON report alone that no test case is owned by two entities. |
|
|
Write the attribution worksheet: evidence that counts toward two or more entities. |
|
|
|
|
|
Check test evidence from after |
|
|
Run a test binary and convert its output to traceability JUnit. |
|
|
Append one test case to a JUnit file (shell and ad-hoc harnesses). |
rr --version prints the installed version (rr 0.3.0).
Exit status: 0 on success; 1 when validation fails, scan finds undefined
ids, or a report --fail-on / --pyramid-policy error condition holds, or
an attribution issue is an error (with report --strict, any attribution
warning); 2 when the model is invalid for scan, report, graph,
attribution, sets and migrate, or a report format cannot be inferred
(migrate still runs on a model whose only errors are shared-case /
same-code-multiple-owners: resolving them is its job; sets on one whose
only errors are about the lock); 3 when report finds a quarantined test
case (after writing the reports; --on-attribution-error=warn keeps the
status) and when sets lock refuses to lock one. attribution --check and
sets check exit 1 on a quarantine, a missing case, lock drift or an
error-level attribution issue; check-report exits 1 when the report breaks
the one-owner partition, its counts disagree, or it names a JSON key twice in
one object, 2 when it is no v2 report.
migrate apply --stage model exits 1, writing nothing, when the owner table
would change, the evidence holds a quarantine, a worksheet decision disagrees
with the evidence, or the new claims fail check_claims. cases,
attribution, sets and migrate plan exit 2 when the
--evidence paths hold no evidence at all. migrate apply exits 1, and writes
nothing unless given --partial, when it refused a file or could not find a
decided case’s test in the module it names, and 2 when the worksheet is
unreadable or an owner is not one of the ids its case counts toward.
migrate verify exits 1 when a decided case does not declare exactly its
owner or has no result, or, with --baseline, an undecided case’s ids
changed or a case disappeared (--allow-missing excuses a missing case only
when its target has no result file at all: a test.xml with no testcase
means the target ran), and 2 when the worksheet is
unreadable or invalid, the evidence or baseline holds none, or it names no
build target while the worksheet’s cases belong to build targets. wrap
exits with the wrapped command’s status; case exits 2 when it cannot record
the case (no output file, more than one id, a malformed id or --artifact).
migrate apply judges the code only an if __name__ == "__main__": block
runs like any other code unless given --trust-main-guard. That opt-in
exclusion is best-effort: only use it together with a definitive check (the
collection check, or migrate verify against fresh test evidence before
merging).
The reference below is generated from the command’s own argument parser.
usage: rr [-h] [--version]
{validate,scan,check-annotations,report,aggregate,graph,ingest,cases,migrate,attribution,sets,check-report,diff,serve,case,wrap}
...
Positional Arguments¶
- command
Possible choices: validate, scan, check-annotations, report, aggregate, graph, ingest, cases, migrate, attribution, sets, check-report, diff, serve, case, wrap
Named Arguments¶
- --version
show program’s version number and exit
Sub-commands¶
validate¶
validate the model
rr validate [-h] [--strict] [--format {text,json}] [--known-targets FILE]
[--sets-lock PATH] [--junit PATH]
[model ...]
Positional Arguments¶
- model
Default:
['requirements']
Named Arguments¶
- --strict
treat warnings as errors
Default:
False- --format
Possible choices: text, json
Default:
'text'- --known-targets
labels of every test target, one per line (bazel query ‘tests(//…)’); a claim, config.variants entry or lock target naming any other label is an unknown-target error
Default:
''- --sets-lock
check this lock instead of config.sets_lock
Default:
''- --junit
also write one JUnit case per check family (rr.validate::shape, ::references, ::coverage-rules, ::claims, ::lock); default $XML_OUTPUT_FILE when set (under bazel test)
Default:
''
scan (check-annotations)¶
check source annotations
rr scan [-h] [--model MODEL [MODEL ...]] [--root ROOT] [--include INCLUDE]
[--exclude EXCLUDE] [--files FILES [FILES ...]] [--list] [--json JSON]
[--ignore-model-errors] [--strict]
Named Arguments¶
- --model, --requirements
model files/directories
Default:
['requirements']- --root
source tree to scan (default: workspace)
Default:
''- --include
glob of files to scan (repeatable)
- --exclude
glob of files to skip (repeatable)
- --files
scan exactly these files (relative to –root)
- --list
print every annotation found
Default:
False- --json
write annotations as JSON
Default:
''- --ignore-model-errors
Default:
False- --strict
treat annotation warnings (multi-verifies-annotation) as errors
Default:
False
report¶
build the traceability report
rr report [-h] [--model MODEL [MODEL ...]] [--evidence [EVIDENCE ...]]
[--format FORMAT] [--ingestor INGESTOR] [--html HTML] [--json JSON]
[--md MD] [--out OUT] [--queue-out QUEUE_OUT] [--title TITLE]
[--strict] [--fail-on {none,failed,unverified,gaps}]
[--pyramid-policy {off,warn,error}] [--current-build KEY=VALUE]
[--scan] [--sets-lock PATH | --no-lock] [--lane NAME]
[--lane-targets FILE] [--on-attribution-error {fail,warn}]
[--root ROOT] [--include INCLUDE] [--exclude EXCLUDE]
[--files FILES [FILES ...]]
Named Arguments¶
- --model, --requirements
model files/directories
Default:
['requirements']- --evidence, --junit
evidence files/dirs/globs
Default:
['bazel-testlogs']- --format
only use these ingestors (repeatable)
- --ingestor
load an extra ingestor, module:attr
- --html
Default:
''- --json
Default:
''- --md
Default:
''- --out
output file; format from extension (repeatable)
- --queue-out
write the gaps as a JSON work queue
Default:
''- --title
Default:
''- --strict
treat model and attribution warnings as errors
Default:
False- --fail-on
Possible choices: none, failed, unverified, gaps
Default:
'none'- --pyramid-policy
Possible choices: off, warn, error
Default:
'warn'- --current-build
current artifact identity; mismatching evidence is stale
- --scan
also scan sources for implementation annotations
Default:
False- --sets-lock
read this verification-set lock, not config.sets_lock
Default:
''- --no-lock
read no verification-set lock (the sets are not pinned)
Default:
False- --lane
stamp the report with this lane (e.g. software)
Default:
''- --lane-targets
the targets this lane runs, one label per line: not-run members of other targets read ‘out of lane’ and their gaps stay out of –queue-out (verdicts never change)
Default:
''- --on-attribution-error
Possible choices: fail, warn
a quarantined test case (several ids, several claimants, one test code with several owners) makes rr report exit 3 after writing the reports (fail, the default); warn keeps the exit status (the cases still count for nobody, and every entity they name is INVALID)
Default:
'fail'- --root
source tree to scan (default: workspace)
Default:
''- --include
glob of files to scan (repeatable)
- --exclude
glob of files to skip (repeatable)
- --files
scan exactly these files (relative to –root)
aggregate¶
build the traceability report (alias)
rr aggregate [-h] [--model MODEL [MODEL ...]] [--evidence [EVIDENCE ...]]
[--format FORMAT] [--ingestor INGESTOR] [--html HTML]
[--json JSON] [--md MD] [--out OUT] [--queue-out QUEUE_OUT]
[--title TITLE] [--strict]
[--fail-on {none,failed,unverified,gaps}]
[--pyramid-policy {off,warn,error}] [--current-build KEY=VALUE]
[--scan] [--sets-lock PATH | --no-lock] [--lane NAME]
[--lane-targets FILE] [--on-attribution-error {fail,warn}]
[--root ROOT] [--include INCLUDE] [--exclude EXCLUDE]
[--files FILES [FILES ...]]
Named Arguments¶
- --model, --requirements
model files/directories
Default:
['requirements']- --evidence, --junit
evidence files/dirs/globs
Default:
['bazel-testlogs']- --format
only use these ingestors (repeatable)
- --ingestor
load an extra ingestor, module:attr
- --html
Default:
''- --json
Default:
''- --md
Default:
''- --out
output file; format from extension (repeatable)
- --queue-out
write the gaps as a JSON work queue
Default:
''- --title
Default:
''- --strict
treat model and attribution warnings as errors
Default:
False- --fail-on
Possible choices: none, failed, unverified, gaps
Default:
'none'- --pyramid-policy
Possible choices: off, warn, error
Default:
'warn'- --current-build
current artifact identity; mismatching evidence is stale
- --scan
also scan sources for implementation annotations
Default:
False- --sets-lock
read this verification-set lock, not config.sets_lock
Default:
''- --no-lock
read no verification-set lock (the sets are not pinned)
Default:
False- --lane
stamp the report with this lane (e.g. software)
Default:
''- --lane-targets
the targets this lane runs, one label per line: not-run members of other targets read ‘out of lane’ and their gaps stay out of –queue-out (verdicts never change)
Default:
''- --on-attribution-error
Possible choices: fail, warn
a quarantined test case (several ids, several claimants, one test code with several owners) makes rr report exit 3 after writing the reports (fail, the default); warn keeps the exit status (the cases still count for nobody, and every entity they name is INVALID)
Default:
'fail'- --root
source tree to scan (default: workspace)
Default:
''- --include
glob of files to scan (repeatable)
- --exclude
glob of files to skip (repeatable)
- --files
scan exactly these files (relative to –root)
graph¶
export the trace graph
rr graph [-h] [--model MODEL [MODEL ...]] [--format {dot,mermaid,json,svg}]
[--evidence [EVIDENCE ...]] [--methods] [--cases] [--out OUT]
Named Arguments¶
- --model, --requirements
model files/directories
Default:
['requirements']- --format
Possible choices: dot, mermaid, json, svg
Default:
'mermaid'- --evidence
color nodes by status
Default:
[]- --methods
include test methods
Default:
False- --cases
add a node per owned test case, with one edge from its one owner (needs –evidence)
Default:
False- --out
Default:
'-'
ingest¶
print the test cases parsed from evidence
rr ingest [-h] [--format FORMAT] [--ingestor INGESTOR] paths [paths ...]
Positional Arguments¶
- paths
Named Arguments¶
- --format
- --ingestor
cases¶
list every test case key in the evidence (no model needed)
rr cases [-h] [--evidence [EVIDENCE ...]] [--target TARGET] [--json]
[--format FORMAT] [--ingestor INGESTOR]
Named Arguments¶
- --evidence
evidence files/dirs/globs
Default:
['bazel-testlogs']- --target
only this target (repeatable)
- --json
print JSON instead of tab-separated lines
Default:
False- --format
only use these ingestors (repeatable)
- --ingestor
load an extra ingestor, module:attr
migrate¶
move to one requirement per test case: worksheet and codemod
rr migrate [-h] {plan,apply,verify} ...
Positional Arguments¶
- migrate_command
Possible choices: plan, apply, verify
Sub-commands¶
plan¶
write the attribution worksheet: evidence counting toward 2+ entities
rr migrate plan [-h] [--model MODEL [MODEL ...]] [--evidence [EVIDENCE ...]]
[--format FORMAT] [--ingestor INGESTOR] [--out OUT]
[--json JSON] [--md MD] [--merge MERGE]
Named Arguments¶
- --model, --requirements
model files/directories
Default:
['requirements']- --evidence
evidence files/dirs/globs
Default:
['bazel-testlogs']- --format
only use these ingestors (repeatable)
- --ingestor
load an extra ingestor, module:attr
- --out
worksheet to write (.rrplan, YAML); stdout if no output is given
Default:
''- --json
also write the worksheet as JSON
Default:
''- --md
also write the worksheet as Markdown
Default:
''- --merge
carry the decisions of an earlier worksheet over
Default:
''
apply¶
rewrite test tags to the owners decided on a worksheet
rr migrate apply [-h] --stage {tags,model} [--compress]
[--evidence [EVIDENCE ...]] [--ingestor INGESTOR]
[--root ROOT] [--only ONLY] [--unassigned {refuse,drop}]
[--line-length LINE_LENGTH] [--partial] [--dry-run]
[--model MODEL [MODEL ...]] [--no-collect-check]
[--trust-main-guard] [--python PYTHON]
[--pytest-args PYTEST_ARGS]
worksheet
Positional Arguments¶
- worksheet
the decided .rrplan (or .json) worksheet
Named Arguments¶
- --stage
Possible choices: tags, model
tags: split multi-id pytest/unittest tags; model: write an explicit selector for every current owner into the model (the owner table must stay unchanged under attribution: model)
- --compress
–stage model: a ‘*’ glob where it selects exactly the entity’s cases (none skipped, no overlap)
Default:
False- --evidence
–stage model: the evidence the owners come from (default: the worksheet’s inputs)
Default:
[]- --ingestor
load an extra ingestor, module:attr
- --root
source tree to rewrite (default: workspace)
Default:
''- --only
only rewrite files below this path (repeatable)
- --unassigned
Possible choices: refuse, drop
a multi-id test without a decision: leave its file unchanged (refuse) or drop its tags
Default:
'refuse'- --line-length
black’s line length, for lines that need wrapping
Default:
88- --partial
when files are refused or decided cases not found, still write each rewritten file that holds no such case and is not linked to a refused file or one holding such a case (default: write nothing). Two files are linked when one star-imports the other or passes it around as a module, or imports, references or subclasses a class, a test-named name or a name not defined at its top level; importing a plain helper function or constant does not link them. A file that cannot be read, a class whose base cannot be resolved, and an import call whose module cannot be named are linked to the files refused with them
Default:
False- --dry-run
print a diff instead of writing; the collection check still runs (exit 1 when apply would refuse)
Default:
False- --model, --requirements
check the decided owners exist
Default:
[]- --no-collect-check
skip the dynamic collection check (run pytest –collect-only before and after, and refuse unless every test keeps exactly the ids it should; it runs whenever anything would be written, with –partial and –dry-run too): write on the static guards alone, which are best-effort and cannot see tests pytest collects dynamically
Default:
False- --trust-main-guard
leave out of the static guards the code only an ‘if __name__ == “__main__”:’ block runs (its body and the module-level functions only it reaches), which pytest does not run when it imports the module (default: judge that code like any other). The exclusion is best-effort: static analysis cannot prove what Python runs at import, so only use it together with a definitive check – the collection check, or rr migrate verify against fresh test evidence before merging
Default:
False- --python
the interpreter whose pytest and project dependencies collect the tests for the collection check (default: the interpreter running rr)
Default:
''- --pytest-args
extra arguments for the collection check’s pytest, one shell-quoted string (e.g. “-c pytest.ini –rootdir . -p myplugin”, “–ignore=scripts”). Both collections run from –root with no path argument, so the project’s ini (testpaths included) picks what is collected; name paths here to collect others. With –strict-markers, pass ‘-p rules_requirements.hooks.pytest_plugin’ if the project loads rr’s plugin that way
Default:
''
verify¶
check test evidence from after apply against the worksheet (the check for Bazel projects)
rr migrate verify [-h] --worksheet WORKSHEET --evidence EVIDENCE
[EVIDENCE ...] [--baseline BASELINE [BASELINE ...]]
[--allow-missing] [--model MODEL [MODEL ...]]
[--format FORMAT] [--ingestor INGESTOR]
Named Arguments¶
- --worksheet
the decided .rrplan (or .json) worksheet
- --evidence
evidence from after the rewrite (files/dirs/globs, e.g. CI’s)
- --baseline
evidence from before the rewrite: every undecided case must keep its ids, and no case may disappear
Default:
[]- --allow-missing
a case with no result is a warning, not an error, when its target has no result file at all in the evidence (a HITL or manual target CI does not run); a case missing from a target that ran stays an error. A target with any result file ran: a test.xml with no testcase (pytest collected nothing) or only Bazel’s synthetic whole-run result included
Default:
False- --model, --requirements
check the decided owners exist, and the verified_by owner of decided cases that declare no id
Default:
[]- --format
only use these ingestors (repeatable)
- --ingestor
load an extra ingestor, module:attr
attribution¶
print who owns each test case (and why), or check that nothing is wrong
rr attribution [-h] [--model MODEL [MODEL ...]] [--evidence [EVIDENCE ...]]
[--ingestor INGESTOR] [--sets-lock PATH | --no-lock]
[--target TARGET] [--unowned] [--format {tsv,json}] [--check]
[--suggest]
Named Arguments¶
- --model, --requirements
model files/directories
Default:
['requirements']- --evidence
evidence files/dirs/globs
Default:
['bazel-testlogs']- --ingestor
load an extra ingestor, module:attr
- --sets-lock
read this verification-set lock, not config.sets_lock
Default:
''- --no-lock
read no verification-set lock (the sets are not pinned)
Default:
False- --target
only this target (repeatable)
- --unowned
only cases no entity owns (quarantined ones included)
Default:
False- --format
Possible choices: tsv, json
Default:
'tsv'- --check
exit 1 on any quarantine, missing case, lock drift or error-level attribution issue
Default:
False- --suggest
print the selector to add for each tag-owned or unclaimed-tag case
Default:
False
sets¶
the verification-set lock: write it, check it, show one set
rr sets [-h] {lock,check,show} ...
Positional Arguments¶
- sets_command
Possible choices: lock, check, show
Sub-commands¶
lock¶
compute the lock from the evidence; print the diff, or –write it
rr sets lock [-h] [--model MODEL [MODEL ...]] [--evidence [EVIDENCE ...]]
[--format FORMAT] [--ingestor INGESTOR] [--sets-lock PATH]
[--write] [--allow-removals] [--out PATH]
Named Arguments¶
- --model, --requirements
model files/directories
Default:
['requirements']- --evidence
evidence files/dirs/globs
Default:
['bazel-testlogs']- --format
only use these ingestors (repeatable)
- --ingestor
load an extra ingestor, module:attr
- --sets-lock
the lock to read (default: config.sets_lock)
Default:
''- --write
write the lock (default: print the diff)
Default:
False- --allow-removals
drop entries the evidence no longer has, including those of a suite:/record: pseudo-target it does not hold (default: keep them, so a crashed or filtered run never shrinks a set silently)
Default:
False- --out
write here instead (relative: to the workspace root)
Default:
''
check¶
exit 1 when the lock disagrees with the evidence (missing cases, unlocked members, owner changes)
rr sets check [-h] [--model MODEL [MODEL ...]] [--evidence [EVIDENCE ...]]
[--format FORMAT] [--ingestor INGESTOR] [--sets-lock PATH]
Named Arguments¶
- --model, --requirements
model files/directories
Default:
['requirements']- --evidence
evidence files/dirs/globs
Default:
['bazel-testlogs']- --format
only use these ingestors (repeatable)
- --ingestor
load an extra ingestor, module:attr
- --sets-lock
the lock to read (default: config.sets_lock)
Default:
''
show¶
print one entity’s verification set
rr sets show [-h] [--model MODEL [MODEL ...]] [--evidence [EVIDENCE ...]]
[--format FORMAT] [--ingestor INGESTOR] [--sets-lock PATH]
entity
Positional Arguments¶
- entity
a user need, requirement or mitigation id
Named Arguments¶
- --model, --requirements
model files/directories
Default:
['requirements']- --evidence
evidence files/dirs/globs
Default:
['bazel-testlogs']- --format
only use these ingestors (repeatable)
- --ingestor
load an extra ingestor, module:attr
- --sets-lock
the lock to read (default: config.sets_lock)
Default:
''
check-report¶
re-prove from a JSON report alone that no test case is owned by two entities
rr check-report [-h] report
Positional Arguments¶
- report
a JSON report (rules_requirements/report/v2)
diff¶
semantic diff of the model between two git refs
rr diff [-h] [--model MODEL [MODEL ...]] [--root ROOT] [--json] [--exit-code]
old [new]
Positional Arguments¶
- old
git ref (e.g. main, v1.0, HEAD~3)
- new
git ref, or WORKTREE (default)
Default:
'WORKTREE'
Named Arguments¶
- --model, --requirements
model files/directories
Default:
['requirements']- --root
repository root (default: workspace)
Default:
''- --json
Default:
False- --exit-code
exit 1 when the model changed
Default:
False
serve¶
interactive web editor with tracing, versioning and agents
rr serve [-h] [--model MODEL [MODEL ...]] [--evidence [EVIDENCE ...]]
[--root ROOT] [--host HOST] [--port PORT] [--token TOKEN]
[--allow-host ALLOW_HOST] [--author AUTHOR]
[--current-build KEY=VALUE] [--lane-targets NAME=FILE] [--no-scan]
[--no-llm] [--agent-model AGENT_MODEL] [--agent-effort AGENT_EFFORT]
Named Arguments¶
- --model, --requirements
model files/directories
Default:
['requirements']- --evidence
test evidence (e.g. bazel-testlogs)
Default:
[]- --root
repository root (default: workspace)
Default:
''- --host
Default:
'127.0.0.1'- --port
Default:
8080- --token
require this bearer token on API requests
Default:
''- --allow-host
extra Host header value to accept (e.g. behind a proxy)
- --author
default author for edits and commits, “Name <email>”
Default:
''- --current-build
- --lane-targets
the targets lane NAME runs, one label per line: the case ledger can filter by lane
- --no-scan
skip the source annotation scan
Default:
False- --no-llm
disable LLM-backed agent workflows
Default:
False- --agent-model
Claude model for agents (default claude-opus-5-5)
Default:
''- --agent-effort
effort for agent requests (default high)
Default:
''
case¶
Append one test case to the JUnit file at –out (default $XML_OUTPUT_FILE), creating it if needed. Exits 0 whatever the case’s status.
rr case [-h] [--out OUT] --name NAME [--status {passed,failed,error,skipped}]
[--classname CLASSNAME] [--suite SUITE] [--requirement ID]
[--level LEVEL] [--artifact KEY=VALUE] [--message MESSAGE]
[--duration DURATION] [--file FILE]
Named Arguments¶
- --out
JUnit file to append to (default: $XML_OUTPUT_FILE)
Default:
''- --name
the case’s name
- --status
Possible choices: passed, failed, error, skipped
Default:
'passed'- --classname
the case’s classname (default: the suite)
Default:
''- --suite
suite to append to (default: the name part of $TEST_TARGET, else rr)
Default:
''- --requirement
the ONE requirement id the case verifies
- --level
the verification level the case provides
Default:
''- --artifact
artifact identity (repeatable)
- --message
failure, error or skip message
Default:
''- --duration
seconds
Default:
0.0- --file
source file of the test code, recorded as rr.file
Default:
''
wrap¶
run a test binary and emit traceability JUnit
rr wrap ...
Positional Arguments¶
- rest