# PRD 0058: Add built-in Pi agent provider - **Status:** Active - **Author:** codex - **Created:** 2026-06-09 - **Issue:** #221 ## Summary Add `pi` as a built-in `agent_provider.template`. The provider runs the Pi coding-agent CLI, provisions its agent config under `~/.pi/agent`, and writes a provider settings file that targets an unauthenticated Ollama-compatible server. The default settings assume an Ollama server at `http://ollama:11434/v1`, using the `openai-completions` API with a dummy API key because Ollama ignores it. Users can override the provider id, base URL, model list, API key, API-key env reference, API type, and compatibility flags through a new `agent_provider.settings` object. ## Problem bot-bottle currently ships Claude and Codex as built-in agent providers. Pi is a useful third harness, but using it today requires a custom provider plugin and a custom image. That repeats boilerplate for prompt copying, skill copying, provider config, and runtime registration. Pi's local-model path is also easy to misconfigure: its custom-model docs require `~/.pi/agent/models.json`, an API entry, at least one model id, and a dummy `apiKey` for Ollama even though the server does not authenticate. bot-bottle should generate that shape consistently. ## Goals / Success Criteria - `agent_provider.template: pi` is accepted as a built-in provider. - `bot_bottle/contrib/pi/` provides a Pi image and `PiAgentProvider`. - Pi receives the bot-bottle prompt at `~/.bot-bottle-prompt.txt` and starts in print-mode prompt delivery like Codex. - Pi skills are copied into `~/.pi/agent/skills//`. - Pi provider settings are configurable from the bottle manifest via `agent_provider.settings`. - The default Pi provider settings configure an unauthenticated Ollama-compatible server. - Unit tests cover manifest parsing, runtime selection, plan generation, prompt, skills, and provider provisioning. ## Non-goals - Managing or launching an Ollama server. - Authenticating to Ollama or any remote Pi provider. - Forwarding host Pi credentials. - Implementing Pi extensions or MCP registration. - Changing Claude or Codex provider behavior. ## Design ### Manifest Extend `agent_provider` with an optional `settings` object. It is currently only supported for built-in `pi`. Supported keys: - `base_url`: string, defaults to `http://ollama:11434/v1` - `provider`: string, defaults to `ollama` - `api`: string, defaults to `openai-completions` - `api_key`: string, defaults to `ollama` - `api_key_env`: string, optional host env var name for egress auth injection - `models`: non-empty array of strings, defaults to `["qwen2.5-coder:7b"]` - `supports_developer_role`: boolean, defaults to `false` - `supports_reasoning_effort`: boolean, defaults to `false` The snake-case manifest keys are converted into Pi's JSON field names: `baseUrl`, `apiKey`, `supportsDeveloperRole`, and `supportsReasoningEffort`. `api_key` and `api_key_env` are mutually exclusive. When targeting a hosted provider through bot-bottle's egress sidecar, omit `api_key` and set `api_key_env` to the host env var that holds the API key. The generated `models.json` receives only an `egress-placeholder` API key, and the egress route injects the real `Authorization` header from the sidecar env. For example, OpenRouter can use provider id `openrouter` with `api_key_env: OPENROUTER_API_KEY`, keeping the key out of the agent env and `models.json`. ### Provider `PiAgentProvider.provision_plan` writes `models.json` into the per-launch state directory and returns an `AgentProvisionPlan` that copies it to `~/.pi/agent/models.json`. The provider also declares an unauthenticated egress route for the configured base URL host so the egress layer can allow the Ollama endpoint. The Pi runtime uses: - `command="pi"` - `prompt_mode="append_system_prompt"` - `image="bot-bottle-pi:latest"` - `bypass_args=()` - `resume_args=()` - `remote_control_args=()` The Dockerfile installs `@earendil-works/pi-coding-agent` globally from npm and keeps the same Debian/node base shape as the existing provider images. ### Supervise MCP Pi does not have built-in MCP support in the current public docs, so `provision_supervise_mcp` is a no-op. This keeps Pi bottles launchable with `supervise: true` while preserving the explicit non-goal of implementing Pi extensions. ## Merge rule(s) This PR can merge when the focused unit tests pass and the PRD status is flipped from Draft to Active in the final implementation commit.