@bacnh85/pi-permission
Granular permission system for Pi — allow/ask/deny rules per tool with wildcard patterns, external-directory boundary, and a doom-loop guard. Config-driven, opt-in companion to Pi's container-first philosophy. Inspired by OpenCode's permission config.
Package details
Install @bacnh85/pi-permission from npm and Pi will load the resources declared by the package manifest.
$ pi install npm:@bacnh85/pi-permission- Package
@bacnh85/pi-permission- Version
0.2.0- Published
- Aug 17, 2026
- Downloads
- 372/mo · 325/wk
- Author
- bacnh85
- License
- MIT
- Types
- extension
- Size
- 24.5 KB
- Dependencies
- 0 dependencies · 0 peers
Pi manifest JSON
{
"extensions": [
"./extensions/index.js"
]
}Security note
Pi packages can execute code and influence agent behavior. Review the source before installing third-party packages.
README
pi-permission
Granular permission system for Pi — an opt-in companion to Pi's container-first philosophy for users who can't always containerize.
Config-driven allow / ask / deny rules per tool, with wildcard pattern matching, an external-directory boundary, and a doom-loop guard. Inspired by OpenCode's permission config.
Pi's default stance is "No permission popups. Run in a container, or build your own." This package is the middle ground: a config-driven policy for users who run Pi without a container but still want guardrails.
Install
pi install npm:@bacnh85/pi-permission
Configuration
Add a permission object to .pi/settings.json (project) or ~/.pi/agent/settings.json (global):
{
"permission": {
"*": "ask",
"bash": { "*": "ask", "git *": "allow", "npm *": "allow", "rm *": "deny" },
"edit": { "*": "deny", "src/*.ts": "allow" },
"write": { "*": "deny", "src/*": "allow" },
"read": { "*": "allow", "*.env": "deny", "*.env.*": "deny" },
"external_directory": { "~/projects/personal/*": "allow" }
}
}
Actions
| Action | Behavior |
|---|---|
allow |
Runs silently, no prompt |
ask |
Prompts via the Pi UI (Allow once / Allow for this session / Add to permanent allowlist / Deny). "Allow for this session" skips prompts for the exact same call subject until the session ends; "Add to permanent allowlist" writes the allow rule into settings.json. Tools without a command/path subject get only Allow once/Deny. Dismissing the dialog blocks. Session promotions never override an explicit deny. |
deny |
Blocks immediately |
Patterns
*matches zero or more of any character (including/)?matches exactly one character- Everything else is literal
- Last matching rule wins (OpenCode semantics)
~and$HOMEexpand at the start of path patterns
Rule keys
| Key | Matches |
|---|---|
bash |
the shell command |
read / write / edit |
the file path |
grep / find / ls |
the path/glob/pattern |
external_directory |
deny-gate for paths outside the project cwd |
* |
global default |
Flags
| Flag | Description |
|---|---|
--yolo |
Auto-approve all ask prompts (explicit deny rules still enforced) |
--auto |
Alias for --yolo |
Doom-loop guard
Blocks the 3rd identical tool call in a row. Cheap insurance against model loops. Always on when pi-permission is configured.
Default security
By design, when no rule matches, pi-permission has no opinion (allows). This honors Pi's philosophy — the extension only acts when you've opted into rules. To lock down, set a "*": "ask" or "*": "deny" default.
The .env deny pattern (OpenCode's default) is a good baseline:
{ "read": { "*": "allow", "*.env": "deny", "*.env.*": "deny", "*.env.example": "allow" } }
Why
Pi's "no permission popups" philosophy is clean but binary: containerize, or trust everything. Many users run Pi locally without a container and still want to prevent rm -rf, protect .env, or restrict writes to src/. This package provides that middle ground, opt-in.
License
MIT