@dougbots/pi-rm-guard
Pi extension: model-driven approval for rm cleanup commands
Package details
Install @dougbots/pi-rm-guard from npm and Pi will load the resources declared by the package manifest.
$ pi install npm:@dougbots/pi-rm-guard- Package
@dougbots/pi-rm-guard- Version
0.6.1- Published
- Nov 5, 2026
- Downloads
- 919/mo · 121/wk
- Author
- sdougbrown
- License
- MIT
- Types
- extension
- Size
- 162.6 KB
- Dependencies
- 0 dependencies · 1 peer
Pi manifest JSON
{
"extensions": [
"./src/index.ts"
]
}Security note
Pi packages can execute code and influence agent behavior. Review the source before installing third-party packages.
README
@dougbots/pi-rm-guard
Let routine cleanup run without another approval dialog. This pi
extension sends recursive-force rm commands and session evidence to a decision
model. The model judges whether to proceed, ask you, or deny the command.
How it works
- A small text detector routes commands containing an
rmtoken with both recursive and force flags —rm -rf,rm -fr,rm -r -f,rm -Rf,rm --recursive --force, in any position. Commands without that combination pass through unguarded, as they do without this extension. - The model receives the raw command, cwd, recent user requests, and bounded recent tool calls/results. No parser claims that deletion targets are verified.
- A confident approval runs the command. A confident denial blocks it. An ask, low confidence, or model error opens confirmation when a UI is available; otherwise it blocks.
There are no static path allowlists, literal-only matching, or shell parsing:
flag matching is lexical over the whole command text. Split flags such as
rm -r -f route just like rm -rf, quoted mentions of recursive-force rm
still route, and a neighboring command's flags may over-route (one extra model
call, never a missed route). Plain rm and single-flag rm pass through
unguarded. The model decides whether a routed command is harmless or the
cleanup is appropriate.
This is an autonomy aid, not a sandbox. Detection does not interpret arbitrary shell programs or inspect external scripts. The model can make mistakes. Use OS permissions or a sandbox for isolation, rather than treating approval as proof that a command cannot damage data.
Configure a reachable model
The default backend is classifier, using typesafe/jev-latest. It needs pi
credentials or TYPESAFE_API_KEY; without a reachable model, commands escalate.
For a decisions endpoint registered as a pi classifier, put this rmGuard block
in global or project pi settings:
{
"rmGuard": {
"backend": "classifier",
"registerProvider": true,
"classifier": "decisions/gemma4",
"url": "http://localhost:4000/v1/decisions",
"model": "gemma4",
"timeoutMs": 1500
}
}
url must serve OpenAI's Decisions API (POST /v1/decisions, the schema
client.decisions.create sends) on a model with a chat template: text input,
predicate/choice/score questions, and answers listed in question order.
Structured state reaches the model as JSON text.
Set backend to decisions to call that endpoint directly instead.
Direct requests and the registered decisions provider share state and question
encoding. Other pi-known classifier models use provider/model-id, such as
openrouter/typesafe/jev-1.13.
| Setting | Environment override | Default |
|---|---|---|
backend |
RM_GUARD_BACKEND |
classifier |
classifier |
RM_GUARD_CLASSIFIER |
typesafe/jev-latest |
url |
RM_GUARD_URL |
http://localhost:4000/v1/decisions |
model |
RM_GUARD_MODEL |
gemma4 |
timeoutMs |
RM_GUARD_TIMEOUT_MS |
1500 |
threshold |
RM_GUARD_THRESHOLD |
Backend default |
registerProvider |
RM_GUARD_REGISTER_PROVIDER (1/0) |
false |
keyFile |
RM_GUARD_JEV_KEY_FILE |
~/.secrets/jev.key |
Environment overrides settings. Unknown backend values are configuration errors,
not aliases for another engine. Config and provider registration resolve on the
first routed command. RM_GUARD_API_KEY supplies an optional endpoint token for
both direct and registered-provider requests. Other classifier credentials come
from pi. keyFile is a legacy
fallback: keep it private, since this extension does not enforce file modes.
The decisions backend approves at p≥0.85; the classifier backend defaults to
p≥0.6. threshold overrides the approval threshold. Both require p≥0.99 for denial.
Bool-only classifiers can approve or ask, but cannot deny. Calibrate your chosen
weights rather than assuming these defaults suit every model.
Command text, recent requests, and tool excerpts are sent to your configured model and recorded in rm-guard session entries. Choose an endpoint appropriate for the data in your sessions.
Install
pi install git:github.com/sdougbrown/pi-rm-guard
# or
pi install npm:@dougbots/pi-rm-guard
Verify
npm test
RM_GUARD_URL=http://localhost:4000/v1/decisions npm run eval:live
Unit tests prove routing, evidence delivery, transport handling, and execution of
model verdicts. Live evals present commands to actual weights without executing
them; their expected outcomes are not runtime rules.
The standalone eval reads endpoint and credential environment overrides, not pi's
merged settings. Mirror those settings through the documented environment variables.
Jev shares the runtime's key-file resolver, including RM_GUARD_JEV_KEY_FILE.
Before shipping, follow the real-pi verification procedure. Its real-pi fixtures prove settings loading, model calls, and filesystem outcomes. Stubbed approvals alone do not prove that a real model makes useful judgments.