pi-guard

内容来源:README.md(说明文档) · 原始地址 · 查看安装指南

原始内容

pi-guard

Permission system for pi tools

pi-guard intercepts tool calls and prompts for approval before executing potentially dangerous operations. It provides fine-grained, pattern-based permissions for bash commands, file access, and any custom tool — with sensible defaults that let you start safely.

Features

  • Bash command matching — Parses shell commands with an AST parser, handles pipes, subshells, wrapper commands (sudo, xargs, bash -c, find -exec), and supports glob tokens in rules
  • Path matching — Glob patterns for file read/write/edit permissions
  • Extensible — Add matchers for any tool with exact, glob, or bash matching
  • Sensible defaults — Reading is safe, writing is dangerous. Works out of the box
  • Layered configuration — Default → user → project → env → profile → session, last match wins
  • Non-interactive support — Denied commands are silently blocked in CI/CD; use PI_GUARD env var for automation
  • Session rules — "Always allow for this session" without modifying config files

Examples

When a tool call is covered by an ask rule, pi-guard intercepts it and prompts for approval. Commands get reformatted and abridged to make them easier to review. Allowed commands get ✔, unauthorized ones get ✖.

When the agent runs:

rm -rf dist/

The prompt looks like:

⚠️ Unapproved Commands

✖ rm -rf dist/

→ Allow
  Always allow rm (this session)
  Reject

For commands with pipes and subshells, each sub-command is checked independently. When the agent runs:

