Blog6 min read

Use SolCard Inference in the Pi coding agent

Add SolCard Inference to Pi with one models.json provider: the api type, compat flags, context and token limits, a check, and what a turn costs.

Contents

Pi takes any OpenAI-compatible API as a custom provider: add one entry to ~/.pi/agent/models.json with api set to openai-completions, baseUrl set to https://api.solcardinference.ai/v1, and our three model ids. Pi’s README calls it “a minimal, extensible agent harness”, and its file asks for more than a URL and a key: limits, prices and a few compatibility flags. This guide fills in each one. Using OpenCode instead? See Use SolCard Inference in OpenCode.

What you need

  • A SolCard Inference API key. Make one on the dashboard’s API keys page. Keys start with sk-si- and are shown once.
  • Some balance or a plan. One prepaid USD balance pays for every key and model; see how billing works.
  • Pi. Its README installs it with npm install -g --ignore-scripts @earendil-works/pi-coding-agent.

Export the key in the shell you start Pi from:

export SOLCARD_INFERENCE_API_KEY=sk-si-...

The models.json entry

models.json lives in Pi’s agent directory, which Pi’s configuration docs say “defaults to ~/.pi/agent”. Set PI_CODING_AGENT_DIR to move it. Create or extend the file:

{
  "$schema": "https://pi.dev/schemas/models.schema.json",
  "providers": {
    "solcard-inference": {
      "name": "SolCard Inference",
      "baseUrl": "https://api.solcardinference.ai/v1",
      "api": "openai-completions",
      "apiKey": "$SOLCARD_INFERENCE_API_KEY",
      "compat": {
        "supportsStore": false,
        "supportsDeveloperRole": false
      },
      "models": [
        {
          "id": "solcard-inference-fast",
          "name": "SolCard Inference Fast",
          "contextWindow": 1048576,
          "maxTokens": 32768,
          "cost": { "input": 1.25, "output": 2.5, "cacheRead": 0.125, "cacheWrite": 0 }
        },
        {
          "id": "solcard-inference-large",
          "name": "SolCard Inference Large",
          "contextWindow": 1000000,
          "maxTokens": 32768,
          "cost": { "input": 3.75, "output": 6.25, "cacheRead": 0.375, "cacheWrite": 0 }
        },
        {
          "id": "solcard-inference-base",
          "name": "SolCard Inference Base",
          "contextWindow": 262144,
          "maxTokens": 32768,
          "cost": { "input": 1.25, "output": 3.75, "cacheRead": 0.125, "cacheWrite": 0 }
        }
      ]
    }
  }
}

What each field does, per Pi’s models.json reference:

FieldWhat it’s for
$schemaOptional. Gives your editor validation and completion.
solcard-inferenceThe provider id. Any id that isn’t a built-in provider adds a new one.
baseUrlThe API endpoint. Ours ends in /v1; don’t add /chat/completions.
apiWhich request format Pi speaks. openai-completions is Chat Completions.
apiKeyA literal key, $NAME to read an environment variable, or !command to use a command’s output.
compatOverrides for APIs that differ from OpenAI’s.
idSent to the API as the model. Must match ours exactly.
contextWindowContext size in tokens, from our models page.
maxTokensOutput tokens per request.
costUSD per 1M tokens, which Pi uses to estimate spend.

Three fields matter more than they look:

  • maxTokens: Pi’s default is 16,384. Our models stop at 32,768 tokens per request, so setting it lets Pi use the whole cap.
  • contextWindow: Pi assumes 128,000 when you leave it out, far less than Fast’s or Large’s real context.
  • cost: Pi marks all four price fields as required. Our price list has no cache-write rate, so cacheWrite is 0. Pi’s total is its own estimate; what you’re charged follows how billing works.

The two compat flags

Pi’s docs say most compat flags are “auto-detected from URL”, and ours isn’t a URL Pi knows, so setting two of them yourself removes the guess.

  • supportsStore: false keeps Pi from sending OpenAI’s store field. Our errors page lists store: true as a 400 unsupported_parameter.
  • supportsDeveloperRole: false makes Pi send its system prompt with the system role instead of developer.

Pi’s author ran into the same split across providers. In a November 2025 post on building Pi, the author lists APIs that “don’t like the store field” and others that “don’t support the developer role for system prompts”, which is why these switches exist.

We left reasoning at its default, false, on all three. Large always reasons on its own, per our models page, so this guide doesn’t turn on Pi’s thinking controls. Pi’s models docs say /thinking offers only the “levels supported by the selected model”.

Check it works

Pi reads the file again when you open the model picker, so there’s no restart. Its models docs say: “Opening /model reloads the file.” From a terminal, list what Pi sees:

pi --list-models solcard

You should see the three SolCard Inference models. Then send one prompt in print mode, which Pi’s CLI docs say writes “the final assistant text to stdout” and exits:

pi --model solcard-inference/solcard-inference-fast -p "Say hello in five words."

If nothing comes back, test the key and URL without Pi:

curl https://api.solcardinference.ai/v1/models \
  -H "Authorization: Bearer $SOLCARD_INFERENCE_API_KEY"

Switching models

Start on Fast and press Ctrl+S on it in /model to make it the default for new sessions. Pi’s models docs also say “Ctrl+P cycles through available models”, and /scoped-models limits that cycle to the ones you pick, so a scope of Fast and Large gives you a one-key jump when a change needs planning. Large costs three times as much on input. Fast, Large or Base compares the three.

What a turn costs

Pi’s own prompt is small, so most of each turn is your conversation, resent at the cached rate. In November 2025, its author wrote that “pi’s system prompt and tool definitions together come in below 1000 tokens.” A turn on Fast that resends 60,000 tokens, 55,000 of them cached, and writes 1,000 tokens is about $0.016. The same turn on Large is about $0.046, before its reasoning tokens.

Troubleshooting

These are the API’s codes from our errors page; Pi may word them differently.

  • Models missing from /model: Pi’s docs say the picker “shows models whose providers have usable authentication.” Check the variable is exported in the shell that started pi, and that apiKey keeps its leading $.
  • 401 invalid_api_key: the key is wrong, revoked or unset.
  • 400 model_not_found: an id doesn’t match. Use solcard-inference-fast, -large or -base.
  • 400 unsupported_parameter: something Pi sent isn’t accepted. Check supportsStore is false.
  • 400 unsupported_content: an image reached the model. Our models take text only, and Pi’s input default is ["text"], so don’t add "image".
  • 402 insufficient_balance: top up, then retry.

FAQ

Can I keep Pi’s built-in providers? Yes. A new provider id adds a provider next to the others. Pick between them in /model.

Can I keep the key out of my environment? Yes. Pi’s reference says apiKey accepts !command, and its models docs say such commands “run at request time and are not cached by Pi”, so a password manager’s read command works there.

Can I use the Anthropic Messages format instead? Pi has an anthropic-messages type, and our API speaks Anthropic Messages too. Pi’s docs don’t say whether that type adds /v1 to baseUrl, so this guide sticks to openai-completions.

Are my prompts stored? Not on our side. Prompts and responses are never logged or stored; keeps nothing follows one request through.

Bring the prompt that got refused.

Private. No refusals. In the app, or in the tools you already use.

Pay in crypto. No KYC.