Skip to main content
Grudge logo

Grudge

Deterministic regression scars for AI agents

Turn one recurring agent mistake into a small, reviewable rule that can be replayed offline, checked in CI, and enforced before the same action happens again.

npm version PyPI version MIT License Node.js 18 or newer Python 3.11 to 3.14

Quick start · How it works · CLI reference · Development

Release status: source version 0.1.6 is being prepared. Verify the package registries and complete the release checklist before publishing.

Table of contents

Overview

AI agents can repeat the same unsafe or incorrect action after a prompt change, tool-result change, or model change. A transcript can show the failure, but it does not provide a compact regression test that can be replayed against the live policy.

Grudge turns the failure into a Scar:

  1. Capture the agent's typed trace.
  2. Freeze only the external world in a replay cassette.
  3. Shrink the cassette to the smallest causal example.
  4. Describe the failure with a readable deterministic predicate.
  5. Prove that the bad behavior is red and the fixed behavior is green.
  6. Run the Scar again in CI or enforce it locally before a tool executes.

The core workflow is local-first, deterministic, and designed to work without provider credentials or network access.

Why Grudge

Problem Grudge's answer
Long transcripts are difficult to review Store a compact cassette and predicate
Replaying a transcript can hide policy changes Replay the world while keeping the policy live
Generated rules can be vague Compile and evaluate deterministic DSL predicates
A one-off test is easy to over-trust Require red/green admission evidence and benign controls
Agents can repeat a known mistake locally Install a lightweight Node Guard with Claude Code hooks
Tool output may contain secrets Redact captured content before persistence

Features

Python engine

  • Typed trace capture and schema validation.
  • Secret-aware redaction for recorded traces.
  • Strict cassette replay with ordered, single-use entries.
  • Delta debugging and content reducers for shrinking failures.
  • Deterministic predicates for call shape, ordering, and MVP taint flow.
  • Scar admission with bad-agent, fixed-agent, and benign-control evidence.
  • Wilson-bound statistical gating for repeated checks.
  • Offline demo, JSON output, Markdown/Rich reports, and a local event viewer.

Node Guard

  • Interactive setup for repository, user, or all-project scopes.
  • Claude Code hook registration for SessionStart, UserPromptSubmit, PreToolUse, PostToolUse, and Stop.
  • Deterministic blocking of admitted mistakes before a tool runs.
  • Duplicate hook accounting protection across overlapping scopes.
  • Status-line reporting with estimated savings.
  • doctor diagnostics, dry-run setup, timestamped backups, and safe uninstall.
  • Selective cleanup that preserves user content and third-party hooks/status lines.
  • Self-contained bundled runtime with no npm runtime dependencies.

Documentation and operations

  • Architecture, trust-model, integration, hook, and token-budget docs.
  • Local package smoke tests for npm and Python artifacts.
  • Release metadata consistency checks.
  • No telemetry, hosted service, MCP server, or runtime network requirement.

How it works

agent run
    │
    ▼
typed trace ──► cassette ──► shrinker ──► minimal causal world
    │                                      │
    │                                      ▼
    └──────────────────────────────► predicate and Scar
                                           │
                                           ▼
                              admission proof and CI gate
                                           │
                                           ▼
                              local Guard enforcement

The three Scar artifacts

  1. Cassette — the frozen external world. Replay serves only matching, single-use responses; the policy still computes its next action.
  2. Predicate — the readable never-again rule. It describes the call shape, ordering, or taint flow that identifies the failure.
  3. Verdict — the evidence that the rule discriminates correctly: red on the vulnerable path, green on the fixed path, and nonempty benign controls.

Architecture

Grudge pipeline architecture

The engine is CLI-first. The recorder emits typed events, replay freezes only the external world, the shrinker minimizes the cassette, deterministic code evaluates predicates, admission proves the Scar, and the gate turns repeated clean runs into a decision.

The local viewer consumes demo events over a local SSE server. It does not own pipeline state or verdict logic.

For the detailed contracts, see:

Quick start

1. Install the local Node Guard

From any repository where you want local protection:

npx grudge-cli@latest setup
npx grudge-cli@latest doctor

For a non-interactive Claude Code repository setup:

npx grudge-cli@latest setup --yes --agents claude-code --scope repo
npx grudge-cli@latest doctor

Preview changes without writing files:

npx grudge-cli@latest setup --dry-run

Remove only Grudge-managed content:

npx grudge-cli@latest uninstall

2. Install the Python engine

python -m pip install grudge-cli
grudge --help

For a checkout-based development install:

python -m pip install -e .

3. Run the offline demo

grudge demo --no-browser --fast --json

To run the two-session Claude-style hook proof:

