docs
// Guides

pi Coding Agent

Project-local, one folder. pi has no built-in MCP client and its models.json is global, so the Erebine bundle ships a .pi/ folder whose extension registers the workspace provider and bridges every Erebine tool, prompt and resource, while APPEND_SYSTEM.md carries the rules into pi's default system prompt without replacing it.

pi is Earendil's minimal coding agent. It reads a project-local .pi/ folder from the directory it is launched in: settings, extensions, and system-prompt files. Model providers beyond the built-in set come from an extension, because pi's own models.json is user-level only. There is no MCP client in pi at all.

The Client-tab download is that folder. Four files, plus a README.txt:

FileWhat it does
.pi/erebine.json Connection descriptor: the MCP URL and headers, plus the inference base URL, key and model list when this workspace advertises models. The extension reads it; nothing else does.
.pi/settings.json pi settings: defaultProvider, defaultModel, the ids Ctrl+P cycles, and the default thinking level.
.pi/APPEND_SYSTEM.md The Erebine tool-use rules. pi appends this file to its default system prompt.
.pi/extensions/erebine.ts The extension. Registers the erebine provider from erebine.json and bridges every Erebine MCP tool, prompt and resource into pi.

Nothing in the bundle replaces pi's system prompt. .pi/SYSTEM.md would; the bundle ships APPEND_SYSTEM.md instead, and the extension adds no prompt text of its own.

See the general MCP integration documentation for the full tool catalog, the governed-execution model, and the security gates that apply to every MCP request.

Quick Start

Download the pi bundle from the Chat page's Client tab (visible once a specific workspace is selected). The archive is the .pi/ folder itself, so extract it into that folder from your project root:

Shell
mkdir -p .pi && unzip erebine-<workspace>-pi-config.zip -d .pi pi
  1. pi loads .pi/ from its working directory, not from the git root, so launch it in the folder you extracted into.
  2. Answer the trust prompt. Project-local settings and extensions only load in a trusted folder. /trust persists the answer. For -p, --mode json and --mode rpc, pass --approve or set "defaultProjectTrust": "always" in ~/.pi/agent/settings.json.
  3. /model lists the erebine provider and this workspace's models.
  4. Prompt: Call erebine_intelligence_brief and summarize this workspace. The answer proves both halves of the bundle.

Add .pi/erebine.json to .gitignore. It carries your workspace API key, in the Authorization header and in the inference block. The other three files carry no secrets. Re-downloading rotates the key and revokes the one in your previous bundle.

Inference Endpoint

The extension calls pi.registerProvider("erebine", ...) with the inference block of erebine.json: base URL, key, api: "openai-completions", the X-Erebine-Augment-Corrective-Retries header, and the model list. Registration happens in the extension factory, which pi awaits before it resolves settings, so the provider exists by the time the default model is looked up.

settings.json pins what pi starts on:

JSON
{ "defaultProvider": "erebine", "defaultModel": "<endpoint-slug>", "enabledModels": [ "<endpoint-slug>" ], "modelThinkingLevels": { "erebine/<endpoint-slug>": "medium" } }
  • defaultProvider and defaultModel start every session on this workspace's default endpoint.
  • enabledModels is the Ctrl+P cycling list: every model the bundle advertises, in catalog order.
  • modelThinkingLevels seeds the starting thinking level, and is emitted only for a reasoning model whose default effort has a pi equivalent.

Per-model thinking levels come from the efforts the model's reasoning parser accepts. A supported level maps to itself and pi sends it as reasoning_effort; an unsupported level maps to null and pi hides it from the picker rather than sending a value the backend rejects.

The routing mode chosen at download time decides how much of the fleet lands in the file:

  • Direct (default): every generative model in the project. The model travels in the request payload, so Ctrl+P switches models without a re-download.
  • Semantic router: one entry pointing at the semantic router, which scores the fleet per request.
  • Pinned: the resolved endpoint, pinned. One model.

A workspace with no advertised models yields an MCP-only bundle: erebine.json has no inference block, settings.json is {}, and pi keeps whatever provider you already use.

MCP Bridge

pi ships no MCP client, so the extension is the transport. In its factory it opens a session (initialize, then notifications/initialized), reads tools/list, prompts/list, resources/list and resources/templates/list, and registers what it finds.

  • One pi tool per Erebine tool. Dots become underscores, because providers accept only [A-Za-z0-9_-] in function names: erebine.intelligence.brief registers as erebine_intelligence_brief. The MCP inputSchema is passed through verbatim as the tool's parameter schema.
  • One extra tool, erebine_resource_read, takes a uri and returns the resource body. Its description lists the URIs and templates this workspace advertises.
  • Calls carry the tool call's abort signal and a per-request timeout from mcp.timeoutMs (30000 ms by default).

The session id the router stamps on Mcp-Session-Id is echoed on every later request. If the server answers 404 because the session is unknown or expired, the extension re-initializes once and retries the call. If the server was unreachable when pi started, the extension registers no tools and says so at session start; /reload re-runs the factory once the server is back.

To hand-author the connection instead of downloading it, this is the whole file:

