Damage control for the Pi coding agent. Protects sensitive files, enforces workspace boundaries, and gates dangerous commands so a runaway tool call never wrecks your day.
pi install npm:@pi-vault/pi-guardrailsReload Pi after install:
/reload
To try a local checkout before publishing:
pi -e /absolute/path/to/pi-guardrailspi-guardrails works out of the box — no configuration needed.
Any tool call the agent (or a ! user command) tries to make goes through three checks: sensitive paths, workspace boundary, and dangerous commands. Each check produces a three-state decision:
- Allow — run silently.
- Ask — show a three-button dialog:
Allow once,Allow for session,Deny. - Deny — block with a clear reason.
Allow for session remembers the decision for the same action for the rest of the session, so repeated runs of the same safe command don't keep prompting.
- Sensitive file protection — blocks reads and writes to
.env,.env.*,.dev.vars,.git/**,~/.ssh/**,~/.aws/**, and~/.gnupg/**. Exception patterns allow.env.example,.env.test,*.example.env, and*.pubSSH keys. - Workspace boundary enforcement — file actions that target paths outside the current working directory prompt for confirmation by default.
- Bash command allowlist — known-safe commands (
ls,cat,git status,git log,npm install, etc.) run without prompting. - Bash command denylist — known-dangerous patterns (
rm -rf /,mkfs,dd if=/dev/zero, fork bomb, etc.) are always blocked. - Shell composition detection — commands using
&&,||,;,|,>,>>,<,<<,$(...), or backticks prompt for confirmation. - Bash path extraction — sensitive files are blocked even when accessed via an allowlisted command (e.g.
cat .env,grep ~/.ssh/id_rsa). - Symlink resolution — file paths are canonicalized before rules run, so a symlink inside the workspace pointing to
~/.aws/credentialsis still blocked. - Session-scoped approvals — once you approve an action for the session, the same action bypasses checks for the rest of the session.
- Fail-closed — when no interactive UI is available,
Askdecisions block instead of silently allowing. Rule errors are treated as dangerous. - Three-state decision model —
sensitive-pathanddangerous-commandalways deny.outside-workspaceandshell-compositionfollow your policy (askordeny). Everything else asks.
| Action | Default |
|---|---|
Reading or writing a sensitive file (.env, ~/.ssh/, ~/.aws/, .git/, ~/.gnupg/) |
Deny |
Running a known-dangerous command (rm -rf /, mkfs, fork bomb, etc.) |
Deny |
| Accessing a file or directory outside the current workspace | Ask |
Running a shell command with &&, |, >, $(), backticks, etc. |
Ask |
Running a command not in the safe-command list (e.g. git commit, npm publish) |
Ask |
Running a safe command (ls, cat, git status, npm install, etc.) |
Allow |
- Environment files —
.env,.env.local,.env.production,.dev.vars. Exception:.env.example,.env.test,.env.sample,*.example.env. - Git internals — everything under
.git/. - SSH keys —
~/.ssh/id_rsa,~/.ssh/config, etc. Exception:*.pub(public keys). - AWS credentials — everything under
~/.aws/. - GnuPG keys — everything under
~/.gnupg/.
rm -rf /,rm -rf ~,rm -rf /*:(){ :|:& };:(the fork bomb)mkfs,dd if=/dev/zero,dd if=/dev/random> /dev/sda,shred,wipefs,blkdiscard
Create a config file to override the defaults. The default location is resolved by your pi settings. All fields are optional — missing ones fall back to built-in defaults.
{
"enabled": true,
"protectedPaths": [
{
"id": "env-files",
"enabled": false
}
],
"bashAllowlist": ["my-custom-readonly-tool"],
"bashDenylist": ["my-custom-evil-command"],
"outsideWorkspacePolicy": "ask",
"shellOperatorPolicy": "ask",
"debug": false
}enabled— set tofalseto disable every check without uninstalling. Default:true.protectedPaths— array of rules matched against file paths. Override a default rule by itsidor append a new one. See Protected path rules.bashAllowlist— array of single-word or multi-word prefixes.git statusmatchesgit status --shortbut notgit statusbar. Merged with the default allowlist. Default: ~95 safe commands.bashDenylist— array of substring patterns matched against the full command. Merged with the default denylist. Default: 11 dangerous patterns.outsideWorkspacePolicy— what to do when a file action targets a path outside the current directory."ask"(default) or"deny".shellOperatorPolicy— what to do when a bash command uses&&,|,>, etc."ask"(default) or"deny".debug— whentrue, logs everyAskdecision toconsole.debugin addition to the defaultconsole.warnfor blocks. Default:false.
{
"id": "my-secret-files",
"description": "Project-specific secrets",
"patterns": [{ "pattern": "secrets/**" }],
"allowedPatterns": [{ "pattern": "secrets/public/**" }],
"enabled": true
}id— stable identifier used to override or disable a default rule byid.description— human-readable label shown in block reasons.patterns— array of file or directory patterns to protect.allowedPatterns— optional exceptions (e.g..env.example).enabled— set tofalseto skip this rule. Default:true.
Patterns support glob (*, **) by default and case-insensitive regex when "regex": true. A pattern with no / matches the basename anywhere; a pattern with / matches the full path. A leading ~ is expanded to your home directory.
Invalid patterns (bad regex, empty string) disable just that rule and log a warning — they never throw or silently disable the whole extension.
Set the master switch:
{ "enabled": false }Or disable a single rule by id:
{
"protectedPaths": [
{ "id": "env-files", "enabled": false }
]
}- Node
>=22.19.0 - Peer dependencies:
@earendil-works/pi-coding-agent,@earendil-works/pi-tui - Intended for Pi sessions with package and extension support
pnpm install
pnpm check
pnpm pack --dry-runMIT