Duvet is a tool that establishes a bidirectional link between implementation and specification. This practice is called requirements traceability, which is defined as:
the ability to describe and follow the life of a requirement in both a forwards and backwards direction (i.e., from its origins, through its development and specification, to its subsequent deployment and use, and through periods of ongoing refinement and iteration in any of these phases)
Before getting started, Duvet requires a rust toolchain.
-
Install command
$ cargo install duvet --locked -
Initialize repository
In this example, we are using Rust. However, Duvet can be used with any language.
$ duvet init --lang-rust --specification https://www.rfc-editor.org/rfc/rfc2324 -
Add a implementation comment in the project
// src/lib.rs //= https://www.rfc-editor.org/rfc/rfc2324#section-2.1.1 //# A coffee pot server MUST accept both the BREW and POST method //# equivalently.
-
Generate a report
$ duvet report
duvet query is a development-time companion to duvet report. Where report produces the full traceability artifact for CI, query answers focused questions during development:
- Have I annotated the requirements I'm working on?
- Does my implementation have a test?
- Did the test actually execute the implementation?
- Are there duplicate annotations covering the same text?
Each question is a check (--check / -c), composable per invocation:
$ duvet query -c implementation,test --section my-spec.md
$ duvet query -c coverage -r 'target/jacoco/*.xml' -f jacoco-xmlThe coverage check correlates test annotations with executed implementation annotations using a coverage report. For Java sources, duvet uses a verified two-phase coverage model that understands method declarations and other constructs that don't appear in bytecode-based coverage data; for other languages it uses a verified degraded model that reads coverage directly at the annotation's target line.
See the guide for the full reference.
You must have git lfs installed. You can check this by running
git lfs version$ cargo xtask build$ cargo xtask testThe two-phase coverage model in duvet-coverage is formally verified
with Verus. CI runs the
verifier on every push and PR. To verify locally:
-
Download the pinned Verus release. The version that matches
vstdinCargo.lockis in.github/workflows/ci.ymlasVERUS_VERSION. Verus ships pre-built binaries for x86_64 Linux, x86_64 macOS, arm64 macOS, and x86_64 Windows; pick the one for your host:$ VERUS_VERSION="0.2026.05.24.ecee80a" $ curl -L -o verus.zip \ "https://github.com/verus-lang/verus/releases/download/release%2F${VERUS_VERSION}/verus-${VERUS_VERSION}-x86-linux.zip" $ unzip -q verus.zip
The archive extracts to
verus-x86-linux/(or-x86-macos, etc.) and contains theverusandcargo-verusbinaries, the bundledz3solver, and thevstdstandard library. -
Add the directory to
PATH.$ export PATH="$PWD/verus-x86-linux:$PATH" -
Install the Rust toolchain Verus needs. The first time
verusruns, it prints the exactrustup installcommand for the toolchain it pins. Run that command:$ verus verus: required rust toolchain X.Y.Z-x86_64-unknown-linux-gnu not found run the following command (in a bash-compatible shell) to install the necessary toolchain: rustup install X.Y.Z-x86_64-unknown-linux-gnu ... $ rustup install X.Y.Z-x86_64-unknown-linux-gnu
On macOS, you may also need to clear the Gatekeeper quarantine on the binaries; the archive includes
macos_allow_gatekeeper.sh. -
Verify the proofs.
$ cargo verus build -p duvet-coverage --features verifyExpected output:
verified N functions, 0 errors. A non-zero error count indicates a regression in the proofs.The
verifyfeature is what pulls invstd. It is off by default so thatvstdstays out of the published dependency graph — everyvstdpath induvet-coverageis ghost, so a plaincargo builderases all of them. Omitting--features verifyhere will fail with unresolvedvstdimports.
The Verus prebuilt binary (and the z3 it bundles) are built against
glibc 2.34+ / 2.31+, so older distributions (Amazon Linux 2, Ubuntu
20.04, CentOS 7) cannot run them. On those hosts, build Verus — and, if
its prebuilt z3 also won't start, z3 — from source so they link against
the local glibc (see Verus's BUILD.md: vargo build --release, then put
source/target-verus/release on PATH).
A from-source z3 reports a build-hash-suffixed SMT version string that
the verifier rejects by default. It is still the pinned z3 version, so
results are identical; pass the (supported) flag to skip the cosmetic
check — vargo build accepts --no-solver-version-check, and the verify
step uses the -V form:
$ cargo verus build -p duvet-coverage --features verify -- -V no-solver-version-checkOtherwise, rely on CI for verification.
See CONTRIBUTING for more information.
This project is licensed under the Apache-2.0 License.