omp packages

pi-bouncer0.4.0

Guards Pi's bash tool: asks before destructive commands, blocks catastrophic ones, with an optional model-judged auto mode

GitHub Actions Published 6 days ago MIT ~868 downloads/mo

Untested on omp

This is a pi package. No one has reported whether it works on omp yet. If you try it, add your result below.

Did it work for you?

Result

One report per person. A new report replaces your old one.

Reports 0

No reports yet.

Readme

pi-bouncer

Guards Pi's bash tool: asks before destructive commands, blocks catastrophic ones, with an optional model-judged auto mode.

Every command the model runs through bash is parsed and checked, including inside chains, $(…), wrappers such as env or xargs, and bash -c. Recoverable mistakes, such as rm -rf build or git reset --hard, open a dialog. Catastrophic ones, such as sudo, rm -rf ~ or formatting a disk, are denied outright.

The bouncer is a guard rail against accidents, not a sandbox. A determined or prompt-injected model can find commands it does not recognise, and Pi's write and edit tools are not gated. MCP tool calls ask unless allowed by name. For real isolation, run Pi in a container or virtual machine, as Pi's security guide describes.

Install

Install the package from npm:

pi install npm:pi-bouncer

To follow the latest commit instead, install it from GitHub:

pi install git:github.com/gvanderclay/pi-bouncer

Pi installs the bash parser, unbash, with the package. A local checkout is not installed for you, so run npm install in it once; without the parser, the bouncer denies every bash call and says so.

When no one can answer a dialog, a refused rm -rf tells the agent to move the folder to the trash instead, so the deletion can be undone. macOS has a trash command built in. On Linux, install trash-cli for trash-put, or use a desktop with gio; trashCommand names any other program.

Quick start

Start Pi. With no config file, the first session shows "Bouncer is on: it asks before destructive bash commands. /bouncer shows rules and config." The built-in rules apply, and an ask opens a dialog such as:

Bouncer: recursive rm deletes whole directory trees (rule: recursive-rm)
rm -rf build

You can allow it once or for the session, deny it (optionally with a reason for the model), or deny and stop the turn. /bouncer shows the mode, the config files, every rule's level and the log path, and /bouncer explain <command> shows what the bouncer would do with a command without running it. /bouncer init writes an empty config file to ~/.pi/agent/bouncer.json.

A recursive rm of a folder the agent made earlier in the session, with mkdir, mktemp -d or a recursive cp into a new path, runs without a dialog. The agent is told to make the folder in one call and delete it with a plain rm -rf of the same literal path in a later one; anything older inside the folder, a variable or a wrapper still asks. Details are in How the bouncer decides, and "trustAgentMade": false turns it off.

To let a model decide asks for you, add a judge list to that file and run /auto:

{
  "auto": { "models": ["anthropic/claude-haiku-4-5"] }
}

Any model Pi has credentials for works. Read Auto mode first: it sends your commands and messages to that model's provider.

Modes

Mode Turn it on What happens to an ask
normal the default a dialog opens
auto /auto, pi --auto, or "startMode": "auto" a judge model allows it, denies it, or hands it to the dialog
YOLO /yolo or pi --yolo it is allowed

Auto mode never overrides a deny. YOLO mode allows rules set to deny as well, but neither mode ever allows the always-deny set (marked below), a command that cannot be parsed, or a steer rule. The mode lasts until the Pi process ends, and the footer shows auto or YOLO while it is on.

Rules

Each rule has a level: ask opens the dialog, deny blocks with no dialog.

Rule Level Catches
rm-root ✱ deny recursive rm of /, a system directory, ~, or a folder such as ~/Documents or ~/.ssh
privilege ✱ deny sudo, su, doas
power ✱ deny shutdown and reboot
disk-format ✱ deny formatting, erasing or repartitioning a disk
dd-device ✱ deny dd writing to a /dev path
trash-root deny moving /, a system directory, ~, or a folder such as ~/Documents to the trash
recursive-rm ask any other recursive rm, except of a folder the agent made this session (mkdir, mktemp -d, recursive cp)
find-delete ask find -delete
find-exec ask find -exec, -execdir, -ok, -okdir
fd-exec ask fd -x, fd -X
rg-pre ask rg --pre
opaque-exec ask parallel, rush, rust-parallel
git-clean ask git clean -f
git-reset-hard ask git reset --hard
git-checkout-discard ask git checkout -- <path>, git checkout ., git checkout -f
git-restore-worktree ask git restore of the working tree
git-stash-destroy ask git stash drop, git stash clear
git-push-force ask force and mirror pushes
git-push-delete ask pushes that delete or prune remote branches and tags
remote-script ask a download piped into a shell, such as curl … | sh
publish ask publishing a package, such as npm publish
gh-delete ask deleting a GitHub repository or release
bouncer-escape deny pi --yolo, or setting or clearing an agent variable

