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:
| File | What 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:
mkdir -p .pi && unzip erebine-<workspace>-pi-config.zip -d .pi
pi
- pi loads
.pi/from its working directory, not from the git root, so launch it in the folder you extracted into. - Answer the trust prompt. Project-local settings and extensions only load in a trusted folder.
/trustpersists the answer. For-p,--mode jsonand--mode rpc, pass--approveor set"defaultProjectTrust": "always"in~/.pi/agent/settings.json. /modellists theerebineprovider and this workspace's models.- 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:
{
"defaultProvider": "erebine",
"defaultModel": "<endpoint-slug>",
"enabledModels": [
"<endpoint-slug>"
],
"modelThinkingLevels": {
"erebine/<endpoint-slug>": "medium"
}
}
defaultProvideranddefaultModelstart every session on this workspace's default endpoint.enabledModelsis the Ctrl+P cycling list: every model the bundle advertises, in catalog order.modelThinkingLevelsseeds 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.briefregisters aserebine_intelligence_brief. The MCPinputSchemais passed through verbatim as the tool's parameter schema. - One extra tool,
erebine_resource_read, takes auriand 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:
{
"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 theinferencescope. Mint one witherectl keys --create --name "pi" --scopes inference.<workspace_id>, thews_xxxidentifier this connection pins to. List options witherectl 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:
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:
| Surface | Supported | Mechanism |
|---|---|---|
| Inference provider | yes | Extension, pi.registerProvider |
| MCP tools | yes | Bridged, one pi tool per Erebine tool |
| Prompts | yes | /erebine:<name> commands |
| Resources | yes | erebine_resource_read tool |
| Project rules | yes | APPEND_SYSTEM.md, appended to the default prompt |
| Streaming transport | no | The bridge requests Accept: application/json, not a stream |
| OAuth | no | Bearer header from erebine.json |
| Sampling, elicitation, roots | no | The 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.