pi coding agent

One provider block in models.json: base URL, key, the model ids you want, every model on one key, pay as you go.

Checked 2026-10-28

·All guides·Models

At the end you have pi on a provider named uplinkswitch in ~/.pi/agent/models.json, pointed at https://api.uplinkswitch.com/v1 with one key from the console. Every id you list appears in /model, Claude included, and each request bills per token to the prepaid balance behind the key: 335 chat models on one key, no subscription. The table below is what the 6 ids in the block cost today.

Before you start

You need pi installed (curl -fsSL https://pi.dev/install.sh | sh, or the npm package @earendil-works/pi-coding-agent, Node 22.19 or newer), an account on the console with credit on it, and one key created there. Create the key for pi alone, so its requests sit apart from any other tool on the Usage page. Nothing is installed on the UplinkSwitch side: the base URL and the key are the whole configuration.

Where the settings are

pi keeps user configuration in its agent directory, ~/.pi/agent by default (PI_CODING_AGENT_DIR moves it). Compatible endpoints and custom models go in models.json there; startup defaults go in settings.json. pi takes a compatible endpoint through models.json, so the Anthropic-style variables from the Claude Code guide do not apply.

The field reference is pi's models-configuration.md and the compatible-endpoint walkthrough is in models.md, both read 2026-10-28.

The provider block

Any key under providers that is not a built-in id adds a provider; it needs baseUrl and an api. Use openai-completions, which calls /chat/completions under the base URL. The cost fields are what pi shows in its own session figure; they are filled here from the live catalog. headers are sent on every request, and the gateway files X-Title as the client app on the Usage page.

~/.pi/agent/models.json
{
  "$schema": "https://pi.dev/schemas/models.schema.json",
  "providers": {
    "uplinkswitch": {
      "name": "UplinkSwitch",
      "baseUrl": "https://api.uplinkswitch.com/v1",
      "api": "openai-completions",
      "apiKey": "$UPLINKSWITCH_API_KEY",
      "headers": {
        "HTTP-Referer": "https://uplinkswitch.ai",
        "X-Title": "pi"
      },
      "models": [
        {
          "id": "claude-sonnet-5-5",
          "name": "Claude Sonnet 5.5",
          "input": [
            "text",
            "image"
          ],
          "cost": {
            "input": 1.2,
            "output": 3,
            "cacheRead": 0.075,
            "cacheWrite": 1.2
          },
          "contextWindow": 1000000,
          "maxTokens": 128000
        },
        {
          "id": "claude-opus-5-5",
          "name": "Claude Opus 5.5",
          "input": [
            "text",
            "image"
          ],
          "cost": {
            "input": 2.8,
            "output": 10,
            "cacheRead": 0.15,
            "cacheWrite": 2.8
          },
          "contextWindow": 1000000,
          "maxTokens": 128000
        },
        {
          "id": "gpt-6.1-sol",
          "name": "GPT-6.1 Sol",
          "input": [
            "text",
            "image"
          ],
          "cost": {
            "input": 0.6,
            "output": 3,
            "cacheRead": 0.06,
            "cacheWrite": 0.6
          },
          "contextWindow": 1050000,
          "maxTokens": 128000
        },
        {
          "id": "gemini-3.1-pro-preview",
          "name": "Gemini 3.1 Pro Preview",
          "input": [
            "text",
            "image"
          ],
          "cost": {
            "input": 1.2,
            "output": 7.2,
            "cacheRead": 0.12,
            "cacheWrite": 1.2
          },
          "contextWindow": 1048576,
          "maxTokens": 65536
        },
        {
          "id": "deepseek-v4-pro-0813",
          "name": "DeepSeek V4 Pro 0813",
          "cost": {
            "input": 0.792,
            "output": 1.188,
            "cacheRead": 0.0625,
            "cacheWrite": 0.792
          },
          "contextWindow": 1048576,
          "maxTokens": 393216
        },
        {
          "id": "kimi-k3",
          "name": "Kimi K3",
          "input": [
            "text",
            "image"
          ],
          "cost": {
            "input": 0.9,
            "output": 4.5,
            "cacheRead": 0.12,
            "cacheWrite": 0.9
          },
          "contextWindow": 1048576,
          "maxTokens": 1048576
        }
      ]
    }
  }
}

A models entry needs id and the four cost fields; name is what /model shows and what --model matches by fuzzy search. Omitted contextWindow and maxTokens fall back to pi's defaults of 128,000 and 16,384 tokens, so set them where the model page lists larger figures. Add any other id from the Models page the same way.

The key

"$UPLINKSWITCH_API_KEY" reads the variable from the environment, so export it in the shell that starts pi. A literal key in apiKey works too, and a value starting with ! runs a command and uses its output, for a secret manager.

shell
export UPLINKSWITCH_API_KEY="sk-uplink-live-..."
pi --model uplinkswitch/claude-sonnet-5-5

Pick the model

--model takes provider/id, an exact id, or a fuzzy match on id or name; --provider uplinkswitch narrows the lookup to this provider. Inside pi, /model searches every model with usable authentication, Ctrl+S on a model saves it as the default for new sessions, and Ctrl+P cycles. The same default as a file:

~/.pi/agent/settings.json
{
  "defaultProvider": "uplinkswitch",
  "defaultModel": "claude-sonnet-5-5"
}

enabledModels in the same file, or --models on the command line, limits the startup pick and the cycle to a list of exact ids, fuzzy matches or globs.

Which model id to list

Any chat id on the Models page. Tool calling works on every chat model here, and pi's agent needs it for every file read, edit and shell command, so no id on the list is a dead end. The ids in the block are the usual coding set: a Claude flagship for planning and hard edits, GPT-6.1 Sol and Gemini 3.1 Pro as second opinions, DeepSeek V4 Pro and Kimi K3 where the input price decides.

ModelInput / 1MOutput / 1MCached input / 1MList inputUnder list
Claude Sonnet 5.5$1.20$3.00$0.075$2.0040% on input
Claude Opus 5.5$2.80$10.00$0.15$4.0030% on input
GPT-6.1 Sol$0.60$3.00$0.06$2.0070% on input
Gemini 3.1 Pro Preview$1.20$7.20$0.12$2.0040% on input
DeepSeek V4 Pro 0813$0.792$1.188$0.0625$1.3240% on input
Kimi K3$0.90$4.50$0.12$3.0070% on input

USD per million tokens, live from GET /v1/catalog. List: the developer’s own published price. The same figures fill the cost fields in the block above.

Input decides the cost of an agent session, because the conversation and every tool result travel up again on each step. Cached input bills at the cache-read price by itself; there is no switch to set. The Claude Code pricing post works an hour, a day and a month of agent steps at these rates.

Check it

Confirm the key from a shell before you open pi:

shell
curl https://api.uplinkswitch.com/v1/models -H "Authorization: Bearer $UPLINKSWITCH_API_KEY"

Then run pi and /model: UplinkSwitch and the ids you listed appear in the picker. Send one prompt. The request shows on the console Usage page within seconds, with its tokens, its charge and pi as the client app.

Errors you will see

  • 401 invalid_api_key: the key is wrong, revoked, or the variable was not set in the shell that started pi. Copy it again from the console and export it before pi. If a literal key still returns 401, add "authHeader": true to the provider so pi sends it as Authorization: Bearer.
  • 402 insufficient_balance: the balance does not cover the request. Top up in the console.
  • 402 monthly_limit_reached: the key hit the monthly spend limit you set on it. Raise it in the console, or wait for the first of the month.
  • 404 model_not_found: the id in the models array is not on the Models page at this base URL. Copy the id from the page rather than typing it: a dot, a dash or a date suffix out of place is enough.
  • 403 scope_denied: the key carries a model allowlist and this id is not on it. Pick an allowed id or use a key without the limit.
  • 429 rate_limited: the key hit its requests-per-minute or concurrency limit. The response carries retry-after in seconds. Wait that long and resend.
  • The model is missing from /model: pi hides a custom model until it can resolve the provider's credentials. Check the variable, then open /model again to reload the file.

Good to know

  • Opening /model reloads models.json, so a new id needs no restart.
  • A models entry whose id matches an existing model on the provider replaces it; modelOverrides changes metadata on a built-in model without replacing the list.
  • input: ["text", "image"] lets pi attach screenshots to a model that takes them; the block sets it where the model page lists image input.
  • A key per tool keeps pi's spend apart from Claude Code or OpenCode on the Usage page; all keys draw on the same balance. A monthly spend limit on the pi key caps what an unattended run can cost.

The same key in other agents

OpenCode and OpenClaw read a provider block much like pi's; Claude Code takes two environment variables; Cline and Kilo Code take the base URL and key in a settings panel. One balance serves all of them.

Questions

Yes. pi's models.json takes any endpoint that speaks an API it already supports, and openai-completions is one of them (pi docs, read 2026-10-28). A provider entry needs baseUrl, api, apiKey and a models list; the block on this page is that entry for https://api.uplinkswitch.com/v1.

Add an object with the model id to the models array of your provider in ~/.pi/agent/models.json. Opening /model reloads the file, so the new id appears in the picker without a restart. Any id on the Models page works, Claude included.

Yes. claude-sonnet-5-5 and claude-opus-5-5 answer the OpenAI chat completions format here, so they sit in the same openai-completions provider as gpt-6.1-sol or deepseek-v4-pro-0813. No Anthropic provider entry and no ANTHROPIC_API_KEY are needed.

Press Ctrl+S on a model in /model, or set defaultProvider and defaultModel in ~/.pi/agent/settings.json. For one run, pi --model uplinkswitch/claude-sonnet-5-5 picks the model on the command line.

pi is free and open source; the model is the only bill, per token at the rates in the table above. Claude Sonnet 5.5 is $1.20 per million input tokens and $3.00 per million output tokens today. Each request shows on the console Usage page within seconds with its tokens and charge.

pi lists a custom model only once it can resolve the provider's credentials (pi docs, read 2026-10-28). Export UPLINKSWITCH_API_KEY in the shell that starts pi, or put the key in apiKey as a literal, then open /model again.

Get a key in the console: prepaid credit, no subscription, 30-day price lock.