rqtk
Requirements that live in your repository, proven by tests.
rqtk keeps requirements, stakeholder needs and verification evidence as TOML files next to your code. A requirement change is a commit, a baseline is a git tag, and history is git log. There is no separate tool or database, and no export step between your requirements and your version control.
.rqtk/
config.toml ← project policy: categories, states, lint rules
requirements/SYS/SYS-0001.toml
needs/NEED-0001.toml
stakeholders/STK-0001.toml
evidence.toml ← which tests passed, against which version of each requirement
Why
Most requirements tools are separate systems: documents, spreadsheets or SaaS platforms, disconnected from source control. Engineers end up maintaining two ledgers, and the two drift apart.
rqtk treats requirements as source code, and it holds them to the same standard as code:
- Checked like code.
rqtk lintrejects typos, unknown references, cycles and vague statements, with the file and line of every finding. - Proven, not claimed. A requirement counts as verified only when the tests linked to it passed against its current wording. Reword the requirement and it becomes Suspect until those tests pass again. Nobody can mark a requirement done by editing a file.
- Operable by agents. Every command prints JSON with
--json, exits with documented codes, and never prompts. Agent skills plug rqtk into a coding agent’s normal workflow.
Where to go next
- Install rqtk, then follow the quick start.
- Read how verification from test evidence works: it is the core idea.
- Using Claude Code, Codex, Cursor or another coding agent? See Coding agents.
Installation
Prebuilt binaries
On macOS and Linux:
curl -LsSf https://rqtk.dev/install.sh | sh
On Windows (PowerShell):
powershell -ExecutionPolicy Bypass -c "irm https://rqtk.dev/install.ps1 | iex"
Both scripts download the right binary for your platform from the latest GitHub release and verify its checksum. You can also download an archive from the release page yourself.
With pip or uv
pip install rqtk # or: uv tool install rqtk
The Python package contains the full command line and the @rqtk.verifies decorator for linking pytest tests. Wheels are available for Linux, macOS and Windows on Python 3.9 and later.
With Cargo
cargo install rqtk --locked
This needs Rust 1.88 or later.
Linking tests
Linking tests to requirements needs nothing extra for most languages: a // rqtk: verifies VA-… comment above a test is enough. Two languages have a checked annotation:
- Rust: add
rqtk = { version = "1", default-features = false, features = ["macros"] }to[dev-dependencies]and annotate tests with#[rqtk::verifies("VA-…")]. An unknown activity ID is a compile error. (The standalonerqtk-macroscrate works too.) - Python:
pip install rqtkand decorate tests with@rqtk.verifies("VA-…"). An unknown activity ID fails test collection.
See Verifying with tests.
Check the installation
rqtk --version
Quick start
This walks through the whole loop: set up a repository, write a requirement, prove it with a test, and watch it go Suspect when it changes.
1. Initialise
In a git repository:
rqtk init
This creates .rqtk/config.toml with a starter policy, named after your project. Add --agents to also install the agent skills, --hook for a pre-commit hook that lints before every commit, and --example for an example stakeholder and need. Everything except history (impact, diff, log, baseline) works outside a git repository too.
2. Add a requirement
rqtk add --category SYS --type Functional \
--title "Fast boot" \
--statement "The system shall boot in under 5 seconds." \
--rationale "Operators restart the unit during a pass." \
--criteria "Boot completes in under 5 s on reference hardware." \
--activity "Boot time test"
rqtk assigns the next free ID (here REQ-SYS-0001) and writes .rqtk/requirements/SYS/REQ-SYS-0001.toml, with a verification activity VA-SYS-0001-01:
[verification]
method = "Test"
level = "Unit"
phase = "Development"
success_criteria = "Boot completes in under 5 s on reference hardware."
[[verification.activities]]
id = "VA-SYS-0001-01"
name = "Boot time test"
--parent and --satisfies link it to the requirement it derives from and the need it serves; rqtk add-activity adds more activities later. Then check it:
rqtk lint
3. Link a test
Put the activity ID above the test that proves it:
#![allow(unused)]
fn main() {
// rqtk: verifies VA-SYS-0001-01
#[test]
fn boots_in_under_five_seconds() {
// …
}
}
rqtk scan lists every link it finds, and the test each one is attached to.
4. Record the results
Run your tests with JUnit output, then hand the report to rqtk:
cargo nextest run # writes target/nextest/default/junit.xml
rqtk verify --results target/nextest/default/junit.xml
rqtk coverage
The requirement is now Verified, and .rqtk/evidence.toml records which test passed, at which commit, against which version of the requirement. Commit it with the code.
5. Change the requirement
Tighten the statement to “under 3 seconds” and run rqtk coverage again. The requirement is now Suspect: its tests passed for the old wording, and nothing has proven the new one.
Rerunning the same test doesn’t settle it: it passed for 5 seconds and says nothing about 3. Update the test for the new limit, run it, and rqtk verify again. (If a test already checks the new wording, record that with rqtk review REQ-SYS-0001 --note "…".)
rqtk coverage --strict exits 1 until every requirement is Verified, so it works as a CI gate.
Writing requirements
rqtk tracks three kinds of item, each a TOML file named after its ID:
| Item | Lives in | Says |
|---|---|---|
| Stakeholder | .rqtk/stakeholders/ | who cares about the system |
| Need | .rqtk/needs/ | what a stakeholder needs, and why |
| Requirement | .rqtk/requirements/<CATEGORY>/ | what the system shall do, and how that is verified |
Requirements satisfy needs, decompose into child requirements through trace.parents, and are proven by verification activities. Every link is by ID, and rqtk lint checks that every link resolves.
Creating items
rqtk add-stakeholder --name "Operator" --role "Runs the ground station"
rqtk add-need --title "Fast recovery" \
--statement "Operators need the unit back within seconds after a restart." \
--stakeholders STK-0001
rqtk add --category SYS --type Functional --title "Fast boot" \
--statement "The system shall boot in under 5 seconds." \
--rationale "Operators restart the unit during a pass." \
--satisfies NEED-0001 \
--criteria "Boot completes in under 5 s on reference hardware." \
--activity "Boot time test"
rqtk assigns the next free ID in each case. Pass --dry-run to see the file without writing it, and --json to get the assigned ID in machine-readable form.
rqtk add also takes --parent (repeatable) for the requirement it decomposes, --priority, and --method, --level and --phase for how it is verified. A category listed in validation.require_parent_for_categories needs --parent.
Each --activity gets an ID derived from the requirement’s: REQ-SYS-0001 gets VA-SYS-0001-01, VA-SYS-0001-02, and so on. Tests cite these IDs. Add an activity to an existing requirement with:
rqtk add-activity REQ-SYS-0001 --name "Cold boot test"
Anatomy of a requirement
id = "REQ-SYS-0001"
title = "Fast boot"
category = "SYS"
type = "Functional"
state = "Approved"
priority = "High"
statement = "The system shall boot in under 5 seconds."
rationale = "Operators restart the unit during a pass."
[trace]
satisfies = ["NEED-0001"]
# parents, derived_from, refines, depends_on, conflicts_with, related: all by ID
[verification]
method = "Test"
level = "System"
phase = "Development"
success_criteria = "Boot completes in under 5 s on reference hardware."
[[verification.activities]]
id = "VA-SYS-0001-01"
name = "Boot time test"
The full list of fields is on the File formats page, and rqtk schema requirement prints the JSON Schema. Unknown fields are errors, so a typo is reported instead of silently ignored.
Good statements
rqtk lint enforces the basics, and the project configuration can tighten them:
- One sentence, with the shall keyword (RQ010). Split compound requirements.
- Measurable. A test must be able to decide pass or fail. Forbid vague words such as “fast” or “user-friendly” with
validation.forbidden_keywords(RQ011). - Justified. A
rationalesays why the requirement exists (RQ007). - Traced. Set
trace.parentsto the requirement it decomposes, andtrace.satisfiesto the need it serves. Withforbid_orphans, every requirement must trace back to a root category (RQ018).
Finding your way around
rqtk search boot -i # substring search across requirements, needs and stakeholders
rqtk trace REQ-SYS-0001 # parents and children
rqtk context REQ-SYS-0001 # everything about one item: links, tests, status, findings
rqtk graph > trace.dot # the whole graph, for Graphviz
Configuration
.rqtk/config.toml decides the vocabulary: categories and their hierarchy, requirement types, lifecycle states, priorities, verification methods, and which lint rules apply. See Configuration.
To add a category, add a table for it:
[categories.SW]
name = "Software"
level = 2
Requirement IDs are checked against <prefix>-<CATEGORY>-<NUMBER> for the configured categories (RQ001). Set identification.id_pattern only if your IDs follow another scheme; then new categories must be added to it too.
Verifying with tests
A requirement is verified only by recorded test results, never by editing a file. rqtk records which tests passed against which version of each requirement. When the requirement changes afterwards, that evidence turns Suspect until the tests run again.
The loop
- Link a test to a verification activity.
- Run the tests with JUnit XML output.
- Record the results with
rqtk verify. - Check with
rqtk coverage --strict, and commit.rqtk/evidence.tomlwith the code.
Linking tests
Put the activity ID directly above the test. Only blank lines, comments, other tags and attributes (#[test], @Test, @pytest.mark.parametrize(…), [Fact]) may sit in between; the first other line must be the test.
| Language | Annotation | Checked when |
|---|---|---|
| Rust | #[rqtk::verifies("VA-…")] (the rqtk crate with default-features = false, features = ["macros"]) | compile time |
| Python | @rqtk.verifies("VA-…") | test collection |
| Anything | // rqtk: verifies VA-… (or #, --, /* */) | rqtk lint |
rqtk recognises these test declarations:
| Language | Tests |
|---|---|
| Rust | fn name |
| Python | def test_x, async def test_x, methods of test classes |
| Go | func TestX, including methods func (s *S) TestX |
| JavaScript, TypeScript | it, test and describe (a whole group), with .only, .skip, .concurrent, .each(…); function name |
| Java, C#, C, C++ | methods and functions (void name(), public async Task Name()), GoogleTest TEST, TEST_F, TEST_P, Catch2 and doctest TEST_CASE |
| Kotlin, Swift, Ruby, Zig, Elixir | fun, func, def, test "name", RSpec it "…" do |
rqtk scan shows what each link is attached to. A tag with no test declaration below it can never match a result; rqtk lint reports it as an error (RQ030).
A test can verify several activities, and an activity can have several tests; it passes only when all of them pass. rqtk lint also reports links to unknown activities (RQ028).
One case of a table-driven test
Tag the case’s row, and name the case:
func TestIntact(t *testing.T) {
cases := []struct{ name string; flip bool }{
// rqtk: verifies VA-SYS-0003-01 case "flipped byte is corrupt"
{"flipped byte is corrupt", true},
// rqtk: verifies VA-SYS-0003-02 case "intact file passes"
{"intact file passes", false},
}
// …
}
The link belongs to the enclosing test and matches the runner’s result for that case: Go’s TestIntact/flipped_byte_is_corrupt, or pytest’s test_x[case]. In Python and Rust, pass case to the annotation instead: @rqtk.verifies("VA-…", case="neg").
The same works for rows of a JS/TS it.each([...]) table, where the case is any part of the rendered title (case "1+1" for "adds 1+1"), and for GoogleTest value-parameterised tests, where the case is the parameter’s value: tag the TEST_P with // rqtk: verifies VA-… case "7".
Display names
JUnit’s @DisplayName("…") and @ParameterizedTest(name = "…"), and xUnit’s DisplayName = "…", change the name some runners report (Gradle does; Maven Surefire reports the method name). rqtk reads them from the annotations above the test and matches either name. A parameterised JUnit test without a name is reported by Gradle as [1] … with no trace of the method, so give it a name.
Choosing what is scanned
In .rqtk/config.toml:
[scan]
paths = ["."] # default; .gitignore is honoured
exclude = ["tests/fixtures/**"] # gitignore-style globs
Running tests with JUnit output
rqtk reads JUnit XML, which nearly every test runner can write:
| Ecosystem | Command |
|---|---|
| Rust (nextest) | cargo nextest run, with [profile.default.junit] path = "junit.xml" in .config/nextest.toml; the report lands in target/nextest/default/ |
| Rust (stable libtest) | RUSTC_BOOTSTRAP=1 cargo test --tests -- -Z unstable-options --format junit > junit.xml |
| Python | pytest --junitxml=junit.xml |
| Go | go test -v ./... 2>&1 | go-junit-report > junit.xml (go install github.com/jstemmer/go-junit-report/v2@latest), or gotestsum --junitfile junit.xml |
| JS/TS | vitest run --reporter=junit --outputFile=junit.xml, bun test --reporter=junit --reporter-outfile=junit.xml, or jest with jest-junit |
| JVM | Maven Surefire and Gradle write JUnit XML by default (target/surefire-reports/*.xml, build/test-results/test/*.xml) |
| C/C++ | ctest --output-junit junit.xml (CMake 3.21+), or GoogleTest’s --gtest_output=xml:junit.xml |
--results takes several files, so one per package or module works too.
How results are matched
A result matches a link by test name (or display name), together with the suite for GoogleTest and the case for a case link. When several tests share a name, rqtk narrows by the source file the runner reports (Bun, vitest, GoogleTest) or by what the link’s path says about the result’s class or module. If a linked test still matches several distinct tests, rqtk verify records nothing for it and says which tests it matched; rename one. Disabled and skipped tests leave an activity incomplete.
Recording results
rqtk verify --results junit.xml
rqtk matches each test case to the functions linked to each activity and records one entry per activity in .rqtk/evidence.toml: the outcome, the tests, the commit, and the content hash of the requirement at that moment.
- An activity passes only when every linked test ran and passed; a skipped test leaves it incomplete.
- A run that covers only some tests, such as the Python suite without the Rust one, leaves other activities’ evidence untouched.
verifycounts the linked tests it found no result for, so a runner naming tests differently doesn’t go unnoticed. - Evidence names each test as
<source file>::<name>, so the same test gets the same entry whichever runner reported it. verifyexits 1 if a linked test failed, if a linked test matched several tests, or if the results matched no linked test at all (usually the wrong file, or tags rqtk can’t attach).verify --checkwrites nothing and exits 1 if the committed evidence doesn’t match this run. Use it in CI.
Coverage states
rqtk coverage puts every requirement in one state:
| State | Meaning | What to do |
|---|---|---|
| Verified | Every activity passed: linked tests against the current wording, or a manual status of Passed/Waived | nothing |
| Suspect | Evidence no longer settles it; see Suspect | depends on the reason |
| Failed | A linked test failed, or a manual status is Failed | fix the code, or with the stakeholder, the requirement |
| In Progress | Some activities passed or started | finish the rest |
| Planned | Activities defined, nothing run yet | link and run tests |
| Gap | No activities, or no success criteria | define them |
rqtk coverage --strict exits 1 unless every requirement is Verified and every need is satisfied. For requirements written ahead of their implementation, --allow planned (and --allow in-progress) accepts those states too.
Suspect
A requirement becomes Suspect when evidence recorded for it no longer settles it. rqtk coverage and rqtk context say why:
| Reason | What happened | What settles it |
|---|---|---|
| changed since its tests passed | its content hash changed after its tests passed | run the tests, rqtk verify |
| passed again with unchanged tests | it changed, and the same tests that passed for the old wording passed again | change the tests for the new wording and run them, or rqtk review |
| upstream changed | a parent requirement, or a need it or its ancestors satisfy, changed after it was verified | check it still fits, then rqtk review |
The content hash covers what the requirement demands and how it is verified: the statement, its structural links (parents, depends_on, derived_from, refines, satisfies), its parameters, and the verification method, level and phase. Editing the title, keywords, priority or notes changes nothing.
This is deliberate. A reworded requirement may no longer be what the tests check, so rqtk refuses to carry the old verdict over, and rerunning a test that was never updated proves nothing new. rqtk impact <base> lists every activity to re-run after a change. Change control covers rqtk review.
Activities no test can check
Inspections, analyses and demonstrations keep a hand-written status:
[[verification.activities]]
id = "VA-SYS-002-01"
name = "Thermal analysis"
status = "Passed"
executed_at = 2026-03-14
evidence = ["reports/thermal-2026-03.pdf"]
As soon as a test is linked to an activity, its status is ignored, and rqtk lint warns until you remove it (RQ029).
Baselines and change control
Requirement changes that slip through without review are harder to catch than code changes: there is no compiler to notice a modified shall statement. rqtk leans on git for the record and adds what git can’t tell you.
Baselines
A baseline is an annotated git tag, rqtk/<version>:
rqtk baseline 1.0.0 --dry-run # show what would be stamped and tagged
rqtk baseline 1.0.0
It writes approval.baselined_at and approval.baselined_by into every requirement (leaving the rest of each file untouched), commits that, and tags the commit.
What changed
rqtk diff 0.9.0 1.0.0 # between baselines, branches, tags or SHAs
rqtk impact main # between a revision and your working tree
rqtk log SYS-0001 # git history of one requirement
diff classifies each modified requirement as semantic (its content hash changed: statement, links, parameters or verification) or cosmetic (anything else).
impact goes further. For a branch or pull request it lists:
- requirements and needs added, removed or changed;
- requirements downstream of a semantic change, which may need their own review;
- every verification activity to re-run, because its requirement changed or a file containing one of its tests changed, with the tests to run. Activities whose evidence already covers the change are listed separately.
Review debt
Two kinds of change leave a requirement Suspect until someone deals with them, however often the tests run:
- Its tests didn’t change with it. The requirement was reworded and the same tests that passed for the old wording passed again. They may still prove it, or they may test the old behaviour; rqtk can’t tell which.
- Something upstream changed. A parent requirement, or a need it or its ancestors satisfy, changed after it was verified. The child may no longer fit.
Each is settled one way:
- update the tests for the new wording and run them, then
rqtk verify; - or confirm the requirement still holds, and record that:
rqtk review REQ-SW-0004 --note "Threshold follows the parent; tests check the configured value."
The review lands in .rqtk/evidence.toml with the date, the commit and the note, and shows in rqtk report. It lasts until the requirement or anything upstream changes again. A review doesn’t stand in for running a changed requirement’s tests: that Suspect reason stays until they pass.
Review and sign-off
Two platform features make the git log an auditable change record:
CODEOWNERS routes changes to the right reviewer:
.rqtk/requirements/SYS/ @systems-lead
.rqtk/requirements/SW/ @software-lead
Signed commits, enforced by branch protection, tie every change to a verified identity.
The [approval] table in each requirement is a readable summary for anyone looking at the TOML. The authoritative record is the git log: who signed the commit, and who approved the pull request.
[approval]
baselined_at = 2026-11-01
baselined_by = "systems-lead"
approved_by = ["systems-lead", "chief-engineer"]
ecr_ids = ["ECR-0042"]
Pre-commit hook
rqtk install-hook # or, in a new repository: rqtk init --hook
This adds a managed block to .git/hooks/pre-commit that runs rqtk rehash (refresh any stored content hashes) and rqtk lint before each commit. Existing hook content is kept.
New files carry no content_hash; rqtk computes it when it needs it. Stamp every file with rqtk rehash --all if you want the hash visible in the TOML; lint rule RQ021 then reports when it goes stale.
Coding agents
rqtk is built to be driven by coding agents as well as people: nothing prompts, every command prints JSON with --json, and exit codes are fixed. Four agent skills bring it into an agent’s normal workflow.
Skills
rqtk skills install # or, in a new repository: rqtk init --agents
| Skill | Invoked by | What it does |
|---|---|---|
rqtk-requirements | agent or you | Reading and writing .rqtk/: find the governing requirement, read its briefing, author items that lint clean. |
rqtk-verification | agent or you | The proof loop: link a test, run it, rqtk verify; done when rqtk lint and rqtk coverage --strict exit 0. |
/to-requirements | you | Turn a spec or discussion into needs and requirements with verification activities; you approve the draft before anything is written. |
/requirements-review | you | Review a diff against the requirements it touches: facts from rqtk impact, then a verdict per requirement, and the rqtk review commands that would settle what is still Suspect. |
The skills follow the open Agent Skills format, so they work with any agent that supports it:
| Agents | Read skills from | What rqtk installs |
|---|---|---|
| Codex, Cursor, GitHub Copilot, Gemini CLI, OpenCode, Amp, Cline, Zed, Warp, … | .agents/skills/ | the skill files |
| Claude Code | .claude/skills/ | a link per skill into .agents/skills/ |
rqtk skills install --for claude or --for universal installs for one family only; --copy writes copies instead of links; --dir installs anywhere else. The skills are compiled into the binary, so they always describe the rqtk you have. Reinstall after upgrading: untouched skills are updated, and skills you edited are kept.
rqtk also adds a short block to AGENTS.md (and to CLAUDE.md, unless it already imports @AGENTS.md) telling agents where requirements live and when work is done. It never creates those files unless you name one with --instructions.
Where the skills fit
The skills are small and slot into an existing flow rather than imposing one. They were designed alongside mattpocock/skills:
grill → /to-spec → /to-requirements → /to-tickets → /implement → /code-review + /requirements-review
/to-requirementsturns the spec into requirements with activity IDs.- Tickets cite those IDs in their acceptance criteria.
- The implementer’s tests cite the activity IDs, and
rqtk verifyrecords them. /requirements-reviewchecks the result on the requirements axis, next to the usual code review.
Commands agents use most
rqtk context REQ-SYS-0001 --json # the briefing: statement, links, tests, status, findings
rqtk impact main --json # what a change touches, what to re-verify, and with which tests
rqtk lint --json # findings with code, severity and file:line
rqtk explain RQ010 # what a rule checks and how to fix it
rqtk schema requirement # the JSON Schema of a file kind
rqtk add … --parent … --criteria … --activity … # a complete requirement in one command
Exit codes and the JSON contract are described under JSON output and exit codes.
Machine-readable docs
These docs are also available in plain Markdown for agents: /llms.txt indexes every page, and /llms-full.txt contains them all in one file.
Continuous integration
Three commands make a complete requirements gate:
rqtk lint # every file valid, every link resolves
rqtk verify --check --results junit.xml # committed evidence matches this test run
rqtk coverage --strict # every requirement Verified
Each exits 1 when it finds a problem, so any CI system can use them directly. If you write requirements ahead of their implementation, rqtk coverage --strict --allow planned lets those through while still failing on anything Suspect, Failed or half-done.
GitHub Actions
name: Requirements
on: [push, pull_request]
jobs:
requirements:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: dtolnay/rust-toolchain@stable
- uses: taiki-e/install-action@v2
with:
tool: cargo-nextest
- name: Install rqtk
run: curl -LsSf https://rqtk.dev/install.sh | sh
- name: Test
run: cargo nextest run --profile ci # writes target/nextest/ci/junit.xml
- run: rqtk lint
- run: rqtk verify --check --results target/nextest/ci/junit.xml
- run: rqtk coverage --strict
Configure the ci nextest profile to write JUnit in .config/nextest.toml:
[profile.ci.junit]
path = "junit.xml"
Why verify --check
Evidence is committed, so it is reviewed like code. verify --check makes sure it is honest: it fails when the committed .rqtk/evidence.toml doesn’t match what this CI run observed. For example, someone may have changed a requirement without re-running its tests, or a test may now fail. To fix it, run the tests and rqtk verify locally, then commit the updated evidence. Editing a test that still passes doesn’t count as a mismatch.
Reviews recorded with rqtk review live in the same file, so they reach the main branch through the same pull request review as the change they settle.
Pull request review
rqtk impact origin/main --json lists the requirements a pull request changes, the requirements downstream of them, and the activities to re-verify. It is a good input for a review bot, or for the /requirements-review agent skill.
Commands
Every command accepts --json (one JSON document on stdout) and --repo-root <DIR>. The same text is available from rqtk <command> --help.
Requirements Toolkit
Usage: rqtk [OPTIONS] <COMMAND>
Commands:
init Scaffold a new requirement set in the current repo
add Add a new requirement with the next free ID in its category
add-activity Add a verification activity to an existing requirement
add-stakeholder Add a new stakeholder definition
add-need Add a new stakeholder need
lint Check every file against the schema, the config and the `verifies` links in source
context Everything relevant to one requirement, need or stakeholder: links, tests, status, evidence and lint findings. Designed as the briefing for working on an item
impact What changed since a git revision, and which requirements and activities it affects
trace Show the parent/child traceability chain of a requirement
coverage Report need satisfaction and verification status (verified / suspect / failed / …)
graph Print the traceability graph of stakeholders, needs and requirements
baseline Stamp all requirements and create a git tag baseline for HEAD
export Export requirements to a file in the given format
diff Show requirements that changed between two git revisions or baselines
scan List `verifies` links between source code and verification activities
verify Record test results as verification evidence in `.rqtk/evidence.toml`
review Confirm a requirement still holds after something it depends on changed
search Search requirements, needs and stakeholders by substring
open Open a requirement file in $EDITOR
log Show the git commit history for a single requirement
install-hook Install a git pre-commit hook that runs `rqtk rehash` and `rqtk lint`
rehash Refresh stored content hashes that no longer match their requirement or need
report Generate a Markdown requirements report
schema Print the JSON Schema of a file kind, or list the kinds
explain Explain a lint rule and how to fix it, or list all rules
skills Agent skills for working with rqtk in coding agents (Claude Code, Codex, …)
help Print this message or the help of the given subcommand(s)
Options:
--repo-root <REPO_ROOT> Repository root (the directory containing `.rqtk/`) [default: .]
--json Print one JSON document to stdout instead of text. Errors go to stderr as JSON
-h, --help Print help
-V, --version Print version
Exit codes:
0 success, nothing to report
1 findings: lint errors, failed or suspect verification, stale evidence
2 usage error: bad arguments or unsupported option
3 error: configuration, I/O or git failure
rqtk init
Scaffold a new requirement set in the current repo
Usage: rqtk init [OPTIONS]
Options:
--repo-root <REPO_ROOT>
Repository root (the directory containing `.rqtk/`) [default: .]
--requirements-dir <REQUIREMENTS_DIR>
--force
Overwrite an existing `.rqtk/config.toml`
--json
Print one JSON document to stdout instead of text. Errors go to stderr as JSON
--agents
Also install the agent skills (see `rqtk skills install`)
--example
Also create an example stakeholder and need
--hook
Also install the git pre-commit hook (see `rqtk install-hook`)
--dry-run
Report the files that would be created without writing them
-h, --help
Print help
rqtk add
Add a new requirement with the next free ID in its category
Usage: rqtk add [OPTIONS] --category <CATEGORY> --type <REQ_TYPE> --title <TITLE> --statement <STATEMENT>
Options:
--category <CATEGORY> Category key from `.rqtk/config.toml`, e.g. SYS
--repo-root <REPO_ROOT> Repository root (the directory containing `.rqtk/`) [default: .]
--json Print one JSON document to stdout instead of text. Errors go to stderr as JSON
--type <REQ_TYPE> Requirement type from `types.allowed`
--title <TITLE>
--statement <STATEMENT> A single normative sentence, e.g. "The system shall …"
--rationale <RATIONALE>
--parent <PARENTS> Parent requirement ID (repeatable, or comma-separated)
--satisfies <SATISFIES> ID of a need this requirement satisfies (repeatable, or comma-separated)
--priority <PRIORITY> Priority from `priority.levels` [default: Medium, or the middle level]
--method <METHOD> Verification method from `verification.methods` [default: the first]
--level <LEVEL> Verification level from `verification.levels` [default: the first]
--phase <PHASE> Verification phase from `verification.phases` [default: the first]
--criteria <CRITERIA> Success criteria: what a passing verification shows
--activity <ACTIVITIES> Add a verification activity with this name (repeatable). IDs are generated as VA-<CATEGORY>-<NUMBER>-<NN>
--dry-run Print the file that would be created without writing it
-h, --help Print help
rqtk add-activity
Add a verification activity to an existing requirement
Usage: rqtk add-activity [OPTIONS] --name <NAME> <REQUIREMENT>
Arguments:
<REQUIREMENT> Requirement ID
Options:
--name <NAME> What the activity checks
--repo-root <REPO_ROOT> Repository root (the directory containing `.rqtk/`) [default: .]
--id <ID> Defaults to the next free VA-<CATEGORY>-<NUMBER>-<NN>
--json Print one JSON document to stdout instead of text. Errors go to stderr as JSON
--dry-run Print the activity that would be added without writing it
-h, --help Print help
rqtk add-stakeholder
Add a new stakeholder definition
Usage: rqtk add-stakeholder [OPTIONS] --name <NAME>
Options:
--id <ID> Defaults to the next free STK-NNN
--repo-root <REPO_ROOT> Repository root (the directory containing `.rqtk/`) [default: .]
--json Print one JSON document to stdout instead of text. Errors go to stderr as JSON
--name <NAME>
--role <ROLE>
--organization <ORGANIZATION>
--dry-run Print the file that would be created without writing it
-h, --help Print help
rqtk add-need
Add a new stakeholder need
Usage: rqtk add-need [OPTIONS] --title <TITLE> --statement <STATEMENT>
Options:
--id <ID> Defaults to the next free NEED-NNNN
--repo-root <REPO_ROOT> Repository root (the directory containing `.rqtk/`) [default: .]
--json Print one JSON document to stdout instead of text. Errors go to stderr as JSON
--title <TITLE>
--statement <STATEMENT>
--stakeholders <STAKEHOLDERS> Stakeholder IDs associated with this need (comma-separated)
--rationale <RATIONALE> Why the stakeholders need it
--dry-run Print the file that would be created without writing it
-h, --help Print help
rqtk lint
Check every file against the schema, the config and the `verifies` links in source
Usage: rqtk lint [OPTIONS]
Options:
--repo-root <REPO_ROOT> Repository root (the directory containing `.rqtk/`) [default: .]
--json Print one JSON document to stdout instead of text. Errors go to stderr as JSON
-h, --help Print help
rqtk context
Everything relevant to one requirement, need or stakeholder: links, tests, status, evidence and lint findings. Designed as the briefing for working on an item
Usage: rqtk context [OPTIONS] <ID>
Arguments:
<ID>
Options:
--repo-root <REPO_ROOT> Repository root (the directory containing `.rqtk/`) [default: .]
--json Print one JSON document to stdout instead of text. Errors go to stderr as JSON
-h, --help Print help
rqtk impact
What changed since a git revision, and which requirements and activities it affects
Usage: rqtk impact [OPTIONS] <BASE>
Arguments:
<BASE> Branch, tag, SHA, `HEAD~N` or baseline name to compare the working tree against
Options:
--repo-root <REPO_ROOT> Repository root (the directory containing `.rqtk/`) [default: .]
--json Print one JSON document to stdout instead of text. Errors go to stderr as JSON
-h, --help Print help
rqtk trace
Show the parent/child traceability chain of a requirement
Usage: rqtk trace [OPTIONS] <ID>
Arguments:
<ID>
Options:
--repo-root <REPO_ROOT> Repository root (the directory containing `.rqtk/`) [default: .]
--json Print one JSON document to stdout instead of text. Errors go to stderr as JSON
-h, --help Print help
rqtk coverage
Report need satisfaction and verification status (verified / suspect / failed / …)
Usage: rqtk coverage [OPTIONS]
Options:
--repo-root <REPO_ROOT>
Repository root (the directory containing `.rqtk/`)
[default: .]
--strict
Exit 1 unless every requirement is Verified and every need is satisfied
--allow <ALLOW>
With --strict, also accept requirements in this state (repeatable), e.g. for requirements written ahead of their implementation
Possible values:
- planned: Activities defined, nothing run yet
- in-progress: Some activities done, not all
--json
Print one JSON document to stdout instead of text. Errors go to stderr as JSON
-s, --short
Print only the one-line summary
-h, --help
Print help (see a summary with '-h')
rqtk graph
Print the traceability graph of stakeholders, needs and requirements
Usage: rqtk graph [OPTIONS]
Options:
--format <FORMAT>
Possible values:
- dot: Graphviz DOT
[default: dot]
--repo-root <REPO_ROOT>
Repository root (the directory containing `.rqtk/`)
[default: .]
--json
Print one JSON document to stdout instead of text. Errors go to stderr as JSON
-h, --help
Print help (see a summary with '-h')
rqtk baseline
Stamp all requirements and create a git tag baseline for HEAD
Usage: rqtk baseline [OPTIONS] <VERSION>
Arguments:
<VERSION>
Options:
--dry-run Report what would be stamped and tagged without changing anything
--repo-root <REPO_ROOT> Repository root (the directory containing `.rqtk/`) [default: .]
--json Print one JSON document to stdout instead of text. Errors go to stderr as JSON
-h, --help Print help
rqtk export
Export requirements to a file in the given format
Usage: rqtk export [OPTIONS] --format <FORMAT>
Options:
--format <FORMAT> [possible values: csv, json, markdown]
--repo-root <REPO_ROOT> Repository root (the directory containing `.rqtk/`) [default: .]
--json Print one JSON document to stdout instead of text. Errors go to stderr as JSON
--output <OUTPUT>
-h, --help Print help
rqtk diff
Show requirements that changed between two git revisions or baselines
Usage: rqtk diff [OPTIONS] <FROM> <TO>
Arguments:
<FROM>
<TO>
Options:
--repo-root <REPO_ROOT> Repository root (the directory containing `.rqtk/`) [default: .]
--json Print one JSON document to stdout instead of text. Errors go to stderr as JSON
-h, --help Print help
rqtk scan
List `verifies` links between source code and verification activities
Usage: rqtk scan [OPTIONS]
Options:
--repo-root <REPO_ROOT> Repository root (the directory containing `.rqtk/`) [default: .]
--json Print one JSON document to stdout instead of text. Errors go to stderr as JSON
-h, --help Print help
rqtk verify
Record test results as verification evidence in `.rqtk/evidence.toml`.
Reads JUnit XML (cargo-nextest, pytest --junitxml, go-junit-report, jest-junit, …), matches test cases to `verifies` links and records each activity's outcome against the requirement's current content hash.
Usage: rqtk verify [OPTIONS] --results <RESULTS>...
Options:
--repo-root <REPO_ROOT>
Repository root (the directory containing `.rqtk/`)
[default: .]
--results <RESULTS>...
JUnit XML result files
--check
Do not write; exit 1 if the evidence file is out of date
--json
Print one JSON document to stdout instead of text. Errors go to stderr as JSON
--dry-run
Report what would be recorded without writing
-h, --help
Print help (see a summary with '-h')
rqtk review
Confirm a requirement still holds after something it depends on changed.
Settles a Suspect requirement whose tests passed again unchanged after it was reworded, or whose ancestor or need changed. Recorded in `.rqtk/evidence.toml`.
Usage: rqtk review [OPTIONS] <ID>
Arguments:
<ID>
Requirement ID
Options:
--note <NOTE>
Why the requirement still holds, kept with the review
--repo-root <REPO_ROOT>
Repository root (the directory containing `.rqtk/`)
[default: .]
--dry-run
Report what would be recorded without writing
--json
Print one JSON document to stdout instead of text. Errors go to stderr as JSON
-h, --help
Print help (see a summary with '-h')
rqtk search
Search requirements, needs and stakeholders by substring
Usage: rqtk search [OPTIONS] <PATTERN>
Arguments:
<PATTERN> Pattern to search for
Options:
-i, --ignore-case Case-insensitive matching
--repo-root <REPO_ROOT> Repository root (the directory containing `.rqtk/`) [default: .]
-f, --field <FIELD> Restrict search to specific fields: id, title, statement, rationale, notes, keywords
--json Print one JSON document to stdout instead of text. Errors go to stderr as JSON
-h, --help Print help
rqtk open
Open a requirement file in $EDITOR
Usage: rqtk open [OPTIONS] <ID>
Arguments:
<ID>
Options:
--repo-root <REPO_ROOT> Repository root (the directory containing `.rqtk/`) [default: .]
--json Print one JSON document to stdout instead of text. Errors go to stderr as JSON
-h, --help Print help
rqtk log
Show the git commit history for a single requirement
Usage: rqtk log [OPTIONS] <ID>
Arguments:
<ID>
Options:
--repo-root <REPO_ROOT> Repository root (the directory containing `.rqtk/`) [default: .]
--json Print one JSON document to stdout instead of text. Errors go to stderr as JSON
-h, --help Print help
rqtk install-hook
Install a git pre-commit hook that runs `rqtk rehash` and `rqtk lint`
Usage: rqtk install-hook [OPTIONS]
Options:
--repo-root <REPO_ROOT> Repository root (the directory containing `.rqtk/`) [default: .]
--json Print one JSON document to stdout instead of text. Errors go to stderr as JSON
-h, --help Print help
rqtk rehash
Refresh stored content hashes that no longer match their requirement or need.
Only files that carry a `content_hash` are touched; `--all` also stamps the rest.
Usage: rqtk rehash [OPTIONS]
Options:
--all
Also write a hash into files that have none
--repo-root <REPO_ROOT>
Repository root (the directory containing `.rqtk/`)
[default: .]
--dry-run
Report stale hashes without writing
--json
Print one JSON document to stdout instead of text. Errors go to stderr as JSON
-h, --help
Print help (see a summary with '-h')
rqtk report
Generate a Markdown requirements report
Usage: rqtk report [OPTIONS]
Options:
-o, --output <OUTPUT> Write to this file instead of stdout
--repo-root <REPO_ROOT> Repository root (the directory containing `.rqtk/`) [default: .]
--json Print one JSON document to stdout instead of text. Errors go to stderr as JSON
-h, --help Print help
rqtk schema
Print the JSON Schema of a file kind, or list the kinds
Usage: rqtk schema [OPTIONS] [KIND]
Arguments:
[KIND] config, requirement, need, stakeholder or evidence
Options:
--repo-root <REPO_ROOT> Repository root (the directory containing `.rqtk/`) [default: .]
--json Print one JSON document to stdout instead of text. Errors go to stderr as JSON
-h, --help Print help
rqtk explain
Explain a lint rule and how to fix it, or list all rules
Usage: rqtk explain [OPTIONS] [CODE]
Arguments:
[CODE]
Options:
--repo-root <REPO_ROOT> Repository root (the directory containing `.rqtk/`) [default: .]
--json Print one JSON document to stdout instead of text. Errors go to stderr as JSON
-h, --help Print help
rqtk skills
Agent skills for working with rqtk in coding agents (Claude Code, Codex, …)
Usage: rqtk skills [OPTIONS] <COMMAND>
Commands:
list List the bundled skills and who can invoke them
install Write the skills into the repo and point AGENTS.md / CLAUDE.md at them
help Print this message or the help of the given subcommand(s)
Options:
--repo-root <REPO_ROOT> Repository root (the directory containing `.rqtk/`) [default: .]
--json Print one JSON document to stdout instead of text. Errors go to stderr as JSON
-h, --help Print help
rqtk skills list
List the bundled skills and who can invoke them
Usage: rqtk skills list [OPTIONS]
Options:
--repo-root <REPO_ROOT> Repository root (the directory containing `.rqtk/`) [default: .]
--json Print one JSON document to stdout instead of text. Errors go to stderr as JSON
-h, --help Print help
rqtk skills install
Write the skills into the repo and point AGENTS.md / CLAUDE.md at them.
By default the skills go into `.agents/skills` (read by Codex, Cursor, GitHub Copilot, Gemini CLI, OpenCode, Amp and most other agents), and `.claude/skills` links to them for Claude Code. Skills you have edited are kept unless --force is given. The rqtk block goes into AGENTS.md and/or CLAUDE.md where they exist; no file is created unless named with --instructions.
Usage: rqtk skills install [OPTIONS]
Options:
--for <TARGETS>
Agents to install for
Possible values:
- universal: `.agents/skills`: the shared location read by Codex, Cursor, GitHub Copilot, Gemini CLI, OpenCode, Amp, Cline, Zed, Warp and others
- claude: `.claude/skills`: Claude Code
[default: universal claude]
--repo-root <REPO_ROOT>
Repository root (the directory containing `.rqtk/`)
[default: .]
--dir <DIR>
Install a single copy into this directory instead (overrides --for)
--json
Print one JSON document to stdout instead of text. Errors go to stderr as JSON
--copy
Copy the skills into .claude/skills instead of linking to .agents/skills
--instructions <INSTRUCTIONS>
Instructions file (AGENTS.md or CLAUDE.md) to add the rqtk block to; created if missing. Repeat for several
--force
Replace skills that were edited locally
--dry-run
Report what would be written without writing
-h, --help
Print help (see a summary with '-h')
Configuration
.rqtk/config.toml sets the project’s vocabulary and policy. rqtk init writes a starting point; rqtk schema config prints the JSON Schema.
Fields
| Field | Type | Required | Description |
|---|---|---|---|
categories | table of Category | yes | |
criticality | CriticalityPolicy | yes | |
identification | IdentificationScheme | yes | |
lifecycle | LifecyclePolicy | yes | |
priority | PriorityPolicy | yes | |
project | ProjectMeta | yes | |
repository | RepositoryLayout | ||
scan | ScanConfig | ||
schema_version | integer | yes | File format version; must equal the version supported by this build of rqtk. |
standards | list of Standard | ||
types | TypePolicy | yes | |
validation | ValidationRules | yes | |
verification | VerificationPolicy | yes |
Category
| Field | Type | Required | Description |
|---|---|---|---|
description | string (optional) | ||
is_root | boolean | Marks this category as a traceability root. At least one category should set this to true for orphan detection to work. | |
level | integer | yes | |
name | string | yes |
CriticalityPolicy
| Field | Type | Required | Description |
|---|---|---|---|
levels | list of string | yes |
IdentificationScheme
| Field | Type | Required | Description |
|---|---|---|---|
id_pattern | string (optional) | Regular expression every requirement ID must match (RQ001). When omitted, it is derived from prefix, id_separator, the category keys and zero_padding, so a new category needs no pattern change. | |
id_separator | string | ||
prefix | string | ||
zero_padding | integer |
LifecyclePolicy
| Field | Type | Required | Description |
|---|---|---|---|
default_state | string | yes | |
states | list of string | yes |
PriorityPolicy
| Field | Type | Required | Description |
|---|---|---|---|
levels | list of string | yes |
ProjectMeta
| Field | Type | Required | Description |
|---|---|---|---|
classification | string (optional) | ||
created | string (optional) | ||
description | string (optional) | ||
mission_phase | string (optional) | ||
name | string | yes | |
organization | ProjectOrganization (optional) | ||
risk_posture | string (optional) | ||
short_name | string (optional) | ||
updated | string (optional) | ||
version | string | yes |
RepositoryLayout
| Field | Type | Required | Description |
|---|---|---|---|
needs_dir | string | ||
required_dirs | list of string | ||
required_files | list of string | ||
requirements_dir | string | ||
stakeholders_dir | string |
ScanConfig
Where rqtk scan looks for verifies annotations in source code.
| Field | Type | Required | Description |
|---|---|---|---|
exclude | list of string | Glob patterns (gitignore syntax) to skip, e.g. "tests/fixtures/**". | |
extensions | list of string | File extensions to read. | |
paths | list of string | Directories to scan, relative to the repository root. .gitignore is honoured. |
Standard
| Field | Type | Required | Description |
|---|---|---|---|
id | string | yes | |
revision | string (optional) | ||
title | string | yes |
TypePolicy
| Field | Type | Required | Description |
|---|---|---|---|
allowed | list of string | yes |
ValidationRules
| Field | Type | Required | Description |
|---|---|---|---|
allow_tbd | boolean | yes | |
allow_tbr | boolean | yes | |
forbid_circular_traces | boolean | yes | |
forbid_orphans | boolean | yes | |
forbidden_keywords | list of string | ||
require_parent_for_categories | list of string | Category keys whose requirements must have at least one parent (RQ012). require_parent_for_levels is accepted as an older name. | |
require_rationale | boolean | yes | |
require_verification_method | boolean | yes | |
shall_keywords | list of string |
VerificationPolicy
| Field | Type | Required | Description |
|---|---|---|---|
levels | list of string | yes | |
methods | list of string | yes | |
phases | list of string | yes |
ProjectOrganization
| Field | Type | Required | Description |
|---|---|---|---|
center | string (optional) | ||
cognizant_authority | string (optional) | ||
program | string (optional) | ||
responsible_engineer | string (optional) |
File formats
Every file under .rqtk/ is TOML and is checked against these fields; unknown fields are errors. Dates may be native TOML dates (2026-03-14) or strings. rqtk schema <kind> prints the JSON Schema of each.
Requirement
One requirement file. Scalars sit at the top level; related groups are tables.
| Field | Type | Required | Description |
|---|---|---|---|
allocation | Allocation (optional) | ||
approval | Approval (optional) | ||
assumptions | list of string | ||
category | string | yes | |
content_hash | string (optional) | Fingerprint of the semantic fields, see [Requirement::compute_content_hash]. Maintained by rqtk rehash; checked by lint rule RQ021. | |
criticality | string (optional) | ||
custom | object | ||
id | RequirementId | yes | |
keywords | list of string | ||
maturity | string (optional) | ||
notes | string (optional) | ||
parameters | list of Parameter | ||
priority | string | yes | |
rationale | string (optional) | ||
risk | Risk (optional) | ||
state | string | yes | |
statement | string | yes | The normative statement, e.g. “The system shall …”. |
tbd | boolean | ||
tbr | boolean | ||
title | string | yes | |
trace | Traceability | ||
type | string | yes | |
validation | ValidationSpec (optional) | ||
verification | Verification | yes |
Allocation
| Field | Type | Required | Description |
|---|---|---|---|
components | list of string | ||
software_modules | list of string | ||
source_files | list of string | ||
subsystems | list of string |
Approval
| Field | Type | Required | Description |
|---|---|---|---|
approved_by | list of string | ||
baselined_at | string (optional) | ||
baselined_by | string (optional) | ||
ecr_ids | list of string |
Parameter
| Field | Type | Required | Description |
|---|---|---|---|
name | string | yes | |
operator | string | yes | |
tolerance | number (optional) | ||
unit | string (optional) | ||
value | any | yes |
RequirementId
Identifier of a requirement, e.g. FOBC-SYS-0001.
Type: string
Risk
| Field | Type | Required | Description |
|---|---|---|---|
fmea_ref | string (optional) | ||
hazards | list of string | ||
mitigations | list of string | ||
safety_critical | boolean | ||
security_sensitive | boolean |
Traceability
| Field | Type | Required | Description |
|---|---|---|---|
conflicts_with | list of RequirementId | ||
depends_on | list of RequirementId | ||
derived_from | list of RequirementId | ||
external | list of ExternalTrace | ||
parents | list of RequirementId | ||
refines | list of RequirementId | ||
related | list of RequirementId | ||
satisfies | list of NeedId |
ValidationSpec
| Field | Type | Required | Description |
|---|---|---|---|
acceptance_criteria | string (optional) | ||
method | string (optional) | ||
stakeholder | StakeholderId (optional) | ||
status | string (optional) |
Verification
| Field | Type | Required | Description |
|---|---|---|---|
activities | list of VerificationActivity | ||
level | string | yes | |
method | string | yes | |
owner | string (optional) | ||
phase | string | yes | |
success_criteria | string (optional) |
ExternalTrace
| Field | Type | Required | Description |
|---|---|---|---|
ref | string | yes | |
type | string | yes |
NeedId
Identifier of a stakeholder need, e.g. NEED-0001.
Type: string
StakeholderId
Identifier of a stakeholder, e.g. STK-001.
Type: string
VerificationActivity
| Field | Type | Required | Description |
|---|---|---|---|
evidence | list of string | ||
executed_at | string (optional) | ||
expected_result | string (optional) | ||
id | string | yes | |
name | string | yes | |
procedure | string (optional) | ||
status | string (optional) |
Need
| Field | Type | Required | Description |
|---|---|---|---|
acceptance | Acceptance (optional) | ||
content_hash | string (optional) | ||
id | NeedId | yes | |
keywords | list of string | ||
priority | string (optional) | ||
rationale | string (optional) | ||
stakeholders | list of StakeholderId | ||
state | string | yes | |
statement | string | yes | |
title | string | yes |
Acceptance
| Field | Type | Required | Description |
|---|---|---|---|
criteria | string (optional) | ||
validated_at | string (optional) | ||
validated_by | string (optional) |
NeedId
Identifier of a stakeholder need, e.g. NEED-0001.
Type: string
StakeholderId
Identifier of a stakeholder, e.g. STK-001.
Type: string
Stakeholder
| Field | Type | Required | Description |
|---|---|---|---|
authority | StakeholderAuthority | ||
concerns | StakeholderConcerns | ||
id | StakeholderId | yes | |
name | string | yes | |
organization | string (optional) | ||
role | string (optional) |
StakeholderAuthority
| Field | Type | Required | Description |
|---|---|---|---|
approval_scope | string (optional) | ||
sign_off_required | boolean |
StakeholderConcerns
| Field | Type | Required | Description |
|---|---|---|---|
primary | list of string | ||
secondary | list of string |
StakeholderId
Identifier of a stakeholder, e.g. STK-001.
Type: string
Evidence (.rqtk/evidence.toml)
| Field | Type | Required | Description |
|---|---|---|---|
activity | list of ActivityEvidence | ||
review | list of Review | ||
schema_version | integer | yes | |
written_by | string (optional) | Version of rqtk that last wrote the file. |
ActivityEvidence
The latest recorded result for one verification activity. Unknown fields are ignored so that files written by a later rqtk still load.
| Field | Type | Required | Description |
|---|---|---|---|
commit | string (optional) | Commit checked out when the evidence was recorded. | |
id | string | yes | Verification activity ID. |
outcome | Outcome | yes | |
requirement | RequirementId | yes | Requirement that owned the activity when the evidence was recorded. |
requirement_hash | string | yes | The requirement’s content hash when the evidence was recorded. If the requirement’s current hash differs, the evidence is stale and the activity is Suspect. |
tests | list of string | yes | Test cases that produced the outcome, as path::name: the linked test’s source file and the name the runner gave the case. |
tests_hash | string (optional) | Hash of the linked tests’ source when they last ran. | |
unchanged_tests | boolean | The requirement was re-verified after it changed, by the same tests that passed for its earlier wording. It stays Suspect until someone runs rqtk review. | |
upstream | table of string | Content hashes of the requirement’s ancestors and of the needs they satisfy, when this version of the requirement was first verified. A later change to any of them makes the requirement Suspect until it is reviewed. |
Review
A person’s or agent’s confirmation that a requirement still holds after something it depends on changed, recorded with rqtk review.
| Field | Type | Required | Description |
|---|---|---|---|
commit | string (optional) | Commit checked out when the review was recorded. | |
date | string | yes | Date of the review, YYYY-MM-DD. |
note | string (optional) | ||
requirement | RequirementId | yes | |
requirement_hash | string | yes | The requirement’s content hash when it was reviewed; a later change voids the review. |
upstream | table of string | Content hashes of its ancestors and their needs when it was reviewed. |
Outcome
Type: passed | failed
RequirementId
Identifier of a requirement, e.g. FOBC-SYS-0001.
Type: string
Lint rules
rqtk lint reports these findings. Codes are stable: a code keeps its meaning and is never reused. rqtk explain <code> prints the same information.
| Code | Severity | Checks | How to fix |
|---|---|---|---|
| RQ001 | error | requirement ID does not match the ID pattern | Rename the ID (and file) to <prefix>-<CATEGORY>-<NUMBER>, as rqtk add does, or set identification.id_pattern in .rqtk/config.toml to accept it. |
| RQ002 | error | unknown category | Use a key from [categories] in .rqtk/config.toml, or add the category there. |
| RQ003 | error | unknown requirement type | Use a value from types.allowed, or add the type there. |
| RQ004 | error | invalid lifecycle state | Use a value from lifecycle.states. |
| RQ005 | error | invalid priority | Use a value from priority.levels. |
| RQ006 | error | invalid criticality | Use a value from criticality.levels, or remove criticality. |
| RQ007 | error | rationale is required but missing | Add rationale = "…" explaining why the requirement exists. |
| RQ008 | error | verification method is required but missing | Set verification.method to a value from verification.methods. |
| RQ009 | error | invalid verification method | Use a value from verification.methods. |
| RQ010 | error | statement is not exactly one sentence with a shall keyword | Rewrite statement as one sentence using a keyword from validation.shall_keywords; split compound requirements. |
| RQ011 | error | statement uses a forbidden keyword | Replace the vague word with a measurable criterion. |
| RQ012 | error | category requires at least one parent | Add the requirement it decomposes to trace.parents. |
| RQ013 | error | TBD is not allowed by project policy | Resolve the open item and set tbd = false. |
| RQ014 | error | TBR is not allowed by project policy | Resolve the open item and set tbr = false. |
| RQ015 | error | unknown parent reference | Correct the ID in trace.parents or create the parent requirement. |
| RQ016 | error | unknown depends_on reference | Correct the ID in trace.depends_on. |
| RQ017 | error | requirement is part of a traceability cycle | Remove one of the parents/depends_on/derived_from/refines links named in the message. |
| RQ018 | warning | orphan requirement has no path to a root category | Add a trace.parents chain that reaches a category with is_root = true. |
| RQ019 | error | repository is missing a required directory | Create the directory, or remove it from repository.required_dirs. |
| RQ020 | error | repository is missing a required file | Create the file, or remove it from repository.required_files. |
| RQ021 | warning | content hash is stale | Run rqtk rehash. |
| RQ022 | error | trace.satisfies references an unknown need | Correct the need ID or create it with rqtk add-need. |
| RQ023 | error | reference to an unknown stakeholder | Correct the stakeholder ID or create it with rqtk add-stakeholder. |
| RQ024 | error | invalid verification level | Use a value from verification.levels. |
| RQ025 | error | invalid verification phase | Use a value from verification.phases. |
| RQ026 | error | unknown derived_from / refines / conflicts_with / related reference | Correct the ID in the named trace field. |
| RQ027 | error | verification activity ID is defined more than once | Give each [[verification.activities]] entry a unique id. |
| RQ028 | error | verifies annotation names an unknown verification activity | Correct the activity ID in the annotation, or add the activity to a requirement. |
| RQ029 | warning | hand-written status on an activity whose status comes from tests | Remove status (and executed_at) from the activity; run tests and rqtk verify instead. |
| RQ030 | error | verifies annotation is not followed by a test rqtk recognises | Place the annotation directly above the test, with only comments and attributes in between. For one case of a table-driven test, tag its row: // rqtk: verifies VA-… case "name". rqtk scan shows what each annotation is attached to. |
| RQ031 | warning | an activity’s evidence file does not exist | Correct the path (relative to the repository root), add the file, or link to it with a URL. |
| RQ100 | error | file could not be read or parsed (syntax error, unknown or missing field) | Fix the TOML at the reported line; rqtk schema <kind> lists the allowed fields. |
| RQ101 | error | ID is defined in more than one file | Give one of the items a new ID and rename its file to match. |
| RQ102 | error | file name does not match the ID it contains | Rename the file to <ID>.toml. |
JSON output and exit codes
--json
Every command accepts --json and prints exactly one JSON document on stdout.
- Paths are relative to the repository root.
- Diagnostics carry
code,severity,message,subject(the item they concern) andlocation(path,line,column). - Errors go to stderr as
{"error": {"kind": "usage" | "error", "message": "…"}}, and stdout stays empty. - Commands whose output is a document in another format (
report,graph,open) reject--jsonwith a usage error.
Within 1.x, JSON output only gains fields. No field is removed, renamed or given a different type; a test in the rqtk repository enforces this against a recorded snapshot of every command’s output. Parse leniently and ignore fields you don’t know.
Exit codes
| Code | Meaning |
|---|---|
| 0 | Success, nothing to report. |
| 1 | Findings: lint errors, any requirement not Verified under coverage --strict, failed or ambiguous tests in verify or results that match no linked test, stale evidence under verify --check, link errors in scan. |
| 2 | Usage error: bad arguments, an unknown category, type, rule or schema kind, or --json on a command that doesn’t support it. |
| 3 | Error: missing or invalid configuration, I/O or git failure. |
Dry runs
Every command that writes files accepts --dry-run: init, add, add-activity, add-need, add-stakeholder, rehash, baseline, verify, review and skills install. A dry run reports exactly what would be written and changes nothing.
Why JUnit XML
rqtk verify needs one thing from a test run: which tests ran, and whether they passed, failed or were skipped. JUnit XML is the one results format that almost every test runner writes (nextest, pytest, go-junit-report, jest-junit, vitest, Maven, Gradle, .NET) and every CI system reads. Many projects already produce it for their CI’s test reports.
Reading it keeps rqtk out of your test loop: rqtk records evidence and doesn’t care how you run tests. The trade-off is that JUnit XML isn’t strictly standardised, and not every runner says which source file a test lives in. rqtk therefore matches test cases to linked tests by name, narrowed by the file and line the runner reports (Bun, vitest, GoogleTest) or by the classname or module its path implies. A name that still matches several distinct tests is reported as ambiguous rather than guessed.
Stability
From 1.0, the rqtk command line follows semantic versioning. Within 1.x, the following change only in backwards-compatible ways:
| Surface | Promise within 1.x |
|---|---|
File format (schema_version = 1) | Files valid today stay valid. New optional fields may be added. A breaking change gets a new schema_version. |
| Commands and flags | None removed or renamed. |
--json output | Fields are only added, never removed, renamed or retyped. |
| Exit codes | 0, 1, 2 and 3 keep their meaning. |
| Lint rule codes | A code keeps its meaning and is never reused. New rules may be added, so lint can find new problems after an upgrade. |
| Content hash | Tagged with its version (v1:); a different algorithm gets a new tag. |
Not covered: human-readable text output, and the Rust library crates (rqtk-core, rqtk-export, rqtk-report, rqtk-macros), which stay at 0.x and may change between minor versions, along with their re-exports from the rqtk crate (rqtk::core, rqtk::export, rqtk::macros). The #[rqtk::verifies("…")] attribute itself is covered.
Changelog
All notable changes to the rqtk command line. The format follows
Keep a Changelog; the project follows
semantic versioning as described under Stability in the README.
[1.2.0] — 2026-09-24
Field trials on six stacks (Python, Rust, TypeScript on Bun, Go, Java on Maven, C++ with GoogleTest) found cases where rqtk reported a requirement verified when it wasn’t. This release fixes them; some checks are stricter as a result.
Upgrade notes
coverage --strictrequires every requirement to be Verified. It used to pass Planned and In Progress requirements. Add--allow planned(and--allow in-progress) to accept requirements written ahead of their implementation.- RQ030 is an error: a
verifiestag with no test declaration below it can never be verified. Only comments and attributes may sit between a tag and its test now. verifyexits 1 when the results match no linked test, or a linked test matches several distinct tests.- Suspect lasts longer. A requirement stays Suspect after it changes, even when the same
unchanged tests pass again, and after a parent requirement or need changes; see Review debt
below. Run your tests and
rqtk verifyonce after upgrading and commit.rqtk/evidence.toml, so the evidence records test source hashes and upstream hashes. - Evidence written by 1.2 can’t be read by 1.1 (it has new fields). Upgrade everyone who
runs
rqtk verifytogether. From 1.2 on, unknown fields in the evidence file are ignored. - Rust:
#[requirements_docs]moved to therequirements-docsfeature;features = ["macros"]now brings only#[verifies].
Fixed: verdicts
- Test declarations in Java, Kotlin, C#, C and C++ (including GoogleTest
TEST/TEST_F/TEST_Pand Catch2TEST_CASE) are recognised; before, nothing in those languages could be verified. - A tag binds only to the test directly below it. It used to bind to the next test it
recognised within 12 lines, so
it.each(…)gave its activity to an unrelated test. - JS/TS
.only,.skip,.concurrent,.each(…)anddescribegroups; Go methods; Pythonasync def; Kotlin backtick names. - Results are matched by the file and line the runner reports where available, then by what the link’s path says about the classname. A name that still matches several distinct tests is reported as ambiguous instead of all of them deciding the outcome.
- CTest and GoogleTest disabled tests (
status="disabled",status="notrun") count as skipped, not passed. verifyno longer says “Evidence is up to date” when nothing matched.
Added
- Review debt. Evidence records a hash of each activity’s test source and of everything
upstream of the requirement. A requirement re-verified by unchanged tests after it changed,
or whose parent or need changed, is Suspect until its tests change or someone records
rqtk review <ID> [--note …].coverage,contextandreportsay why a requirement is Suspect (suspect_reasonsin JSON). - Table-driven and parameterised tests:
// rqtk: verifies VA-… case "name"on a table row, orverifies("VA-…", case = "…"), links one case: Go subtests, pytest parameters, rows ofit.each([...]), and GoogleTest parameter values. - JUnit
@DisplayName/@ParameterizedTest(name = …)and xUnitDisplayNameare read from the annotations, so tests match under Gradle, which reports display names. - Evidence names tests as
<source file>::<name>, the same whichever runner reported them (Bun and vitest, CTest and GoogleTest). verifycounts linked tests that got no result, and warns when it records evidence with no commit to record it against.init --hookinstalls the pre-commit hook.- The report header shows uncommitted requirement changes and the latest baseline.
rqtk addwrites complete requirements:--parent,--satisfies,--criteria,--activity(IDsVA-<CATEGORY>-<NUMBER>-<NN>),--priority,--method,--level,--phase. It refuses a category that requires a parent when none is given.rqtk add-activity <ID> --name …, andadd-need --rationale.coverage --strict --allow planned|in-progress.rqtk reportopens with what needs attention, shows the tests and commit (or date and files) behind every activity, and adds a stakeholders table and a need → requirement → activity → evidence matrix.impactnames the tests to run for each activity and separates activities whose evidence already covers the change (tests,done).- Lint rule RQ031: an activity’s evidence file doesn’t exist.
activity_statesin verification JSON: activity states as objects.initnames the project afterCargo.toml,pyproject.toml,package.jsonorgo.mod, and warns outside a git repository.
Changed
initcreates the example stakeholder and need only with--example.- New requirements get priority Medium (or the middle configured level), not the first level.
- New requirement and need files carry no
content_hash, so editing them leaves no stale-hash warning.rehashrefreshes stored hashes only;rehash --allstamps every file. validation.require_parent_for_categoriesis the documented name of the parent rule;require_parent_for_levelsstill works.identification.id_patternis optional: without it, IDs are checked against<prefix>-<CATEGORY>-<NUMBER>for the configured categories, so adding a category is one table.initno longer writes it.- Everything except history (
impact,diff,log,baseline) works outside a git repository;lintused to fail there. - New stakeholder and need IDs follow
zero_padding(STK-0001), or the width a project’s existing IDs already use. - Requirements in top-level categories default to verification level System.
tracesays when a requirement is top-level or a leaf instead of printing empty lists, and shows titles.rqtk = { default-features = false, features = ["macros"] }builds 16 crates instead of about 270: the macros look activities up with a TOML parser, and therqtkcrate’s dependencies hang off itslib,cliandmacrosfeatures.scanshows what each link is attached to and counts links not attached to a test.
Fixed: other
- A closed stdout (
rqtk … | head) ends the command quietly instead of panicking. - The workspace builds on macOS with a plain
cargo build(the Python extension links). skills installsays “Added” when it adds its block to an existing AGENTS.md.
[1.1.0] — 2026-09-23
Added
pip install rqtk(oruv tool install rqtk): the Python package on PyPI now contains the fullrqtkcommand line as well as the@rqtk.verifiesdecorator. One abi3 wheel per platform (Linux glibc and musl, macOS, Windows) covers Python 3.9 and later.
Fixed
- Building the whole workspace on Windows no longer fails: the Python extension’s library is
now
_rqtk(imported asrqtk._rqtk) instead ofrqtk, which collided with therqtkbinary’srqtk.exe/rqtk.pdb.
[1.0.0] — 2026-09-23
First stable release: from here on the command line, file format, --json output, exit codes
and lint rule codes follow the Stability promise in the README. The code is the same as
0.1.0; the list below is everything that changed on the way from the first internal drafts,
where breaking changes were still allowed.
Verification from test evidence
rqtk scanfindsverifieslinks in source: Rust#[verifies("…")], Python@verifies("…"), and a// rqtk: verifies …comment tag for any language.rqtk verify --results junit.xmlrecords test outcomes per activity in.rqtk/evidence.toml, against the requirement’s content hash.--checkfails when the committed evidence is out of date.- Coverage adds Suspect (tests passed for an earlier version of the requirement) and
Failed. The hand-written
statusof a test-linked activity is ignored (lint RQ029). #[verifies]rebuilds the annotated test when its requirement file changes.- Rust projects need just one crate:
rqtkwith itsmacrosfeature provides#[rqtk::verifies("…")](also asrqtk::macros), without pulling in the CLI’s dependencies.
For coding agents
- Global
--jsonon every command; fixed exit codes (0 ok, 1 findings, 2 usage, 3 error);--dry-runon every command that writes; no interactive prompts. rqtk context <ID>(briefing for one item),rqtk impact <rev>(what a change touches and what to re-verify),rqtk schema <kind>,rqtk explain <code>.- Agent skills (
rqtk-requirements,rqtk-verification,/to-requirements,/requirements-review), installed withrqtk skills installorrqtk init --agentsinto.agents/skillswith links for Claude Code; also available as a Claude Code plugin.
Distribution
- Prebuilt binaries for macOS, Linux and Windows with shell and PowerShell installers
(
curl -LsSf https://rqtk.dev/install.sh | sh), built by cargo-dist on each release tag. - Documentation at rqtk.dev, with
llms.txtand a Markdown copy of every page for agents.
File format (schema_version 1)
- Flat files:
statement = "…"and status fields at the top level, links in[trace]. - Unknown fields are errors; every broken file is reported in one run with its line (RQ100–RQ102); duplicate IDs and file-name mismatches are caught.
- Native TOML dates are accepted.
rehashandbaselinepreserve comments and layout.- Content hashes are versioned (
v1:) and no longer collide across field boundaries.
Lint
- New rules RQ024–RQ030;
RQ017names every requirement in a cycle and ignores symmetric links;RQ011checks all statements with whole-word matching; STK001 became RQ023.
Removed
- C++ bindings (
rqtk-cpp,codegen-cpp-verifies), GraphML output, the Typst/PDF report (rqtk reportnow writes Markdown), interactive prompts, and the unused[change_control]and[export]configuration sections.
[0.1.0] — 2026-09-23
Pre-release of the same code as 1.0.0, published to exercise the release pipeline: GitHub
Release with installers, crates.io, and rqtk.dev. The library crates (rqtk-core,
rqtk-export, rqtk-report, rqtk-macros) remain at 0.1.0.