A code-orchestrated engine that runs the SPARRING method: grounded, cross-vendor adversarial review for AI-in-the-loop decisions.
Project description
Rapier Runtime
A code-orchestrated engine that runs the SPARRING method — grounded, cross-vendor adversarial review for AI-in-the-loop decisions.
Most AI tooling helps you build agent workflows. Rapier is different: it governs them. It runs a structured, adversarial, grounded review over an AI's proposed answer — cross-vendor by construction, with mechanical grounding checks and a correctness gate — so that confident wrongness is structurally hard to ship. The method is SPARRING; Rapier is the runtime that executes it.
Method vs. runtime. SPARRING is the method (the concept, described in its own papers and framework). Rapier is the runtime that executes a SPARRING method declared in a manifest. Upgrade the runtime, or swap a model in a manifest, without changing the method.
Free and open source (Apache-2.0). Not monetized.
Status: pre-alpha — the full ceremony runs end-to-end (M0–M3 complete; M4 in progress)
This is early software, pinned pre-1.0 — but the whole method runs. What works today:
- The full SPARRING ceremony, end-to-end. The Proposer (divergent
generation → false-novelty filter → the Cut — a cross-vendor convergence loop)
hands a committed option to the Resolver (author → cross-vendor review →
anchored correction → a correctness definitiveness gate → an external-canon
citation gate → a two-part report). Run the Resolver alone (
spar) or the whole loop (sparring). - A front door that types the input (
rapier frame). It classifies the input as a question, a proposition, or a hybrid/leaning and routes accordingly — the model judges the type, but the route is decided in code, so a question is never silently graded as though it were a committed decision. A stated decision passes the Presentation (an earnedness check) before it reaches the Resolver; a leaning is seeded into the Proposer's field, where it competes without privilege (--seed). Tune how far the Proposer diverges with--depth shallow|standard|deep—shallowis a quick answer, several times faster than the full spread. - Cross-vendor by construction. Author and reviewer are always distinct vendors when two keys are present, and it degrades honestly to single-vendor (and says so) when only one is. Any role can be Anthropic, OpenAI, Gemini, Grok, or any OpenAI-compatible endpoint — vendor and model names live only in a manifest.
- A manifest is the method. Reorder stages, swap a model, or point two
roles at two vendors — with no engine-code change. Built-in presets (
frame,spar,sparring,proposer) cover the common cases;--settle/--verifytune the resolver, and--depth/--seedtune the proposer. - Grounding + a correctness gate. The definitiveness gate checks that every hard specific in the answer is traceable to the given facts or explicitly flagged as an estimate; the citation gate resolves cited external canon (CWE / RFC / DOI / …). Both wrap one shared, battle-tested verification service — no duplicate copies.
- Auditable by default. Every run persists a redacted, owner-only record
(verbatim model-call transcript + per-stage records + verdict + report) to
~/.rapier/runs— no flag required — and the report's THE RECORD section names the path. Opt out per-run with--no-save/RAPIER_NO_PERSIST. Plus env-only secrets + redaction;yaml.safe_load; a threat model and a security policy.
167 tests pass. Cross-vendor runs are live-proven (Anthropic×OpenAI, Gemini×Grok).
Honest boundary. The definitiveness gate, anchored correction, and the two-part trust rider are exploratory governance instruments — useful, but not yet validated by a pre-registered study. Rapier makes confident wrongness structurally harder to ship; it does not make an answer correct.
Quickstart
pip install . # or: pip install git+https://github.com/muddyone/rapier-runtime.git
export ANTHROPIC_API_KEY=... # author + gate
export OPENAI_API_KEY=... # a distinct cross-vendor reviewer
# (or GEMINI_API_KEY / XAI_API_KEY)
rapier spar --request "Should we adopt Kubernetes for one flat-traffic web app?"
rapier sparring --request "Monorepo or separate repos for our three services?"
spar runs the Resolver on a chosen option; sparring runs the full four-phase
ceremony. Add --settle N for extra decision-stability rounds, or
--verify off|gate|round to tune the citation gate; add --depth shallow|standard|deep (a quick answer vs. the full option spread) or --seed "<option>" (drop a candidate into the field) to tune the Proposer half. Every
run is recorded to ~/.rapier/runs (override with --ledger-dir or the
RAPIER_RUNS_DIR env var; opt out with --no-save), and the report ends with a
THE RECORD section naming exactly where the transcript and records landed.
Not sure an input is even a decision yet? rapier frame --request "…" classifies
it (question / proposition / hybrid) and recommends a route, without spending a
whole ceremony:
rapier frame --request "Should we adopt Kubernetes for one flat-traffic web app?"
# -> {"input_type": "question", "route": "propose", ...} (a question — generate first)
No keys? The mock vendor needs none:
rapier run --manifest manifests/echo.yaml --request "should we ship X?"
# -> [mock:rapier-echo-1] should we ship X?
Runtime dependencies are just requests and pyyaml — every vendor is called
over the wire; no provider SDKs.
Configure your keys
Rapier reads vendor keys from the environment only — never from a file it reads itself. Scaffold and check your setup:
rapier init # writes .env.example (key names, no values)
# fill in .env, then load it into your shell:
set -a; source .env; set +a
rapier doctor # shows which vendors are configured (names only — never values)
doctor reports each vendor's key env var as set/unset and whether cross-vendor
review is available (two or more keys). A ceremony launched with no keys
fails loudly with an actionable message instead of producing empty output.
Keep your keys loaded
Environment variables last only for the current shell, so source .env sets
them up for this session — a new terminal starts empty. That's the same as
aws, gh, and most API-key CLIs, and it's deliberate here: Rapier reads keys
only from the environment and never persists a secret itself. To avoid re-running
the command each time, set it up once:
-
Load in every shell — add the source line to your shell profile (e.g.
~/.bashrcor~/.zshrc), pointing at a keys file you keep outside any repo:# add once to ~/.bashrc set -a; source ~/.config/rapier/keys.env; set +a
Simplest for a personal machine. (Trade-off: the keys then load into every shell, and live in a file on disk — fine for your own box, less so on a shared one.)
-
Load per directory —
direnv— auto-loads a project's.envwhen youcdin and unloads it when you leave. Cleaner isolation; a one-timedirenv allowper directory. -
Per session — just run
set -a; source .env; set +awhen you sit down to use it. Fine for occasional use.
One gotcha: source runs the file as shell, so every value with spaces must be
quoted (FOO="a b c", not FOO=a b c) or source will try to run the extra
words as a command. If sourcing errors, that's usually the cause.
Use it from an MCP client (optional)
Expose spar / sparring (and a rapier_doctor check) as tools to any MCP
client — Claude Desktop, editors, agents:
pip install "rapier-runtime[mcp]"
Point the client at the stdio server. Keys travel in the server's env block —
the client launches the process with them, and the engine reads them from the
environment (it still reads no secret from a file):
{
"mcpServers": {
"rapier": {
"command": "rapier",
"args": ["mcp"],
"env": { "ANTHROPIC_API_KEY": "…", "OPENAI_API_KEY": "…" }
}
}
}
Updating & staying current
Check your version, and update to the latest release:
rapier --version # what you have (also shown by `rapier doctor`)
pip install -U rapier-runtime # update to the latest ( add [mcp] if you use the MCP server )
Because Rapier can read files, fetch URLs, and call model vendors, staying current matters for security. How to hear about issues:
- Security fixes are published as GitHub Security Advisories, which flow
into the Python vulnerability databases — so
pip-auditand GitHub Dependabot will flag an affected version automatically if you use them. - Watch Releases on GitHub (Watch → Custom → Releases) to be notified of new versions.
- Found a vulnerability? Report it privately — see
SECURITY.md. Please don't open a public issue.
Rapier does not phone home to check for updates — nothing about your usage leaves your machine except the model calls you configure.
A manifest is the method
name: echo
pipeline:
- stage: echo
config: { note: "hello from Rapier" }
roles:
author: { vendor: mock, model: rapier-echo-1 }
Editing the manifest changes the method — reorder stages, swap a model, point two roles at two different vendors — without touching engine code.
Roadmap
| Milestone | What | |
|---|---|---|
| M0 | Skeleton + threat model + security baseline | ✅ |
| M1 | Resolver ported (one shared grounding/verification service) | ✅ |
| M2 | The Proposer (convergence primitive; SPARK / Pattern Lock / the Cut; cross-vendor roles) | ✅ |
| M3 | Full controller + the spar / sparring adapters (the whole ceremony end-to-end) |
✅ |
| M4 | Hardening + packaging + first public release | in progress |
Development
pip install -e '.[dev]'
pytest -q
License
Apache-2.0. See LICENSE.
Rapier Runtime and the SPARRING method are projects of ResourceForge.
Project details
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file rapier_runtime-0.4.0.tar.gz.
File metadata
- Download URL: rapier_runtime-0.4.0.tar.gz
- Upload date:
- Size: 202.2 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.3
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
6a19cf8aed6ca3167b71280d5bb244b77a9a358ea329175d984ed60112e46dbb
|
|
| MD5 |
1028d2a777086999f67b2548a1da60b9
|
|
| BLAKE2b-256 |
0c2843a68cd6315a1cd615ec03542c27b32c18c7cdd560895da286afdc971c15
|
File details
Details for the file rapier_runtime-0.4.0-py3-none-any.whl.
File metadata
- Download URL: rapier_runtime-0.4.0-py3-none-any.whl
- Upload date:
- Size: 132.9 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.3
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
173c43e9cfd173807511cb41f3a4d53f980491dcd9ff844936f836a98b22f1b8
|
|
| MD5 |
edc4b763855c5b70a8c4fdc14f770ad5
|
|
| BLAKE2b-256 |
0f5e2855aad11955db223f9b6ee6d88ff3610e08d2be1a83d36a798a88ac10c5
|