Pi
Pi support runs through Claudette’s bundled Pi SDK harness, not through the Pi RPC server. Claudette ships a compiled Bun sidecar that embeds @earendil-works/pi-coding-agent; the Rust app talks to that sidecar over a small JSONL protocol and maps Pi session events into the same chat, tool-call, permission, stop, and attention UI used by Claude Code and Codex.
This is a production provider path. It is always available in normal builds and is not hidden behind Experimental settings. Distributions that need to ship without Pi can drop the pi-sdk cargo feature at build time — see Building without the Pi harness.
- Install Pi (the
piCLI is optional but useful forpi authandpi /loginoutside Claudette). - Launch Claudette and open Settings > Models > Pi. The card now embeds a per-provider configuration list (see Configuring providers below) — configure GitHub Copilot, OpenRouter, OpenAI, Anthropic, Google Gemini, DeepSeek, and a handful of others without leaving Claudette.
- The model list refreshes automatically after each configure / sign-in round-trip. Use Refresh models to force a re-discovery if you change credentials outside Claudette.
- Pick a Pi model as the default in Settings > Models > Default model, or choose one per chat from the model picker.
The Pi card does not need a base URL or a card-level API key — keys are scoped per provider via the inline list.
Configuring providers
Section titled “Configuring providers”The Pi card surfaces a curated list of providers Pi knows how to talk to:
- Default visible — GitHub Copilot (OAuth, supports GHES), OpenRouter, OpenAI, Anthropic, Google Gemini, DeepSeek (API keys).
- More providers… disclosure — xAI, Groq, Cerebras, Mistral, Fireworks, OpenCode Zen (API keys).
- Env-only — Amazon Bedrock, Google Vertex AI, Azure OpenAI — these need too many environment variables to model in a dialog; the row links to Pi’s docs and reflects the configured state once the env vars are set.
For each row:
- API-key providers open a Configure dialog where you paste the key. A “Keep this key private to Claudette” checkbox controls storage scope:
- Unchecked (default) → key is written to Pi’s
~/.pi/agent/auth.json. Visible to the terminalpiCLI too. - Checked → key is stored in Claudette’s OS keychain under bucket
piProviderSecretsand pushed to the harness as the matching env var (e.g.OPENROUTER_API_KEY) at spawn time. Invisible to terminalpi.
- Unchecked (default) → key is written to Pi’s
- OAuth providers (currently GitHub Copilot) open a Sign in modal that drives Pi’s device-code flow. For Copilot the modal prompts for an optional GitHub Enterprise Server domain, displays the verification URL + user code, and closes when Pi reports success.
- Env-only providers open the relevant Pi docs page in a browser; the row’s status dot turns green once Pi detects the env vars on next refresh.
The card also shows a per-row source label once configured (via auth.json, via $OPENROUTER_API_KEY, via models.json, …) so you can tell which credential path Pi will actually use.
OpenRouter-backed Pi turns report per-turn token usage and cost in the chat footer and the composer usage meter. Claudette also polls OpenRouter’s /credits endpoint with the OpenRouter key configured for Pi and shows remaining / used credits next to the local token totals when the call succeeds.
Harness Architecture
Section titled “Harness Architecture”Claudette owns the Pi process lifecycle:
- Rust adapter:
src/agent/pi_sdk.rsstarts the sidecar, correlates JSONL requests, and converts Pi events into ClaudetteAgentEvents. - Bun sidecar:
src-pi-harness/importsAuthStorage,ModelRegistry,SessionManager,DefaultResourceLoader, andcreateAgentSessionfrom@earendil-works/pi-coding-agent. - Model discovery: Settings calls Pi’s
ModelRegistry.getAvailable()through the sidecar and stores the returned model ids/context windows in Claudette’s backend settings. - Session persistence: each Claudette chat gets a Claudette-owned Pi session directory under the app data directory. Resetting or deleting the chat remains authoritative from Claudette’s point of view.
- Packaging: the sidecar is compiled and staged with the other Tauri external binaries. The build also stages Pi package metadata so the SDK can resolve its bundled assets at runtime.
Permissions And Tools
Section titled “Permissions And Tools”Pi’s default mutating tools are not exposed directly. Claudette registers custom Pi tools instead:
- read/search/list tools can execute in read-only permission modes.
- bash/write/edit tools emit a Claudette
tool_request. - approval and denial flow through the same pending-permission cards, cleanup auto-deny, stop/reset draining, and notification attention path used by other harnesses.
The visible transcript shows Pi tool calls through Claudette’s native tool-call UI rather than as raw sidecar logs.
Model Selection
Section titled “Model Selection”Pi models appear under a Pi group in the chat model picker. The picker splits Pi’s registry into one sub-section per real provider (Anthropic, OpenAI, Google, Mistral, Ollama, LM Studio, …) so the list stays scannable when Pi returns hundreds of entries. Each sub-section shows a few primary models with a Show all (N)… disclosure for the rest, and the picker’s top search filters across every section at once.
Per-session choice is persisted with the same keys as other harnesses:
model:<session_id>model_provider:<session_id>with provider valuepi
Default Pi selection uses the existing global model settings:
default_modeldefault_agent_backend
Anthropic via Pi is blocked for Claude subscription users
Section titled “Anthropic via Pi is blocked for Claude subscription users”When the local Claude CLI is signed in with an OAuth subscription token (claude auth status reports authMethod: oauth_token), Claudette hides Pi’s Anthropic sub-section in the picker and the Rust resolver also refuses any chat-send that would route an anthropic/* model through Pi (ensure_anthropic_not_routed_through_pi_via_oauth in src-tauri/src/commands/agent_backends/runtime_dispatch.rs). The block exists so Claude OAuth tokens never leave the Claude CLI subprocess. Non-Anthropic Pi sub-sections (OpenAI, Google, Ollama, …) continue to work normally.
Routing other backends through Pi
Section titled “Routing other backends through Pi”Beyond the dedicated Pi card, Ollama, LM Studio, OpenAI API, Custom OpenAI, and Codex Native can also be routed through the Pi harness via Settings > Models > $(card) > Runtime. The default for Ollama and LM Studio is now Pi (Claude CLI is the optional fallback). For Codex Native and the OpenAI cards, the default stays unchanged and Pi is opt-in. The provider prefix that Pi expects (ollama/, lmstudio/, openai/) is prepended automatically when Claudette dispatches the chat. See the Runtime row on each card.
Slash Commands
Section titled “Slash Commands”/modellists Pi models when they are available and accepts provider-qualified ids such aspi/openai/gpt-5.4./loginfor a Pi-selected chat opens the Pi provider picker modal (Pi is multi-provider, so/logindoesn’t blind-launch one OAuth flow the way it does for Codex or Claude Code — you pick which provider to configure)./permissionskeeps controlling Claudette’s permission mode for Pi, Claude Code, and Codex.
Context Lifecycle
Section titled “Context Lifecycle”Pi sessions surface the same end-of-turn affordances as the Claude CLI gateway:
- Auto-compaction is visible. When Pi’s native context manager fires
compaction_startfor any trigger — manual/compact, threshold (thekeepRecentTokensbudget), or overflow (context window exhausted) — the chat flips to Compacting context… instead of leaving a generic spinner. On success thecompact_boundarydivider renders the pre/post token counts and the meter resets to the post-compaction baseline; on auto-compaction failure the status returns to Running without a divider so the surviving turn keeps streaming. - The context meter shows end-of-turn occupancy. The meter reads
AgentSession.getContextUsage()(Pi’s own end-of-turn context size + the model’s actual context window) rather than a cumulative tally across the agent loop’s internal LLM rounds. A 136 k turn on a 272 k model reads ~50%, not 1100%.
Tool Execution
Section titled “Tool Execution”Pi tool calls — including the shell-backed bash and Pi’s exec tools —
resolve as soon as the spawned command exits, even when the command
backgrounded a descendant that inherited stdout / stderr (a typical
example is bash -c "codex exec …", where the Codex CLI forks helper
processes that hold the inherited pipe open). If you press Stop on the
chat, the running command is cancelled via the abort signal. There is
no automatic per-command timeout; pressing Stop is the only way to
cancel a genuinely stuck command.
Troubleshooting
Section titled “Troubleshooting”Refresh models returns only the seed models. Make sure pi auth has been run and provider configuration exists in Pi. Then click Refresh models again.
A write or shell command is waiting. Approve or deny the Claudette permission card in the chat timeline. Pi mutating tools intentionally wait on Claudette approval.
claudette-pi-harness not installed in a dev build. Launch via ./scripts/dev.sh (not bare cargo tauri dev). The launcher stages the Bun-compiled sidecar into src-tauri/binaries/ and, on macOS, mirrors it into the dev .app’s Contents/MacOS/ so the resolver’s current_exe.parent() lookup succeeds the same way it does in a release build. If you must run cargo tauri dev directly for some reason, export CLAUDETTE_PI_HARNESS=$(pwd)/src-tauri/binaries/claudette-pi-harness-$(rustc -vV | awk '/host:/ {print $2}') to point the resolver at the staged binary. Release builds stage everything automatically.
See also
Section titled “See also”- Alternative Providers - capability matrix and provider architecture
- Agent Configuration - model picker and reasoning controls
- Authentication - how provider auth is delegated