npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

pi-permission-system

v0.1.8

Published

Permission enforcement extension for the Pi coding agent.

Readme

🔐 pi-permission-system

Version License: MIT

Permission enforcement extension for the Pi coding agent that provides centralized, deterministic permission gates for tool, bash, MCP, skill, and special operations.

Permission Prompt Example

Features

  • Tool Filtering — Hides disallowed tools from the agent before it starts (reduces "try another tool" behavior)
  • System Prompt Sanitization — Removes denied tool entries from the Available tools: system prompt section so the agent only sees tools it can actually call
  • Runtime Enforcement — Blocks/asks/allows at tool call time with UI confirmation dialogs
  • Bash Command Control — Wildcard pattern matching for granular bash command permissions
  • MCP Access Control — Server and tool-level permissions for MCP operations
  • Skill Protection — Controls which skills can be loaded or read from disk
  • Per-Agent Overrides — Agent-specific permission policies via YAML frontmatter
  • Subagent Permission Forwarding — Forwards ask confirmations from non-UI subagents back to the main interactive session
  • JSON Schema Validation — Full schema for editor autocomplete and config validation

Installation

Place this folder in one of the following locations:

| Scope | Path | |---------|-----------------------------------------------| | Global | ~/.pi/agent/extensions/pi-permission-system | | Project | .pi/extensions/pi-permission-system |

Pi auto-discovers extensions in these paths.

Usage

Quick Start

  1. Create the global policy file at ~/.pi/agent/pi-permissions.jsonc:
{
  "defaultPolicy": {
    "tools": "ask",
    "bash": "ask",
    "mcp": "ask",
    "skills": "ask",
    "special": "ask"
  },
  "tools": {
    "read": "allow",
    "write": "deny"
  }
}
  1. Start Pi — the extension automatically loads and enforces your policy.

Permission States

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 |

Pi Integration Hooks

The extension integrates via Pi's lifecycle hooks:

| Hook | Behavior | |----------------------|-------------------------------------------------------------------------------------------| | before_agent_start | Filters active tools, removes denied tool entries from the system prompt, and hides denied skills | | tool_call | Enforces permissions for every tool invocation | | input | Intercepts /skill:<name> requests and enforces skill policy |

Additional behaviors:

  • Unknown/unregistered tools are blocked before permission checks (prevents bypass attempts)
  • The Available tools: system prompt section is rewritten to match the filtered active tool set
  • The task delegation tool is restricted to the orchestrator agent only
  • When a subagent hits an ask permission without direct UI access, the request can be forwarded to the main interactive session for confirmation
  • When a subagent triggers an ask permission without UI access, the request can be forwarded to the main session and answered there

Configuration

Global Policy File

Location: ~/.pi/agent/pi-permissions.jsonc

The policy file is a JSON object with these sections:

| Section | Description | |-----------------|------------------------------------------| | defaultPolicy | Fallback permissions per category | | tools | Built-in tool permissions | | bash | Command pattern permissions | | mcp | MCP server/tool permissions | | skills | Skill name pattern permissions | | special | Reserved permission checks |

Note: Trailing commas are not supported. If parsing fails, the extension falls back to ask for all categories.

Per-Agent Overrides

Override global permissions for specific agents via YAML frontmatter in ~/.pi/agent/agents/<agent>.md:

---
name: my-agent
permission:
  tools:
    read: allow
    write: deny
    mcp: allow
  bash:
    git status: allow
    git *: ask
  mcp:
    chrome_devtools_*: deny
    exa_*: allow
  skills:
    "*": ask
---

Precedence: Agent frontmatter overrides global config (shallow-merged per section).

MCP behavior: permission.tools.mcp is the coarse entry/fallback permission for the built-in mcp tool. More specific permission.mcp target rules override that fallback when they match.

Limitations: The frontmatter parser is intentionally minimal. Use only key: value scalars and nested maps. Avoid arrays, multi-line scalars, and YAML anchors.


Policy Reference

defaultPolicy

Sets fallback permissions when no specific rule matches:

{
  "defaultPolicy": {
    "tools": "ask",
    "bash": "ask",
    "mcp": "ask",
    "skills": "ask",
    "special": "ask"
  }
}

tools

Controls built-in tools by exact name (no wildcards):

| Tool | Description | |---------|--------------------------------| | bash | Shell command execution | | read | File reading | | write | File creation/overwriting | | edit | Surgical file edits | | grep | Pattern searching | | find | File discovery | | ls | Directory listing | | mcp | MCP proxy tool entry/fallback |

{
  "tools": {
    "read": "allow",
    "write": "deny",
    "edit": "deny",
    "mcp": "allow"
  }
}

Note: Setting tools.bash affects the default for bash commands, but bash patterns can provide command-level overrides.

Note: Setting tools.mcp controls coarse access to the built-in mcp tool. Specific mcp rules still override it when a target pattern matches.

bash

Command patterns use * wildcards and match against the full command string. Patterns are sorted by specificity:

  1. Fewer wildcards wins
  2. Longer literal text wins
  3. Longer overall pattern wins
{
  "bash": {
    "git status": "allow",
    "git diff": "allow",
    "git *": "ask",
    "rm -rf *": "deny"
  }
}

mcp

MCP permissions match against derived targets from tool input. These rules are more specific than tools.mcp and override that fallback when a pattern matches:

| Target Type | Examples | |-------------------|---------------------------------------------| | Baseline ops | mcp_status, mcp_list, mcp_search, mcp_describe, mcp_connect | | Server name | myServer | | Server/tool combo | myServer:search, myServer_search | | Generic | mcp_call |

{
  "mcp": {
    "mcp_status": "allow",
    "mcp_list": "allow",
    "myServer:*": "ask",
    "dangerousServer": "deny"
  }
}

