Skip to main content
Glama
README.md
# pi-subagent-mcp

MCP server that exposes [pi](https://github.com/earendil-works/pi) (`pi --mode rpc`)
as a sub-agent for MCP-capable coding assistants (e.g. Kimi CLI).

## Build

    npm install
    npm run build

## Tools

| Tool | Purpose |
|---|---|
| `pi_dispatch` | Spawn a pi session on a task (`task`, `cwd`, `model?`, `name?`, `interactive?`, `approve?`) → `{taskId}` |
| `pi_send` | Message a task (`mode`: `auto`/`prompt`/`steer`/`followUp`) |
| `pi_status` | State, streaming flag, last assistant text, current tool, `pendingRequest` |
| `pi_read` | Incremental event buffer read (`since` seq) |
| `pi_wait` | Block until the run finishes or a dialog needs answering; returns last assistant text + progress snapshot (`isStreaming`/`eventCount`/`currentTool`) + `pendingRequest`. Timeout is a checkpoint, not a failure — no server-side max, use a large `timeoutMs` for long tasks (see [async-wait model](docs/design/async-wait-model.md)) |
| `pi_respond` | Answer a `pendingRequest` dialog (`value` / `confirmed` / `cancelled`) |
| `pi_abort` | Abort current operation; session stays alive |
| `pi_close` | Kill the process, drop the task |
| `pi_list` | All tasks |
| `pi_bridges` | List pi sessions running elsewhere (e.g. in a terminal) that have the bridge extension and can be attached |
| `pi_attach` | Attach to a bridge session (`sessionId` or `socketPath`) → `taskId`; all task tools then work on it |
| `pi_detach` | Disconnect an attached task; the pi session stays alive |
| `pi_notify` | Push text onto an attached pi's TUI console (`level`: `info`/`warning`/`error`) |

## Extension UI dialogs (bidirectional interaction)

pi extensions can block on `select`/`confirm`/`input`/`editor` dialogs
(`extension_ui_request`). By default (`interactive: true`) the server surfaces these as
`pendingRequest` in `pi_status`/`pi_wait` — which returns early — and the caller answers
with `pi_respond`. With `interactive: false` (unattended runs) dialogs are auto-cancelled,
preserving the original behavior.

Note: project-local pi extensions (`.pi/extensions/`) only load when the project is
trusted — pass `approve: true` to `pi_dispatch` to grant that for the run. Also, pi
delays the command response for extension commands that block on a dialog; the server
therefore treats dialog activity as command acceptance so `pi_dispatch`/`pi_send`
return instead of deadlocking.

## Attaching to terminal pi sessions (bridge)

pi's RPC mode is stdio-only, so a pi already running in your terminal cannot be
attached retroactively. The bridge extension solves this: installed once, every pi
session started **afterwards** (interactive TUI included) exposes a Unix socket at
`~/.pi/bridge/<sessionId>.sock` that this server can attach to.

Install (user scope, loads in every pi session):

    pi install /absolute/path/to/extensions/bridge.ts

Then from any MCP client:

    pi_bridges                    → discover running sessions
    pi_attach { sessionId }       → get a taskId; pi_send / pi_wait / pi_read /
                                    pi_status / pi_abort work as usual
    pi_notify { taskId, message } → text appears on that pi's TUI console
    pi_detach { taskId }          → disconnect; the terminal session stays alive

Limitations: sessions started before the install can never be attached; attached
sessions answer their own extension dialogs in their terminal (no `pendingRequest`);
session replacement (`/new`, `/resume`) ends the attachment (re-attach via
`pi_bridges`); Unix sockets only (no Windows named pipes). See
[docs/design/terminal-bridge.md](docs/design/terminal-bridge.md).

## Configuration

Environment variables:

- `PI_SUBAGENT_SESSION_DIR` — where pi session files are stored
  (default: `.pi-subagent/sessions/` next to the package).
- `PI_SUBAGENT_PI_PATH` — override the pi binary path (default: `pi`).

MCP registration (example): point your client at `node /path/to/dist/src/server.js`.

## Test

    npm test   # unit + smoke + (if pi is installed and logged in) integration

Additional end-to-end scripts in `scripts/` (`acceptance-test.mjs`,
`mcp-e2e-test.mjs`, `dialog-e2e-test.mjs`, `bridge-e2e-test.mjs`). Issues found during development are
logged in [docs/issues/](docs/issues/README.md); design notes in
[docs/design/](docs/design/async-wait-model.md).

TDQS

A4.1/5.0

Scored across 9 tools

Disambiguation5/5

pi_status, pi_read, and pi_wait all concern state but are clearly differentiated as snapshot, event stream, and blocking wait respectively. pi_dispatch and pi_send are also distinct (create new vs. message existing). No two tools appear to do the same thing.

Naming Consistency5/5

All nine tools are prefixed with pi_ and use lowercase imperative-style names (dispatch, send, read, wait, respond, abort, close, list). The only mild outlier is pi_status, which uses a noun rather than a verb, but it still fits the established pattern and creates no confusion.

Tool Count5/5

With nine tools, the server is in the ideal range for its purpose. Each tool addresses a specific aspect of the subagent lifecycle without redundancy or bloat.

Completeness5/5

The set covers the full workflow: dispatch to create, send to communicate, status/read/wait to observe, respond to handle dialogs, abort to interrupt, close to clean up, and list to enumerate. There are no missing operations that would trap an agent mid-workflow.

Maintenance

ActivityMaintained
ResponsivenessNo issues