Architecture
pibox is a thin layer on the aicodebox base image. The base owns the container entrypoint, the user and permission setup, the startup hooks, and every mode: the HTTP API, the OpenAI-compatible endpoint, MCP, Telegram and cron. pibox adds Pi and the pieces that connect it.
host: pibox (wrapper.sh)
docker run psyb0t/pibox
container: pibox-entrypoint PIBOX_* -> AICODEBOX_*, provider bootstrap
aicodebox-entrypoint user, hooks, mode selection
mode (API, Telegram, cron, MCP) or plain Pi
PiAdapter run request -> pi argv, NDJSON -> result
pi -p --mode json
upstream LLM
The pieces
| Piece | Source | Role |
|---|---|---|
| Host wrapper | wrapper.sh | Builds the docker run command: workspace and state mounts, forwarded variables, image choice, nested launch context |
| Installer | install.sh | Creates the host directories and SSH key, pulls the image, installs the wrapper |
| pibox entrypoint | pibox-entrypoint.sh | Copies PIBOX_* to AICODEBOX_*, exports the provider key, runs the provider bootstrap, adds --provider and --model for plain Pi runs, then hands over to the base entrypoint |
| Provider bootstrap | setup-provider-env.sh | Writes the managed provider into Pi’s models.json and the selected provider and model into pibox-provider.json |
| Adapter | adapter.py | PiAdapter, the aicodebox AgentAdapter for Pi |
| Startup script | 10-pi-extensions.sh | Registers the MCP bridge extension in Pi’s settings on first start |
| MCP bridge extension | mcp-bridge/index.ts | Gives Pi the tools of stdio MCP servers listed in a workspace .mcp.json |
| Images | Dockerfile, Dockerfile.full | Install Pi from npm, the adapter with uv pip --no-deps, the extension’s npm dependencies, and set AICODEBOX_ADAPTER=pibox.adapter:PiAdapter |
The adapter
The base modes turn every request into a run request and hand it to the adapter named by AICODEBOX_ADAPTER. PiAdapter then:
- Builds the command line. It always runs
pi -p --mode json, because only the JSON event stream carries the session ID, usage and errors. It maps the request to--model,--thinking,--system-prompt,--append-system-prompt,--session,--no-sessionor--continue,--toolsor--no-tools, then appends any extra arguments. A JSON schema becomes an extra appended system prompt, since Pi has no schema option. The prompt goes to stdin, never to the arguments. - Pins the provider. When the provider bootstrap left a marker in
pibox-provider.json, orANTHROPIC_BASE_URLis set, it adds--providerunless the caller chose one, so a model name cannot be claimed by one of Pi’s built-in providers. - Validates. It rejects unknown thinking levels and a tool allowlist combined with
noTools. - Parses the output. It reads the NDJSON stream for the session ID, the assistant text from
message_endevents, usage fromturn_end, and provider errors from assistant turns that stop withstopReason: error. Usage is reported under both Pi’s names (input,output) and the OpenAI-style names (input_tokens,output_tokens). - Streams. For streaming chat, it turns
text_deltaevents into text chunks andagent_endinto the stop reason. Thinking and tool events are not sent to the stream. - Names Pi’s state.
auth_pathslistsauth.json,settings.json,models.json,pibox-provider.jsonandsessionsunder~/.pi/agent.
The provider flow
- The entrypoint sees a
PIBOX_PROVIDER_*variable, orANTHROPIC_BASE_URL. - The bootstrap runs as
aicode, validates the settings, and writes the provider entry with every model from the primary model plusPIBOX_AVAILABLE_MODELS. For the generic path, the key stays in the environment asOPENAI_API_KEY. - Plain
piboxandpibox -pruns get--providerand--modelfrom the entrypoint. Mode runs get them from the adapter.
What lives where
| Path in the container | Host source with the wrapper | Contents |
|---|---|---|
| The workspace path | The directory you ran pibox from | Your files |
/home/aicode/.pi | PIBOX_DATA_DIR, default ~/.pi | Pi settings, auth, models.json, pibox-provider.json, sessions |
/home/aicode/.aicodebox | PIBOX_STATE_DIR, default ~/.aicodebox | Mode configuration, cron history, Telegram overrides, bin/, init.d/ |
/home/aicode/.ssh | PIBOX_SSH_DIR, default ~/.ssh/pibox | The SSH key from the installer |
/opt/pibox | The image | The adapter, scripts and the MCP bridge extension |