pi-permission-gate

Config-driven permission system for Pi agents. Deny-by-default tool restriction with glob matching, path normalization, self-protection, and structured logging.

Packages

Package details

extension

Install pi-permission-gate from npm and Pi will load the resources declared by the package manifest.

$ pi install npm:pi-permission-gate
Package
pi-permission-gate
Version
0.1.3
Published
Jun 12, 2026
Downloads
734/mo · 239/wk
Author
juanjeojeda
License
MIT
Types
extension
Size
15.9 KB
Dependencies
1 dependency · 5 peers
Pi manifest JSON
{
  "extensions": [
    "./extensions"
  ]
}

Security note

Pi packages can execute code and influence agent behavior. Review the source before installing third-party packages.

README

pi-permission-gate

Config-driven permission system for Pi agents. Deny-by-default tool restriction with glob matching, path normalization, self-protection, and structured logging.

Install

From npm:

pi install npm:pi-permission-gate

From git:

pi install git+https://github.com/juanje/pi-permission-gate.git

Or load directly without installing:

pi -e /path/to/pi-permission-gate/extensions/permission-gate.ts

Quick start

Create .pi/permissions.json in your project:

{
  "defaultMode": "deny",
  "permissions": {
    "tools": {
      "read": { "paths": { "allow": ["**"] }, "default": "allow" },
      "write": { "paths": { "allow": ["tmp/*"] }, "default": "deny" },
      "bash": {
        "allow": ["date", "date *", "git *", "bin/*"],
        "deny": ["rm *", "curl *", "wget *", "*.env*"],
        "default": "deny"
      }
    }
  }
}

Optional local overrides in .pi/permissions.local.json (gitignored).

How it works

The extension hooks into three Pi events:

  1. session_start — loads and merges policy files, initializes the permission log
  2. before_agent_start — hides tools blocked at session level via setActiveTools()
  3. tool_call — enforces granular rules before each tool executes

Evaluation order

For each tool call:

  1. Self-protection — blocks operations on .pi/permissions.json, .pi/permissions.local.json, and .pi/extensions/ (hardcoded, cannot be overridden)
  2. Simple rules"allow" or "deny" for the entire tool
  3. Deny patterns — command/path glob patterns (deny always wins)
  4. Allow patterns — command/path glob patterns
  5. Tool default — per-tool default mode
  6. Policy default — global defaultMode

Glob matching

Patterns use * (any sequence) and ? (single character). Tilde expansion is supported in patterns (~/.ssh/*). Paths are normalized (~, ./, ../, absolute → relative) before matching.

Secret redaction

Logged inputs and reasons are automatically scanned for credentials before writing. Two layers of detection:

  1. Vendor prefixes (via secret-sniff) — AWS AKIA*, GitHub ghp_*, GitLab glpat-*, Anthropic sk-ant-*, OpenAI sk-proj-*, Slack xoxp-*, Stripe, JWT, PEM, and more
  2. Variable name patterns — catches SECRET=, _KEY=, _TOKEN=, PASSWORD=, CREDENTIAL=, AUTH=, DATABASE_URL=, REDIS_URL=, and Bearer headers regardless of value format

Structured log

Each decision is appended to .pi/logs/permission-gate_{timestamp}.jsonl (secrets redacted):

{"ts":"2026-06-09T00:05:16.733Z","tool":"bash","input":"cat .env","decision":"deny","reason":"'cat .env' matches deny pattern for bash"}

Custom log directory via logPath in the policy:

{
  "defaultMode": "deny",
  "logPath": "var/audit",
  "permissions": { "tools": {} }
}

Policy format

interface Policy {
  defaultMode: "allow" | "deny";
  logPath?: string; // optional, relative to project root
  permissions: {
    tools: Record<string, "allow" | "deny" | ToolRule>;
  };
}

interface ToolRule {
  default?: "allow" | "deny";
  allow?: string[];   // glob patterns (bash commands, etc.)
  deny?: string[];
  paths?: {
    allow?: string[];
    deny?: string[];
  };
}

Merge strategy

When both .pi/permissions.json and .pi/permissions.local.json exist:

  • defaultMode — local wins
  • Tool rules — deep merged (arrays concatenated)
  • Local string rule ("allow" / "deny") — overrides base entirely

Development

git clone https://github.com/juanje/pi-permission-gate.git
cd pi-permission-gate
npm install
npm run check    # typecheck + lint + test

License

MIT — see LICENSE.