@gotgenes/pi-permission-system
Permission enforcement extension for the Pi coding agent.
Package details
Install @gotgenes/pi-permission-system from npm and Pi will load the resources declared by the package manifest.
$ pi install npm:@gotgenes/pi-permission-system- Package
@gotgenes/pi-permission-system- Version
14.0.0- Published
- Jun 17, 2026
- Downloads
- 18K/mo · 5,220/wk
- Author
- gotgenes
- License
- MIT
- Types
- extension
- Size
- 1.5 MB
- Dependencies
- 2 dependencies · 2 peers
Pi manifest JSON
{
"extensions": [
"./src/index.ts"
]
}Security note
Pi packages can execute code and influence agent behavior. Review the source before installing third-party packages.
README
@gotgenes/pi-permission-system
Permission enforcement extension for the Pi coding agent that provides centralized, deterministic permission gates over tool, bash, MCP, skill, and special operations.
Fork notice: This package is a full fork of MasuRii/pi-permission-system, published to npm as
@gotgenes/pi-permission-system. It has diverged substantially from upstream in config format, internal architecture, and permission model.
What It Does
- Hides disallowed tools before the agent starts — no wasted turns probing for blocked tools
- Enforces allow / ask / deny at tool-call time with UI confirmation dialogs
- Controls bash commands with wildcard pattern matching (
git *: ask,rm -rf *: deny) - Gates MCP and skill access at server, tool, and skill-name granularity
- Protects sensitive file patterns — cross-cutting
pathrules deny.env,~/.ssh/*, etc. across all tools and bash at once - Guards external paths — prompts before file tools or bash commands reach outside
cwd - Forwards prompts from subagents —
askpolicies work even in non-UI execution contexts - Broadcasts UI prompt events —
permissions:ui_promptfires only when the permission system is about to invoke the active user-facing permission UI - Native
@gotgenes/pi-subagentsintegration — in-process child sessions register with the permission system automatically, enabling per-agent policy enforcement andask-state forwarding to the parent UI without configuration
Install
pi install npm:@gotgenes/pi-permission-system
Quick Start
Create the global config file at
~/.pi/agent/extensions/pi-permission-system/config.json:{ "permission": { "*": "allow", "path": { "*": "allow", "*.env": "deny", "*.env.*": "deny", "*.env.example": "allow" }, "bash": { "rm -rf *": "deny", "sudo *": "ask" }, "external_directory": "ask" } }Start Pi — the extension automatically loads and enforces your policy.
All permissions use one of three states:
| State | Behavior |
|---|---|
allow |
Permits the action silently |
deny |
Blocks the action with an error message |
ask |
Prompts the user for confirmation via UI |
When the dialog prompts, you can approve once or approve a pattern for the rest of the session. See docs/session-approvals.md for details on session-scoped rules and pattern suggestions.
The path surface is a cross-cutting gate that applies to all file access — Pi tools, bash commands, MCP calls, and extension tools alike.
Extension and MCP tools that operate on paths (via input.path, MCP's input.arguments.path, or a registered access extractor) are gated by default, so a path deny cannot be overridden by a per-tool allow — making it the right place to protect sensitive files like .env or ~/.ssh/* from every tool at once.
For per-tool path patterns (read, write, edit, find, grep, ls), patterns are matched against the file path from input.path.
This lets you express rules like "allow reads but deny .env files" at the individual tool level.
When Pi's current working directory is known, relative path inputs also match their cwd-normalized absolute form, so src/App.jsx can match both src/* and /workspace/project/*.
The external_directory surface is the CWD-boundary gate: it decides whether reaching outside the working tree is allowed, and accepts a pattern map so you can allow specific outside-CWD directories without opening up all external access.
This is the right surface for silencing repeated prompts on a local cache like ~/.cargo/registry — allow it here, not on path:
{
"permission": {
"external_directory": {
"*": "ask",
"~/.cargo/registry/*": "allow"
}
}
}
The trailing * is greedy and crosses subdirectory boundaries, so it allows every file beneath the directory; a bare ~/.cargo/registry matches only the directory entry itself.
Four layers compose with most-restrictive-wins: path (cross-cutting) → external_directory (CWD boundary) → per-tool patterns → bash command patterns.
Because ask is more restrictive than allow, a path allow cannot loosen an external_directory: ask boundary — allow outside-CWD directories on external_directory.
See docs/configuration.md for the full recipe.
Configuration
Config lives in one JSON file per scope:
| Scope | Path |
|---|---|
| Global | ~/.pi/agent/extensions/pi-permission-system/config.json |
| Project | <cwd>/.pi/extensions/pi-permission-system/config.json |
Project overrides global; per-agent YAML frontmatter overrides both.
Within a surface map like bash or mcp, last matching rule wins — put broad catch-alls first and specific overrides after.
For the full reference — all surfaces, runtime knobs, per-agent overrides, merge semantics, and common recipes — see docs/configuration.md.
Documentation
| Document | Contents |
|---|---|
| docs/configuration.md | Full policy reference, runtime knobs, per-agent overrides, recipes |
| docs/session-approvals.md | Session-scoped rules, pattern suggestions, bash arity table |
| docs/cross-extension-api.md | Cross-extension service accessor, event bus integration, prompt and decision broadcasts |
| docs/subagent-integration.md | Permission forwarding, coexistence with subagent extensions |
| docs/guides/permission-frontmatter-for-subagent-extensions.md | Convention guide for subagent extension authors |
| docs/opencode-compatibility.md | OpenCode compatibility — shared concepts, divergences, porting guide |
| docs/troubleshooting.md | Common issues, diagnostic logging, threat model |
| docs/migration/legacy-to-flat.md | Migration from pre-v2 config layout |
Development
pnpm run check # Type-check TypeScript (no emit)
pnpm run lint # Biome + ESLint + lint:md
pnpm run lint:md # rumdl on README and docs
pnpm run test # Run tests from ./test
pnpm run test:watch # Run tests in watch mode
Pre-commit hooks
This project uses prek to run Biome, ESLint, and rumdl on staged files before each commit.
Run pnpm install to set up hooks automatically.
Acknowledgments
This project began as a fork of MasuRii/pi-permission-system. Thank you to MasuRii for the original work that made this possible.
Thank you to the OpenCode team for the permission model design that inspired the flat config format and evaluation semantics used in this extension.