Skip to main content

Grudge

Agents repeat mistakes. Grudge makes each one happen exactly once.

The problem

Agent failures are often buried in long, provider-dependent transcripts that are difficult to reproduce. A copied transcript can show what happened, but it cannot show whether the live policy would make the same decision when the world changes. Grudge turns one failure into a small, reviewable regression Scar that can run offline and block the same behavior from returning.

30-second quickstart

Use Python 3.14.0 or another interpreter supported by pyproject.toml, then run the complete offline demo from the repository root:

pip install -e . && grudge demo

The command opens the local viewer and plays the five-beat story: capture the vulnerable run, shrink its world, synthesize a predicate, prove red-on-bad and green-on-fixed admission, then reintroduce the bug and block it. The demo is offline and deterministic: it uses checked-in fake tools, scripted policies, the checked-in Scar, and the fallback predicate; it does not call a provider or the public network. For a headless smoke run, use python -m grudge demo --no-browser --fast --json. For the two-session Claude-style hook proof, use python -m grudge demo --guard --json.

Install the local guard

These commands exercise the checkout's Node package from the repository root; they do not resolve a package from the npm registry:

npm --prefix packages/grudge run build
npm --prefix packages/grudge run setup:repo
npm --prefix packages/grudge run doctor:repo

If grudge has been published, run the interactive registry setup with npx grudge-cli setup. Use the arrow keys to move, Space to select agents, and Enter to confirm the agent and scope choices. When working from packages/grudge, use node dist/grudge.mjs and add --cwd ../.. when the hooks should target the repository root. The short package-directory commands are npm run setup:repo and npm run doctor:repo. Do not combine cd packages/grudge with the root-relative path packages/grudge/dist/grudge.mjs, or it resolves to packages/grudge/packages/grudge/dist/grudge.mjs.

Claude Code is the verified Guard tier. Codex, Gemini CLI, GitHub Copilot, OpenCode, and Windsurf are Advisory integrations; Cursor is unverified and the installer writes no Cursor files. See the integration matrix. Use node packages/grudge/dist/grudge.mjs setup --dry-run to inspect a plan and node packages/grudge/dist/grudge.mjs uninstall to remove Grudge-managed files.

What the shrink shows

The headline visual is the shrink: many captured tool responses become the small causal world that still reproduces the failure. The repository includes a static visual reference for the story; the live viewer animates the same transition from the retained shrink.* events.

Shrink visual reference: a captured trace reduced to a three-entry cassette

Architecture

The engine is CLI-first. The recorder emits a typed trace, replay freezes only the external world while the policy stays live, the shrinker reduces the cassette, deterministic predicate code checks behavior, admission proves that the rule discriminates, and the gate turns repeated clean runs into a CI decision. The local demo server adds an event stream consumed by the static viewer; the viewer never owns pipeline state or verdict logic.

Grudge pipeline architecture

agent run → trace → cassette + live policy → minimal cassette
                                      ↓
                         predicate → admission proof → statistical gate
                                      ↓
                         demo events → local SSE server → static viewer

The full contracts and boundaries are in docs/architecture.md.

How a failure becomes a Scar

Each Scar contains three reviewable artifacts:

  1. Cassette — the frozen world. An ordered set of task/tool-response entries. Replay serves only cassette responses, with strict matching and single-use entries, while the policy computes its next action from the resulting messages. This keeps replay hermetic without replaying a transcript verbatim. See docs/cassette-format.md and docs/why-not-replay.md.
  2. Predicate — the never-again rule. A small readable DSL expresses call shape, ordering, and MVP-lite taint flow. The parser/compiler returns exact trace evidence and a deterministic PredicateResult; optional model synthesis can draft text, but deterministic code decides. See docs/predicate-dsl.md.
  3. Verdict — proof and gate evidence. Admission requires witnessed red bad-agent runs, clean successful fixed-agent runs, nonempty benign controls, and fail-closed replay/checker behavior. The statistical gate repeats an admitted Scar and passes only when its Wilson lower bound reaches the threshold. Offline repetitions demonstrate repeatability, not independent statistical samples. See docs/statistics.md and docs/architecture.md.

