Below is a concrete implementation spec for the **Pi (pi-coding-agent CLI)** runner shipped in Takopi (v0.5.0). --- ## Scope ### Goal Provide the **`pi`** engine backend so Takopi can: * Run Pi non-interactively via the **pi CLI** (`pi --print`). * Stream progress by parsing **`--mode json`** (newline-delimited JSON). Each line is a JSON object. * Support resumable sessions via **`--session `** (Takopi emits a canonical resume line the user can reply with). ### Non-goals (v1) * Interactive TUI flows (session picker, prompts, etc.) * RPC mode (requires a long-running process and JSON commands) --- ## UX and behavior ### Engine selection * Default: `takopi` (auto-router uses `default_engine` from config) * Override: `takopi pi` ### Resume UX (canonical line) Takopi appends a **single backticked** resume line at the end of the message, like: ```text `pi --session /home/user/.pi/agent/sessions/--repo--/2026-01-02T12-34-56-789Z_abcd.jsonl` ``` Notes: * `pi --resume/-r` opens an interactive session picker, so Takopi uses `--session ` instead. * The resume token is the **session file path** (JSONL), treated as an opaque string. * If the path contains spaces, the runner will quote it. ### Non-interactive runs Use `--print` and `--mode json` for headless JSONL output. Pi does not accept `-- ` to protect prompts starting with `-`. Takopi prefixes a leading space if the prompt begins with `-` so it is not parsed as a flag. --- ## Config additions Takopi config lives at `~/.takopi/takopi.toml`. Add a new optional `[pi]` section. Recommended v1 schema: ```toml # ~/.takopi/takopi.toml default_engine = "pi" [pi] cmd = "pi" # optional; defaults to "pi" extra_args = [] # optional list of strings, appended verbatim model = "..." # optional; passed as --model provider = "..." # optional; passed as --provider session_dir = "..." # optional; directory for session files session_title = "pi" # optional; defaults to model or "pi" ``` Notes: * `extra_args` lets you pass new Pi flags without changing Takopi. * If `session_dir` is omitted, Takopi uses Pi's default session dir: `~/.pi/agent/sessions/----` (with path separators replaced by `-`). --- ## Code changes (by file) ### 1) New file: `src/takopi/runners/pi.py` Expose a module-level `BACKEND = EngineBackend(...)`. #### Runner invocation The runner should launch Pi in headless JSON mode: ```text pi --print --mode json --session ``` When resuming, `` is the resume token extracted from the chat. #### Event translation Pi JSONL output is `AgentSessionEvent` (from `@mariozechner/pi-agent-core`). The runner should translate: * `tool_execution_start` -> `action` (phase: started) * `tool_execution_end` -> `action` (phase: completed) * `agent_end` -> `completed` For the final answer, use the most recent assistant message text (from `message_end` events). For errors, if the assistant stopReason is `error` or `aborted`, emit `completed(ok=false, error=...)`. --- ## Installation and auth Install the CLI globally: ```text npm install -g @mariozechner/pi-coding-agent ``` Auth is stored under `~/.pi/agent/auth.json`. Run `pi` once interactively to set up credentials before using Takopi. --- ## Known pitfalls * `--resume` is interactive; Takopi uses `--session ` instead. * Prompts that start with `-` are interpreted as flags by the CLI. Takopi prefixes a space to make them safe. --- If you want, I can also add a sample `takopi.toml` snippet to the README or include a small quickstart section for Pi in the onboarding panel.