A Pi extension that registers Command Code as a dynamic model provider.
I built it because I subscribe to Command Code and got tired of maintaining a models.json by hand — every time they added or removed a model, I'd have to update mine and restart Pi. This extension pulls Command Code's live catalog, so new models just show up.
It exposes two providers backed by the same key, both participating in Pi's built-in /login flow:
| Provider ID | Display Name | Wire Protocol |
|---|---|---|
command-code |
Command Code | OpenAI Chat Completions |
command-code-anthropic |
Command Code (Anthropic) | Anthropic Messages |
Pricing and capability metadata are layered in from Command Code's published GOAT plan table, cached on disk for 24h. Per-model maxTokens and contextWindow overrides are supported, with automatic extended-thinking support for Claude models.
Note: I have the GOAT subscription, which is the only tier I've personally tested. The
/modelsendpoint and GOAT-plan enrichment should behave the same for other Command Code subscriptions, but if something breaks on another tier, please file an issue!
Setting this up takes three simple steps:
Run this single command in your terminal:
pi install git:github.com/jstokke/pi-command-code-providerTo pin a specific release, add the tag:
pi install git:github.com/jstokke/pi-command-code-provider@v0.3.0(The HTTPS form works too: pi install https://github.com/jstokke/pi-command-code-provider)
That's it! Pi downloads the extension, registers it in ~/.pi/agent/settings.json, and loads it automatically whenever you run pi.
Not on npm. This extension is distributed only from this repository. There is a separate, independently maintained package called
pi-commandcode-provideron npm — the names differ by a single hyphen, so make sure you have the one you intended.
Start Pi (or run this inside an existing Pi session):
/login command-code
When prompted, paste your Command Code API key (grab one from commandcode.ai).
- Pi prompts with a masked secret input, validates the key against Command Code's API, and securely saves it to
~/.pi/agent/auth.json. - You only need to do this once. Both
command-codeandcommand-code-anthropicshare the same credential, so logging into either one authenticates both.
In Pi, open the model picker:
/model
You'll see the live Command Code catalog (e.g. command-code/deepseek/..., command-code/gpt-..., or command-code-anthropic/claude-...).
Pick any model, press Enter, and start coding!
Whenever updates or fixes are released, update your installed Pi extensions with:
pi update --extensions(Or pi update --all to update both Pi and all packages.)
If you ever want to remove the extension:
pi remove git:github.com/jstokke/pi-command-code-providerFor headless servers, scripts, or CI environments where an interactive /login prompt isn't possible, set the environment variable:
export COMMAND_CODE_API_KEY="your-command-code-api-key"The extension checks COMMAND_CODE_API_KEY first before falling back to auth.json.
If you want to clone this repository and hack on the code directly:
# 1. Clone the repository
git clone https://github.com/jstokke/pi-command-code-provider.git
cd pi-command-code-provider
# 2. Install the local directory into Pi
pi install .Tip for live development: If you want Pi to reflect edits immediately without reinstalling, symlink src/ into your Pi extensions directory:
mkdir -p ~/.pi/agent/extensions
ln -s "$(pwd)/src" ~/.pi/agent/extensions/command-codeCommand Code serves each model on the endpoint matching its API format. The extension inspects each model and routes it automatically (classifyWire() in src/core.mjs):
- Explicit
api_typefield from/models, if Command Code ever provides one. owned_byvendor metadata containinganthropic.- Model ID matching
(^|/)claude(the Claude family). - Everything else defaults to OpenAI Chat Completions.
Command Code's /models endpoint supplies id, name, owned_by, context_length, and max_tokens, but lacks pricing, vision support flags, and reasoning model indicators.
The extension scrapes Command Code's published GOAT plan table to fill in the missing details:
- Scraped metadata is cached at
~/.pi/agent/command-code-enrichment-cache.json(respects$PI_CODING_AGENT_DIR) with a 24-hour TTL. - The cache and live catalog are fetched lazily inside Pi's
refreshModels()callback (on first model use or/modelrefresh, bounded to 8s). - If the docs site is unreachable or times out, models fall back to safe defaults (zero cost, text only, no reasoning flag).
- No API key is ever sent to the docs site.
Two escape hatches:
# Point to a mirror/proxy if the docs page moves:
export COMMAND_CODE_ENRICHMENT_URL="https://mirror.example.com/goat"
# Skip scraping entirely and rely only on /models:
export COMMAND_CODE_NO_ENRICHMENT=1Command Code's docs table does not list Claude models, meaning they would default to reasoning: false and miss out on extended thinking.
The extension detects Claude-family model IDs (inferClaudeThinking() in src/core.mjs) and:
- Enables
reasoning: trueso Pi turns on extended thinking. - Emits a
thinkingLevelMapso Pi's thinking level picker exposes the top levels (xhigh/max):
| Model | reasoning |
thinkingLevelMap |
|---|---|---|
claude-opus-4-7*, opus-4.7* |
true |
{ xhigh: "xhigh" } |
claude-sonnet-4-6*, sonnet-4.6* |
true |
{ xhigh: "xhigh" } |
claude-opus-4-6*, opus-4.6* |
true |
{ xhigh: "max" } |
| Older Claude (Haiku, Sonnet 4.x) | true |
(None — budget-based thinking used) |
| Non-Claude models | Unchanged | Unchanged |
When an LLM response cuts off with finish_reason="length", Pi raises Response was truncated before completion. This often happens on DeepSeek V4 Flash, Kimi, and Claude with extended thinking because the reasoning tokens consume part of the output budget.
Per model, maxTokens is resolved in order (raise-only):
max_tokensfrom/models: The floor set by Command Code.- Per-model override: From
~/.pi/agent/command-code-model-overrides.json(can raise, never lower). COMMAND_CODE_DEFAULT_MAX_TOKENS: Global env var override.- Compile-time defaults:
131072(128k) for reasoning models,65536(64k) otherwise.
To raise the global default:
export COMMAND_CODE_DEFAULT_MAX_TOKENS=65536Create ~/.pi/agent/command-code-model-overrides.json (or under $PI_CODING_AGENT_DIR):
{
"deepseek/deepseek-v4-flash-latest": { "maxTokens": 65536 },
"Claude Sonnet 5": { "maxTokens": 32768 }
}- Keys can be the model ID or catalog display name (case- and whitespace-insensitive).
- Supports
maxTokensandcontextWindow(must be positive integers).
To send the x-cmd-zdr: 1 header on every request to Command Code:
export CMD_ZDR=1The extension prints concise, actionable diagnostics without ever logging your API key:
- **
Command Code: no API key found. Run \/login command-code` in Pi...** First-time setup or cleared credentials. Run/login command-codeor setCOMMAND_CODE_API_KEY`. Command Code: authentication failed (HTTP 401/403).
The API key was rejected by Command Code. Check your key and re-run/login command-code.Command Code: catalog fetch failed: ...
Network or parsing error reaching/models. Pi continues using the previously cached catalog, and will retry on the next refresh.Command Code enrichment failed: ... (using stale cached metadata | conservative defaults)
Failed to scrape the GOAT documentation page. Stale cached data or conservative defaults are used.
Run the test suite:
npm test106 unit tests (109 including the declaration-consistency tests), fully mocked HTTP, zero live API dependencies. Runs in ~300ms.
Run type-checking:
npm run typecheckNot affiliated with, endorsed by, or sponsored by Command Code. "Command Code",
and the model names referenced by its catalog, are trademarks of their
respective owners, used here only to describe what this extension interoperates
with. The command-code GOAT pricing table is read from a public Command Code
page; check that this fits their terms for your own use.
MIT © Joachim Stokke