permission-pi
v1.0.1
Published
Layered permission control extension for pi-coding-agent
Maintainers
Readme
Permission Extension
Layered permission control for pi-coding-agent.
Levels
| Level | Description | Allowed Operations |
|-------|-------------|-------------------|
| minimal | Read-only (default) | cat, ls, grep, git status/log/diff, npm list |
| low | File operations | + write/edit files |
| medium | Dev operations | + npm install, git commit, build commands |
| high | Full operations | + git push, deployments, scripts |
Dangerous commands (always prompt, even at high): sudo, rm -rf, chmod 777, dd, mkfs
Usage
Interactive Mode
# Extension loads automatically from ~/.pi/agent/extensions/ or .pi/extensions/
piCommands:
/permission- Show selector to change level/permission medium- Set level directly (asks session/global)/permission-mode- Switch between ask/block when permission is required/permission-mode block- Block instead of prompting
When a command needs higher permission:
🔒 Requires Medium: npm install lodash
[Allow once] → Execute this command only
[Allow all (Medium)] → Update global settings and execute
[Cancel] → Don't executeIf permission mode is set to block, commands that require higher permission are blocked without prompting. Use /permission-mode ask to restore prompts.
Print Mode
Permission mode is ignored in print mode; insufficient permissions always block.
# Set level via environment variable
PI_PERMISSION_LEVEL=medium pi -p "install deps and run tests"
# Bypass all permission checks (CI/containers - dangerous!)
PI_PERMISSION_LEVEL=bypassed pi -p "do anything"If permission is insufficient: The command is blocked but execution continues. The agent receives:
Blocked by permission (minimal). Command: npm install lodash
Allowed at this level: read-only (cat, ls, grep, git status/diff/log, npm list, version checks)
User can re-run with: PI_PERMISSION_LEVEL=medium pi -p "..."The agent can then work around the limitation or inform the user.
Environment Variables
| Variable | Values | Description |
|----------|--------|-------------|
| PI_PERMISSION_LEVEL | minimal, low, medium, high, bypassed | Set permission level |
Settings
Global settings stored in ~/.pi/agent/settings.json:
{
"permissionLevel": "medium",
"permissionMode": "ask"
}permissionMode accepts ask (prompt) or block (deny without prompting).
Custom Configuration
Configure permission overrides and prefix mappings in ~/.pi/agent/settings.json:
{
"permissionLevel": "medium",
"permissionMode": "ask",
"permissionConfig": {
"overrides": {
"minimal": ["tmux list-*", "tmux show-*"],
"medium": ["tmux attach*", "tmux new*"],
"high": ["rm -rf *"],
"dangerous": ["dd if=* of=/dev/*"]
},
"prefixMappings": [
{ "from": "fvm flutter", "to": "flutter" },
{ "from": "nvm exec", "to": "" },
{ "from": "rbenv exec", "to": "" }
]
}
}Override Patterns
Glob patterns matched against the full command:
*matches any characters?matches single character- Patterns are case-insensitive
Override priority (highest to lowest):
dangerous- Always prompt, even at high levelhigh- Require high permissionmedium- Require medium permissionlow- Require low permissionminimal- Allow at minimal (read-only)
Note: When a command matches patterns in multiple levels, the most restrictive level wins. Avoid overlapping patterns across levels. For example, don't put
tmux *in medium if you wanttmux list-*to be minimal.
Examples:
{
"overrides": {
"minimal": [
"tmux list-*", // tmux list-sessions, tmux list-windows, etc.
"tmux show-*", // tmux show-options, tmux show-messages, etc.
"screen -list" // List screen sessions
],
"medium": [
"tmux attach*", // Attach to sessions
"tmux new*", // Create new sessions
"screen -r *" // Reattach to screen
],
"high": [
"rm -rf *", // Force rm with any arguments
"dd of=/dev/*" // dd writing to any device
],
"dangerous": [
"dd if=* of=/dev/*" // dd writing to device from any source
]
}
}Prefix Mappings
Normalize version manager commands to their base tools:
fvm flutter build→ treated asflutter build(medium)rbenv exec ruby→ treated asruby(classified normally)
Common mappings:
{
"prefixMappings": [
{ "from": "fvm flutter", "to": "flutter" },
{ "from": "nvm exec", "to": "" },
{ "from": "rbenv exec", "to": "" },
{ "from": "pyenv exec", "to": "" }
]
}How it works:
- Commands are checked against prefix mappings first
- If a prefix matches, it's replaced with the mapped value
- The normalized command is then classified
/permission config Command
View and manage configuration from the CLI:
/permission config show # Display current configuration
/permission config reset # Reset to default (empty)Edit ~/.pi/agent/settings.json directly for full control.
Command Classification
The principle: building/installing is MEDIUM, running code is HIGH.
Minimal Level (Read-only)
- File reading:
cat,less,head,tail,bat - Directory:
ls,tree,pwd,find,fd - Search:
grep,rg,ag - Info:
echo,whoami,date,uname,ps,env - Git read:
git status,git log,git diff,git show,git branch,git fetch - Package info:
npm list,pip list,cargo tree
Medium Level (Build/Install/Test - Reversible)
- Node.js:
npm install/ci/test/build,yarn install/add/build/test,pnpm,bun - npm run (safe scripts only):
build,test,lint,format,check,typecheck - Python:
pip install,poetry install/build,pytest - Rust:
cargo build/test/check/clippy/fmt(NOTcargo run) - Go:
go build/test/get/mod(NOTgo run) - Ruby:
gem install,bundle install - CocoaPods:
pod install,pod update,pod repo update - PHP:
composer install - Java:
mvn compile/test,gradle build/test - .NET:
dotnet build/test - Git local:
git add,git commit,git pull,git checkout,git merge,git clone - Build tools:
make,cmake,ninja - Linters: All static analysis tools that only check/report without executing code
- JavaScript/TypeScript:
eslint,prettier,tsc --noEmit,tslint,standard,xo - Python:
pylint,flake8,black,mypy,pyright,ruff,pyflakes,bandit - Rust:
cargo clippy,cargo fmt,rustfmt - Go:
gofmt,go vet,golangci-lint,golint,staticcheck,errcheck,misspell - Ruby:
rubocop,standardrb,reek,brakeman - Swift:
swiftlint,swiftformat - Kotlin:
ktlint,detekt - Dart/Flutter:
dart analyze,flutter analyze,dart format,flutter format - C/C++:
clang-tidy,clang-format,cppcheck - Java:
checkstyle,pmd,spotbugs,error-prone - C#:
dotnet format,dotnet build -t:RunCodeAnalysis - PHP:
phpcs,phpmd,phpstan,psalm,php-cs-fixer - Lua:
luacheck - Shell:
shellcheck - Infrastructure as Code:
checkov,tflint,terraform validate - Protocol Buffers:
buf lint,protoc --lint - SQL:
sqlfluff - YAML:
yamllint - Markdown:
markdownlint - HTML/Django:
djlint,djhtml - Git:
commitlint
- JavaScript/TypeScript:
- File ops:
mkdir,touch,cp,mv
High Level (Runs Code / Irreversible)
- Running code:
python script.py,node app.js,cargo run,go run - npm run (unsafe scripts):
dev,start,serve,watch,preview - Package executors:
npx,bunx,pnpx(run arbitrary packages) - Git remote:
git push,git push --force - Git irreversible:
git reset --hard,git clean,git restore - Network:
curl,wget(can't verify trusted endpoints) - Deployment:
docker push,kubectl,helm,terraform - Remote access:
ssh,scp,rsync - Shell execution:
eval,exec,source,xargs
Dangerous (Always Prompt)
sudo(any form)rmwith-rAND-fflagschmod 777ora+rwxdd of=/dev/...mkfs,mkfs.ext4,fdisk,partedshutdown,reboot,halt,poweroff
Shell Trick Detection
Commands containing these patterns require HIGH permission:
- Command substitution:
$(cmd),`cmd` - Process substitution:
<(cmd),>(cmd) - Dangerous expansions:
${VAR:-$(cmd)}(nested command substitution)
Installation
Install the package and enable extensions:
pi install git:github.com/prateekmedia/pi-hooks
pi configDependencies are installed automatically during pi install.
File Structure
| File | Purpose |
|------|---------|
| permission.ts | Extension (entry point + state management + handlers) |
| permission-core.ts | Core permission logic (classification, config) |
| package.json | Declares extension via "pi" field |
License
MIT
