124 lines
4.9 KiB
Markdown
124 lines
4.9 KiB
Markdown
# 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/<name>/`.
|
|
- 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"]`
|
|
- `context_window`: positive integer, defaults to `4096`; this is the Ollama
|
|
runtime context, and bot-bottle subtracts `max_tokens` before writing Pi's
|
|
`contextWindow` so output space is reserved
|
|
- `max_tokens`: positive integer, defaults to `1024`
|
|
- `max_tokens_field`: `max_tokens` or `max_completion_tokens`, defaults to
|
|
`max_tokens`
|
|
- `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`, `contextWindow`, `maxTokens`,
|
|
`supportsDeveloperRole`, and `supportsReasoningEffort`. `context_window`
|
|
describes the server's total context; Pi's `contextWindow` receives
|
|
`context_window - max_tokens` because Pi uses it as an input compaction target.
|
|
|
|
`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.
|