ACP wrapper for the Pi coding agent (mirrors @agentclientprotocol/claude-agent-acp pattern)
  • TypeScript 91.2%
  • JavaScript 8.8%
Find a file
roxy a5e1021bc4
All checks were successful
CI / build (push) Successful in 30s
feat: initial ACP wrapper for the Pi coding agent
Mirrors the @agentclientprotocol/claude-agent-acp pattern: one process
per ACP session, each spawning `pi --mode rpc` and translating frames
between ACP (JSON-RPC 2.0) and Pi's bare-JSON RPC.

What's wired:
- ACP initialize/newSession/prompt/cancel/setSessionModel
- Pi message_update (text + thinking) → agent_message_chunk / agent_thought_chunk
- Pi tool_execution_* → tool_call / tool_call_update
- ACP cancel → Pi abort; stopReason derived from Pi's done/error reason
- Prompt content blocks flattened to Pi's {message, images?} shape

What's not (yet):
- session/request_permission round-trips (Pi is auto-approve for now)
- loadSession (capability advertised false)
- extension UI dialogs surfaced through ACP
2026-05-20 17:16:19 -04:00
.forgejo/workflows feat: initial ACP wrapper for the Pi coding agent 2026-05-20 17:16:19 -04:00
src feat: initial ACP wrapper for the Pi coding agent 2026-05-20 17:16:19 -04:00
.gitignore feat: initial ACP wrapper for the Pi coding agent 2026-05-20 17:16:19 -04:00
package-lock.json feat: initial ACP wrapper for the Pi coding agent 2026-05-20 17:16:19 -04:00
package.json feat: initial ACP wrapper for the Pi coding agent 2026-05-20 17:16:19 -04:00
README.md feat: initial ACP wrapper for the Pi coding agent 2026-05-20 17:16:19 -04:00
tsconfig.json feat: initial ACP wrapper for the Pi coding agent 2026-05-20 17:16:19 -04:00

pi-agent-acp

Agent Client Protocol wrapper for the Pi coding agent. Speaks ACP on its stdio, spawns pi --mode rpc per session, translates between the two.

Mirrors the shape of @agentclientprotocol/claude-agent-acp and @zed-industries/codex-acp.

Usage

# inside a container or environment with `pi` on PATH:
pi-agent-acp [--pi-binary /path/to/pi] [--provider anthropic] [--model claude-sonnet-4-20250514]

The wrapper is a one-process-per-session bridge:

ACP client (Zed / OpenClaw acpx)
    │   ACP / JSON-RPC 2.0 over stdio
    ▼
pi-agent-acp
    │   Pi RPC (JSONL over stdio)
    ▼
pi --mode rpc

Mapping

ACP Pi RPC
initialize (no-op; advertise capabilities)
session/new spawn pi --mode rpc
session/prompt prompt
session/cancel abort
agent_message_chunk update message_update with text_delta
agent_thought_chunk update message_update with thinking_delta
tool_call / tool_call_update tool_execution_*
stopReason: "end_turn" done.reason = "stop"
stopReason: "cancelled" error.reason = "aborted"

Status

Experimental — first cut. Things that intentionally aren't wired up yet:

  • ACP session/request_permission callbacks (Pi handles permissions internally via its approval modes; we run Pi in auto-approve and never ask the ACP client to confirm tool calls).
  • loadSession (the loadSession capability is advertised as false).
  • ACP audio / embedded-context content blocks.
  • Surfacing Pi extension_ui_request dialogs back through ACP — they're currently logged and silently auto-resolved by Pi's defaults.

Layout

src/
├── lib.ts             public exports
├── cli.ts             bin entry — wires stdio to AgentSideConnection
├── acp-agent.ts       implements ACP `Agent`, one PiRpcClient per session
├── pi-rpc-client.ts   LF-framed JSONL client for `pi --mode rpc`
└── translate.ts       pure event → ACP update mapping