CLI reference

Run grudge --help or append --help to any command. Every implemented command accepts --json for one machine-readable document on stdout and --debug for a traceback on stderr. Expected input/engine failures use exit code 2; a gate passes with 0 and is blocked with 1.

Capture

grudge capture AGENT_MODULE --out PATH [--json] [--debug]

Calls the module's run_agent or run entry point and writes canonical JSONL trace output.

Shrink

grudge shrink TRACE --failure RULE --out PATH
    [--agent AGENT_MODULE] [--json] [--debug]

Reduces a trace-derived cassette while retaining the supplied DSL rule. --failure demo selects the checked-in hand-verified demo rule; --agent defaults to examples.leaky_agent.agent.

Admit

grudge admit CASSETTE --bad AGENT_MODULE --good AGENT_MODULE --out PATH
    [--id TEXT] [--predicate RULE|demo] [--controls PATH] [--runs INT]
    [--json] [--debug]

Builds a candidate Scar and admits it only after repeated red/green proof and benign controls. --controls defaults to examples/leaky_agent/controls; --runs defaults to 3; --predicate demo uses the fallback rule.

Run the gate

grudge run --scars PATH --agent AGENT_MODULE
    [--runs INT] [--threshold FLOAT] [--json] [--debug]

Runs one Scar file or every *.scar.json in a directory. Defaults come from grudge.config (20 runs and threshold 0.80). The report labels the normal path offline/deterministic.

Demo and viewer

grudge demo [--live] [--guard] [--port INT] [--no-browser] [--runs INT] [--fast]
    [--json] [--debug]
grudge viewer [--json] [--debug]

demo defaults to the local viewer server on port 8765; --no-browser prints the URL instead. --fast removes presenter pacing. --live is a reserved future provider mode and currently reports an error. viewer remains an explicit roadmap stub; the supported viewer path is grudge demo. grudge demo --guard --json runs the offline two-session proof: it captures a real Claude-style hook payload, proposes and accepts the rule, then blocks the same data-flow attempt at PreToolUse. The proof uses no network or model call.

Browse Scars

grudge scars list [--scars PATH] [--json] [--debug]
grudge scars show SCAR [--scars PATH] [--json] [--debug]
grudge scars retire SCAR [--json] [--debug]

list and show are implemented. retire is reserved for the future registry and returns an explicit roadmap error.

For a shell pipeline and JSON/error examples, see docs/demo-guide.md.

Status

Area MVP status STRETCH status
Typed trace, cassette, predicate, and Scar schemas Implemented and persisted —
Recording and redaction Recorder, decorator, raw SDK boundary, and configurable redaction implemented MCP and LangGraph adapters are stubs
Replay and shrinking Hermetic cassette replay, ddmin, content reducers, and deterministic history implemented Fault locator is a stub
Predicates Call shape, ordering, and MVP-lite taint flow implemented; outcome AST parses Outcome checker is a stub
Admission and statistics Red/green proof, controls, Wilson gate, Rich/Markdown reports implemented Changed-Scar selector is a stub
CLI and demo Capture, shrink, admit, run, demo, Guard proof, and Scar list/show implemented viewer and scars retire commands are explicit stubs
Static viewer CDN-free event-driven dashboard with replay, pause, reconnect, and evidence panels implemented Full Scar browser/registry integration remains a stub/minimal boundary
Ecosystem integrations Local/offline path needs no external service SQLite registry, fuzzer, locator, pytest/GitHub integrations, and workflow are deferred

Guard tiers and token budgets

Tier Agents Meaning
Guard Claude Code (verified) Hooks enforce expressible scars before a tool runs.
Advisory Agents that read instruction files The model receives the rule; compliance is not guaranteed.
CI only Other agents Check scars afterward with grudge run in CI.

Injected output is bounded: SessionStart 1,200 characters and 8 scars, block reason 400 characters, prompt nudge 200 characters, and the managed block 1,000 characters across at most 12 lines. Token savings are always labeled est.

