Pi Extensions
Pi coding agent extensions: security-guard, macos-notify, github-prs, and save
#pi-extensions
Pi coding agent extensions.
| Extension | Description |
|---|---|
| github-prs | Shows your open GitHub PRs with reviewer approval status via /prs. (source) |
| macos-notify | Sends a native macOS notification when the agent finishes working. Shows elapsed time and tab info (Ghostty, iTerm2, Terminal.app), and flags the tab with an attention cue that clears when you return. (source) |
| save | Saves the last assistant message as markdown to a file via /save [filepath]. Auto-generates a filename from context if none is given. (source) |
| security-guard | Blocks or prompts on dangerous bash commands, sensitive file writes, and sensitive file reads. Configurable via a TOML file. (source) |
#Install All Extensions
pi install git:github.com/joeygibson/pi-extensions
#Install Selectively
To install only one extension, add to your ~/.pi/agent/settings.json
(or .pi/settings.json for project-local):
{ "packages": [ { "source": "git:github.com/joeygibson/pi-extensions", "extensions": ["extensions/security-guard.ts"] } ] }
Or just the notification extension:
{ "packages": [ { "source": "git:github.com/joeygibson/pi-extensions", "extensions": ["extensions/macos-notify.ts"] } ] }
Or just the GitHub PRs extension:
{ "packages": [ { "source": "git:github.com/joeygibson/pi-extensions", "extensions": ["extensions/github-prs.ts"] } ] }
Or just the save extension:
{ "packages": [ { "source": "git:github.com/joeygibson/pi-extensions", "extensions": ["extensions/save.ts"] } ] }
#Extension Details
#github-prs
Registers a /prs command that fetches your open pull requests from GitHub and
displays them in a box-drawn table with ANSI colors. Each PR shows its number
(as a clickable hyperlink in supported terminals), title, and the approval
status of every reviewer.
Reviewer statuses:
- ✔ (green) — Approved
- ✘ (red) — Changes requested
- ● (yellow) — Commented
- ○ (gray) — Dismissed
- ◌ (dim) — Pending (requested but hasn't reviewed yet)
The extension uses gh pr list --author @me under the hood, so it
automatically shows PRs for whoever is authenticated with the GitHub CLI. No
repo-specific configuration is needed.
Prerequisites:
- GitHub CLI (
gh) installed and on yourPATH - Authenticated via
gh auth login
#security-guard
Intercepts tool_call events and checks bash commands, file writes, and file
reads against a set of rules. Each rule specifies a substring pattern and an
action (prompt, block, or allow). When multiple rules match, the most
specific (longest pattern) wins — so you can create narrow allow exceptions
to broader block rules.
Configuration: On first load, an example config is written to
~/.pi/agent/security-guard.toml.example. Copy it to
~/.pi/agent/security-guard.toml and customize:
[operations] rm -rf = prompt sudo = prompt dd if= = block > /dev/ = block > /dev/null = allow [writes] .env = block ~/.ssh = block [reads] ~/.ssh = block ~/.aws/credentials = prompt
Without a config file, sensible defaults are used. Rules are reloaded on
/reload.
Prompt highlighting: When a command or path triggers a prompt, the
offending command segment is highlighted in red and wrapped in »…« markers
— from the trigger through its arguments — so dangerous operations like a
nested rm -rf are easy to spot. Highlighting stops at shell separators
(&&, ||, |, ;, newline), so neighboring commands stay uncolored.
Approval notifications: When a rule triggers a prompt, pi blocks and
waits for your answer — which is easy to miss if you've stepped away. To catch
your attention, security-guard fires a native macOS notification titled
“pi — approval needed” (with the Submarine sound) the moment the prompt
appears, and re-fires it every 30 seconds until you respond. This is distinct
from the one-shot “Done” toast that macos-notify shows on
completion, so you can tell “pi finished” apart from “pi needs me.” The
notification reuses the same PiNotify.app bundle as macos-notify; if that app
isn't available the prompt still works, just without the toast. The sound and
interval are constants (APPROVAL_SOUND, NUDGE_INTERVAL_MS) at the top of
extensions/security-guard.ts.
#save
Registers a /save command that writes the last assistant message as markdown
to a file. Accepts an optional filepath argument:
/save— auto-generates a filename from the content (e.g.your-content-slug-202605261507.md)/save notes/design— writes tonotes/design.md(.mdadded if no extension is present)/save output.txt— writes tooutput.txtas-is
Runs entirely client-side — no LLM round-trip. Creates parent directories automatically if they don't exist.
#macos-notify
Sends a native macOS notification (with pi's icon) when the agent has been
working for 3+ seconds and finishes. Includes tab name and number if
available. Supports Ghostty, iTerm2, and Terminal.app — the
terminal is detected automatically via TERM_PROGRAM. For unknown terminals,
all three are tried in sequence.
This extension requires a small native macOS app bundle (PiNotify.app) to
deliver notifications. Using an .app bundle — rather than bare osascript —
is what lets macOS show pi's icon in Notification Center. The app is a ~100KB
Swift binary that runs display notification via NSAppleScript, then exits. It
never appears in the Dock (LSUIElement).
A pre-built universal binary (arm64 + x86_64) is checked into the repo
under macos-notify-app/, so pi install works with no
extra steps. The full source (PiNotify.swift) and build script are in the
same directory. If the binary is missing for any reason, the extension
automatically rebuilds it from source on first load (requires Xcode Command
Line Tools). You can also rebuild manually:
cd macos-notify-app
./build.sh
See macos-notify-app/README.md for details.
Tab attention cue: When the notification fires, the extension also flags the tab so you can spot it at a glance:
- iTerm2 — tints the tab title bar (orange) via an OSC 6 escape sequence.
- Ghostty — prepends a green dot (🟢) to the tab title via OSC 0, since Ghostty has no tab-color API.
- Terminal.app / others — no cue (Terminal.app can only tint the entire background, which is too intrusive).
The cue is cleared automatically when you return to the tab and submit your next
prompt, or when you quit / /reload / switch sessions.
The cue is automatically suppressed when pi is running inside a herdr pane
(detected via the HERDR_* env vars), since herdr already indicates which
agent needs attention.