JSON
{ "schemaVersion": 1, "workspace": "<workspace_id>", "mcp": { "url": "https://api.erebine.ai/proj_ABC123/v1/mcp", "headers": { "Authorization": "Bearer <api_key>", "X-Erebine-Workspace": "<workspace_id>" }, "timeoutMs": 30000 } }
  • <api_key>, a key with the inference scope. Mint one with erectl keys --create --name "pi" --scopes inference.
  • <workspace_id>, the ws_xxx identifier this connection pins to. List options with erectl workspaces list.

Project Rules

.pi/APPEND_SYSTEM.md carries the shared Erebine tool-use rules every other client receives through its own rules surface, plus a pi addendum that spells out the tool naming and the slash commands. pi appends the file to its default system prompt at session start.

Without it the agent will sometimes ask you about workspace state instead of calling the Erebine tools to retrieve it.

APPEND_SYSTEM.md appends; SYSTEM.md replaces. The bundle never writes .pi/SYSTEM.md, which would discard pi's own prompt. If your project already keeps an APPEND_SYSTEM.md, append the bundle's content to yours rather than overwriting the file; pi reads one APPEND_SYSTEM.md per project.

Prompts and Resources

The Erebine MCP server advertises 6 prompts and 4 resources alongside the tool catalog. The extension registers each prompt as a pi slash command:

  • /erebine:brief, the intelligence brief plus the five most recent decisions.
  • /erebine:session_init, prime a session with one keystroke.
  • /erebine:onboard <topic>, a context pack for one topic.
  • /erebine:save-this <note>, persist a note with link candidates pre-filled.
  • /erebine:mcp-loop <mode>, toggle or read the guidance-evolution loop.
  • /erebine:erepress <mode>, toggle or read this workspace's in-path token compression.

Every Erebine prompt takes at most one argument, so the whole command tail is that argument: /erebine:onboard semantic routing sends semantic routing as the topic. The command expands through prompts/get and the expansion is sent as your next user message.

Resources are read through the erebine_resource_read tool with a URI such as erebine://workspace/current/brief. Ask for a resource by name and the model calls the tool; the tool's description carries the advertised URIs and templates. The prompts and resources themselves are documented on the general MCP integration page.

CLI Setup

erectl writes the connection descriptor directly, and the extension source is served from this site:

Shell
mkdir -p .pi/extensions erectl mcp setup --client pi --workspace <uuid> > .pi/erebine.json curl -o .pi/extensions/erebine.ts https://erebine.ai/docs/pi/erebine.ts

The erectl output writes the key as the placeholder {env:EREBINE_API_KEY}. The extension expands it from the environment, so export EREBINE_API_KEY before launching pi, or pass --inline-api-key to erectl.

The CLI prints the descriptor to stdout, with the inference block built from the workspace's _direct models over the management API. Pass --out-dir <dir> to also write settings.json, APPEND_SYSTEM.md and the extension, or --mcp-only to keep the model provider you already use.

.pi/extensions/erebine.ts is the same bytes for every workspace: it carries no keys, no URLs and no workspace identifiers, and reads all of them from erebine.json at load time. Rotating a key is a one-line edit to that JSON.

Capability Matrix

What the bundle wires into pi, and how:

SurfaceSupportedMechanism
Inference provideryesExtension, pi.registerProvider
MCP toolsyesBridged, one pi tool per Erebine tool
Promptsyes/erebine:<name> commands
Resourcesyeserebine_resource_read tool
Project rulesyesAPPEND_SYSTEM.md, appended to the default prompt
Streaming transportnoThe bridge requests Accept: application/json, not a stream
OAuthnoBearer header from erebine.json
Sampling, elicitation, rootsnoThe bridge advertises no client capabilities

See the full per-client comparison in docs/mcp, Security.

Troubleshooting

pi never asked to trust the project, and no Erebine tools appear

pi discovers .pi/ under its working directory. Launch it from the folder that holds .pi/, confirm .pi/extensions/erebine.ts exists (the archive nests it one level down, so extract with -d .pi, not into the project root), then run /reload.

"Unknown or expired MCP session"

The extension re-initializes once and retries, so a single expiry is invisible. A message that persists means the key itself is gone: each Client-tab download rotates your personal key and revokes the previous one. Re-download the bundle, or mint a standalone key with erectl keys --create --name "pi" --scopes inference.

Model not found at startup

settings.json names a defaultModel that erebine.json no longer lists, usually after the workspace's endpoint changed. Re-download the bundle, or edit defaultModel and enabledModels to an id that appears in erebine.json.

401 Unauthorized on every tool call

The key in .pi/erebine.json is missing, malformed, or revoked. Re-download the bundle, or replace the Authorization header value with a key carrying the inference scope.

403 Forbidden with code scope_insufficient

The key authenticated but does not carry the inference scope the MCP surface requires. Mint a replacement with the command above.

Already running pi-mcp-adapter

Keep it for your other servers. The adapter prefixes tool names with the server name, so its tools and the bundle's erebine_* tools do not collide; running both only means the Erebine catalog is registered twice. To route Erebine through the adapter instead, add the same URL and headers from erebine.json to its .mcp.json and delete the bridge from the extension, keeping the registerProvider call.