TOKEN=$(curl -s https://api.example.com/token | jq -r .access_token) && \
curl -H "Authorization: Bearer $TOKEN" https://api.example.com/data

The prompt looks like:

⚠️ Unapproved Commands

✔ TOKEN=$(...) &&
✖ curl -s https://api.example.com/token |
✔ jq -r .access_token

✖ curl -H "Authorization: Bearer $TOKEN" https://api.example.com/data

→ Allow
  Always allow curl (this session)
  Reject

Wrapper commands (xargs, find -exec) are expanded — the wrapper gets ✔, the inner command is checked on its own line. When the agent runs:

grep -rl 'TODO' src/ | xargs sed --in-place 's/TODO/DONE/g'

The prompt looks like:

⚠️ Unapproved Commands

✔ grep -rl 'TODO' src/ |
✔ xargs ...
✖ sed --in-place s/TODO/DONE/g

→ Allow
  Always allow sed (this session)
  Reject

Or with find -exec:

find src/ -name '*.test.ts' -exec rm {} \;

The prompt looks like:

⚠️ Unapproved Commands

✔ find src/ -name *.test.ts -exec ...
✖ rm {}

→ Allow
  Always allow rm (this session)
  Reject

For file operations, there's no command to parse — the prompt shows the path being accessed:

⚠️ Write Permission Required

src/lib/config.ts

→ Allow
  Always allow write (this session)
  Reject

For custom tools, the prompt shows the matched parameter value:

⚠️ web_fetch Permission Required

https://api.github.com/repos/jdiamond/pi-guard/issues

→ Allow
  Always allow web_fetch (this session)
  Reject

In non-interactive mode (e.g., CI), unauthorized commands are silently blocked without a prompt.

Install

pi install npm:pi-guard

Configuration

Configure in ~/.pi/agent/settings.json or .pi/settings.json (project-level):

{
  "guard": {
    "enabled": true,
    "matchers": {
      "spawn": { "param": "agent", "type": "exact" },
      "webfetch": { "param": "url", "type": "glob" }
    },
    "rules": {
      "*": "ask",
      "bash": {
        "*": "ask",
        "git status": "allow",
        "git log": "allow",
        "rm": "deny"
      },
      "read": {
        "*": "allow",
        "**/*.env": "deny",
        "**/*.pem": "deny"
      },
      "write": { "*": "ask" },
      "edit": { "*": "ask" },
      "spawn": {
        "build": "allow",
        "test": "allow",
        "*": "deny"
      },
      "webfetch": {
        "*": "ask",
        "https://github.com/*": "allow"
      }
    }
  }
}

Shorthand

Disable all checks:

{ "guard": { "enabled": false } }

Whole-tool action (no pattern matching needed):

{ "guard": { "rules": { "write": "allow" } } }

Environment variable

Set PI_GUARD to inject rules from outside (e.g., by pi-spawn or CI/CD):

PI_GUARD='{"*":"deny","bash":{"git diff":"allow"}}'

Matchers

Matchers define how to extract and match input from a tool call. Each matcher has a param (which tool parameter to extract) and a type (how to match).

Type Description Use case
bash Parse command, extract all commands, subsequence match Bash commands
glob * and ** matching (paths, URLs) File paths, URLs
exact String equality Enum values, agent names

Tools without a matcher get simple allow/ask/deny for the whole tool.

Bash matching

  1. Parse the command with the unbash AST parser
  2. Extract all commands from the AST (handles pipes, subshells, command substitutions, process substitutions, heredocs, if/while/for/case, functions)
  3. Expand wrapper commands (xargs rmxargs + rm, sudo rmsudo + rm, bash -c 'rm -rf /'bash -c + rm, find -exec rm {} \;find -exec + rm)
  4. For each command, check rules using subsequence matching — rule tokens must appear in order, extra arguments are allowed

[!TIP] "git log" matches git log, git log --oneline, and git log --oneline -10. This means you can allow a command without enumerating every flag combination.

Wildcard tokens in bash rules

Tokens containing * or ? are matched as globs against the corresponding command argument:

"sed": "allow",
"sed -i*": "ask",
"sed --in-place*": "ask"
Command Result Reason
sed -E 's/old/new/' allow sed rule, no -i flag
sed -i 's/old/new/' ask -i matches glob -i*
sed -i.bak 's/old/new/' ask -i.bak matches glob -i*

This only applies to */? inside rule tokens. The bare "*" key is the catch-all for any command (see Rule precedence).

Glob matching

Standard glob patterns:

  • * matches anything except /
  • ** matches anything including /
  • ? matches a single character
  • ~ expands to home directory

Exact matching

Simple string equality. Rule "build" only matches input build.

Actions

Each permission rule resolves to one of:

Action Behavior
allow Run without approval
ask Prompt for approval (block in non-interactive mode)
deny Block the action

Rule precedence

default → user config → project config → env (PI_GUARD) → profile → session rules

Last match wins within a tool's rules. Put the catch-all "*" first, specific rules after:

"bash": {
  "*": "ask",
  "git status": "allow",
  "git log": "allow",
  "rm": "deny"
}

Default rules

See src/defaults.ts for the built-in defaults.

The defaults follow a simple principle: reading is safe, writing is dangerous. Read-only bash commands (ls, cat, git log, grep, etc.) are allowed, while anything that modifies state asks for approval. Note that sed is allowed by default, but sed -i* (in-place edit) is set to ask since it modifies files. File reads are mostly allowed except for sensitive patterns (*.env, *.pem). All edits and writes require approval.

[!TIP] To trust the agent with file modifications (useful in containers or trusted environments):

{
  "guard": {
    "rules": { "edit": "allow", "write": "allow" }
  }
}

Profiles

Profiles let you define named rule overlays and switch between them during a session. Only one profile can be active at a time.

{
  "guard": {
    "profiles": {
      "read-write": {
        "edit": { "*": "allow" },
        "write": { "*": "allow" }
      }
    }
  }
}

Activate with /guard profile read-write, deactivate with /guard profile off.

[!WARNING] Profiles are layered between env and session rules. A profile with "*": "allow" will override specific rules from earlier layers (like "rm": "deny") because "*" always matches last and wins.

Shortcuts

Define custom slash commands for quick access to guard actions:

{
  "guard": {
    "profiles": {
      "read-write": {
        "edit": { "*": "allow" },
        "write": { "*": "allow" }
      }
    },
    "shortcuts": {
      "rw": "profile read-write",
      "ro": "profile off",
      "yolo": "disable",
      "safe": "enable"
    }
  }
}

Now /rw activates the read-write profile, /ro deactivates it, and /yolo//safe quickly toggle the guard.

Shortcuts can reference any guard subcommand: profile, list, toggle, enable, or disable.

Commands

Command Description
/guard enable Enable guard
/guard disable Disable guard
/guard toggle Toggle guard on/off
/guard list Show current rules by provenance layer
/guard profile Show active profile and available profiles
/guard profile <name> Activate a profile
/guard profile off Deactivate current profile