grudge-cli 0.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (128) hide show
  1. grudge_cli-0.1.0/LICENSE +21 -0
  2. grudge_cli-0.1.0/PKG-INFO +313 -0
  3. grudge_cli-0.1.0/README.md +292 -0
  4. grudge_cli-0.1.0/examples/__init__.py +1 -0
  5. grudge_cli-0.1.0/examples/leaky_agent/__init__.py +1 -0
  6. grudge_cli-0.1.0/examples/leaky_agent/agent.py +250 -0
  7. grudge_cli-0.1.0/examples/leaky_agent/agent_fixed.py +183 -0
  8. grudge_cli-0.1.0/examples/leaky_agent/tools.py +153 -0
  9. grudge_cli-0.1.0/grudge/__init__.py +5 -0
  10. grudge_cli-0.1.0/grudge/__main__.py +6 -0
  11. grudge_cli-0.1.0/grudge/_stubs.py +8 -0
  12. grudge_cli-0.1.0/grudge/admission/__init__.py +6 -0
  13. grudge_cli-0.1.0/grudge/admission/court.py +239 -0
  14. grudge_cli-0.1.0/grudge/admission/verdict.py +26 -0
  15. grudge_cli-0.1.0/grudge/cli/__init__.py +1 -0
  16. grudge_cli-0.1.0/grudge/cli/_common.py +126 -0
  17. grudge_cli-0.1.0/grudge/cli/admit.py +93 -0
  18. grudge_cli-0.1.0/grudge/cli/capture.py +39 -0
  19. grudge_cli-0.1.0/grudge/cli/compile.py +37 -0
  20. grudge_cli-0.1.0/grudge/cli/demo.py +136 -0
  21. grudge_cli-0.1.0/grudge/cli/main.py +54 -0
  22. grudge_cli-0.1.0/grudge/cli/run.py +60 -0
  23. grudge_cli-0.1.0/grudge/cli/scars.py +91 -0
  24. grudge_cli-0.1.0/grudge/cli/shrink.py +108 -0
  25. grudge_cli-0.1.0/grudge/config.py +35 -0
  26. grudge_cli-0.1.0/grudge/demo/__init__.py +1 -0
  27. grudge_cli-0.1.0/grudge/demo/events.py +228 -0
  28. grudge_cli-0.1.0/grudge/demo/orchestrator.py +326 -0
  29. grudge_cli-0.1.0/grudge/demo/server.py +222 -0
  30. grudge_cli-0.1.0/grudge/errors.py +25 -0
  31. grudge_cli-0.1.0/grudge/fuzzer/__init__.py +1 -0
  32. grudge_cli-0.1.0/grudge/fuzzer/fingerprint_guard.py +10 -0
  33. grudge_cli-0.1.0/grudge/fuzzer/mutators.py +10 -0
  34. grudge_cli-0.1.0/grudge/gate/__init__.py +5 -0
  35. grudge_cli-0.1.0/grudge/gate/report.py +125 -0
  36. grudge_cli-0.1.0/grudge/gate/runner.py +323 -0
  37. grudge_cli-0.1.0/grudge/gate/selector.py +10 -0
  38. grudge_cli-0.1.0/grudge/gate/wilson.py +36 -0
  39. grudge_cli-0.1.0/grudge/guard/__init__.py +5 -0
  40. grudge_cli-0.1.0/grudge/guard/compile.py +251 -0
  41. grudge_cli-0.1.0/grudge/guard/import_session.py +106 -0
  42. grudge_cli-0.1.0/grudge/integrations/__init__.py +1 -0
  43. grudge_cli-0.1.0/grudge/integrations/github_comment.py +10 -0
  44. grudge_cli-0.1.0/grudge/integrations/pytest_plugin.py +10 -0
  45. grudge_cli-0.1.0/grudge/llm/__init__.py +6 -0
  46. grudge_cli-0.1.0/grudge/llm/cache.py +92 -0
  47. grudge_cli-0.1.0/grudge/llm/client.py +82 -0
  48. grudge_cli-0.1.0/grudge/locator/__init__.py +1 -0
  49. grudge_cli-0.1.0/grudge/locator/fork.py +10 -0
  50. grudge_cli-0.1.0/grudge/locator/point_of_no_return.py +10 -0
  51. grudge_cli-0.1.0/grudge/predicates/__init__.py +25 -0
  52. grudge_cli-0.1.0/grudge/predicates/call_shape.py +116 -0
  53. grudge_cli-0.1.0/grudge/predicates/compiler.py +116 -0
  54. grudge_cli-0.1.0/grudge/predicates/dsl.py +295 -0
  55. grudge_cli-0.1.0/grudge/predicates/fallback_rules.py +10 -0
  56. grudge_cli-0.1.0/grudge/predicates/ordering.py +33 -0
  57. grudge_cli-0.1.0/grudge/predicates/outcome.py +14 -0
  58. grudge_cli-0.1.0/grudge/predicates/prompts/synthesize.md +15 -0
  59. grudge_cli-0.1.0/grudge/predicates/synthesizer.py +127 -0
  60. grudge_cli-0.1.0/grudge/predicates/taint_flow.py +84 -0
  61. grudge_cli-0.1.0/grudge/recorder/__init__.py +5 -0
  62. grudge_cli-0.1.0/grudge/recorder/adapters/__init__.py +1 -0
  63. grudge_cli-0.1.0/grudge/recorder/adapters/langgraph.py +8 -0
  64. grudge_cli-0.1.0/grudge/recorder/adapters/mcp_proxy.py +8 -0
  65. grudge_cli-0.1.0/grudge/recorder/adapters/raw_sdk.py +159 -0
  66. grudge_cli-0.1.0/grudge/recorder/recorder.py +374 -0
  67. grudge_cli-0.1.0/grudge/recorder/redact.py +105 -0
  68. grudge_cli-0.1.0/grudge/registry/__init__.py +1 -0
  69. grudge_cli-0.1.0/grudge/registry/db.py +10 -0
  70. grudge_cli-0.1.0/grudge/registry/fingerprint.py +10 -0
  71. grudge_cli-0.1.0/grudge/registry/flakiness.py +10 -0
  72. grudge_cli-0.1.0/grudge/registry/retirement.py +10 -0
  73. grudge_cli-0.1.0/grudge/replay/__init__.py +19 -0
  74. grudge_cli-0.1.0/grudge/replay/cassette_player.py +159 -0
  75. grudge_cli-0.1.0/grudge/replay/sandbox.py +340 -0
  76. grudge_cli-0.1.0/grudge/replay/scripted_llm.py +382 -0
  77. grudge_cli-0.1.0/grudge/schema/__init__.py +45 -0
  78. grudge_cli-0.1.0/grudge/schema/cassette.py +206 -0
  79. grudge_cli-0.1.0/grudge/schema/predicate.py +263 -0
  80. grudge_cli-0.1.0/grudge/schema/scar.py +113 -0
  81. grudge_cli-0.1.0/grudge/schema/trace.py +243 -0
  82. grudge_cli-0.1.0/grudge/shrinker/__init__.py +12 -0
  83. grudge_cli-0.1.0/grudge/shrinker/cassette_builder.py +328 -0
  84. grudge_cli-0.1.0/grudge/shrinker/ddmin.py +243 -0
  85. grudge_cli-0.1.0/grudge/shrinker/oracle.py +230 -0
  86. grudge_cli-0.1.0/grudge/shrinker/reducers.py +331 -0
  87. grudge_cli-0.1.0/grudge_cli.egg-info/PKG-INFO +313 -0
  88. grudge_cli-0.1.0/grudge_cli.egg-info/SOURCES.txt +126 -0
  89. grudge_cli-0.1.0/grudge_cli.egg-info/dependency_links.txt +1 -0
  90. grudge_cli-0.1.0/grudge_cli.egg-info/entry_points.txt +2 -0
  91. grudge_cli-0.1.0/grudge_cli.egg-info/requires.txt +12 -0
  92. grudge_cli-0.1.0/grudge_cli.egg-info/top_level.txt +2 -0
  93. grudge_cli-0.1.0/pyproject.toml +55 -0
  94. grudge_cli-0.1.0/setup.cfg +4 -0
  95. grudge_cli-0.1.0/tests/test_admission_court.py +470 -0
  96. grudge_cli-0.1.0/tests/test_cassette_builder.py +71 -0
  97. grudge_cli-0.1.0/tests/test_cassette_player.py +81 -0
  98. grudge_cli-0.1.0/tests/test_cassette_schema.py +67 -0
  99. grudge_cli-0.1.0/tests/test_cli.py +293 -0
  100. grudge_cli-0.1.0/tests/test_config.py +35 -0
  101. grudge_cli-0.1.0/tests/test_ddmin.py +108 -0
  102. grudge_cli-0.1.0/tests/test_demo_flow.py +188 -0
  103. grudge_cli-0.1.0/tests/test_docs_check.py +32 -0
  104. grudge_cli-0.1.0/tests/test_errors.py +22 -0
  105. grudge_cli-0.1.0/tests/test_gate_report.py +43 -0
  106. grudge_cli-0.1.0/tests/test_gate_runner.py +75 -0
  107. grudge_cli-0.1.0/tests/test_guard_compile.py +69 -0
  108. grudge_cli-0.1.0/tests/test_guard_conformance.py +17 -0
  109. grudge_cli-0.1.0/tests/test_import_session.py +62 -0
  110. grudge_cli-0.1.0/tests/test_leaky_agents.py +136 -0
  111. grudge_cli-0.1.0/tests/test_leaky_tools.py +74 -0
  112. grudge_cli-0.1.0/tests/test_phase12.py +136 -0
  113. grudge_cli-0.1.0/tests/test_predicate_compiler.py +327 -0
  114. grudge_cli-0.1.0/tests/test_predicate_schema.py +62 -0
  115. grudge_cli-0.1.0/tests/test_predicate_synthesizer.py +289 -0
  116. grudge_cli-0.1.0/tests/test_predicates_dsl.py +150 -0
  117. grudge_cli-0.1.0/tests/test_recorder.py +117 -0
  118. grudge_cli-0.1.0/tests/test_redact.py +56 -0
  119. grudge_cli-0.1.0/tests/test_reducers.py +76 -0
  120. grudge_cli-0.1.0/tests/test_replay_sandbox.py +165 -0
  121. grudge_cli-0.1.0/tests/test_sample_scar.py +216 -0
  122. grudge_cli-0.1.0/tests/test_scar_schema.py +61 -0
  123. grudge_cli-0.1.0/tests/test_shrinker_oracle.py +90 -0
  124. grudge_cli-0.1.0/tests/test_stretch_stubs.py +46 -0
  125. grudge_cli-0.1.0/tests/test_trace_hypothesis.py +45 -0
  126. grudge_cli-0.1.0/tests/test_trace_schema.py +104 -0
  127. grudge_cli-0.1.0/tests/test_viewer_static.py +109 -0
  128. grudge_cli-0.1.0/tests/test_wilson.py +49 -0
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Grudge contributors
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,313 @@
1
+ Metadata-Version: 2.2
2
+ Name: grudge-cli
3
+ Version: 0.1.0
4
+ Summary: Deterministic regression scars for agent mistakes.
5
+ Author: Grudge contributors
6
+ License: MIT
7
+ Requires-Python: <3.15,>=3.11
8
+ Description-Content-Type: text/markdown
9
+ License-File: LICENSE
10
+ Requires-Dist: pydantic==2.12.5
11
+ Requires-Dist: typer==0.15.1
12
+ Requires-Dist: click==8.1.8
13
+ Requires-Dist: rich==13.9.4
14
+ Requires-Dist: httpx==0.28.1
15
+ Provides-Extra: dev
16
+ Requires-Dist: pytest==8.3.4; extra == "dev"
17
+ Requires-Dist: pytest-cov==6.0.0; extra == "dev"
18
+ Requires-Dist: hypothesis==6.123.10; extra == "dev"
19
+ Requires-Dist: ruff==0.14.14; extra == "dev"
20
+ Requires-Dist: mypy==1.18.2; extra == "dev"
21
+
22
+ # Grudge
23
+
24
+ **Agents repeat mistakes. Grudge makes each one happen exactly once.**
25
+
26
+ ## The problem
27
+
28
+ 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.
29
+
30
+ ## 30-second quickstart
31
+
32
+ Use Python 3.14.0 or another interpreter supported by `pyproject.toml`, then run
33
+ the complete offline demo from the repository root:
34
+
35
+ ```bash
36
+ pip install -e . && grudge demo
37
+ ```
38
+
39
+ The command opens the local viewer and plays the five-beat story: capture the
40
+ vulnerable run, shrink its world, synthesize a predicate, prove red-on-bad and
41
+ green-on-fixed admission, then reintroduce the bug and block it. The demo is
42
+ offline and deterministic: it uses checked-in fake tools, scripted policies,
43
+ the checked-in Scar, and the fallback predicate; it does not call a provider or
44
+ the public network. For a headless smoke run, use
45
+ `python -m grudge demo --no-browser --fast --json`. For the two-session
46
+ Claude-style hook proof, use `python -m grudge demo --guard --json`.
47
+
48
+ ### Install the local guard
49
+
50
+ These commands exercise the checkout's Node package from the repository root;
51
+ they do not resolve a package from the npm registry:
52
+
53
+ ```bash
54
+ npm --prefix packages/grudge run build
55
+ npm --prefix packages/grudge run setup:repo
56
+ npm --prefix packages/grudge run doctor:repo
57
+ ```
58
+
59
+ If `grudge` has been published, the equivalent registry workflow is
60
+ `npx grudge-cli ...`. When working from `packages/grudge`, use `node dist/grudge.mjs`
61
+ and add `--cwd ../..` when the hooks should target the repository root. The
62
+ short package-directory commands are `npm run setup:repo` and
63
+ `npm run doctor:repo`. Do not combine `cd packages/grudge` with the
64
+ root-relative path `packages/grudge/dist/grudge.mjs`, or it resolves to
65
+ `packages/grudge/packages/grudge/dist/grudge.mjs`.
66
+
67
+ Claude Code is the verified **Guard** tier. Codex, Gemini CLI, GitHub Copilot,
68
+ OpenCode, and Windsurf are **Advisory** integrations; Cursor is unverified and
69
+ the installer writes no Cursor files. See [the integration matrix](docs/integrations.md).
70
+ Use `node packages/grudge/dist/grudge.mjs setup --dry-run` to inspect a plan and
71
+ `node packages/grudge/dist/grudge.mjs uninstall` to remove Grudge-managed files.
72
+
73
+ ## What the shrink shows
74
+
75
+ The headline visual is the shrink: many captured tool responses become the
76
+ small causal world that still reproduces the failure. The repository includes
77
+ a static visual reference for the story; the live viewer animates the same
78
+ transition from the retained `shrink.*` events.
79
+
80
+ ![Shrink visual reference: a captured trace reduced to a three-entry cassette](docs/assets/shrink.svg)
81
+
82
+ ## Architecture
83
+
84
+ The engine is CLI-first. The recorder emits a typed trace, replay freezes only
85
+ the external world while the policy stays live, the shrinker reduces the
86
+ cassette, deterministic predicate code checks behavior, admission proves that
87
+ the rule discriminates, and the gate turns repeated clean runs into a CI
88
+ decision. The local demo server adds an event stream consumed by the static
89
+ viewer; the viewer never owns pipeline state or verdict logic.
90
+
91
+ ![Grudge pipeline architecture](docs/assets/pipeline.svg)
92
+
93
+ ```text
94
+ agent run → trace → cassette + live policy → minimal cassette
95
+ ↓
96
+ predicate → admission proof → statistical gate
97
+ ↓
98
+ demo events → local SSE server → static viewer
99
+ ```
100
+
101
+ The full contracts and boundaries are in
102
+ [`docs/architecture.md`](docs/architecture.md).
103
+
104
+ ## How a failure becomes a Scar
105
+
106
+ Each Scar contains three reviewable artifacts:
107
+
108
+ 1. **Cassette — the frozen world.** An ordered set of task/tool-response
109
+ entries. Replay serves only cassette responses, with strict matching and
110
+ single-use entries, while the policy computes its next action from the
111
+ resulting messages. This keeps replay hermetic without replaying a
112
+ transcript verbatim. See [`docs/cassette-format.md`](docs/cassette-format.md)
113
+ and [`docs/why-not-replay.md`](docs/why-not-replay.md).
114
+ 2. **Predicate — the never-again rule.** A small readable DSL expresses call
115
+ shape, ordering, and MVP-lite taint flow. The parser/compiler returns exact
116
+ trace evidence and a deterministic `PredicateResult`; optional model
117
+ synthesis can draft text, but deterministic code decides. See
118
+ [`docs/predicate-dsl.md`](docs/predicate-dsl.md).
119
+ 3. **Verdict — proof and gate evidence.** Admission requires witnessed red
120
+ bad-agent runs, clean successful fixed-agent runs, nonempty benign controls,
121
+ and fail-closed replay/checker behavior. The statistical gate repeats an
122
+ admitted Scar and passes only when its Wilson lower bound reaches the
123
+ threshold. Offline repetitions demonstrate repeatability, not independent
124
+ statistical samples. See [`docs/statistics.md`](docs/statistics.md) and
125
+ [`docs/architecture.md`](docs/architecture.md#admission-rules).
126
+
127
+ ## CLI reference
128
+
129
+ Run `grudge --help` or append `--help` to any command. Every implemented
130
+ command accepts `--json` for one machine-readable document on stdout and
131
+ `--debug` for a traceback on stderr. Expected input/engine failures use exit
132
+ code `2`; a gate passes with `0` and is blocked with `1`.
133
+
134
+ ### Capture
135
+
136
+ ```text
137
+ grudge capture AGENT_MODULE --out PATH [--json] [--debug]
138
+ ```
139
+
140
+ Calls the module's `run_agent` or `run` entry point and writes canonical JSONL
141
+ trace output.
142
+
143
+ ### Shrink
144
+
145
+ ```text
146
+ grudge shrink TRACE --failure RULE --out PATH
147
+ [--agent AGENT_MODULE] [--json] [--debug]
148
+ ```
149
+
150
+ Reduces a trace-derived cassette while retaining the supplied DSL rule.
151
+ `--failure demo` selects the checked-in hand-verified demo rule;
152
+ `--agent` defaults to `examples.leaky_agent.agent`.
153
+
154
+ ### Admit
155
+
156
+ ```text
157
+ grudge admit CASSETTE --bad AGENT_MODULE --good AGENT_MODULE --out PATH
158
+ [--id TEXT] [--predicate RULE|demo] [--controls PATH] [--runs INT]
159
+ [--json] [--debug]
160
+ ```
161
+
162
+ Builds a candidate Scar and admits it only after repeated red/green proof and
163
+ benign controls. `--controls` defaults to
164
+ `examples/leaky_agent/controls`; `--runs` defaults to `3`; `--predicate demo`
165
+ uses the fallback rule.
166
+
167
+ ### Run the gate
168
+
169
+ ```text
170
+ grudge run --scars PATH --agent AGENT_MODULE
171
+ [--runs INT] [--threshold FLOAT] [--json] [--debug]
172
+ ```
173
+
174
+ Runs one Scar file or every `*.scar.json` in a directory. Defaults come from
175
+ `grudge.config` (`20` runs and threshold `0.80`). The report labels the normal
176
+ path `offline/deterministic`.
177
+
178
+ ### Demo and viewer
179
+
180
+ ```text
181
+ grudge demo [--live] [--guard] [--port INT] [--no-browser] [--runs INT] [--fast]
182
+ [--json] [--debug]
183
+ grudge viewer [--json] [--debug]
184
+ ```
185
+
186
+ `demo` defaults to the local viewer server on port `8765`; `--no-browser`
187
+ prints the URL instead. `--fast` removes presenter pacing. `--live` is a
188
+ reserved future provider mode and currently reports an error. `viewer` remains
189
+ an explicit roadmap stub; the supported viewer path is `grudge demo`.
190
+ `grudge demo --guard --json` runs the offline two-session proof: it captures a
191
+ real Claude-style hook payload, proposes and accepts the rule, then blocks the
192
+ same data-flow attempt at PreToolUse. The proof uses no network or model call.
193
+
194
+ ### Browse Scars
195
+
196
+ ```text
197
+ grudge scars list [--scars PATH] [--json] [--debug]
198
+ grudge scars show SCAR [--scars PATH] [--json] [--debug]
199
+ grudge scars retire SCAR [--json] [--debug]
200
+ ```
201
+
202
+ `list` and `show` are implemented. `retire` is reserved for the future
203
+ registry and returns an explicit roadmap error.
204
+
205
+ For a shell pipeline and JSON/error examples, see
206
+ [`docs/demo-guide.md`](docs/demo-guide.md).
207
+
208
+ ## Status
209
+
210
+ | Area | MVP status | STRETCH status |
211
+ |---|---|---|
212
+ | Typed trace, cassette, predicate, and Scar schemas | Implemented and persisted | — |
213
+ | Recording and redaction | Recorder, decorator, raw SDK boundary, and configurable redaction implemented | MCP and LangGraph adapters are stubs |
214
+ | Replay and shrinking | Hermetic cassette replay, ddmin, content reducers, and deterministic history implemented | Fault locator is a stub |
215
+ | Predicates | Call shape, ordering, and MVP-lite taint flow implemented; outcome AST parses | Outcome checker is a stub |
216
+ | Admission and statistics | Red/green proof, controls, Wilson gate, Rich/Markdown reports implemented | Changed-Scar selector is a stub |
217
+ | CLI and demo | Capture, shrink, admit, run, demo, Guard proof, and Scar list/show implemented | `viewer` and `scars retire` commands are explicit stubs |
218
+ | 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 |
219
+ | Ecosystem integrations | Local/offline path needs no external service | SQLite registry, fuzzer, locator, pytest/GitHub integrations, and workflow are deferred |
220
+
221
+ ### Guard tiers and token budgets
222
+
223
+ | Tier | Agents | Meaning |
224
+ |---|---|---|
225
+ | **Guard** | Claude Code (verified) | Hooks enforce expressible scars before a tool runs. |
226
+ | **Advisory** | Agents that read instruction files | The model receives the rule; compliance is not guaranteed. |
227
+ | **CI only** | Other agents | Check scars afterward with `grudge run` in CI. |
228
+
229
+ Injected output is bounded: SessionStart 1,200 characters and 8 scars, block
230
+ reason 400 characters, prompt nudge 200 characters, and the managed block 1,000
231
+ characters across at most 12 lines. Token savings are always labeled **est.**
232
+
233
+ The complete stub/design register is [`docs/roadmap.md`](docs/roadmap.md).
234
+
235
+ ## Benchmark status
236
+
237
+ The row below is a measured offline CLI run on WSL Ubuntu-D with Python 3.11.17
238
+ using the checked-in vulnerable agent and the command path documented in
239
+ `docs/demo-guide.md`. Wall time includes capture and shrink; cassette bytes are
240
+ the pretty-printed JSON artifact written by `grudge shrink --json`. Repeat on a
241
+ different machine before comparing timings; do not infer measurements from the
242
+ demo narration.
243
+
244
+ | Workload | Original steps | Minimal steps / entries | Oracle calls | Wall time | Cassette bytes |
245
+ |---|---:|---:|---:|---:|---:|
246
+ | Demo leak (offline, deterministic; WSL Ubuntu-D / Python 3.11.17) | 71 | 23 | 1,254 | 46.357 s | 3,756 |
247
+
248
+ The implementation already reports shrink statistics (`original_entries`,
249
+ `minimal_entries`, `oracle_calls`, and byte sizes) in `grudge shrink --json`,
250
+ which is the source for the measured row above. The deterministic input helper
251
+ can generate a configurable trace for stress tests and future benchmark runs:
252
+
253
+ ```bash
254
+ python scripts/generate_trace.py --steps 40 --output artifacts/phase12/trace.jsonl
255
+ ```
256
+
257
+ It does not time shrinking or aggregate measurements automatically; benchmark
258
+ rows must be captured from a clean run and recorded with their environment.
259
+
260
+ ## Checks and reproducibility
261
+
262
+ The default supported runtime is Python 3.14.0, recorded in `.python-version`.
263
+ The package supports Python 3.11 through 3.14, and the lockfile is
264
+ `requirements.lock`. The project Makefile keeps dependencies in a local virtual
265
+ environment:
266
+
267
+ ```bash
268
+ make install
269
+ make test
270
+ make lint
271
+ make typecheck
272
+ make docs-check
273
+ make all
274
+ ```
275
+
276
+ ### Clean Linux commands
277
+
278
+ From a fresh checkout, the shortest reproducible workflow is:
279
+
280
+ ```bash
281
+ git clone https://github.com/harshithKumar12/Grudge.git
282
+ cd Grudge
283
+ python3.14 --version
284
+ make install
285
+ make test
286
+ make demo
287
+ ```
288
+
289
+ `make test` runs the Python suite and the Node package suite when Node.js 18+
290
+ is installed; it remains usable on a Python-only machine. The headless proof
291
+ is useful in CI:
292
+
293
+ ```bash
294
+ .venv/bin/python -m grudge demo --guard --json
295
+ ```
296
+
297
+ The offline path needs no API keys or real personal data. Copy `.env.example`
298
+ only when experimenting with the optional provider boundary; never commit a
299
+ key. Docker remains an optional reproducibility path:
300
+
301
+ ```bash
302
+ docker build -t grudge:latest .
303
+ docker run --rm grudge:latest
304
+ ```
305
+
306
+ ## Repository guide
307
+
308
+ - [Architecture](docs/architecture.md) — contracts and pipeline boundaries.
309
+ - [Documentation index](docs/INDEX.md) — every documentation file and owner phase.
310
+ - [Roadmap](docs/roadmap.md) — every deferred stub and its design notes.
311
+ - [Demo guide](docs/demo-guide.md) — presenter, server, JSON, and shell operation.
312
+ - [Pitch artifacts](pitch/one_liner.md) — one-liner, 90-second script, and slides.
313
+ - [Progress tracker](Progress.md) — canonical phase status.
@@ -0,0 +1,292 @@
1
+ # Grudge
2
+
3
+ **Agents repeat mistakes. Grudge makes each one happen exactly once.**
4
+
5
+ ## The problem
6
+
7
+ 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.
8
+
9
+ ## 30-second quickstart
10
+
11
+ Use Python 3.14.0 or another interpreter supported by `pyproject.toml`, then run
12
+ the complete offline demo from the repository root:
13
+
14
+ ```bash
15
+ pip install -e . && grudge demo
16
+ ```
17
+
18
+ The command opens the local viewer and plays the five-beat story: capture the
19
+ vulnerable run, shrink its world, synthesize a predicate, prove red-on-bad and
20
+ green-on-fixed admission, then reintroduce the bug and block it. The demo is
21
+ offline and deterministic: it uses checked-in fake tools, scripted policies,
22
+ the checked-in Scar, and the fallback predicate; it does not call a provider or
23
+ the public network. For a headless smoke run, use
24
+ `python -m grudge demo --no-browser --fast --json`. For the two-session
25
+ Claude-style hook proof, use `python -m grudge demo --guard --json`.
26
+
27
+ ### Install the local guard
28
+
29
+ These commands exercise the checkout's Node package from the repository root;
30
+ they do not resolve a package from the npm registry:
31
+
32
+ ```bash
33
+ npm --prefix packages/grudge run build
34
+ npm --prefix packages/grudge run setup:repo
35
+ npm --prefix packages/grudge run doctor:repo
36
+ ```
37
+
38
+ If `grudge` has been published, the equivalent registry workflow is
39
+ `npx grudge-cli ...`. When working from `packages/grudge`, use `node dist/grudge.mjs`
40
+ and add `--cwd ../..` when the hooks should target the repository root. The
41
+ short package-directory commands are `npm run setup:repo` and
42
+ `npm run doctor:repo`. Do not combine `cd packages/grudge` with the
43
+ root-relative path `packages/grudge/dist/grudge.mjs`, or it resolves to
44
+ `packages/grudge/packages/grudge/dist/grudge.mjs`.
45
+
46
+ Claude Code is the verified **Guard** tier. Codex, Gemini CLI, GitHub Copilot,
47
+ OpenCode, and Windsurf are **Advisory** integrations; Cursor is unverified and
48
+ the installer writes no Cursor files. See [the integration matrix](docs/integrations.md).
49
+ Use `node packages/grudge/dist/grudge.mjs setup --dry-run` to inspect a plan and
50
+ `node packages/grudge/dist/grudge.mjs uninstall` to remove Grudge-managed files.
51
+
52
+ ## What the shrink shows
53
+
54
+ The headline visual is the shrink: many captured tool responses become the
55
+ small causal world that still reproduces the failure. The repository includes
56
+ a static visual reference for the story; the live viewer animates the same
57
+ transition from the retained `shrink.*` events.
58
+
59
+ ![Shrink visual reference: a captured trace reduced to a three-entry cassette](docs/assets/shrink.svg)
60
+
61
+ ## Architecture
62
+
63
+ The engine is CLI-first. The recorder emits a typed trace, replay freezes only
64
+ the external world while the policy stays live, the shrinker reduces the
65
+ cassette, deterministic predicate code checks behavior, admission proves that
66
+ the rule discriminates, and the gate turns repeated clean runs into a CI
67
+ decision. The local demo server adds an event stream consumed by the static
68
+ viewer; the viewer never owns pipeline state or verdict logic.
69
+
70
+ ![Grudge pipeline architecture](docs/assets/pipeline.svg)
71
+
72
+ ```text
73
+ agent run → trace → cassette + live policy → minimal cassette
74
+ ↓
75
+ predicate → admission proof → statistical gate
76
+ ↓
77
+ demo events → local SSE server → static viewer
78
+ ```
79
+
80
+ The full contracts and boundaries are in
81
+ [`docs/architecture.md`](docs/architecture.md).
82
+
83
+ ## How a failure becomes a Scar
84
+
85
+ Each Scar contains three reviewable artifacts:
86
+
87
+ 1. **Cassette — the frozen world.** An ordered set of task/tool-response
88
+ entries. Replay serves only cassette responses, with strict matching and
89
+ single-use entries, while the policy computes its next action from the
90
+ resulting messages. This keeps replay hermetic without replaying a
91
+ transcript verbatim. See [`docs/cassette-format.md`](docs/cassette-format.md)
92
+ and [`docs/why-not-replay.md`](docs/why-not-replay.md).
93
+ 2. **Predicate — the never-again rule.** A small readable DSL expresses call
94
+ shape, ordering, and MVP-lite taint flow. The parser/compiler returns exact
95
+ trace evidence and a deterministic `PredicateResult`; optional model
96
+ synthesis can draft text, but deterministic code decides. See
97
+ [`docs/predicate-dsl.md`](docs/predicate-dsl.md).
98
+ 3. **Verdict — proof and gate evidence.** Admission requires witnessed red
99
+ bad-agent runs, clean successful fixed-agent runs, nonempty benign controls,
100
+ and fail-closed replay/checker behavior. The statistical gate repeats an
101
+ admitted Scar and passes only when its Wilson lower bound reaches the
102
+ threshold. Offline repetitions demonstrate repeatability, not independent
103
+ statistical samples. See [`docs/statistics.md`](docs/statistics.md) and
104
+ [`docs/architecture.md`](docs/architecture.md#admission-rules).
105
+
106
+ ## CLI reference
107
+
108
+ Run `grudge --help` or append `--help` to any command. Every implemented
109
+ command accepts `--json` for one machine-readable document on stdout and
110
+ `--debug` for a traceback on stderr. Expected input/engine failures use exit
111
+ code `2`; a gate passes with `0` and is blocked with `1`.
112
+
113
+ ### Capture
114
+
115
+ ```text
116
+ grudge capture AGENT_MODULE --out PATH [--json] [--debug]
117
+ ```
118
+
119
+ Calls the module's `run_agent` or `run` entry point and writes canonical JSONL
120
+ trace output.
121
+
122
+ ### Shrink
123
+
124
+ ```text
125
+ grudge shrink TRACE --failure RULE --out PATH
126
+ [--agent AGENT_MODULE] [--json] [--debug]
127
+ ```
128
+
129
+ Reduces a trace-derived cassette while retaining the supplied DSL rule.
130
+ `--failure demo` selects the checked-in hand-verified demo rule;
131
+ `--agent` defaults to `examples.leaky_agent.agent`.
132
+
133
+ ### Admit
134
+
135
+ ```text
136
+ grudge admit CASSETTE --bad AGENT_MODULE --good AGENT_MODULE --out PATH
137
+ [--id TEXT] [--predicate RULE|demo] [--controls PATH] [--runs INT]
138
+ [--json] [--debug]
139
+ ```
140
+
141
+ Builds a candidate Scar and admits it only after repeated red/green proof and
142
+ benign controls. `--controls` defaults to
143
+ `examples/leaky_agent/controls`; `--runs` defaults to `3`; `--predicate demo`
144
+ uses the fallback rule.
145
+
146
+ ### Run the gate
147
+
148
+ ```text
149
+ grudge run --scars PATH --agent AGENT_MODULE
150
+ [--runs INT] [--threshold FLOAT] [--json] [--debug]
151
+ ```
152
+
153
+ Runs one Scar file or every `*.scar.json` in a directory. Defaults come from
154
+ `grudge.config` (`20` runs and threshold `0.80`). The report labels the normal
155
+ path `offline/deterministic`.
156
+
157
+ ### Demo and viewer
158
+
159
+ ```text
160
+ grudge demo [--live] [--guard] [--port INT] [--no-browser] [--runs INT] [--fast]
161
+ [--json] [--debug]
162
+ grudge viewer [--json] [--debug]
163
+ ```
164
+
165
+ `demo` defaults to the local viewer server on port `8765`; `--no-browser`
166
+ prints the URL instead. `--fast` removes presenter pacing. `--live` is a
167
+ reserved future provider mode and currently reports an error. `viewer` remains
168
+ an explicit roadmap stub; the supported viewer path is `grudge demo`.
169
+ `grudge demo --guard --json` runs the offline two-session proof: it captures a
170
+ real Claude-style hook payload, proposes and accepts the rule, then blocks the
171
+ same data-flow attempt at PreToolUse. The proof uses no network or model call.
172
+
173
+ ### Browse Scars
174
+
175
+ ```text
176
+ grudge scars list [--scars PATH] [--json] [--debug]
177
+ grudge scars show SCAR [--scars PATH] [--json] [--debug]
178
+ grudge scars retire SCAR [--json] [--debug]
179
+ ```
180
+
181
+ `list` and `show` are implemented. `retire` is reserved for the future
182
+ registry and returns an explicit roadmap error.
183
+
184
+ For a shell pipeline and JSON/error examples, see
185
+ [`docs/demo-guide.md`](docs/demo-guide.md).
186
+
187
+ ## Status
188
+
189
+ | Area | MVP status | STRETCH status |
190
+ |---|---|---|
191
+ | Typed trace, cassette, predicate, and Scar schemas | Implemented and persisted | — |
192
+ | Recording and redaction | Recorder, decorator, raw SDK boundary, and configurable redaction implemented | MCP and LangGraph adapters are stubs |
193
+ | Replay and shrinking | Hermetic cassette replay, ddmin, content reducers, and deterministic history implemented | Fault locator is a stub |
194
+ | Predicates | Call shape, ordering, and MVP-lite taint flow implemented; outcome AST parses | Outcome checker is a stub |
195
+ | Admission and statistics | Red/green proof, controls, Wilson gate, Rich/Markdown reports implemented | Changed-Scar selector is a stub |
196
+ | CLI and demo | Capture, shrink, admit, run, demo, Guard proof, and Scar list/show implemented | `viewer` and `scars retire` commands are explicit stubs |
197
+ | 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 |
198
+ | Ecosystem integrations | Local/offline path needs no external service | SQLite registry, fuzzer, locator, pytest/GitHub integrations, and workflow are deferred |
199
+
200
+ ### Guard tiers and token budgets
201
+
202
+ | Tier | Agents | Meaning |
203
+ |---|---|---|
204
+ | **Guard** | Claude Code (verified) | Hooks enforce expressible scars before a tool runs. |
205
+ | **Advisory** | Agents that read instruction files | The model receives the rule; compliance is not guaranteed. |
206
+ | **CI only** | Other agents | Check scars afterward with `grudge run` in CI. |
207
+
208
+ Injected output is bounded: SessionStart 1,200 characters and 8 scars, block
209
+ reason 400 characters, prompt nudge 200 characters, and the managed block 1,000
210
+ characters across at most 12 lines. Token savings are always labeled **est.**
211
+
212
+ The complete stub/design register is [`docs/roadmap.md`](docs/roadmap.md).
213
+
214
+ ## Benchmark status
215
+
216
+ The row below is a measured offline CLI run on WSL Ubuntu-D with Python 3.11.17
217
+ using the checked-in vulnerable agent and the command path documented in
218
+ `docs/demo-guide.md`. Wall time includes capture and shrink; cassette bytes are
219
+ the pretty-printed JSON artifact written by `grudge shrink --json`. Repeat on a
220
+ different machine before comparing timings; do not infer measurements from the
221
+ demo narration.
222
+
223
+ | Workload | Original steps | Minimal steps / entries | Oracle calls | Wall time | Cassette bytes |
224
+ |---|---:|---:|---:|---:|---:|
225
+ | Demo leak (offline, deterministic; WSL Ubuntu-D / Python 3.11.17) | 71 | 23 | 1,254 | 46.357 s | 3,756 |
226
+
227
+ The implementation already reports shrink statistics (`original_entries`,
228
+ `minimal_entries`, `oracle_calls`, and byte sizes) in `grudge shrink --json`,
229
+ which is the source for the measured row above. The deterministic input helper
230
+ can generate a configurable trace for stress tests and future benchmark runs:
231
+
232
+ ```bash
233
+ python scripts/generate_trace.py --steps 40 --output artifacts/phase12/trace.jsonl
234
+ ```
235
+
236
+ It does not time shrinking or aggregate measurements automatically; benchmark
237
+ rows must be captured from a clean run and recorded with their environment.
238
+
239
+ ## Checks and reproducibility
240
+
241
+ The default supported runtime is Python 3.14.0, recorded in `.python-version`.
242
+ The package supports Python 3.11 through 3.14, and the lockfile is
243
+ `requirements.lock`. The project Makefile keeps dependencies in a local virtual
244
+ environment:
245
+
246
+ ```bash
247
+ make install
248
+ make test
249
+ make lint
250
+ make typecheck
251
+ make docs-check
252
+ make all
253
+ ```
254
+
255
+ ### Clean Linux commands
256
+
257
+ From a fresh checkout, the shortest reproducible workflow is:
258
+
259
+ ```bash
260
+ git clone https://github.com/harshithKumar12/Grudge.git
261
+ cd Grudge
262
+ python3.14 --version
263
+ make install
264
+ make test
265
+ make demo
266
+ ```
267
+
268
+ `make test` runs the Python suite and the Node package suite when Node.js 18+
269
+ is installed; it remains usable on a Python-only machine. The headless proof
270
+ is useful in CI:
271
+
272
+ ```bash
273
+ .venv/bin/python -m grudge demo --guard --json
274
+ ```
275
+
276
+ The offline path needs no API keys or real personal data. Copy `.env.example`
277
+ only when experimenting with the optional provider boundary; never commit a
278
+ key. Docker remains an optional reproducibility path:
279
+
280
+ ```bash
281
+ docker build -t grudge:latest .
282
+ docker run --rm grudge:latest
283
+ ```
284
+
285
+ ## Repository guide
286
+
287
+ - [Architecture](docs/architecture.md) — contracts and pipeline boundaries.
288
+ - [Documentation index](docs/INDEX.md) — every documentation file and owner phase.
289
+ - [Roadmap](docs/roadmap.md) — every deferred stub and its design notes.
290
+ - [Demo guide](docs/demo-guide.md) — presenter, server, JSON, and shell operation.
291
+ - [Pitch artifacts](pitch/one_liner.md) — one-liner, 90-second script, and slides.
292
+ - [Progress tracker](Progress.md) — canonical phase status.
@@ -0,0 +1 @@
1
+ """Example agents used by later Grudge phases."""
@@ -0,0 +1 @@
1
+ """Prompt-injection example reserved for Phase 2."""