---
title: Pi
description: Use Pi as a first-class Claudette harness with SDK-backed model discovery, persistent sessions, and Claudette-mediated permissions.
---

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](/claudette/getting-started/installation/#building-without-the-pi-harness).

## Setup

1. Install Pi (the `pi` CLI is optional but useful for `pi auth` and `pi /login` outside Claudette).
2. Launch Claudette and open **Settings > Models > Pi**. The card now embeds a per-provider configuration list (see [Configuring providers](#configuring-providers) below) — configure GitHub Copilot, OpenRouter, OpenAI, Anthropic, Google Gemini, DeepSeek, and a handful of others without leaving Claudette.
3. 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.
4. 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

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 terminal `pi` CLI too.
  - Checked → key is stored in Claudette's OS keychain under bucket `piProviderSecrets` and pushed to the harness as the matching env var (e.g. `OPENROUTER_API_KEY`) at spawn time. Invisible to terminal `pi`.
- 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

Claudette owns the Pi process lifecycle:

- **Rust adapter**: `src/agent/pi_sdk.rs` starts the sidecar, correlates JSONL requests, and converts Pi events into Claudette `AgentEvent`s.
- **Bun sidecar**: `src-pi-harness/` imports `AuthStorage`, `ModelRegistry`, `SessionManager`, `DefaultResourceLoader`, and `createAgentSession` from `@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

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

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 value `pi`

Default Pi selection uses the existing global model settings:

- `default_model`
- `default_agent_backend`

### 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

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

- `/model` lists Pi models when they are available and accepts provider-qualified ids such as `pi/openai/gpt-5.4`.
- `/login` for a Pi-selected chat opens the **Pi provider picker** modal (Pi is multi-provider, so `/login` doesn't blind-launch one OAuth flow the way it does for Codex or Claude Code — you pick which provider to configure).
- `/permissions` keeps controlling Claudette's permission mode for Pi, Claude Code, and Codex.

## 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_start` for any trigger — manual `/compact`, threshold (the
  `keepRecentTokens` budget), or overflow (context window exhausted) —
  the chat flips to **Compacting context…** instead of leaving a
  generic spinner. On success the `compact_boundary` divider 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

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

**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

- [Alternative Providers](/claudette/features/providers/) - capability matrix and provider architecture
- [Agent Configuration](/claudette/features/agent-configuration/) - model picker and reasoning controls
- [Authentication](/claudette/features/authentication/) - how provider auth is delegated
