Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

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 lint rejects 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

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 standalone rqtk-macros crate works too.)
  • Python: pip install rqtk and 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

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:

ItemLives inSays
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 rationale says why the requirement exists (RQ007).
  • Traced. Set trace.parents to the requirement it decomposes, and trace.satisfies to the need it serves. With forbid_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

  1. Link a test to a verification activity.
  2. Run the tests with JUnit XML output.
  3. Record the results with rqtk verify.
  4. Check with rqtk coverage --strict, and commit .rqtk/evidence.toml with 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.

LanguageAnnotationChecked 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:

LanguageTests
Rustfn name
Pythondef test_x, async def test_x, methods of test classes
Gofunc TestX, including methods func (s *S) TestX
JavaScript, TypeScriptit, 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, Elixirfun, 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:

EcosystemCommand
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
Pythonpytest --junitxml=junit.xml
Gogo 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/TSvitest run --reporter=junit --outputFile=junit.xml, bun test --reporter=junit --reporter-outfile=junit.xml, or jest with jest-junit
JVMMaven 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. verify counts 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.
  • verify exits 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 --check writes 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:

StateMeaningWhat to do
VerifiedEvery activity passed: linked tests against the current wording, or a manual status of Passed/Waivednothing
SuspectEvidence no longer settles it; see Suspectdepends on the reason
FailedA linked test failed, or a manual status is Failedfix the code, or with the stakeholder, the requirement
In ProgressSome activities passed or startedfinish the rest
PlannedActivities defined, nothing run yetlink and run tests
GapNo activities, or no success criteriadefine 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:

ReasonWhat happenedWhat settles it
changed since its tests passedits content hash changed after its tests passedrun the tests, rqtk verify
passed again with unchanged testsit changed, and the same tests that passed for the old wording passed againchange the tests for the new wording and run them, or rqtk review
upstream changeda parent requirement, or a need it or its ancestors satisfy, changed after it was verifiedcheck 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
SkillInvoked byWhat it does
rqtk-requirementsagent or youReading and writing .rqtk/: find the governing requirement, read its briefing, author items that lint clean.
rqtk-verificationagent or youThe proof loop: link a test, run it, rqtk verify; done when rqtk lint and rqtk coverage --strict exit 0.
/to-requirementsyouTurn a spec or discussion into needs and requirements with verification activities; you approve the draft before anything is written.
/requirements-reviewyouReview 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:

AgentsRead skills fromWhat 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-requirements turns 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 verify records them.
  • /requirements-review checks 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')
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

FieldTypeRequiredDescription
categoriestable of Categoryyes
criticalityCriticalityPolicyyes
identificationIdentificationSchemeyes
lifecycleLifecyclePolicyyes
priorityPriorityPolicyyes
projectProjectMetayes
repositoryRepositoryLayout
scanScanConfig
schema_versionintegeryesFile format version; must equal the version supported by this build of rqtk.
standardslist of Standard
typesTypePolicyyes
validationValidationRulesyes
verificationVerificationPolicyyes

Category

FieldTypeRequiredDescription
descriptionstring (optional)
is_rootbooleanMarks this category as a traceability root. At least one category should set this to true for orphan detection to work.
levelintegeryes
namestringyes

CriticalityPolicy

FieldTypeRequiredDescription
levelslist of stringyes

IdentificationScheme