grudge demo --guard --json

The demo uses checked-in fake tools and scripted policies. It does not call a model provider or require public-network access.

Install the packages

Grudge has two complementary packages with the same user-facing command name:

Package Install command Main responsibility
grudge-cli on PyPI python -m pip install grudge-cli Full trace, replay, shrinking, admission, gates, and demo
grudge-cli on npm npx grudge-cli setup Local Node Guard, hooks, setup, doctor, and uninstall

Exercise the npm package from this checkout

From the repository root:

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

From packages/grudge itself:

npm run build
npm run setup:repo
npm run doctor:repo
npm run uninstall:repo

Do not combine cd packages/grudge with the root-relative path packages/grudge/dist/grudge.mjs; use node dist/grudge.mjs from that directory or node packages/grudge/dist/grudge.mjs from the repository root.

Docker

The project is local-first and does not require Docker for normal use. Docker is useful for a clean Linux smoke environment or CI job.

Example development container:

FROM python:3.14-slim

WORKDIR /workspace
COPY . .

RUN python -m pip install --upgrade pip \
    && python -m pip install -e .

CMD ["python", "-m", "grudge", "demo", "--no-browser", "--fast", "--json"]

Build and run it from the repository root:

docker run --rm grudge-demo

The Docker path is intended for headless Python validation. The Node Guard requires access to the agent configuration files it is installing into, so use the host environment when testing Claude Code hook behavior.

CLI reference

Run grudge --help or append --help to any command. Implemented Python commands include:

grudge capture AGENT_MODULE --out PATH
grudge shrink TRACE --failure RULE --out PATH
grudge admit CASSETTE --bad AGENT_MODULE --good AGENT_MODULE --out PATH
grudge run --scars PATH --agent AGENT_MODULE
grudge demo [--guard] [--no-browser] [--fast] [--json]
grudge scars list [--scars PATH]
grudge scars show SCAR [--scars PATH]

The Node Guard runtime provides:

grudge setup [--yes] [--dry-run] [--scope repo|global|all] [--agents LIST]
grudge doctor
grudge uninstall [--json]
grudge hook SessionStart|UserPromptSubmit|PreToolUse|PostToolUse|Stop
grudge propose --rule RULE --why EXPLANATION [--preventive]
grudge accept SCAR_ID
grudge scars list|show
grudge stats
grudge report
grudge statusline

Expected input and engine failures use exit code 2. A passing gate returns 0; a blocked gate returns 1.

Integrations

Integration Tier Notes
Claude Code Guard Verified hook enforcement and scope-aware CLAUDE.md instructions
Codex Advisory Instruction-file integration; enforcement is not guaranteed
Gemini CLI Advisory Instruction-file integration; enforcement is not guaranteed
GitHub Copilot Advisory Instruction-file integration; enforcement is not guaranteed
OpenCode Advisory Instruction-file integration; enforcement is not guaranteed
Windsurf Advisory Instruction-file integration; enforcement is not guaranteed
Cursor Unverified The installer writes no Cursor files

See the full integration matrix and hook contract.

Project structure

grudge/
├── grudge/                 # Python engine
├── examples/               # Vulnerable and fixed demo agents
├── packages/grudge/        # Node Guard package and bundled runtime
├── tests/                  # Python tests
├── packages/grudge/test/   # Node tests
├── docs/                   # Architecture, contracts, and guides
├── scripts/                # Documentation and release checks
├── pyproject.toml          # Python package metadata
├── Makefile                # Reproducible development commands
└── CHANGELOG.md            # Release history

Configuration and data

Grudge stores local runtime state in .grudge/ when the Node Guard is enabled. This includes compiled rules, pending proposals, scars, session events, stats, and timestamped setup backups.

The installer may update:

  • .claude/settings.json or .claude/settings.local.json;
  • scope-matching CLAUDE.md instruction files;
  • .gitignore entries for local Grudge state.

Setup is designed to preserve unrelated user content and third-party hooks or status lines. Inspect a plan first with --dry-run; use doctor after setup.

Testing

Run the primary checks from the repository root:

npm test --prefix packages/grudge
python -m pytest -q
ruff check scripts tests
mypy grudge scripts
python -m scripts.docs_check
python -m scripts.release_check
git diff --check

Build package artifacts without publishing:

