# @skibum1869/pi-permission-gate

A bash permission gate for the [pi coding agent](https://github.com/earendil-works/pi): blocks
dangerous actions while leaving routine work free. Every risky bash command is analyzed with a
shell-aware parser (not flat regexes), severity-ranked, and either prompted, denied, or passed
through depending on the active mode — plus a hard-block list of protected paths.

## Install

```bash
pi install npm:@skibum1869/pi-permission-gate
```

Or try it without installing:

```bash
pi -e npm:@skibum1869/pi-permission-gate
```

## Modes

Three modes, cycled with `/gate` or **Ctrl+Alt+G** (footer shows `🛡 ask` / `🛡 strict` / `🛡 bash-only`):

| Mode | Behavior |
|------|----------|
| `ask` (default) | Risky bash prompts Yes/No; protected-path writes are hard-blocked |
| `strict` | Risky bash denied outright — for unattended runs |
| `bash-only` | Same bash gating as `ask`, but the write gate is off |

Initial mode resolution (lowest → highest): built-in `ask` < global `settings.json` <
project `.pi/settings.json` < session-persisted mode (resume/fork) < `--gate ask|strict|bash-only` flag.

```json
{ "permission-gate": { "defaultMode": "strict" } }
```

## Risk analysis

Commands are tokenized with `shell-quote`, split on `&&`/`||`/`;`, and checked per segment with
command/argument position respected — so `sudo` in a comment or quoted string never false-positives,
while flags are caught in any order (`rm -fr`, `rm --force`, `"FOO=1 sudo x"`).

- **High** (unrecoverable): pipe-into-shell (curl … | sh), fork bombs, `sudo`, recursive/forced
  deletes, `find -delete` / `-exec rm` / `xargs rm`, destructive git (`reset --hard`,
  `push --force`, `clean -f`), raw disk tools (`dd of=`, `mkfs*`, `diskutil erase*`, `cryptsetup`),
  power ops, infrastructure teardown (`kubectl delete`, `terraform destroy`), writes to `/dev/*`.
- **Medium** (scoped or recoverable): plain `rm`, `sed -i`, `kill -9`, `mv/cp -f`, `chmod -R 777`,
  `git checkout .`, unparseable commands.
- **Never flagged**: routine git (add/commit/push/pull/status/…), redirects and plain pipes,
  package installs, reads.

## Approval flow

Risky commands prompt with three choices:

- **Allow once** — re-prompts if the same command runs again.
- **Allow similar (session)** — medium commands also approve their root
  (`git clean` variants pass afterwards); high-severity approvals are exact-command only, so
  `sudo` / `rm -rf` / `git push --force` never auto-widen.
- **Abort** — blocks the command and revokes prior approvals for it.

Retry-loop protection auto-blocks a command that was just aborted. Approvals are in-memory only.
The footer shows `·N` while the current turn has approvals.

### Subagents & headless sessions

Spawned subagents (`PI_SUBAGENT_DEPTH >= 1`) have no one to ask: only catastrophic (high-severity)
operations are hard-blocked there. Non-interactive main sessions (print mode) also have no one to
ask, so `ask` mode blocks all risky commands outright there (same as `strict`).

## Protected paths

Writes to these paths are hard-blocked in all modes (and always in `strict`/`ask`): `.env*`,
`.git/`, `node_modules/`, `.ssh/`, `.aws/credentials`, `.pi/agent/auth.json`, `id_rsa`,
`id_ed25519`, `id_ecdsa`, `credentials.json`, and anything matching `secrets`.

## Legibility

Blocked command reasons are shown in a preview dialog; the full reason is always available in the
transcript (viewable with Ctrl+O).

## Security

Pi extensions run with your user permissions. This gate is a guardrail, not an operating-system
sandbox. It cannot prove arbitrary shell commands are safe.

## License

MIT. Uses [shell-quote](https://github.com/substack/node-shell-quote) (MIT).