Skip to main content

gauntlet

ci PyPI python license

repo dhanizael/gauntlet · PyPI package gauntlet-guard · command gauntlet

The integrity layer for evaluating stateful AI agents: sealed holdouts, persistence-leak guards, and keep/revert verdicts.

YOUR AI DIDN'T GET SMARTER. IT GOT THE ANSWERS.

An agent can look dramatically better after it has seen the test. Gauntlet shows whether that score survives a fresh one — and finds the leak that made it fake.

Is this your problem?

Gauntlet is for you if both of these are true:

  • your agent carries state across sessions: a memory file (LESSONS.md, MEMORY.md, now.md), saved trajectories, a vector store, or result directories a later session can read;
  • you evaluate it more than once on the same tasks.

Then memory quietly becomes the open book for the next exam, and your eval measures memory and capability as one number. It takes one good feature ("learn from feedback") and one reused task set — no malice required:

  • MEMORY.md / LESSONS.md / now.md — "what I learned this run" writes, verbatim, the task you just evaluated it on;
  • saved trajectories & transcripts — the full prompt survives in a log directory the next session retrieves from;
  • result/eval output directories — fixtures copied into run artifacts stay agent-readable;
  • vector stores / retrieval memory — the paraphrase you thought was safe is 6 shingles away from a near hit;
  • generated helper artifacts — the "summary" file that quotes the task to explain it.

Stateless agent, one-shot evals? You don't need this. Gauntlet solves a problem only repeated evaluation of a stateful agent can have — and says so on the box.

Your machine, in 30 seconds

Zero setup, $0, no LLM. Find the memory surfaces your machine would leak through — names, sizes, dates only; the audit never reads file content. Sample below is real tool output (paths abbreviated to ~/ for width):

uvx --from gauntlet-guard gauntlet guard audit
gauntlet guard audit — agent memory surfaces (content-free: names, sizes, dates only)
roots: ~/dev
visited 11 entries in 0.0s

memory files (3)
  ~/dev/MEMORY.md                                          37 B  2026-09-18
  ~/dev/Projects/price-bot/.agent-state/now.md             43 B  2026-09-18
  ~/dev/Projects/price-bot/LESSONS.md                      61 B  2026-09-18

agent state dirs (1)
  ~/dev/Projects/price-bot/.agent-state                     -  2026-09-18

transcript/log dirs (1) ... vector stores (1) ...

next steps:
  seal your holdout:   gauntlet manifest add mf.jsonl --instance t-1 --seed s-1 prompt.txt
  scan them for leaks: gauntlet guard scan mf.jsonl --store <path from above>

Every line above is a place last month's eval could still be living.

The failure mode, in 8 seconds

uvx --from gauntlet-guard gauntlet demo

Eight seconds. $0. No LLM. Deterministic. The demo makes an agent look better on the same test, catches the leaked memory, and asks the claim to survive a fresh holdout.

A three-act Gauntlet proof: the same-test score reaches KEEP net 1.0; Gauntlet catches an exact leak in LESSONS.md; a fresh test returns provisional net 0.0.

Run the proof · Read the real self-audit · Inspect the protocol · Use the share card

Why not just keep the test set secret?

Because the test set is not the only copy of the test. A secret holdout protects against you leaking it — it does nothing about the agent leaking it into itself. "Learning from feedback" is a good feature, and it writes last week's task into next week's open book.

Gauntlet doesn't replace your eval harness; it wraps it: sealed runs, a content-free memory scan, retirement of any holdout that leaked, and a retest on a fresh instance — ending in a verdict, not a score.

The words, in plain language

word plain meaning
holdout / instance a task kept out of the agent's reach, registered from a seed
manifest the private key: fingerprints of your holdout tasks (never published)
slot one sealed, single-use trial workspace
blindpack the judge-facing pack — arms renamed to pseudonyms
shingle an 8-word sliding fingerprint used to spot textual overlap
verdict keep / revert / provisional — and it is the exit code

Quickstart

pipx install gauntlet-guard        # or: uv tool install gauntlet-guard
uvx --from gauntlet-guard gauntlet guard selftest   # prove the scanner before trusting it

# the loop, end to end:
gauntlet run init exp --tasks tasks.json --arms harness,raw --repeats 3
gauntlet run prep   exp --slot t-xxxxxxxx --fixtures fx/
gauntlet run exec   exp --slot t-xxxxxxxx -- python3 my_agent.py
gauntlet run blindpack exp --out pack              # pseudonyms only; judges see no arms
gauntlet run status exp
gauntlet grade    exp --primary harness --baseline raw
# exit code IS the verdict: 0 keep · 1 revert · 2 provisional · 3 integrity failure

What grading actually looks like (real output from examples/mini):

verdict: KEEP  (careful vs quick)
  pairs=8 net=1.0 CI95=[1.0, 1.0] excluded=0.0%
  reason: 95% CI lower bound 1.000 > margin 0.1