FieldTypeRequiredDescription
id_patternstring (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_separatorstring
prefixstring
zero_paddinginteger

LifecyclePolicy

FieldTypeRequiredDescription
default_statestringyes
stateslist of stringyes

PriorityPolicy

FieldTypeRequiredDescription
levelslist of stringyes

ProjectMeta

FieldTypeRequiredDescription
classificationstring (optional)
createdstring (optional)
descriptionstring (optional)
mission_phasestring (optional)
namestringyes
organizationProjectOrganization (optional)
risk_posturestring (optional)
short_namestring (optional)
updatedstring (optional)
versionstringyes

RepositoryLayout

FieldTypeRequiredDescription
needs_dirstring
required_dirslist of string
required_fileslist of string
requirements_dirstring
stakeholders_dirstring

ScanConfig

Where rqtk scan looks for verifies annotations in source code.

FieldTypeRequiredDescription
excludelist of stringGlob patterns (gitignore syntax) to skip, e.g. "tests/fixtures/**".
extensionslist of stringFile extensions to read.
pathslist of stringDirectories to scan, relative to the repository root. .gitignore is honoured.

Standard

FieldTypeRequiredDescription
idstringyes
revisionstring (optional)
titlestringyes

TypePolicy

FieldTypeRequiredDescription
allowedlist of stringyes

ValidationRules

FieldTypeRequiredDescription
allow_tbdbooleanyes
allow_tbrbooleanyes
forbid_circular_tracesbooleanyes
forbid_orphansbooleanyes
forbidden_keywordslist of string
require_parent_for_categorieslist of stringCategory keys whose requirements must have at least one parent (RQ012). require_parent_for_levels is accepted as an older name.
require_rationalebooleanyes
require_verification_methodbooleanyes
shall_keywordslist of string

VerificationPolicy

FieldTypeRequiredDescription
levelslist of stringyes
methodslist of stringyes
phaseslist of stringyes

ProjectOrganization

FieldTypeRequiredDescription
centerstring (optional)
cognizant_authoritystring (optional)
programstring (optional)
responsible_engineerstring (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.

FieldTypeRequiredDescription
allocationAllocation (optional)
approvalApproval (optional)
assumptionslist of string
categorystringyes
content_hashstring (optional)Fingerprint of the semantic fields, see [Requirement::compute_content_hash]. Maintained by rqtk rehash; checked by lint rule RQ021.
criticalitystring (optional)
customobject
idRequirementIdyes
keywordslist of string
maturitystring (optional)
notesstring (optional)
parameterslist of Parameter
prioritystringyes
rationalestring (optional)
riskRisk (optional)
statestringyes
statementstringyesThe normative statement, e.g. “The system shall …”.
tbdboolean
tbrboolean
titlestringyes
traceTraceability
typestringyes
validationValidationSpec (optional)
verificationVerificationyes

Allocation

FieldTypeRequiredDescription
componentslist of string
software_moduleslist of string
source_fileslist of string
subsystemslist of string

Approval

FieldTypeRequiredDescription
approved_bylist of string
baselined_atstring (optional)
baselined_bystring (optional)
ecr_idslist of string

Parameter

FieldTypeRequiredDescription
namestringyes
operatorstringyes
tolerancenumber (optional)
unitstring (optional)
valueanyyes

RequirementId

Identifier of a requirement, e.g. FOBC-SYS-0001.

Type: string

Risk

FieldTypeRequiredDescription
fmea_refstring (optional)
hazardslist of string
mitigationslist of string
safety_criticalboolean
security_sensitiveboolean

Traceability

FieldTypeRequiredDescription
conflicts_withlist of RequirementId
depends_onlist of RequirementId
derived_fromlist of RequirementId
externallist of ExternalTrace
parentslist of RequirementId
refineslist of RequirementId
relatedlist of RequirementId
satisfieslist of NeedId

ValidationSpec

FieldTypeRequiredDescription
acceptance_criteriastring (optional)
methodstring (optional)
stakeholderStakeholderId (optional)
statusstring (optional)

Verification

FieldTypeRequiredDescription
activitieslist of VerificationActivity
levelstringyes
methodstringyes
ownerstring (optional)
phasestringyes
success_criteriastring (optional)

ExternalTrace

FieldTypeRequiredDescription
refstringyes
typestringyes

NeedId

Identifier of a stakeholder need, e.g. NEED-0001.

Type: string

StakeholderId

Identifier of a stakeholder, e.g. STK-001.

Type: string

VerificationActivity

FieldTypeRequiredDescription
evidencelist of string
executed_atstring (optional)
expected_resultstring (optional)
idstringyes
namestringyes
procedurestring (optional)
statusstring (optional)

Need

FieldTypeRequiredDescription
acceptanceAcceptance (optional)
content_hashstring (optional)
idNeedIdyes
keywordslist of string
prioritystring (optional)
rationalestring (optional)
stakeholderslist of StakeholderId
statestringyes
statementstringyes
titlestringyes

Acceptance

FieldTypeRequiredDescription
criteriastring (optional)
validated_atstring (optional)
validated_bystring (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

FieldTypeRequiredDescription
authorityStakeholderAuthority
concernsStakeholderConcerns
idStakeholderIdyes
namestringyes
organizationstring (optional)
rolestring (optional)

StakeholderAuthority

FieldTypeRequiredDescription
approval_scopestring (optional)
sign_off_requiredboolean

StakeholderConcerns

FieldTypeRequiredDescription
primarylist of string
secondarylist of string

StakeholderId

Identifier of a stakeholder, e.g. STK-001.

Type: string

Evidence (.rqtk/evidence.toml)

FieldTypeRequiredDescription
activitylist of ActivityEvidence
reviewlist of Review
schema_versionintegeryes
written_bystring (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.

FieldTypeRequiredDescription
commitstring (optional)Commit checked out when the evidence was recorded.
idstringyesVerification activity ID.
outcomeOutcomeyes
requirementRequirementIdyesRequirement that owned the activity when the evidence was recorded.
requirement_hashstringyesThe 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.
testslist of stringyesTest cases that produced the outcome, as path::name: the linked test’s source file and the name the runner gave the case.
tests_hashstring (optional)Hash of the linked tests’ source when they last ran.
unchanged_testsbooleanThe 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.
upstreamtable of stringContent 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.

FieldTypeRequiredDescription
commitstring (optional)Commit checked out when the review was recorded.
datestringyesDate of the review, YYYY-MM-DD.
notestring (optional)
requirementRequirementIdyes
requirement_hashstringyesThe requirement’s content hash when it was reviewed; a later change voids the review.
upstreamtable of stringContent 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.

CodeSeverityChecksHow to fix
RQ001errorrequirement ID does not match the ID patternRename the ID (and file) to <prefix>-<CATEGORY>-<NUMBER>, as rqtk add does, or set identification.id_pattern in .rqtk/config.toml to accept it.
RQ002errorunknown categoryUse a key from [categories] in .rqtk/config.toml, or add the category there.
RQ003errorunknown requirement typeUse a value from types.allowed, or add the type there.
RQ004errorinvalid lifecycle stateUse a value from lifecycle.states.
RQ005errorinvalid priorityUse a value from priority.levels.
RQ006errorinvalid criticalityUse a value from criticality.levels, or remove criticality.
RQ007errorrationale is required but missingAdd rationale = "…" explaining why the requirement exists.
RQ008errorverification method is required but missingSet verification.method to a value from verification.methods.
RQ009errorinvalid verification methodUse a value from verification.methods.
RQ010errorstatement is not exactly one sentence with a shall keywordRewrite statement as one sentence using a keyword from validation.shall_keywords; split compound requirements.
RQ011errorstatement uses a forbidden keywordReplace the vague word with a measurable criterion.
RQ012errorcategory requires at least one parentAdd the requirement it decomposes to trace.parents.
RQ013errorTBD is not allowed by project policyResolve the open item and set tbd = false.
RQ014errorTBR is not allowed by project policyResolve the open item and set tbr = false.
RQ015errorunknown parent referenceCorrect the ID in trace.parents or create the parent requirement.
RQ016errorunknown depends_on referenceCorrect the ID in trace.depends_on.
RQ017errorrequirement is part of a traceability cycleRemove one of the parents/depends_on/derived_from/refines links named in the message.
RQ018warningorphan requirement has no path to a root categoryAdd a trace.parents chain that reaches a category with is_root = true.
RQ019errorrepository is missing a required directoryCreate the directory, or remove it from repository.required_dirs.
RQ020errorrepository is missing a required fileCreate the file, or remove it from repository.required_files.
RQ021warningcontent hash is staleRun rqtk rehash.
RQ022errortrace.satisfies references an unknown needCorrect the need ID or create it with rqtk add-need.
RQ023errorreference to an unknown stakeholderCorrect the stakeholder ID or create it with rqtk add-stakeholder.
RQ024errorinvalid verification levelUse a value from verification.levels.
RQ025errorinvalid verification phaseUse a value from verification.phases.
RQ026errorunknown derived_from / refines / conflicts_with / related referenceCorrect the ID in the named trace field.
RQ027errorverification activity ID is defined more than onceGive each [[verification.activities]] entry a unique id.
RQ028errorverifies annotation names an unknown verification activityCorrect the activity ID in the annotation, or add the activity to a requirement.
RQ029warninghand-written status on an activity whose status comes from testsRemove status (and executed_at) from the activity; run tests and rqtk verify instead.
RQ030errorverifies annotation is not followed by a test rqtk recognisesPlace 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.
RQ031warningan activity’s evidence file does not existCorrect the path (relative to the repository root), add the file, or link to it with a URL.
RQ100errorfile 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.
RQ101errorID is defined in more than one fileGive one of the items a new ID and rename its file to match.
RQ102errorfile name does not match the ID it containsRename 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) and location (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 --json with 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

CodeMeaning
0Success, nothing to report.
1Findings: 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.
2Usage error: bad arguments, an unknown category, type, rule or schema kind, or --json on a command that doesn’t support it.
3Error: 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:

SurfacePromise 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 flagsNone removed or renamed.
--json outputFields are only added, never removed, renamed or retyped.
Exit codes0, 1, 2 and 3 keep their meaning.
Lint rule codesA code keeps its meaning and is never reused. New rules may be added, so lint can find new problems after an upgrade.
Content hashTagged 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 --strict requires 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 verifies tag with no test declaration below it can never be verified. Only comments and attributes may sit between a tag and its test now.
  • verify exits 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 verify once 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 verify together. From 1.2 on, unknown fields in the evidence file are ignored.
  • Rust: #[requirements_docs] moved to the requirements-docs feature; features = ["macros"] now brings only #[verifies].

Fixed: verdicts

  • Test declarations in Java, Kotlin, C#, C and C++ (including GoogleTest TEST/TEST_F/ TEST_P and Catch2 TEST_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(…) and describe groups; Go methods; Python async 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.
  • verify no 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, context and report say why a requirement is Suspect (suspect_reasons in JSON).
  • Table-driven and parameterised tests: // rqtk: verifies VA-… case "name" on a table row, or verifies("VA-…", case = "…"), links one case: Go subtests, pytest parameters, rows of it.each([...]), and GoogleTest parameter values.
  • JUnit @DisplayName / @ParameterizedTest(name = …) and xUnit DisplayName are 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).
  • verify counts linked tests that got no result, and warns when it records evidence with no commit to record it against.
  • init --hook installs the pre-commit hook.
  • The report header shows uncommitted requirement changes and the latest baseline.
  • rqtk add writes complete requirements: --parent, --satisfies, --criteria, --activity (IDs VA-<CATEGORY>-<NUMBER>-<NN>), --priority, --method, --level, --phase. It refuses a category that requires a parent when none is given.
  • rqtk add-activity <ID> --name …, and add-need --rationale.
  • coverage --strict --allow planned|in-progress.
  • rqtk report opens 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.
  • impact names 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_states in verification JSON: activity states as objects.
  • init names the project after Cargo.toml, pyproject.toml, package.json or go.mod, and warns outside a git repository.

Changed

  • init creates 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. rehash refreshes stored hashes only; rehash --all stamps every file.
  • validation.require_parent_for_categories is the documented name of the parent rule; require_parent_for_levels still works.
  • identification.id_pattern is optional: without it, IDs are checked against <prefix>-<CATEGORY>-<NUMBER> for the configured categories, so adding a category is one table. init no longer writes it.
  • Everything except history (impact, diff, log, baseline) works outside a git repository; lint used 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.
  • trace says 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 the rqtk crate’s dependencies hang off its lib, cli and macros features.
  • scan shows 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 install says “Added” when it adds its block to an existing AGENTS.md.

[1.1.0] — 2026-09-23

Added

  • pip install rqtk (or uv tool install rqtk): the Python package on PyPI now contains the full rqtk command line as well as the @rqtk.verifies decorator. 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 as rqtk._rqtk) instead of rqtk, which collided with the rqtk binary’s rqtk.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 scan finds verifies links in source: Rust #[verifies("…")], Python @verifies("…"), and a // rqtk: verifies … comment tag for any language.
  • rqtk verify --results junit.xml records test outcomes per activity in .rqtk/evidence.toml, against the requirement’s content hash. --check fails 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 status of a test-linked activity is ignored (lint RQ029).
  • #[verifies] rebuilds the annotated test when its requirement file changes.
  • Rust projects need just one crate: rqtk with its macros feature provides #[rqtk::verifies("…")] (also as rqtk::macros), without pulling in the CLI’s dependencies.

For coding agents

  • Global --json on every command; fixed exit codes (0 ok, 1 findings, 2 usage, 3 error); --dry-run on 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 with rqtk skills install or rqtk init --agents into .agents/skills with 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.txt and 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.
  • rehash and baseline preserve comments and layout.
  • Content hashes are versioned (v1:) and no longer collide across field boundaries.

Lint

  • New rules RQ024–RQ030; RQ017 names every requirement in a cycle and ignores symmetric links; RQ011 checks all statements with whole-word matching; STK001 became RQ023.

Removed

  • C++ bindings (rqtk-cpp, codegen-cpp-verifies), GraphML output, the Typst/PDF report (rqtk report now 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.