Note: Baseline discovery targets may auto-allow when you permit any MCP rule.

MCP Tool Fallback via tools.mcp

The mcp built-in tool can use tools.mcp as an entry permission point. This provides a fallback when no specific MCP pattern matches:

{
  "tools": {
    "mcp": "allow"
  }
}

This is useful for per-agent configurations where you want to grant MCP access broadly:

# In ~/.pi/agent/agents/researcher.md
---
name: researcher
permission:
  tools:
    mcp: allow
---

The permission resolution order for MCP operations:

  1. Specific mcp patterns (e.g., myServer:toolName, myServer_*)
  2. tools.mcp fallback (if set)
  3. defaultPolicy.mcp

skills

Skill name patterns use * wildcards:

{
  "skills": {
    "*": "ask",
    "dangerous-*": "deny"
  }
}

special

Reserved permission checks:

| Key | Description | |----------------------|------------------------------------------| | doom_loop | Controls doom loop detection behavior | | external_directory | Controls access outside working directory | | tool_call_limit | (schema only, not enforced yet) |

{
  "special": {
    "doom_loop": "deny",
    "external_directory": "ask"
  }
}

Common Recipes

Read-Only Mode

{
  "defaultPolicy": { "tools": "ask", "bash": "ask", "mcp": "ask", "skills": "ask", "special": "ask" },
  "tools": {
    "read": "allow",
    "grep": "allow",
    "find": "allow",
    "ls": "allow",
    "write": "deny",
    "edit": "deny"
  }
}

Restricted Bash Surface

{
  "defaultPolicy": { "tools": "ask", "bash": "deny", "mcp": "ask", "skills": "ask", "special": "ask" },
  "bash": {
    "git status": "allow",
    "git diff": "allow",
    "git log *": "allow",
    "git *": "ask"
  }
}

MCP Discovery Only

{
  "defaultPolicy": { "tools": "ask", "bash": "ask", "mcp": "ask", "skills": "ask", "special": "ask" },
  "mcp": {
    "mcp_status": "allow",
    "mcp_list": "allow",
    "mcp_search": "allow",
    "mcp_describe": "allow",
    "*": "ask"
  }
}

Per-Agent Lockdown

In ~/.pi/agent/agents/reviewer.md:

---
permission:
  tools:
    write: deny
    edit: deny
  bash:
    "*": deny
---

Technical Details

Subagent Permission Forwarding

When a delegated or routed subagent runs without direct UI access, ask permissions can still be enforced by forwarding the confirmation request through Pi session directories. The main interactive session polls for forwarded requests, shows the confirmation prompt, writes the response, and the subagent resumes once that decision is available.

This keeps ask policies usable even when the original permission check happens inside a non-UI execution context.

Architecture

index.ts                    → Root Pi entrypoint shim
src/
├── index.ts                → Extension bootstrap, permission checks, and subagent forwarding
├── permission-manager.ts   → Policy loading, merging, and resolution with caching
├── bash-filter.ts          → Bash command wildcard pattern matching
├── wildcard-matcher.ts     → Shared wildcard pattern compilation and matching
├── common.ts               → Shared utilities (YAML parsing, type guards, etc.)
├── tool-registry.ts        → Registered tool name resolution
├── types.ts                → TypeScript type definitions
└── test.ts                 → Test runner
schemas/
└── permissions.schema.json → JSON Schema for config validation
config/
└── config.example.json     → Starter configuration template

Module Organization

The extension uses a modular architecture with shared utilities:

| Module | Purpose | |--------|---------| | common.ts | Shared utilities: toRecord(), getNonEmptyString(), isPermissionState(), parseSimpleYamlMap(), extractFrontmatter() | | wildcard-matcher.ts | Compile-once wildcard patterns with specificity sorting: compileWildcardPatterns(), findCompiledWildcardMatch() | | permission-manager.ts | Policy resolution with file stamp caching for performance | | bash-filter.ts | Uses shared wildcard matcher for bash command patterns |

Performance Optimizations

  • File stamp caching: Configurations are cached with file modification timestamps to avoid redundant reads
  • Pre-compiled patterns: Wildcard patterns are compiled to regex once and reused across permission checks
  • Resolved permissions caching: Merged agent+global permissions are cached per-agent with invalidation on file changes

Threat Model

Goal: Enforce policy at the host level, not the model level.

What this stops:

  • Agent calling tools it shouldn't use (e.g., write, dangerous bash)
  • Tool switching attempts (calling non-existent tool names)
  • Accidental escalation via skill loading

Limitations:

  • If a dangerous action is possible via an allowed tool, policy must explicitly restrict it
  • This is a permission decision layer, not a sandbox

Schema Validation

Validate your config against the included schema:

npx --yes ajv-cli@5 validate \
  -s ./schemas/permissions.schema.json \
  -d ./pi-permissions.valid.json

Editor tip: Add "$schema": "./schemas/permissions.schema.json" to your config for autocomplete support.


Troubleshooting

| Problem | Cause | Solution | |---------|-------|----------| | Config not applied (everything asks) | File not found or parse error | Verify file at ~/.pi/agent/pi-permissions.jsonc; check for trailing commas | | Per-agent override not applied | Frontmatter parsing issue | Ensure --- delimiters at file top; keep YAML simple; restart session | | Tool blocked as unregistered | Unknown tool name | Use built-in mcp tool for server tools: { "tool": "server:tool" } | | /skill:<name> blocked | Missing context or deny policy | Requires active agent context; ask behaves as block in headless mode |


Development

npm run build    # Compile TypeScript
npm run lint     # Run linter (uses build)
npm run test     # Run tests
npm run check    # Run lint + test

License

MIT