@pi-lab/permissions

Permission system extension for pi coding agent

Package details

extension

Install @pi-lab/permissions from npm and Pi will load the resources declared by the package manifest.

$ pi install npm:@pi-lab/permissions
Package
@pi-lab/permissions
Version
0.1.5
Published
May 2, 2026
Downloads
463/mo · 10/wk
Author
cheny341
License
MIT
Types
extension
Size
16.1 KB
Dependencies
1 dependency · 2 peers
Pi manifest JSON
{
  "extensions": [
    "./dist/index.mjs"
  ]
}

Security note

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

README

@pi-lab/permissions

A permission system extension for pi coding agent. Intercepts tool calls and enforces allow / deny / ask rules defined in a JSON config file.

Install

pi install npm:@pi-lab/permissions

Configuration

Rules are configured in pi settings and merged into a single list:

  • ~/.pi/agent/settings.json — global
  • .pi/settings.json — project

Example settings.json:

{
  "permissions": {
    "rules": [
      {
        "message": "Block rm -rf",
        "priority": 10,
        "match": { "tool": "bash", "params": { "command": "rm\\s+-rf" } },
        "action": "deny"
      },
      {
        "match": { "tool": "bash", "params": { "command": "sudo" } },
        "action": "ask"
      },
      {
        "message": "Only allow reading files inside the project",
        "priority": 10,
        "match": { "tool": "read", "paths": ["~/projects/my-app/**"] },
        "action": "allow"
      },
      {
        "message": "read is restricted to allowed paths only",
        "match": { "tool": "read" },
        "action": "deny"
      }
    ]
  }
}

Rule fields

Field Type Required Description
match.tool string Tool name, or "*" to match all tools
match.params object Param name → regex pattern. All conditions must match.
match.paths string[] Path patterns the tool's path argument must fall within. Supports glob (**, *) and plain directory prefixes. Supports ~ expansion. Pairs with a higher-priority allow rule to form a whitelist.
match.pathParam string Which input key holds the path. Defaults to "path".
action string allow, deny, or ask
priority number Defaults to 0. Higher values are evaluated first.
message string Reason returned to the LLM when a call is blocked.

Matching order

  1. Rules sorted by priority descending
  2. Same priority: deny > ask > allow

No match defaults to allow.

ask mode

A dialog prompts the user with four options:

  • Allow — allow this call once
  • Allow always — allow identical calls for the rest of the session (not persisted)
  • Deny — deny this call once
  • Deny always — deny identical calls for the rest of the session (not persisted)

Events

The extension broadcasts observational events on pi.events. Listeners cannot change permission decisions, cache behavior, or blocked responses.

Event names

  • permissions:deny — emitted whenever a tool call is blocked
  • permissions:ask — emitted immediately before a real user prompt is shown
  • permissions:user_select — emitted after the prompt resolves

Payloads

All payloads include the matched rule serialized with configured patterns only. Raw tool input is never broadcast.

type SerializedPermissionRule = {
  action: "allow" | "deny" | "ask";
  message?: string;
  priority?: number;
  match: {
    tool: string;
    params?: Record<string, string>;
    paths?: string[];
    pathParam?: string;
  };
};

type PermissionsDenyEvent = {
  toolCallId: string;
  toolName: string;
  reason: string;
  source: "rule" | "cache" | "user" | "no_ui";
  rule: SerializedPermissionRule;
};

type PermissionsAskEvent = {
  toolCallId: string;
  toolName: string;
  rule: SerializedPermissionRule;
  options: ["Allow", "Allow always", "Deny", "Deny always"];
};

type PermissionsUserSelectEvent = {
  toolCallId: string;
  toolName: string;
  selection: "Allow" | "Allow always" | "Deny" | "Deny always" | null;
  decision: "allow" | "deny";
  cached: boolean;
  rule: SerializedPermissionRule;
};

Privacy guarantee

Event payloads never include event.input or derived raw argument values such as shell commands, file paths, or file contents. The params and paths fields contain only the configured rule patterns.

Example listener

pi.events.on("permissions:deny", (event) => {
  console.log(event);
});