Pi coding agent

Human-in-the-loop for pi, in one command.

Pi is a terminal coding agent. It has no built-in MCP support, so ping-a-human-pi ships a tiny embedded MCP client that connects ping-a-human to pi's hooks.

Install

npx ping-a-human-pi

This single command:

  • installs a pi extension into ~/.pi/agent/extensions/ping-a-human-pi/,
  • installs the pah CLI onto your PATH,
  • seeds ~/.pi/agent/ping-a-human.json with defaults (never overwrites an existing one).

Run /reload in pi (or restart it). Remove everything with npx ping-a-human-pi uninstall.

First time with ping-a-human? Configure Telegram once with npx ping-a-human setup.

What you get

  • Toolsnotify_human and ask_human become native pi tools the model can call.
  • Notifications — a Telegram ping with a short summary when each task finishes (pi's agent_end hook).
  • Approval — before risky tool calls (pi's tool_call hook), pi asks via ask_human and blocks unless you approve. Off by default.
  • /ping command — inside pi: /ping or /ping your message.
  • pah CLI — from any terminal, independent of pi.

The pah CLI

pah ping "build finished"      # fire-and-forget notification
pah notify "deploy started"    # alias for ping
pah ask "ship to prod?"        # waits and prints the human's reply
pah help

Because pah ask prints the reply to stdout, you can branch on it in scripts:

if pah ask "deploy to prod?" | grep -qiE '^(y|yes|ok|approve)'; then
  ./deploy.sh
fi

Configuration

All optional — edit ~/.pi/agent/ping-a-human.json:

KeyDefaultMeaning
command / argsnpx -y ping-a-humanhow to launch the server
exposeToolstrueregister notify_human / ask_human as model-callable tools
notify.enabledtrueping you when a task finishes
notify.template✅ pi finished a task in {cwd}…message text; {summary} {cwd} substituted
approval.enabledfalseask before risky tool calls
approval.tools["bash"]which pi tools to gate
approval.patternsdanger regexesonly gate calls whose args match one; empty = gate all

A reply matching yes/ok/approve/allow/sure/go/lgtm/… approves; anything else blocks the call, and the reason is sent back to the model.