# the memory audit: seal the tasks, then catch them if they leak
gauntlet manifest add ~/.private/eval/manifest.jsonl --instance task-0001 --seed s-77 prompt.txt
gauntlet guard scan   ~/.private/eval/manifest.jsonl --store ~/agent/LESSONS.md --store ~/agent/logs/
# findings cite hash references, never content — safe to paste into issues

A worked example you can copy

examples/mini runs the entire protocol on two toy tasks in ~15 seconds — bash walkthrough.sh — and ends by planting a leak in a LESSONS.md and catching it:

verdict: KEEP  (careful vs quick)
  pairs=8 net=1.0 CI95=[1.0, 1.0] excluded=0.0%
grade exit code: 0   (0 keep · 1 revert · 2 provisional · 3 integrity failure)
[EXACT] .../notes/LESSONS.md :: instance mini-A (13/13 shingles, 100.0% overlap, ...)
guard scan exit code: 1   (1 = leakage found -> retire, regenerate)

Swap agent.py for your real agent; the loop stays identical.

We scanned ourselves first

The first real target was the author's own agent infrastructure: 12 sealed task instances against memory files, journals, working-state dirs, and eval results — 271 files, 3.1 seconds, zero false positives on the control scan. Fixtures had persisted verbatim into run-result directories: real contamination vectors, correctly calibrated (NEAR/TRACE). Full write-up: docs/CASE_STUDY.md.

Design principles

  1. The scanner must not leak. Findings are file, position, counts, hash references — never matched text (ADR-0002). The audit goes further: it never opens a file at all (ADR-0011).
  2. Manifests are private keys. Task content lives only in the manifest (ADR-0007).
  3. Deterministic first, judge second. Shingle/hash evidence outranks LLM opinion (ADR-0006).
  4. Leaks are lifecycle events. Detection → retire → regenerate from an unused seed. A holdout that leaked once is dead.
  5. Verdicts over scores. provisional means the claim failed to be proven (ADR-0005).
  6. Decisions written before implementation. Verdict rules frozen in docs/GRADE_DESIGN.md before the code existed.

Status

module what it is state
guard + manifest (v0.1) persistence-leak scanner, content-free reports shipped
run (v0.2) sealed isolated trials: opaque slots, drift forensics, blind packs shipped
grade (v0.3) preregistered verdict engine, bootstrap CI, exit codes as verdicts shipped
demo (v0.3.2) the three-act failure mode, $0, self-asserting in CI shipped
guard audit (v0.3.3) zero-setup memory-surface discovery, content-free shipped
holdout (v0.4) fresh-instance generation + retirement ledger next

Built from a private protocol that runs on its own author: doctrine changes stay PROVISIONAL until they beat the previous version on repeated, holdout-guarded evals.

Written down before it shipped

Decisions precede code and both are public: docs/adr/ records every frozen call (11 ADRs), ROADMAP.md pins non-goals as firmly as targets, SECURITY.md treats "silent untrustworthiness" as the vulnerability class, CONTRIBUTING.md states the gates honestly, and the negative-result issue template makes publishing a failure as easy as publishing a win.

Development

uv sync
uv run pytest                          # 69 tests, incl. the demo's self-assertion
uv run ruff check && uv run ruff format --check
uv run ty check src/
uv run gauntlet demo                   # the story must hold, or CI goes red

License

MIT

Metadata

Release files for gauntlet-guard 0.3.3

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for gauntlet-guard 0.3.3
File Size Uploaded
gauntlet_guard-0.3.3.tar.gz 27.8 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for gauntlet-guard 0.3.3
File Interpreter ABI Platform
gauntlet_guard-0.3.3-py3-none-any.whl Python 3 none any Details

Total release size: 61.6 kB

Release files / gauntlet_guard-0.3.3.tar.gz

Download URL gauntlet_guard-0.3.3.tar.gz
Size 27.8 kB
Tags Source
SHA-256 checksum
How to use checksums
c2aae2c00af2b6d51b575b84e8b6a52a1758c839a419d0e061f1330c4abaf925
BLAKE2b-256 checksum
How to use checksums
a622b95fa3b8fc8165dba7cfc74c3b54bbda3276059a651fc5989983fee1d8a0
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via uv/0.12.16 {"installer":{"name":"uv","version":"0.12.16","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

Release files / gauntlet_guard-0.3.3-py3-none-any.whl

Download URL gauntlet_guard-0.3.3-py3-none-any.whl
Size 33.7 kB
Tags Python 3
SHA-256 checksum
How to use checksums
fabd3331562d88a102cbad3a433da8a091ed4360b93fd27c2e8665b827fc27df
BLAKE2b-256 checksum
How to use checksums
45cfcdf3358d712667f7c1a942aec7b67375da9a5ec014386912d3e6fb8fe3dc
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via uv/0.12.16 {"installer":{"name":"uv","version":"0.12.16","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

Release history Release notifications | RSS feed

0.4.0

2 release files

This release

0.3.3 This release

2 release files

0.3.2

2 release files

0.3.0

2 release files

0.2.0

2 release files

0.1.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page