Connect Pi Agent to Router One with models.json
Pi is a terminal coding agent that runs file and shell tools on your machine. Router One handles its model requests, routing and per-request billing. This guide targets @earendil-works/pi-coding-agent 0.86.1 from the earendil-works/pi repository. Start with the openai-completions adapter: despite its name, it uses Chat Completions, not the legacy text completions endpoint.
Install Pi and export a dedicated gateway key
Pi 0.86.1 requires Node.js 22.19.0 or newer. Check the Node version before installing the pinned package below. Create a dedicated Router One key with a maxSpend cap, then export it in the terminal where Pi will run. ROUTER_ONE_API_KEY is the variable used by this guide; Pi reads it because models.json explicitly references it.
node --version npm install -g --ignore-scripts @earendil-works/pi-coding-agent@0.86.1 pi --version export ROUTER_ONE_API_KEY="sk-your-router-one-key"
Configure Pi Agent to use the Router One base URL
Add router-one inside the providers object of ~/.pi/agent/models.json, preserving any other providers already in that file. If PI_CODING_AGENT_DIR is set, use models.json in that directory instead. apiKey uses the dollar-prefixed environment syntax of Pi 0.86.1. The provider name router-one is a local label; model.id is the complete Router One catalog ID. The example uses a current chat model, keeps reasoning off and sets a 4096-token output cap for the first test. Replace the ID with another current chat model from /models when needed. The compat settings omit store, developer-role and reasoning-effort options in this introductory configuration; they do not declare that every model lacks those features.
{
"providers": {
"router-one": {
"baseUrl": "https://api.router.one/v1",
"api": "openai-completions",
"apiKey": "$ROUTER_ONE_API_KEY",
"compat": {
"supportsStore": false,
"supportsDeveloperRole": false,
"supportsReasoningEffort": false
},
"models": [
{
"id": "anthropic/claude-sonnet-5",
"reasoning": false,
"input": [
"text"
],
"maxTokens": 4096
}
]
}
}
}Select the exact model, then test one text response
Run --list-models to check that Pi loaded the provider; this lists local configuration and does not prove the key or endpoint works. Run the text test below from an empty directory. It disables tools, session saving, extensions and project context, while the model request can still incur usage charges. Match the response with Dashboard → Logs by model, time and request_id, then start a normal interactive coding session. Keep --provider and --model separate so a slash inside the catalog ID remains unambiguous. After editing models.json during a session, reopen /model to reload it. Exporting a new environment variable in another shell does not change the environment of an already-running Pi process.
pi --list-models router-one pi --provider router-one --model anthropic/claude-sonnet-5 \ --no-tools --no-session --no-extensions --no-context-files \ -p -- "Reply with one short greeting." # Start normal interactive use after the text test succeeds pi --provider router-one --model anthropic/claude-sonnet-5
Match the API type to its base URL
Pi chooses the request adapter from api; changing only the URL does not translate protocols. Use separate provider entries if you want both Chat Completions and a native protocol. Do not include the final /chat/completions, /messages or /responses segment in baseUrl.
| Pi api value | baseUrl | Request and model boundary |
|---|---|---|
| openai-completions | https://api.router.one/v1 | POST /v1/chat/completions; current chat models |
| anthropic-messages | https://api.router.one | POST /v1/messages; compatible Claude and DeepSeek IDs |
| openai-responses | https://api.router.one/v1 | POST /v1/responses; confirm support on the selected model page |
Treat local token and cost settings as client configuration
Pi does not populate this custom provider from Router One’s /models endpoint. Add each model ID yourself and update contextWindow, maxTokens, input and reasoning for the selected model. contextWindow defaults to 128000 in Pi 0.86.1; maxTokens limits output, so it is not the context-window field. This example caps output at 4096 and permits text input only. Copy current capabilities from the model detail page before enabling image input or thinking. Omitted cost values default to zero, which can make Pi show zero estimated cost even when Router One bills the request. Router One’s settled Logs are the billing record; Pi’s cost rates are local estimates and do not automatically include account discounts, subscription rules or long-context tiers. Tool turns, retries and context compaction can produce additional model calls.
Which model ID should Pi Agent send?
Copy the exact model ID from /models, preserving case, hyphens, and version suffixes; do not substitute a display name. Open its detail page and match the supported API endpoints, context window, and capabilities such as tool calling to the provider and features selected in Pi Agent. A catalog listing does not mean the client can use every feature of that model. Give each tool a dedicated API key with a maxSpend cap.
Which API protocol is Pi Agent using?
OpenAI-compatible describes an interface format; it does not make Chat Completions (/v1/chat/completions), Responses (/v1/responses), and Anthropic Messages (/v1/messages) interchangeable. Check the installed client version, provider configuration, and actual request path against the model detail page and API compatibility fact sheet. A successful plain-text chat does not establish support for hosted tools, conversation state, or file-editing features.
Verify the Pi Agent call in your request trace
Send a simple text request from Pi Agent, then match its trace in Dashboard → Logs by time, model, and request_id: tokens, cost, latency, and status. Next, test streaming, tool calls, and multi-turn history separately. For failures, retain the actual request path, full error message, and request_id. If there is no matching log, check client configuration and connectivity before attributing the error to the gateway or upstream.
FAQ
Why did a models.json key stop working after upgrading an older Pi installation?
The environment syntax changed. Pi 0.86.1 requires apiKey: "$ROUTER_ONE_API_KEY"; a bare "ROUTER_ONE_API_KEY" is a literal key and can cause 401. In the older 0.74.2 package, the bare variable name was resolved from the environment, while the new dollar form was not supported by that resolver. Check pi --version and use the syntax documented for your installed version. For this guide, upgrade to 0.86.1 and keep the dollar sign. A local mock verified that 0.86.1 sends the bare name literally.
Why is router-one missing from /model, or why is Pi still using an old key?
First check the active configuration directory, valid JSON structure and whether ROUTER_ONE_API_KEY was exported before starting Pi. In 0.86.1, a missing referenced environment variable leaves authentication unresolved and can hide the models from the available list. Credential precedence is CLI --api-key, saved authentication for that provider, built-in provider environment credentials, then models.json. A saved key under the same router-one provider can therefore override this configuration. Reopen /model after file edits; restart Pi if its process needs a newly exported environment variable.
Should I change compat settings when a 400 mentions a parameter?
Read the actual error before changing anything. Pi’s OpenAI adapter normally requests stream_options.include_usage and can send either max_completion_tokens or max_tokens through compat.maxTokensField. Keep usage enabled when supported; only change the token field if the selected model’s response requires it. Likewise, enable reasoning and its format per model rather than assuming every catalog ID accepts OpenAI reasoning_effort. Provider-level compat applies to all of its models, while model-level compat can override individual settings.
Does this reuse my ChatGPT or Claude subscription, or change Pi’s built-in login?
No. router-one is a separate custom provider billed through your Router One account. Pi’s built-in OAuth providers and their /login sessions are separate. Keep the custom name instead of replacing openai, openai-codex or anthropic; changing a built-in provider’s base URL can leave its existing credentials and built-in model IDs in use. Router One does not run Pi’s local tools, session storage, skills or extensions.
Which models can Pi Agent use through the gateway?
Choose a current catalog model that supports both the endpoint and the features Pi Agent uses. Check /models and the model detail page for the exact ID, current rates, and capabilities; a family name such as GPT or Claude is not a compatibility guarantee. Seeing a model in the picker confirms discovery, so verify an actual request too.
Models are listed, but requests fail with 400 or 404. What should I check?
Record the actual request path and error message, then check the exact model ID. A 400 can indicate invalid parameters, unsupported tools, or a model/endpoint mismatch; a 404 can indicate an incorrect path or missing resource, so it does not by itself establish that a model was retired. If the error says must be called via, use the named endpoint or select a model supported on the current endpoint. Do not add or remove /v1 or /chat/completions across all clients indiscriminately.
Does this work from Mainland China?
Yes. The gateway is reachable from Mainland China without a VPN, and the configuration is identical to the global setup.
How do I debug a 401/402/403/429?
Match the request and error message in Dashboard → Logs. For 401, check whether the key was sent and is valid; for 402, check wallet balance and maxSpend; for 403, check key permissions and access restrictions. For 429, distinguish request/token limits from upstream throttling using the error details. Keep the request_id and follow the error-codes reference.