npm pack --prefix packages/grudge
python -m build --outdir release-dist
python -m twine check release-dist/*

The repository's focused checks are the recommended release gate. Broad lint and type commands may inspect example/test modules outside the configured package scope; resolve those findings before treating a release as clean.

Troubleshooting

npm warns about allow-scripts

You may see:

npm warn Unknown env config "allow-scripts".
npm warn Unknown user config "allow-scripts".

These are npm configuration warnings from the local environment, not Grudge runtime failures. If the setting is obsolete in your environment, inspect it with npm config get allow-scripts and remove it with npm config delete allow-scripts.

Version bump tests still expect the previous version

When moving from 0.1.5 to 0.1.6, update all version surfaces together:

  • packages/grudge/package.json;
  • packages/grudge/package-lock.json;
  • packages/grudge/src/version.js;
  • pyproject.toml;
  • release headings and documentation;
  • version assertions in packages/grudge/test/;
  • release-check expectations.

The bundled-runtime test and CLI version test intentionally catch stale version references. A failure that still expects 0.1.5 means the version bump is incomplete; do not weaken the test.

PowerShell strips rule quotes

Pass the DSL through stdin:

'never call shell where command ~ "GRUDGE_TEST"' |
  grudge propose --rule-stdin --why "harmless test rule" --preventive

Setup changes the wrong scope

Use explicit scope flags:

npx grudge-cli setup --yes --agents claude-code --scope repo
npx grudge-cli setup --yes --agents claude-code --scope global

Then run grudge doctor and inspect the reported settings and instruction files.

A third-party status line already exists

Grudge preserves an existing third-party status line and reports a warning. It does not silently replace another tool's status-line configuration.

Development

Create a virtual environment and install the locked development dependencies:

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

The Node package has no runtime npm dependencies. The Python package declares its runtime dependencies in pyproject.toml; development tools are available through the dev optional dependency.

Useful development commands

python -m grudge demo --no-browser --fast --json
python -m grudge demo --guard --json
npm --prefix packages/grudge run build
npm --prefix packages/grudge run doctor:repo

Release checklist

Before publishing a new version:

  1. Update the npm and Python version metadata.
  2. Update CHANGELOG.md, README release status, and package docs.
  3. Run Node tests, Python tests, lint, mypy, docs, and release checks.
  4. Build the npm tarball and Python sdist/wheel locally.
  5. Run twine check and inspect npm pack --dry-run --json.
  6. Commit and tag the release.
  7. Push the tag to GitHub.
  8. Publish npm and PyPI only after the local artifacts and checks are clean.

Publishing is intentionally not performed by ordinary development commands. Keep registry tokens and credentials outside the repository.

Security and privacy

  • Grudge is local-first and does not require telemetry.
  • Captured content is redacted before it is persisted where configured.
  • Runtime hook failures are designed to fail open with a visible warning rather than silently blocking the host agent.
  • Review .grudge/ and backup contents before sharing a workspace.
  • Never commit API keys, tokens, private keys, personal settings, or captured sensitive data.

Read the trust model before enabling capture in a production repository.

Roadmap

The current MVP intentionally leaves several deeper integrations explicit:

  • persistent Scar registry and retirement workflow;
  • changed-Scar selection;
  • fault localization and richer outcome predicates;
  • fuzzer and additional recorder adapters;
  • pytest and GitHub workflow integrations;
  • MCP and LangGraph adapters;
  • full viewer-backed Scar browser.

See docs/roadmap.md for the maintained roadmap.

Contributing

Small, focused changes are preferred. Before opening a pull request:

python -m pytest -q
npm test --prefix packages/grudge
python -m scripts.docs_check
git diff --check

Please include the behavior you changed, the checks you ran, and any platform limitations that remain. Do not remove tests to make a check pass.

License

Grudge is released under the MIT License.

Copyright © 2026 Grudge contributors.

Metadata

Release files for grudge-cli 0.1.6

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.6
File Size Uploaded Provenance
grudge_cli-0.1.6.tar.gz 124.0 kB Without provenance Details

Built distribution (wheel)

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

Total release size: 234.6 kB

Release files / grudge_cli-0.1.6.tar.gz

Download URL grudge_cli-0.1.6.tar.gz
Size 124.0 kB
Tags Source
SHA-256 checksum
How to use checksums
1560c3ae5e0e11a00b9cf134a814a5b54b1bc4641127145f8d57ae627d5f9d61
BLAKE2b-256 checksum
How to use checksums
2e947cad7d6b2c6a1d4c7d94b0fe1f9886b80a93218ab49d585cd70c3584d508
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.6-py3-none-any.whl

Download URL grudge_cli-0.1.6-py3-none-any.whl
Size 110.6 kB
Tags Python 3
SHA-256 checksum
How to use checksums
67efda62613ed80f9ae15dbfc26c0349a882e0336c483d97a7788f2bfdb40ef6
BLAKE2b-256 checksum
How to use checksums
f0126b4d5a860de45786bf80630d76d9401291a600092d5b2f00a33dd5aa7f8f
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.6

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