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-guard

v1.4.0

Published

General-purpose permission system for pi tools, handling permissions for bash and file tools with extensible matchers for custom tools.

Downloads

240

Readme

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 |