✱ The always-deny set: its level can be ask or deny but never off. Every other rule can also be off. Commands that cannot be parsed are always denied. A deny anywhere on a line wins over every ask.

Configuration

The user config is ~/.pi/agent/bouncer.json (Pi's agent dir, or $PI_CODING_AGENT_DIR). A project can add .pi/extensions/bouncer/config.json, which Pi asks you to trust; an untrusted project may only make rules stricter. This config raises a level, turns a rule off, protects one more folder from rm -rf, and adds a rule of your own:

{
  "$schema": "https://raw.githubusercontent.com/gvanderclay/pi-bouncer/main/schema/bouncer.schema.json",
  "levels": { "git-push-force": "deny", "opaque-exec": "off" },
  "protect": { "home": ["code"] },
  "rules": [
    {
      "name": "kubectl-delete",
      "command": "kubectl",
      "args": ["delete"],
      "summary": "deletes cluster resources"
    }
  ]
}

A profile (profiles) is a named group of rule changes for one kind of session, and agents maps an agent name to a profile. A session started with PI_BOUNCER_AGENT=scout, or by a launcher that sets PI_SUBAGENT_AGENT or PI_DADDY_DEFINITION, runs the normal rules with that profile's changes on top; /bouncer status shows it. examples/profiles.json has a read-only and a worker profile.

An MCP tool call asks unless the tool is on mcp.allow, as in { "mcp": { "allow": ["mcp__docs__*"] } }. In auto mode the judge rules on it, and its arguments go to the judge-list providers unless "mcp": { "judge": false }; see mcp.

A custom rule with an instead text is a steer rule: it blocks a command in every mode and tells the model what to run instead. examples/prefer-rg.json sends the model from grep to rg. The configuration reference lists every key, and examples/ has a minimal config, auto mode with Anthropic or OpenRouter, and a project file.

Auto mode

Auto mode needs a judge list, auto.models, in the user config. Each ask goes to the first model in the list that answers; it allows or denies the command, or hands it to the dialog. Each judged ask costs a model call, or more when an entry fails to answer. Three denies in a row, or 20 in a session, pause auto mode until you allow a call. The auto-judge-list skill researches and benchmarks models and writes the list for you.

Privacy: for each ask, auto mode sends the judge's provider the command, the working directory, the git branch and remotes, your recent messages, and the list of commands and file writes the agent made this session. It never sends tool output or file contents.

Optionally, "jev": {} under auto asks Jev, TypeSafe's command classifier, before the judge list. A confident "safe" answer runs the command without a judge call. By default Jev runs through OpenCode Zen with Pi's opencode-go key; auto.jev.model can pick another provider, such as openrouter/typesafe/jev-1.13.

How the bouncer decides covers the judge's exact input, time limits, Jev's cutoffs and the dialog in full.

Commands and skills

Command What it does
/bouncer [status] shows the mode, config files and problems, project trust, rule levels, the log path and auto mode
/bouncer rules lists every rule with its level and what it catches
/bouncer explain <command> shows what the bouncer would do with a command, without running it
/bouncer init writes an empty user config with $schema, if none exists
/bouncer check re-reads both config files and lists their problems
/auto [on|off|status] toggles auto mode, or says why it cannot turn on
/yolo [on|off] toggles YOLO mode

The package also loads two skills. auto-judge-list builds or refreshes the judge list, and bouncer-debug explains why a command was blocked, asked about or let through.

Log and debugging

The bouncer appends one JSON line to ~/.pi/agent/bouncer/log.jsonl (or $PI_BOUNCER_LOG_DIR/log.jsonl) for every deny, dialog answer, auto-mode decision, mode switch and session start. Commands it lets through untouched are not logged. Ask the agent why something was blocked and the bouncer-debug skill reads the log and replays the command.

Integrations

A launcher extension can emit the session:launch event as { args, env } just before it starts a child Pi process. The bouncer appends --auto or --yolo to args when that mode is on, so the child starts in the same mode. When the payload also has an agent name that a profile covers, it sets PI_BOUNCER_AGENT in env to that name, so the child runs that agent's profile; otherwise, if the parent runs a profile, it passes the parent's agent name on. It never overwrites a PI_BOUNCER_AGENT already in env, changes nothing else, and cannot veto the launch.

Compatibility and limitations

  • Pi 1.0 or later, on Node 22.19 or later. On a Pi without project trust the bouncer warns and treats every project as untrusted.
  • macOS and Linux. Only the bash tool and MCP tools are gated: Windows powershell, ! commands you type, Pi's write and edit tools and the MCP resource tools are not.
  • Without a UI (print, JSON or RPC mode with no dialogs), every ask denies.
  • A usage-policy refusal counts as a judge deny only for providers that report it, such as Anthropic.

More

The glossary defines the words the bouncer uses, and the design notes record the evidence behind its defaults. CHANGELOG.md lists changes, and SECURITY.md says how to report a bypass.

License

MIT