{
  "markdown": "<div align=\"center\">\n\n<h1>Agent Trash Guard</h1>\n\n<p>\n  <img src=\"assets/agent-trash-guard-artwork.jpg\" width=\"900\" alt=\"Agent Trash Guard artwork: an armored guardian protecting systems from unsafe deletion\" />\n</p>\n\n<p><strong>A safety net for coding-agent sessions: block permanent deletes and keep recovery within reach.</strong></p>\n\n<p>Agent Trash Guard is developed by <a href=\"https://hermes-labs.ai\">Hermes Labs</a>.</p>\n\n<p>Hermes Labs is an agentic infrastructure company building the reliability layer for autonomous systems.</p>\n\n<a href=\"https://github.com/hermes-labs-ai/agent-trash-guard/releases/latest\"><img alt=\"Latest release\" src=\"https://img.shields.io/github/v/release/hermes-labs-ai/agent-trash-guard?display_name=tag&amp;sort=semver\"></a>\n<a href=\"https://github.com/hermes-labs-ai/agent-trash-guard/actions/workflows/ci.yml\"><img alt=\"CI\" src=\"https://github.com/hermes-labs-ai/agent-trash-guard/actions/workflows/ci.yml/badge.svg\"></a>\n<a href=\"LICENSE\"><img alt=\"License: Apache-2.0\" src=\"https://img.shields.io/badge/License-Apache--2.0-blue.svg\"></a>\n\n<p>\n<a href=\"#install\">Install</a> ·\n<a href=\"#what-gets-blocked\">What gets blocked</a> ·\n<a href=\"#using-the-trash\">Recovery workflow</a> ·\n<a href=\"#how-it-works\">How it works</a> ·\n<a href=\"#tests\">Tests</a>\n</p>\n\n</div>\n\n<p>Native guards for Claude Code, Codex, Cursor, Gemini CLI, OpenClaw, and Pi, backed by one detector and an inspectable <code>agent-trash</code> workflow.</p>\n\nAgents are good at cleaning up. Sometimes they clean up the wrong thing, and\n`rm` has no undo. This project provides native pre-tool adapters for Claude\nCode, Codex, Cursor, Gemini CLI, OpenClaw, and Pi, backed by one detector and the `agent-trash` CLI.\nRecognized guarded delete commands are blocked before execution; use\n`agent-trash put` to make the recoverable move you can inspect and reverse.\n`agent-trash gc` reclaims the space those moves accumulate without ever\nreclaiming work that git cannot prove is safe to lose.\n\nThe project was originally published as `claude-trash-guard`. GitHub redirects\nthat historical repository URL, and `claude-trash` remains as a compatibility\ncommand. New integrations and documentation use the platform-neutral\n`agent-trash-guard` name.\n\nNo dependencies beyond Python 3 (stdlib only) and bash.\n\n## Try it in 30 seconds (no install)\n\nNo plugin, no host setup. This runs the real hook and the real CLI against a\nthrowaway directory and proves the whole loop — block, trash, list, restore —\nbyte-for-byte:\n\n```bash\ngit clone https://github.com/hermes-labs-ai/agent-trash-guard.git\ncd agent-trash-guard\n./tests/recoverability-demo.sh\n```\n\nYou'll see a `rm -rf` get blocked cold (hook exit 2, file untouched), then\n`agent-trash put` / `list` / `restore` move the file out and back with a\nmatching SHA-256. Under a second on most machines, and it never touches your\nfiles or your real trash directory.\n\n## Install\n\n### One-liner: guard + CLI for Claude Code (recommended)\n\n```bash\ngit clone https://github.com/hermes-labs-ai/agent-trash-guard.git\ncd agent-trash-guard\n./install.sh\n```\n\n`install.sh` symlinks `agent-trash` (plus the legacy `claude-trash` alias)\ninto `~/.local/bin` and registers the Claude adapter in\n`~/.claude/settings.json`. A timestamped backup of `settings.json` is written\nbefore any change, existing settings and other hooks are preserved, and the\nedit is idempotent. If `~/.local/bin` is not on your PATH, `install.sh` prints\nthe exact `export PATH=...` line to run for the current shell. Restart any\nrunning Claude Code session afterwards.\n\nIt comes off just as cleanly: `./uninstall.sh` restores `settings.json` from\nthe backup and removes the symlinks, leaving your trash directory intact.\n\n### Host plugin routes\n\nThe repository root is one portable Agent Plugin (`plugin.json`, Agent Plugins\n1.0.0) with one canonical skill, `skills/agent-trash-guard/SKILL.md`. Choose a\nhost route that loads the executable guard. A skill-only install teaches the\nworkflow but cannot intercept shell commands.\n\n| Host | Install | Read back |\n| --- | --- | --- |\n| Claude Code | `claude plugin marketplace add hermes-labs-ai/agent-trash-guard && claude plugin install agent-trash-guard@hermes-labs` | `claude plugin list` |\n| Codex CLI | `codex plugin marketplace add hermes-labs-ai/agent-trash-guard && codex plugin add agent-trash-guard@hermes-labs` | `codex plugin list`, then trust the hook with `/hooks` |\n| Cursor | Clone the repository, then copy `integrations/cursor/` to `~/.cursor/plugins/local/agent-trash-guard/` | Restart Cursor; inspect Customize → Plugins and test a disposable delete |\n| Gemini CLI | `gemini extensions install https://github.com/hermes-labs-ai/agent-trash-guard --ref main` | `gemini skills list` |\n| OpenClaw | `openclaw plugins install ./integrations/openclaw` | `openclaw plugins inspect agent-trash-guard --json` |\n| Pi | `pi install git:github.com/hermes-labs-ai/agent-trash-guard@main` | `pi list`, then test a disposable delete in Pi's Bash tool |\n| skills.sh (skill only) | `npx skills add https://github.com/hermes-labs-ai/agent-trash-guard --skill agent-trash-guard` | `npx skills list` |\n\nThe skill teaches an agent to use `agent-trash put`, `list`, and `restore`\nand states the guard's limits. A skills.sh install copies only the skill; it\ninstalls no hook and no CLI.\n\n### First safe check\n\nThe host readback above confirms that the plugin, extension, or skill was\nregistered; it does not by itself prove that a delete hook is active. After a\nnative plugin or extension install (not a skills.sh-only install), run these\nchecks through your host's shell tool. Use `agent-trash` when it is on `PATH`;\notherwise replace it below with the quoted full path to your installed adapter's\n`bin/agent-trash`, as described in your host's section:\n\n```bash\nagent-trash --version\nagent-trash list\n```\n\nBoth are read-only: `--version` prints the installed CLI's bundled version\n(read from that host's own `plugin.json`/manifest, so it always matches what\nwas actually installed), and `list` shows the configured trash. Neither moves\nor deletes anything. In Codex, also complete the explicit `/hooks` trust\nreview before treating delete interception as active. Until then, Codex loads\nthe skill but skips its non-managed hook.\n\nThe guard is a convenience layer, not universal deletion protection: it fails\nopen when it cannot parse a Claude/Codex/Gemini hook event. The Cursor, OpenClaw,\nand Pi adapters fail closed when they cannot inspect a shell command. All hosts\nhave documented command-pattern limits, and the local trash is not a backup.\nKeep normal backups and inspect the\nsupported-command boundaries below before relying on it for an important path.\n\n### OpenClaw: recover one file end to end\n\nThe OpenClaw adapter intercepts the native `exec` tool. It blocks a recognized\npermanent-delete command; it does **not** rewrite that command into a trash\noperation. After the block, run the recoverable CLI yourself (or instruct the\nagent to run it):\n\n```bash\n# From this repository checkout, install the adapter and restart the gateway.\nopenclaw plugins install -l ./integrations/openclaw\nopenclaw plugins inspect agent-trash-guard --json\n\n# In an OpenClaw exec session, this is rejected before rm receives the file.\nrm -f notes.txt\n\n# Use the bundled recoverable CLI instead. (Use `agent-trash` if your host\n# exposes plugin bin directories on PATH.)\n./integrations/openclaw/bin/agent-trash put notes.txt\n./integrations/openclaw/bin/agent-trash list\n# Copy the entry ID printed by `put` (for example, 20260919-153000-4242).\n./integrations/openclaw/bin/agent-trash restore 20260919-153000-4242\n```\n\nBefore `put`, `notes.txt` is at its original path. After `put`, it is absent\nthere and `list` shows the entry ID and original path. After `restore ID`, the\nsame bytes are back at the original path. `restore` refuses to replace a newer\nfile unless `--force` is explicit. The adapter packages that CLI at\n`integrations/openclaw/bin/agent-trash`.\n\nThis is an `exec`-tool guard, not an LLM conversation test or a general file\nsystem monitor. It recognizes the documented shell delete patterns and leaves\nother deletion mechanisms, overwrites, and truncation outside its scope.\n\n## Claude Code\n\n`agent-trash-guard@hermes-labs` is the repository root. Its manifest reuses the\n`PreToolUse` hook in `integrations/claude/hooks/hooks.json`, which runs the\nroot `hooks/trash_guard.py`, and its `bin/` puts `agent-trash` on the Bash\ntool's `PATH` while the plugin is enabled.\n\n`claude-trash-guard@hermes-labs` remains the guard-only plugin ID for existing\nusers (`integrations/claude/`). Install one of the two, not both, or every\nblocked command is reported twice. `claude plugin validate --strict` on the\nroot manifest reports the Gemini `BeforeTool` entry in the root\n`hooks/hooks.json` as ignored at runtime; that warning is expected.\n\nTo evaluate a local checkout:\n\n```bash\ngit clone https://github.com/hermes-labs-ai/agent-trash-guard.git\ncd agent-trash-guard\n./tests/run.sh\nclaude --plugin-dir \"$PWD\"\n```\n\n## Codex CLI and app\n\nCodex 0.145 or newer installs `agent-trash-guard@hermes-labs` from the\nself-contained `integrations/codex/` adapter, which uses `PreToolUse` for\n`Bash`. Codex requires an explicit trust review for non-managed plugin hooks\nand skips the hook until you trust it with `/hooks`; the skill works either\nway.\n\nCodex ignores a `.codex-plugin` manifest, and with it these hooks, when a\nportable root `plugin.json` exists, so its marketplace entry points at the\nadapter. The adapter's `skills/agent-trash-guard/SKILL.md` is a generated byte\ncopy of the canonical skill, checked like the runtime copies below. For a\nlocal checkout use `codex plugin marketplace add \"$PWD\"`.\n\n## Gemini CLI\n\nGemini CLI is the repository-root extension. It uses `BeforeTool`, names its\nshell tool `run_shell_command`, and discovers the skill under `skills/`:\n\n```bash\ngemini extensions install https://github.com/hermes-labs-ai/agent-trash-guard --ref main\n```\n\nKeep `--ref main`: without a ref, Gemini CLI installs the latest release\narchive, and releases up to v0.1.2 predate the skill.\n\nRestart Gemini CLI afterwards. Update or uninstall it with:\n\n```bash\ngemini extensions update agent-trash-guard\ngemini extensions uninstall agent-trash-guard\n```\n\nThe root `gemini-extension.json` makes this repository eligible for Gemini's\nGallery crawler when the public repository has the `gemini-cli-extension` topic\nand a tagged release. The nested Claude and Codex package roots intentionally\ndo not qualify as Gemini extensions.\n\nFor local development use `gemini extensions link \"$PWD\"`. The old\n`integrations/gemini/install.sh` and `uninstall.sh` remain only to remove or\nmaintain a pre-extension settings-based installation; they are not the primary\ninstallation route.\n\n## Cursor\n\nCursor loads the self-contained bundle at `integrations/cursor/`. Until a\nmarketplace listing is available, use Cursor's documented local-plugin path:\n\n```bash\ngit clone https://github.com/hermes-labs-ai/agent-trash-guard.git\nmkdir -p ~/.cursor/plugins/local\ncp -R agent-trash-guard/integrations/cursor ~/.cursor/plugins/local/agent-trash-guard\n```\n\nRestart Cursor and inspect Customize → Plugins. In an IDE agent session, create\na disposable file and ask Cursor to run `rm FILE_PATH` as a shell command. The\n`beforeShellExecution` hook denies it and gives the bundled `agent-trash` path.\nRun that path with `put FILE_PATH`, `list`, then `restore ENTRY_ID`; the same\nfile should return. Copying the bundle does not add a global `agent-trash`\ncommand. Remove `~/.cursor/plugins/local/agent-trash-guard` to uninstall this\nlocal plugin. Cursor's Tab edits and non-shell tools are outside this hook.\nWhen updating this local copy, remove only\n`~/.cursor/plugins/local/agent-trash-guard` before repeating the copy command;\notherwise `cp -R` can nest a second `cursor/` directory under the old bundle.\n\n## Pi\n\nPi loads the root `skills/` and `extensions/` directories from a Git package:\n\n```bash\npi install git:github.com/hermes-labs-ai/agent-trash-guard@main\npi list\n```\n\nStart a new Pi session (or `/reload` an existing one). The TypeScript extension\nintercepts Pi's `bash` tool at `tool_call` and asks the canonical Python detector\nto decide before the shell runs. It needs Python 3 on `PATH`. In Pi, create a\ndisposable file, then ask for `rm FILE_PATH`: the tool should be blocked and the\nfile should remain. Use the exact bundled `bin/agent-trash` path in the block\nmessage with `put FILE_PATH`, `list`, and `restore ENTRY_ID` to verify recovery.\n`pi list` proves package registration, not that the guard blocked a command.\nRemove it with `pi remove git:github.com/hermes-labs-ai/agent-trash-guard@main`.\n\n## What gets blocked\n\nWhen a supported agent is about to run a shell command that permanently\ndeletes files, the hook stops it and tells the agent to use `agent-trash put`\ninstead:\n\n- `rm`, `unlink`, `shred`, `rmdir` — in command position, including behind\n  `sudo`, `env`, `nohup`, `time`, `xargs`, pipes, `&&`/`;` chains, subshells,\n  and absolute paths like `/bin/rm`\n- `find ... -delete` and `find ... -exec rm ...`\n- `git clean -f` (and `-fd`, `-fdx`, ...)\n\nNot blocked, by design:\n\n- `git rm` — the file is still recoverable from git history\n- `rm` appearing as a plain word (`echo rm is just a word`)\n- overwrites and truncations — out of scope for v0.1\n\n## Using the trash\n\n```bash\nagent-trash put build/ old-notes.md    # move into ~/.claude-trash, keep originals' paths\nagent-trash list                       # show entries with their original locations\nagent-trash restore 20260712-153000-4242          # put everything back\nagent-trash restore 20260712-153000-4242 --force  # ...even over newer files\nagent-trash empty --older-than 7 --yes # the only permanent delete, and it asks twice\n```\n\nEach `put` creates one timestamped entry containing the moved files and a\n`manifest.json` recording their original absolute paths. `restore` refuses to\noverwrite existing files unless you pass `--force` (the displaced file is kept\nin the trash entry, so even `--force` loses nothing).\n\nSet `AGENT_TRASH_DIR` to relocate the trash (default: `~/.claude-trash`). The\nlegacy `CLAUDE_TRASH_DIR` variable remains supported.\n\n## Retention: `agent-trash gc`\n\nA recoverable delete only moves the problem: guarded deletes, dated task\nworktrees, and approved-for-deletion dumps pile up until the disk is full of\nquarantined garbage. `agent-trash gc` reaps that accumulation, and it is built\nso that it can only ever reap work that nothing still points at.\n\n**Budget decides *when* to collect. Reachability decides *what* may be\ncollected.** The size budget is the trigger, the way BuildKit's `keepStorage`\nor ccache's `max_size` are; reachability is the Nix GC-root model, so anything\nstill reachable from something that matters is never a candidate.\n\n```bash\n# report only (the default): what would gc reclaim, and why did it refuse the rest\nagent-trash gc --roots ~/.claude-trash,~/worktrees --budget 5G --older-than 14\n\n# the full machine-readable receipt, one JSON object with an entry per decision\nagent-trash gc --roots ~/.claude-trash --budget 5G --json\n\n# actually reclaim; deleting always needs this explicit flag\nagent-trash gc --roots ~/.claude-trash --budget 5G --older-than 14 --collect\n```\n\n### The decision ladder\n\nEvery candidate runs the same ordered ladder, first match wins, and every\nreceipt names the rule number that decided it:\n\n| # | Rule | Outcome |\n|---|------|---------|\n| 1 | **Protected** — the denylist | never collect, overrides everything below |\n| 2 | **Unknown** — git could not answer | never collect; unknown is treated as reachable |\n| 3 | **Reachable** — something still points at it | never collect |\n| 4 | **Too young** — newer than `--older-than` | never collect; budget pressure does not lower the floor |\n| 5 | **Budget** — footprint exceeds `--budget` | collect, oldest first, until the footprint fits |\n| 6 | **Default** | keep |\n\nRule 5 is the only rule that ever collects anything. Without `--budget`,\nnothing triggers collection at all; `--budget 0` means \"collect everything the\nfirst four rules allow\".\n\n### What \"unreachable\" means\n\nA directory holding git checkouts is unreachable only when *every* checkout\ninside it passes *all* of these:\n\n- `git status --porcelain --untracked-files=all` is empty\n- `git stash list` is empty\n- `git log --branches --not --remotes --oneline` is empty\n- every local branch head, and `HEAD`, is confirmed present on a real remote by\n  `git ls-remote` — not by `git branch -r`, which reads a stale local cache and\n  will happily claim a branch is on a remote that never received it\n\nThe last check is a `git rev-list --count` of the head against everything the\nremote just advertised, not a string comparison of SHAs, so a head the remote\nhas already moved past still counts as pushed. Advertised objects the checkout\ndoes not have are ignored, which can only make the answer more cautious.\n\nIf git errors, times out, is missing, or returns something unparseable, the\nverdict is **UNKNOWN**, not clean. A `dirty=0` produced by git falling over is\nthe most dangerous false negative a collector can have, so it is never treated\nas a pass. The same applies to a subtree whose files could not all be read, and\nto a candidate holding more than `--max-checkouts` repositories. `--offline`\nextends this: a remote that is not a local path cannot be contacted, so its\ncheckout is UNKNOWN and kept.\n\nA path with no git checkout in it falls back to age and budget only.\n\nA scan root that is itself a git checkout — or a directory inside one — is\nnever split into pieces. The checkout is judged atomically as a single unit,\nso pointing `--roots` at a live checkout keeps it whole: its pieces can never\nbe scored as \"0 git checkouts\" and reclaimed one by one.\n\n### The denylist\n\n`~/.claude`, `~/ai-infra`, `~/github-projects`, and any path that names or\ncontains `profiles.db` or `corpus.db` can never be collected. These are\nbuilt in and cannot be switched off; `--protect PATH` and `AGENT_TRASH_PROTECT`\nonly add to them. Rule 1 is re-checked at the moment of deletion, not just\nduring planning. `/` and `$HOME` are refused as scan roots outright: name the\naccumulation directories explicitly.\n\n### Receipts\n\nEvery decision produces a receipt line carrying the path, apparent size, age,\nreachability verdict, the evidence that produced that verdict (the git command,\nits exit code, and what it said), the rule number, and collect or keep.\n`--json` prints the whole run as one object; `--receipt PATH` appends it to a\nJSONL audit log.\n\n### Automating it\n\n`gc` is a single deterministic command with no network calls of its own beyond\n`git ls-remote`, so a cron entry or a launchd agent is enough. Start it in\nreport mode, read a few days of receipts, then add `--collect`:\n\n```\n0 3 * * *  agent-trash gc --roots ~/.claude-trash,~/worktrees --budget 5G --older-than 14 --receipt ~/.claude-trash/gc-receipts.jsonl\n```\n\nVerifying a large accumulation site is minutes of git calls, and a silent\nscan is indistinguishable from a hang, so `--progress` names each candidate on\nstderr as it is verified. It never touches stdout, so it is safe to combine\nwith `--json`.\n\nA budget is about blocks on the disk, so sizes are allocated bytes\n(`st_blocks * 512`) and a multiply-linked inode is counted once per candidate,\nthe way `du` does. This matters more than it sounds: `git clone` from a local\npath hardlinks `.git/objects`, and a dump directory full of local clones reads\nas more than twice its real size if those links are counted once per name,\nwhich would make every reclaim estimate optimistic. The logical total is kept\nalongside it as `apparent_size` in the JSON receipt.\n\nAn entry's age is measured from the newest mtime anywhere in its subtree, which\nis the conservative choice: anything recently touched looks young and is\nspared.\n\n## Escape hatch\n\nFor a genuine permanent delete that you have explicitly approved, prefix the\ncommand with `TRASH_GUARD_ALLOW=1`:\n\n```bash\nTRASH_GUARD_ALLOW=1 rm -rf node_modules\n```\n\nThe override is deliberately visible in the command itself, so it shows up in\nsession logs and permission prompts rather than hiding in configuration.\n\n## How it works\n\n`hooks/trash_guard.py` reads a pre-tool event as JSON on stdin. It accepts the\nClaude/Codex `Bash` and Gemini `run_shell_command` names. If the command matches\na delete pattern, it exits with code 2, which all three runtimes define as a\nblocking decision whose stderr becomes agent guidance. Anything else exits 0.\nThe hook fails open when an event cannot be parsed. The runtime files inside\n`integrations/claude` and `integrations/codex` are generated copies required by\nplugin-cache isolation; do not edit them. Regenerate with\n`python3 tools/build_platform_bundles.py` and verify with `--check`.\n\n## Other agents\n\nOpenClaw's native `before_tool_call` plugin hook blocks `exec` calls through\nthe self-contained adapter in `integrations/openclaw/`. It bridges\n`event.params.command` to the canonical detector and fails closed if that\nbridge cannot complete. No local Hermes Agent/client installation exposed a verified pre-tool interception API;\nthe `hermes` command on this machine is the Hermes Labs command center, not an\nagent runtime. Both are adapter candidates, not live integrations.\n\n## Uninstall\n\nFor the native plugin path, end the `claude --plugin-dir` session or remove the\nplugin through Claude Code's plugin manager. Trash contents remain untouched.\n\nFor the `install.sh` path:\n\n```bash\n./uninstall.sh\n```\n\nRestores `~/.claude/settings.json` from the timestamped backup `install.sh`\nwrote — byte-identical to the pre-install state — removes the `agent-trash`\nand `claude-trash` symlinks, and consumes the install-time backups. Your trash\ndirectory is left intact. If no backup exists (because `install.sh` created\n`settings.json` from scratch), the hook entry is stripped in place instead and\nthe created file is removed.\n\n## Tests\n\n```bash\n./tests/run.sh\npython3 tools/build_platform_bundles.py --check\n```\n\nCovers the hook's block/allow matrix, the full put/list/restore/empty\nlifecycle, the `gc` decision ladder, and the quality rail's review range, in an\nisolated temp directory.\n\nThe `gc` fixtures build real git repositories whose remotes are bare\nrepositories on the same disk, so `git ls-remote` is exercised for real and the\nsuite still needs no network. They pin the cases that matter: a clean pushed\nrepository is collectable, while a dirty tree, a stash, an unpushed commit, an\norphaned worktree whose git calls all fail, and a denylisted path are not.\nThey also pin the trust contract adversarially: a checkout passed as the scan\nroot itself — dirty, unpushed, stashed, remote-deleted, unborn HEAD, or a bare\nrepository — is judged atomically, never split, and survives `--collect`\nbyte-identical.\n\nThe Hermes Gate rail in `.hermes/` keeps its local scope — worktree, index and\nuntracked bytes — when run with no arguments. A hosted checkout has none of\nthose, so CI names the range explicitly:\n\n```bash\npython3 .hermes/hermes_gate_runner.py full --base \"$PULL_REQUEST_BASE_SHA\"\npython3 .hermes/hermes_gate_runner.py full --all\n```\n\n`--base` compares that revision with `HEAD` (`HERMES_GATE_BASE` does the same),\n`--all` reviews every committed byte, and a base the checkout does not carry is\nan error rather than an empty scan. `full` runs every declared stage and reports\neach one; `fast` still stops at the first failure to hold its local budget.\n\n## Recoverability proof\n\n[`tests/recoverability-demo.sh`](tests/recoverability-demo.sh) is a\nself-contained, deterministic proof that the guard blocks a destructive command\nand that the trash workflow loses nothing. It runs entirely inside a freshly\ncreated temporary directory, validates that path before cleaning up, and never\ntouches user files or the real trash directory.\n\n```bash\n./tests/recoverability-demo.sh\n```\n\nUsing the released hook event interface and the `agent-trash` CLI, it shows:\n\n1. a representative `rm -rf FILE` event is blocked (hook exit 2) and the file\n   stays in place\n2. the recommended replacement, `agent-trash put FILE`, passes the hook\n3. `agent-trash put` moves the file into a timestamped trash entry\n4. `agent-trash list` exposes the entry and the file's original path\n5. `agent-trash restore <id>` returns the file to its original path\n6. the restored file's SHA-256 equals the original, pinned digest\n\nThe script stops at the first failed step with a non-zero exit and prints\n`RESULT: PASS (6/6)` when the proof holds.\n\n## License\n\nApache-2.0 — see [LICENSE](LICENSE).\n",
  "bytes": 24672,
  "sha": "9bc851ae4463245d728b5261aeae677fbfe1b456d86d6fa625543f1fe546ea90",
  "repo_slug": "roli-lpci/agent-trash-guard",
  "fonte": "repo",
  "truncated": false,
  "api": "https://api.agentalog.com/api/listings/plg_roli_lpci_agent_trash_guard_483a281a/readme"
}