The complete stub/design register is docs/roadmap.md.

Benchmark status

The row below is a measured offline CLI run on WSL Ubuntu-D with Python 3.11.17 using the checked-in vulnerable agent and the command path documented in docs/demo-guide.md. Wall time includes capture and shrink; cassette bytes are the pretty-printed JSON artifact written by grudge shrink --json. Repeat on a different machine before comparing timings; do not infer measurements from the demo narration.

Workload Original steps Minimal steps / entries Oracle calls Wall time Cassette bytes
Demo leak (offline, deterministic; WSL Ubuntu-D / Python 3.11.17) 71 23 1,254 46.357 s 3,756

The implementation already reports shrink statistics (original_entries, minimal_entries, oracle_calls, and byte sizes) in grudge shrink --json, which is the source for the measured row above. The deterministic input helper can generate a configurable trace for stress tests and future benchmark runs:

python scripts/generate_trace.py --steps 40 --output artifacts/phase12/trace.jsonl

It does not time shrinking or aggregate measurements automatically; benchmark rows must be captured from a clean run and recorded with their environment.

Checks and reproducibility

The default supported runtime is Python 3.14.0, recorded in .python-version. The package supports Python 3.11 through 3.14, and the lockfile is requirements.lock. The project Makefile keeps dependencies in a local virtual environment:

make install
make test
make lint
make typecheck
make docs-check
make all

Clean Linux commands

From a fresh checkout, the shortest reproducible workflow is:

git clone https://github.com/harshithKumar12/Grudge.git
cd Grudge
# Debian/Ubuntu only, if Python reports that ensurepip is unavailable:
# sudo apt-get install python3.14-venv
python3.14 --version
make PYTHON=python3.14 install
make test
make demo

The host prerequisites are Python 3.14 with its venv module and GNU Make. Node.js 18+ is optional for the JavaScript package tests; the Python tests and demo do not require Node.js.

make test runs the Python suite and the Node package suite when Node.js 18+ is installed; it remains usable on a Python-only machine. The headless proof is useful in CI:

.venv/bin/python -m grudge demo --guard --json

The offline path needs no API keys or real personal data. Copy .env.example only when experimenting with the optional provider boundary; never commit a key. Docker remains an optional reproducibility path:

docker build -t grudge:latest .
docker run --rm grudge:latest

Repository guide

Metadata

Release files for grudge-cli 0.1.1

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

Source distribution (sdist)

Source distribution for grudge-cli 0.1.1
File Size Uploaded Provenance
grudge_cli-0.1.1.tar.gz 120.0 kB Without provenance Details

Built distribution (wheel)

Table of built distributions (wheels) for grudge-cli 0.1.1
File Interpreter ABI Platform
grudge_cli-0.1.1-py3-none-any.whl Python 3 none any Details

Total release size: 229.4 kB

Release files / grudge_cli-0.1.1.tar.gz

Download URL grudge_cli-0.1.1.tar.gz
Size 120.0 kB
Tags Source
SHA-256 checksum
How to use checksums
c4c2de32cf36c44da92b62b4e412b5ff0322c0bdf40deed9e88598746c69c71c
BLAKE2b-256 checksum
How to use checksums
bb06ec7192c72f81bd56da359adb5890aa218aee0deb5136da32802c9bc2b6a7
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.14.0

Release files / grudge_cli-0.1.1-py3-none-any.whl

Download URL grudge_cli-0.1.1-py3-none-any.whl
Size 109.3 kB
Tags Python 3
SHA-256 checksum
How to use checksums
88a42ed9cf75196f37edef96bfc2f817c3e9769df87ec176368e5998407c46ec
BLAKE2b-256 checksum
How to use checksums
9ede798976f942c57f336df156cfabaf7e9954220edf37ce2508b967550309e6
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.14.0

Security for grudge-cli 0.1.1

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

No provenance found

None of the files in this release were uploaded with provenance metadata.

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

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