pi-permission-system logo

# @gotgenes/pi-permission-system [![npm version](https://img.shields.io/npm/v/@gotgenes/pi-permission-system?style=flat&logo=npm&logoColor=white)](https://www.npmjs.com/package/@gotgenes/pi-permission-system) [![CI](https://img.shields.io/github/actions/workflow/status/gotgenes/pi-packages/ci.yml?style=flat&logo=github&label=CI)](https://github.com/gotgenes/pi-packages/actions/workflows/ci.yml) [![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg?style=flat)](https://opensource.org/licenses/MIT) [![TypeScript](https://img.shields.io/badge/TypeScript-6.x-3178C6?style=flat&logo=typescript&logoColor=white)](https://www.typescriptlang.org/) [![pnpm](https://img.shields.io/badge/pnpm-%3E%3D11-F69220?style=flat&logo=pnpm&logoColor=white)](https://pnpm.io/) [![Pi Package](https://img.shields.io/badge/Pi-Package-6366F1?style=flat)](https://pi.mariozechner.at/) Permission enforcement extension for the [Pi](https://pi.mariozechner.at/) 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](https://github.com/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. > > **my-pi maintenance note:** This directory was imported from upstream tag `pi-permission-system-v26.2.1` at commit `ec4fdb11343dc94f7185b113e559a4cf9f8dc035`. It is loaded from source and maintained directly by my-pi; npm `dist` output is not used. my-pi uses one global ordinary policy and a separate non-overridable hard-guard file; explicitly configured authorizers may approve any ordinary-policy `ask`, including `path`. ## What It Does - **Enforces `allow` / `ask` / `deny`** at tool-call time with UI confirmation dialogs - **Uses one global ordinary policy file**; project `policy.jsonc` files are not loaded - **Chooses the most specific matching pattern**, so a specific deny wins over a broad `"*": "allow"` regardless of declaration order - **Applies a separate hard-guard policy first** so session grants, per-agent rules, and model review cannot override high-risk denies - **Controls Bash, paths, MCP, skills, and tool surfaces** while leaving active-tool ownership entirely to Tool Search - **Reviews ordinary `ask` requests automatically** with integrated AutoReview; its `allow` verdict is final for ordinary tools and `path`, while `defer` reaches the next authorizer or human terminal - **Follows the session's current model**: AutoReview asks the model you are already chatting with to judge each ask, so the review always reflects the model the operator actually selected; set `autoReview.provider` and `autoReview.model` together to pin a different reviewer - **Decides through tool calls only**: the reviewer reaches its verdict by calling exactly one of two tools, `approve` or `reject`, each carrying a reason — prose answers, even well-formed JSON, are ignored - **Never hard-denies on a refusal or failure**: a `reject` verdict or any review failure defers the ask to the human prompt, with the model's reason shown and labelled model-generated - **Forwards subagent `ask` decisions** to the parent authority and keeps structured audit logs ## Install ```bash pi install npm:@gotgenes/pi-permission-system ``` ## Quick Start 1. Create ordinary policy at `~/.pi/agent/my-pi/permission-system/policy.jsonc`: ```jsonc { "authorizerChain": ["auto-review"], "autoReview": { "enabled": true }, "permission": { "*": "ask", "read": "allow", "bash": { "*": "ask", "git status*": "allow" } } } ``` 2. Create independent hard guards at `~/.pi/agent/my-pi/permission-system/hard-guards.jsonc`: ```jsonc { "version": 1, "permission": { "*": "allow", "*.env": "deny", "*.env.*": "deny", "*.env.example": "allow", "~/.ssh/**": "deny" } } ``` 3. Restart Pi or run `/reload`. Ordinary `ask` requests now reach AutoReview first; only `defer` opens the human dialog. 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`, a unified `mcp` proxy tool'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. A `path` pattern matches both the path as the agent references it and its canonical (symlink-resolved) form, so a deny still fires when a symlink aliases a sensitive target. 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. Like the cross-cutting `path` surface, per-tool patterns match both the referenced path and its canonical (symlink-resolved) form, so a per-tool deny resists symlink-alias evasion. 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/*`. Paths outside the working tree have no separate boundary gate. Configure them with the same `path`, per-tool, and Bash patterns used for in-project paths. These layers still compose with most-restrictive-wins. See [docs/configuration.md](docs/configuration.md) for the full recipe. ## Configuration The integrated extension uses two independent global JSONC files: | Purpose | Scope | Path | | ------- | ----- | ---- | | Ordinary policy, runtime knobs, AutoReview | Global only | `~/.pi/agent/my-pi/permission-system/policy.jsonc` | | Non-overridable hard guards | Global only | `~/.pi/agent/my-pi/permission-system/hard-guards.jsonc` | Project-level `policy.jsonc` files are ignored. Project agent Markdown remains a separate per-agent restriction mechanism. The bundle deploys both files with mode `0600` via `scripts/rebuild-bundle-config.mjs`: every `install.sh` / `update.sh` run rebuilds the whole `/my-pi/` tree, overwriting local edits without a backup — keep durable changes in the repository's `config/` sources. Files left at the former `extensions/pi-permission-system/` location are ignored. Within a pattern map, the most specific match wins: exact patterns, then more literal characters, fewer wildcards, and longer patterns. Declaration order is only a tie-breaker. There is no `external_directory` gate. Outside-CWD paths use the same configured tool, `path`, and Bash rules as other paths. Tool Search alone owns Pi's active tool list. Permission System only decides whether an invoked tool call is allowed, denied, or requires confirmation. See [docs/configuration.md](docs/configuration.md) for the complete reference and [docs/hard-guards.md](docs/hard-guards.md) for the independent hard-guard format. ## Documentation | Document | Contents | | ------------------------------------------------------------------------------------------------------------------------------ | -------------------------------------------------------------------------------------------------------------------- | | [docs/configuration.md](docs/configuration.md) | Full policy reference, runtime knobs, per-agent overrides, recipes | | [docs/session-approvals.md](docs/session-approvals.md) | Session-scoped rules, pattern suggestions, bash arity table | | [docs/cross-extension-api.md](docs/cross-extension-api.md) | Cross-extension service accessor, event bus integration, prompt and decision broadcasts | | [docs/subagent-integration.md](docs/subagent-integration.md) | Permission forwarding, coexistence with subagent extensions | | [docs/guides/permission-frontmatter-for-subagent-extensions.md](docs/guides/permission-frontmatter-for-subagent-extensions.md) | Convention guide for subagent extension authors | | [docs/opencode-compatibility.md](docs/opencode-compatibility.md) | OpenCode compatibility — shared concepts, divergences, porting guide | | [docs/troubleshooting.md](docs/troubleshooting.md) | Common issues, diagnostic logging, threat model | | [docs/migration/legacy-to-flat.md](docs/migration/legacy-to-flat.md) | Migration from pre-v2 config layout | | [docs/migration/strict-config-validation.md](docs/migration/strict-config-validation.md) | Strict config validation (breaking) — rejected configs, and the cross-scope fail-closed clamp | | [docs/migration/0644-project-trust-gating.md](docs/migration/0644-project-trust-gating.md) | Project-trust gating (breaking) — project config loads only after project trust | | [docs/migration/0745-prompt-payload-contracts.md](docs/migration/0745-prompt-payload-contracts.md) | Prompt payload contracts (breaking) — the forwarded wire, the `ui_prompt` broadcast, and the deprecated preview caps | | [docs/migration/0746-review-log-fields.md](docs/migration/0746-review-log-fields.md) | Review-log fields (breaking) — `message` replaced by request facts, and the `reviewLogFieldMaxWidth` bound | ## Development ```bash 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](https://prek.j178.dev/) 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](https://github.com/MasuRii/pi-permission-system). Thank you to [MasuRii](https://github.com/MasuRii) for the original work that made this possible. Thank you to the [OpenCode](https://opencode.ai) team for the permission model design that inspired the flat config format and evaluation semantics used in this extension. ## License [MIT](LICENSE)