extensions/ext-toggle.ts: /ext lists ~/.pi/agent/extensions/ with active/disabled markers and toggles individual extensions by renaming between name.ts and name.ts.off (pi only auto-discovers *.ts). Calls ctx.reload() so the change takes effect without restarting pi. Subdirectory-style extensions (name/index.ts) are listed read-only in v1 — toggling a directory cleanly is more work than the rename trick is worth. install.sh: --uninstall now matches both *.ts and *.ts.off symlinks pointing into this repo, so a disabled extension is still cleaned up. README.md / AGENTS.md: Document ext-toggle alongside the others; AGENTS notes the API surface used (registerCommand, ui.select/confirm/notify, reload) and the rename-not-delete design decision.
8.9 KiB
pi-extensions
Custom and modified extensions for the pi coding-agent.
This repo is the single source of truth for extensions that aren't suitable for general publishing — personal workflow tweaks, modified versions of built-in examples, and extensions written for specific infrastructure. Symlinked into ~/.pi/agent/extensions/ so pi loads them automatically.
Part of the same family as pi-toolkit (bring-up) and skillset (agent skills).
Install
git clone ssh://git@gitea.jordbo.se:2222/joakimp/pi-extensions.git ~/src/src_local/pi-extensions
cd ~/src/src_local/pi-extensions
chmod +x install.sh
./install.sh
Each .ts file in extensions/ is symlinked into ~/.pi/agent/extensions/. Existing real files are backed up with a timestamp. Re-runs are idempotent.
Install a subset:
./install.sh --only ssh-controlmaster # just this one
./install.sh --only "ssh-controlmaster,other" # explicit list
./install.sh --skip "git-checkpoint" # all except these
--only and --skip accept comma-separated names without the .ts suffix. --only takes precedence if both are given.
Alternative: pi install (local path)
Because package.json declares a pi manifest, you can also register this repo as a pi package:
pi install ~/src/src_local/pi-extensions
This makes pi manage the extension loading directly. The install.sh approach (symlinks) and pi install are mutually exclusive for the same extension — pick one per machine.
Uninstall
./install.sh --uninstall
Removes symlinks that point into this repo. Your own files in ~/.pi/agent/extensions/ are never touched.
Extensions
ssh-controlmaster.ts
Transparent SSH remote execution via a persistent ControlMaster socket.
When launched with --ssh user@host, all of pi's native file and shell tools
(read, write, edit, bash) are transparently redirected to execute on
the remote machine. One SSH connection is established at session start; all
subsequent tool calls multiplex over it via a Unix socket. Much faster than
the plain ssh.ts example which opens a new connection per tool call.
Use cases:
- Diagnose and fix issues on a remote server without installing pi there
- Work on Proxmox hosts, LXC containers, or ephemeral VMs
- Any machine you have SSH key access to but don't own
Usage:
# Key-based auth (normal)
pi --ssh user@192.168.1.10
# Explicit remote path (skips the initial pwd call)
pi --ssh root@proxmox-node:/etc/pve
# Password auth — prompts before connecting
pi --ssh user@host --ssh-ask-pass
# Try without modifying your global install
pi -e ~/src/src_local/pi-extensions/extensions/ssh-controlmaster.ts --ssh user@host
Requirements:
- SSH key-based auth (preferred), or password auth via
--ssh-ask-pass(see below) bashavailable on the remote
Note on
--ssh-ask-pass: The password is prompted via pi's input dialog before the SSH connection is opened. Input is not masked — the password is visible while typing. It is passed to SSH via a temporarySSH_ASKPASSscript (/tmp/pi-askpass-<pid>.sh,chmod 700) which is deleted immediately after the master is established.
How it works:
- On
session_start, runsssh -G <host>to read the effective config for that host - If
~/.ssh/configalready configuresControlMaster autooryesfor the host, the existing system socket is reused — no second connection is opened and pi does not tear down the master on exit (it was the system's to manage) - Otherwise pi establishes its own master:
ssh -fN -o ControlMaster=yes -o ControlPersist=yes -o ControlPath=/tmp/pi-cm-<pid>.sock <remote>and shuts it down cleanly on exit - All tool calls multiplex over the socket with
-o ControlMaster=no -o ControlPath=<socket>— near-zero per-call overhead - The system prompt is patched to tell the LLM it's operating on
<remoteCwd> (via SSH ControlMaster: <remote>) - User
!shell commands are also routed over SSH
The status bar shows ⚡ own master or ⚡ system master so you can see which path was taken.
Status bar: Shows SSH ⚡ user@host:/path when the master is ready, ⟳ connecting… during setup, and an error state if the master fails to start.
Path mapping: Paths are rewritten by replacing the local cwd with the remote cwd. This means pi should be started from a directory that maps cleanly to a path on the remote. Use the user@host:/explicit/path form when the remote path differs significantly from your local working directory.
confirm-destructive.ts
Confirmation gates for dangerous bash commands and destructive session actions. Always-on — no flag needed.
Bash commands intercepted:
- Recursive removes (
rm -rf,rm -r, etc.) - Any
sudocommand chmod/chown 777dd if=(disk operations)mkfs(format filesystem)git push --force/git push -f- Writes to
/dev/* truncate --size 0
In non-interactive mode (e.g. pi -p) dangerous commands are blocked outright rather than prompted.
Session actions gated:
/new— confirms before clearing the session/resume— confirms before switching away if the current session has messages/fork— always confirms
git-checkpoint.ts
Creates a git stash checkpoint at the start of each turn, keyed to the session entry ID. If you /fork from a past entry, you're offered the option to restore the code to that point.
Silently skips when the working directory isn't inside a git repo, or when there are no changes to stash. Status bar shows ⎇ N checkpoints during active sessions.
Notes:
- Uses
git stash create— non-destructive, doesn't touch your working tree - Stash objects persist in the git repo even after pi exits, so you can apply them manually with
git stash apply <ref>if needed - Checkpoints are in-memory per session — the entry→ref mapping is lost on restart, but the underlying stash objects remain
notify.ts
Sends a native terminal notification when the agent finishes and is waiting for input. Only fires when the agent ran for longer than the threshold (default 8 seconds) — quick responses are silently skipped.
Terminal support:
- Kitty (
KITTY_WINDOW_ID) → OSC 99 - Windows Terminal / WSL (
WT_SESSION) → Windows toast - Everything else (iTerm2, WezTerm, Ghostty) → OSC 777
Flag:
pi --notify-min-secs 15 # only notify for tasks over 15 seconds
pi --notify-min-secs 0 # notify on every agent completion
ext-toggle.ts
Registers /ext — a slash command that lists extensions in ~/.pi/agent/extensions/ and toggles individual ones on/off without leaving the TUI.
How it works: pi auto-discovers *.ts only. Toggling renames a file (or symlink) between name.ts and name.ts.off, so a disabled extension is invisible to the loader. After a toggle, the extension calls ctx.reload() so the change takes effect immediately — no restart needed.
Usage:
/ext # opens a picker; ● = active, ○ = disabled
Notes:
- Subdirectory-style extensions (
name/index.ts) are listed read-only — v1 doesn't toggle them. Move the directory aside manually if needed. install.sh --uninstallcleans up both.tsand.ts.offsymlinks pointing into this repo, so a disabled extension won't be left behind.
Adding a new extension
- Drop a
.tsfile intoextensions/ - Re-run
./install.sh— it picks up the new file and symlinks it - In a running pi session,
/reloadis enough; no restart needed - (or, with
ext-toggleinstalled:/extto disable noisy ones at runtime)
Each extension is a TypeScript module loaded by jiti — no compilation step. See the pi extensions docs and the built-in examples for the API surface.
Deploying on a new machine
# 1. Prerequisites: pi installed, SSH key auth working
pi --help # creates ~/.pi/agent/ on first run
# 2. Clone and install
git clone ssh://git@gitea.jordbo.se:2222/joakimp/pi-extensions.git ~/src/src_local/pi-extensions
cd ~/src/src_local/pi-extensions && ./install.sh
# 3. Verify
ls -la ~/.pi/agent/extensions/ # should show symlinks into this repo
Related repos
pi-toolkit— pi bring-up: settings template, keybindings, shell env loadermempalace-toolkit— persistent memory layer for pi via MemPalace MCPskillset— agent skills for pi, opencode, and Claude
License
MIT — see LICENSE.