Web editor¶
rr serve starts a local web application for working on the model: authoring
and editing user needs, requirements, risks, mitigations and test methods;
tracing them through a live graph; browsing from any entity to the code and
tests annotated with it; comparing the model across branches, tags and commits;
and running agentic reviews whose findings become notes or new entities.
rr serve --model requirements/ --evidence bazel-testlogs --author "Ada Lovelace <ada@example.com>"
# or, in a Bazel workspace:
bazel run @rules_requirements//python:rr -- serve --model requirements --evidence "$(bazel info bazel-testlogs)"
Open the printed URL (http://localhost:8080/ by default). Everything the
editor changes is written to your checkout as ordinary YAML edits, so the usual
review loop — diff, commit, pull request — stays the source of truth.
What you can do¶
Author and edit. Every entity kind has a list view (status, open notes,
validation issues, file and line) and a form-based editor with pickers for the
references (satisfies, refines, mitigates, implemented_by, method).
New entities get the next free id in your project’s format and are written next
to their siblings: appended to the section file that holds most of that kind, or
as a new one-object file when the model uses that layout. Ids can be renamed —
every reference in the model follows — and deleting an entity that is still
referenced asks first (and can remove the references).
Edits are surgical: only the changed fields of the changed entity are rewritten. Comments, section banners, field order, line endings (per line, in files that mix them), file mode, keys the model does not define and the formatting of every untouched field stay as they were, so a change made in the editor produces the same small diff a person would write by hand.
Every write is also verified before it happens: the edited files are
re-read with the model loader and must differ from the originals exactly as
intended — the edited entities as requested (and of the requested kind), every
other entity, the configuration and the project metadata unchanged, no new
errors, no key the model does not define lost, and no comment gone except from
a field the edit changes or an entity it deletes. Otherwise nothing is written
and the editor explains why. A change spanning several files (a rename, a
delete that removes references) is written all-or-nothing, and deleting the
only entity of a one-object file removes the file unless other documents
(say, project:) live in it.
One owner per test case. A test case verifies at most one requirement
(user need or mitigation); a set of cases may together verify one
(One test case, one requirement). The editor can no more break that
rule than a hand edit can: it writes claims, and the owner of every case is
still decided by attribution. Before any
save — a form, a rename, a note, a finding applied — the editor builds the
model the save would write and runs the same checks as rr validate and
rr report over it: the shared-case and same-code-multiple-owners
witnesses of the claims (the very pairs rr validate reports, also before the
targets have run), the edited entity’s selectors and targets (bad-selector,
bad-target) and whole-target claims (whole-target-reference: one needs a
reason), a second parent (multi-parent-refines for a second refines
parent, multi-parent-implements for a mitigation the requirement
implements plus another parent, while those rules are errors: two parents
would rest on one child’s cases; a requirement that already has several
may drop them but not gain one), the
verification-set lock (lock-owner-changed, and lock-invalid
for an entry whose owner the save would remove), and attribution over the
loaded evidence (a new attribution-conflict, or one source file owned twice).
A save that would introduce any of them is refused with 409, naming the
case and its owner today:
this would make //web:clocksync_test#clocksync::bestSample keeps the min-RTT sample
verify both PR-13 and PR-29 (it is owned by PR-13 now); a test case verifies at
most one requirement
Only problems the edit introduces count, so a conflict already in the model never blocks an unrelated edit (it is still a validation error). None of these checks can be configured off. Renaming an entity renames its lock entries in the same write; deleting one drops them (the response lists the cases).
Saves are checked and written under an advisory lock on the checkout, after
making sure no file the save read changed on disk meanwhile, so two editors on
one checkout (two rr serve processes) cannot both pass the checks with edits
that together give a case two owners: the second is refused with a 409 and
reloads. In hybrid mode a claim may take a case its own tag gives to another
entity (the model wins); the pre-check and the save say so (takes-from-tag)
instead of changing the owner silently.
The form’s verification set widget (validation set, for a user need) edits
verified_by / validated_by one target per row: Cases with one selector
per line and a checklist of the target’s observed cases — a case another
entity owns is disabled and labelled with its owner — or Whole target, with
the reason the target cannot be claimed per case (required: Save stays disabled
without one). While you type, the draft is
pre-checked (POST /api/entities/{id}/precheck): problems show above the Save
button and disable it, each selector shows how many cases it matches, and the
set the entity would get is summarised. An item you do not touch is written
back exactly as it was.
Case ledger. #/cases lists every test case of the loaded evidence with its
one owner (or none), how it got it (model, or tag in hybrid mode), its
result, the entities whose claims select it, its lock entry, and its
quarantine — filterable by owned, unowned, quarantined, (with a lock) not
locked, coarse (selected by a whole-target claim of a target that reports
per-case results) and, with rr serve --lane-targets NAME=FILE (repeatable;
one label per line, as rr report --lane-targets reads it), by lane. A
quarantined case shows no owner: a multi-tag case lists the ids its tags
declare, never as owners. Owners are read from the attribution, never derived
from tags or targets in the browser. Move… (or Assign…) gives a case to another
entity, or to none, only through a model edit: the claims that select it give
it up (a literal selector is dropped; a glob or whole-target claim is rewritten
into literal selectors of the other cases it selects, after you confirm), the
new owner gains a literal selector, a configured lock entry is re-locked in the
same write, and the result must pass the checks above and give the case to the
chosen owner. A multi-tag case cannot be moved: its own evidence names two
ids, so fix the test’s tag.
The verification-set lock. With config.sets_lock, an entity page shows a
banner when the lock is out of date for its set (entries rr sets lock would
add, re-own or remove over the loaded evidence), and the ledger’s
Update lock… runs the same logic (POST /api/lock/update): a dry run
first, a quarantine refuses it, and an entry to remove is kept unless you
confirm its removal. The lock only records owners attribution decided; it never
decides one. The overview shows the invariant —
“N test cases · 0 quarantined · each case → ≤1 requirement” — and a banner
while any case is quarantined.
Some layouts cannot be edited in place without touching their neighbours:
flow-style sections (requirements: [{...}, {...}]), JSON model files, and
entities written as a flow mapping or with merge keys (<<: *base) that carry
comments or custom keys. The editor refuses those the same way; edit them by
hand or convert them to block style. An entity carries a version, so saving a
form over a change someone made in the meantime is a conflict, not a silent
overwrite.
Trace. Each entity page shows its traces in both directions with their verification status — for a risk, the whole chain from user needs through requirements and mitigations — its verification set (every case it owns or expects, with its state: passed, failed, error, skipped, missing, not run, moved or quarantined, flaky and stale flags, the selector and level), the quarantined cases that make it INVALID, and the source locations annotated with it. The trace graph (needs → requirements → mitigations → risks, laid out to keep crossings low) pans and zooms, focuses on an entity’s neighbourhood at a chosen depth, filters by kind, and exports Mermaid.
Browse the implementation. The implementation view lists every @rr(...)
annotation found in the tree (see Source annotations) — implementing and
verifying sites, their symbols and descriptions, unknown ids flagged — and
opens any of them in a code viewer at the annotated line.
Version. The versions view shows the uncommitted model changes, commits
them (with the author you set in the editor, as the git author), names
baselines as annotated tags, lists recent commits touching the model, and shows
a semantic diff between any two refs — branches, tags, commits, or the
working tree: which entities were added, removed or modified, field by field
(rr diff OLD [NEW] prints the same on the command line).
Notes. Any entity can carry notes — comments, questions, TODOs and gaps —
with author, date and an open/resolved status. They are stored in the model
file (notes:), and open gaps, TODOs and questions join the work queue
(Gaps and routing) as note:* gaps, so a finding recorded today drives the
next implementation cycle for a person or an agent. Questions route to a human.
Work queue. Everything between the model and a complete V&V argument, as the
report’s gap list: kind, entity, route (autonomous or human-gate) and
detail, with filters and a JSON export to hand to an agent.
Agentic workflows¶
The agents view runs workflows over the model, its evidence and the source tree. Each produces findings — severity, category, the entity concerned, detail, and optionally a proposal (a new need, requirement, risk or mitigation, or an update to an existing one). A finding can be:
added as a note on its entity (a gap, TODO or question — for a finding about the model as a whole you pick the entity), so it enters the work queue;
turned into the proposed object — the editor opens pre-filled so you can adjust it before saving — or applied as an update;
dismissed.
Workflow |
Needs an LLM |
Question it answers |
|---|---|---|
Completeness check |
no (an optional LLM pass adds more) |
Are there validation issues or traceability gaps — needs without requirements, unverified / under-verified / stale / failing requirements, uncontrolled risks, requirements without implementation links? With an LLM: do the requirements cover each need, are they verifiable as written, do they imply hazards the analysis lacks? |
Test adequacy |
yes |
Do the cases of requirement Y’s verification set (and test code annotated with Y, labelled as not in the set) actually assert what Y states? Each test is judged proves / partially / does not prove / cannot tell, and missing checks are listed. |
Implementation review |
yes |
Does the code annotated as implementing Y implement it completely? |
Mitigation adequacy |
yes |
Do the requirements behind risk W’s mitigations actually control it (ISO 14971 §7), and is the residual estimate plausible? |
Hazard discovery |
yes |
Which hazards and hazardous situations does the risk analysis not cover yet? |
Assistant |
yes |
Describe a change in plain language; get proposed creates, updates and notes to review and apply. |
Assign test cases |
yes |
Which one entity does each unowned or quarantined case verify (or none)? With |
Entity pages offer the relevant workflow for that entity directly (test adequacy and implementation review for a requirement, mitigation adequacy for a risk). Agents only ever propose: nothing is written until you apply a finding.
Agents read a requirement’s tests from its verification set, never from the
tags in the evidence: a case owned by another entity, or quarantined, is no
test of it. They never edit ownership: a proposal never carries
verified_by / validated_by, applying a finding cannot change them (409),
and a proposed case owner is only recorded in the attribution worksheet — as
proposed, reason and proposed_by of its case, never as the decided
owner: — for a person to decide (see rr migrate).
Enabling the LLM workflows¶
The LLM-backed workflows use Claude through the official anthropic SDK, an
optional dependency:
pip install anthropic # or: pip install "rules-requirements[agents] @ git+https://github.com/Studio-Fug/rules_requirements"
export ANTHROPIC_API_KEY=... # or `ant auth login`
rr serve --model requirements/
Under Bazel, give the rr_editor target your pip hub’s
anthropic package (deps = ["@pypi//anthropic"]).
Requests use claude-opus-5-5 with adaptive thinking and structured (JSON
schema) output, streamed; a safety-classifier decline falls back server-side to
the model Anthropic recommends for that case (fallbacks: "default"). Choose
another model or effort with --agent-model / --agent-effort (or
RR_AGENT_MODEL / RR_AGENT_EFFORT); --no-llm disables the LLM workflows.
Without the SDK the deterministic completeness check still runs and the other
workflows show how to enable them.
The prompts contain the model (ids, titles, descriptions, traces and statuses) and, for the adequacy and implementation reviews, excerpts of the linked test and source files — keep that in mind for confidential code.
Where the editor fits in the standards¶
The editor is a working surface for the records the standards ask for (Background: the standards); the model files under version control remain the record.
Editor feature |
Activity it supports |
|---|---|
Authoring needs, requirements, risks and mitigations |
Design inputs and software requirements analysis (ISO 13485 §7.3.3, IEC 62304 §5.2, IEC 60601-1 §14.7); risk analysis and risk control records (ISO 14971 §5, §7) |
Trace view, trace graph, implementation and test links |
Traceability from hazardous situation to software item, cause, risk control measure and its verification (IEC 62304 §7.3.3); of design outputs to design inputs (ISO 13485 §7.3.2) |
Diffs, baselines (tags), history, commits |
Configuration identification and change control, including traceability of change (IEC 62304 §8.1, §8.2); design changes (ISO 13485 §7.3.9) |
Completeness check, test adequacy review |
Requirements that are traceable, testable and verified (IEC 62304 §5.2.6, §5.7); completeness of risk control (ISO 14971 §7.6) |
Mitigation adequacy review |
Verification of the implementation and effectiveness of risk control measures (ISO 14971 §7.2; IEC 62304 §7.3.1) |
Hazard discovery |
Identification of hazards and hazardous situations (ISO 14971 §5.4; IEC 62304 §7.1) |
Notes and findings |
Inputs to software problem resolution (IEC 62304 §9) and to the risk management review (ISO 14971 §9) |
Agent findings are proposals. A person decides what enters the model, as for
any hand edit, and the commit records who made the change (--author, or
the name the UI sends). The editor does not make a record compliant; it makes
complete, consistent records cheaper to keep.
Security¶
The server edits files in your checkout and runs git, so it is built for
local use:
it binds to
127.0.0.1by default (--hostto change — any address other than loopback requires a token, andrr servegenerates one if you give none, because the Host check below is no protection against clients that can reach the port directly);requests whose
Hostheader is not a local name are refused, which defeats DNS-rebinding attacks from web pages (--allow-host NAMEadds a name, e.g. behind a reverse proxy);every mutating request must carry an
X-RR-Request: 1header, which a cross-site form or image cannot send (and no CORS access is ever granted);--token SECRETadditionally requiresAuthorization: Bearer SECRETon the API; open the page ashttp://localhost:8080/#token=SECRETonce and the UI keeps it for the session;the code viewer only serves text files inside the repository (not
.git), and the UI is served with a strict Content-Security-Policy.
API¶
The UI is a client of a small JSON API under /api/, usable from scripts and
agents too (send X-RR-Request: 1 on POST/PUT/PATCH/DELETE, and
X-RR-Author: Name <email> to attribute edits):
Method and path |
Purpose |
|---|---|
|
project, configuration, counts, validation issues, git status, LLM availability |
|
lists; one entity with verdict, verification set ( |
|
create, update (its |
|
dry run of saving a draft ( |
|
the case ledger from the attribution ( |
|
whether the verification-set lock is out of date (for one entity’s set); |
|
|
|
mode, lock, per-target counts and owners, quarantines, attribution issues, each entity’s set |
|
notes |
|
the next id and the file a new entity would go to |
|
trace graph (nodes, edges, SVG, Mermaid) |
|
report JSON, gap queue, re-read evidence and sources |
|
source annotations; a file’s lines |
|
git state |
|
semantic model diff ( |
|
commit model changes; name a baseline |
|
workflows and jobs |
|
act on a finding ( |