Before you start
You need a Consus API key from your Consus admin. Installing Pi and creating its config are covered in the steps below.Step 1: Install Pi
Install with the official script:Step 2: Bootstrap the config directory
Pi reads custom providers from~/.pi/agent/models.json. Launch Pi once to create the ~/.pi/agent/ directory, then exit with Ctrl+C:
Step 3: Set your Consus API key
Export your key in your shell profile (~/.zshrc or ~/.bashrc) so Pi can read it at launch:
<CONSUS_API_KEY> with your actual key, then source ~/.zshrc (or source ~/.bashrc).
Step 4: Create ~/.pi/agent/models.json
Create the file:
models array: one scoped to ITAR / export-controlled data, one listing a broad set of models across compliance levels. Use whichever matches your authorization, or adapt the model list to your classification. Do not mix levels within a single file.
Example: ITAR
Use this when handling ITAR / export-controlled data. It exposes every model with ITAR authorization: Claude Opus 5, Claude Opus 4.8, Claude Sonnet 5, Claude Sonnet 4.5, Grok 4.6, GPT-5.4, GPT-5.6 Terra, GPT-5.6 Luna, and GPT OSS 120B on AWS GovCloud Bedrock, plus GPT-5.1 and GPT-5.6 Sol on Azure Government OpenAI. Opus 4.8 and Grok 4.6 are offered for ITAR only, and Opus 5’s ITAR traffic is served from Bedrock, so those use the standalone:itar ID (Opus 5’s FedRAMP-level IDs route to Vertex AI instead).
Both examples are generated from the gateway’s model catalog, so context windows, output limits, and per-token cost match what the gateway enforces and bills. Pi uses the cost block to show a running spend estimate per session.
models.json (ITAR)
models.json (ITAR)
Example: All models
Lists the models people actually reach for, spanning several compliance levels so you can pick or switch from Pi’s picker with/model (or Ctrl+L) mid-session. Each id carries its own level; trim this list, or swap the levels (:il5+itar, :itar, :il2, :il4, :fedramp-high, and so on), to match your data classification and authorization.
models.json (all models)
models.json (all models)
This is a starting point. Trim it to the models you actually use, or add any other authorized model with the same shape. Run
curl -H "x-api-key: $CONSUS_API_KEY" https://api.consus.io/v1/models to list every composite ID available to your key. Every id must carry a compliance level (e.g. :fedramp-high, :il5, :itar); a bare model name is rejected with a 400.Step 5: Start your session and pick a model
/model (or Ctrl+L) and select one of the Consus models you defined. Pi reloads models.json every time you open the picker, so you can edit the file and re-open /model without restarting.
Step 6: Verify
Ask Pi to do something real:x-consus-served-model confirms which model served each successful request.
What gets served
Every request from Pi (coding turns, reasoning, tool use) is served by the model you select in the picker. With the ITAR example that is one of the ITAR-authorized models on AWS GovCloud Bedrock or Azure Government OpenAI; with the All models example it is whichever model you pick, at the compliance level set in its ID. The gateway routes each request to whichever government-authorized provider hosts that model at the requested compliance level (AWS GovCloud Bedrock, GCP Assured Workloads Vertex AI, Azure Government OpenAI); the compliance boundary is enforced at the gateway architecture level. Pi talks to the gateway over the OpenAI-compatible Chat Completions API. For the full request/response surface (multimodal input, streaming behavior, tool-use shape), seePOST /v1/chat/completions.
What each setting does
baseUrl
: Routes Pi’s requests to the gateway’s OpenAI-compatible endpoint (https://api.consus.io/v1).
api
: openai-completions tells Pi to use the Chat Completions wire format, which the gateway exposes for every provider (Anthropic, OpenAI, Google).
apiKey
: A non-empty placeholder ("consus"). Consus authenticates with the x-api-key header, not Authorization: Bearer, so the real key is supplied via headers below. Do not set authHeader: true; a Bearer token is rejected with a 403.
headers."x-api-key"
: Sends your Consus key on every request. $CONSUS_API_KEY is resolved from the environment (Step 3).
compat
: Tunes the wire format for the gateway. supportsStore: false (the gateway is zero-persistence), maxTokensField: "max_tokens" (not max_completion_tokens), supportsDeveloperRole: false (the gateway accepts system, user, assistant, and tool roles only), supportsStrictMode: false, and thinkingFormat: "openai" so reasoning is sent as a top-level reasoning_effort value. Pi rejects thinkingFormat values outside its documented set, so do not substitute another name.
models[].id
: The composite model ID Pi sends to the gateway. Must include a :level suffix.
models[].reasoning / thinkingLevelMap
: reasoning: true marks a model as supporting extended thinking. The gateway accepts only none, low, medium, high, and xhigh for reasoning_effort (any other token, including minimal, is a 400), so each reasoning model carries a thinkingLevelMap that translates Pi’s levels onto that set: off maps to none (turns reasoning off where the provider allows it), minimal maps to low, and low through high map to themselves. xhigh maps to "xhigh" only on models that advertise it (Grok 4.6, GPT-5.4, GPT-5.6 Sol/Terra/Luna); on every other model it is set to null, which hides the level from Pi’s picker. The gateway would clamp an xhigh request down to the model’s maximum anyway, so hiding it only keeps the picker honest. Pi’s max level is left unmapped and therefore unavailable. Non-reasoning models (Gemini 3.1 Pro, Gemini 3 Flash, GPT-4.1) have reasoning: false and no map.
models[].input
: Pi accepts only text and image here. Claude and Gemini models also accept PDFs through the gateway, but Pi has no PDF input type, so it is omitted.
models[].contextWindow / maxTokens
: The model’s input context window and the maximum output tokens Pi requests per turn, taken from the gateway catalog. Setting maxTokens above a model’s cap returns a 400 from the provider.
models[].cost
: Per-million-token rates (input, output, cacheRead) at gateway prices, used for Pi’s session cost display. cacheWrite is 0 because the gateway does not bill cache writes separately. This is a client-side estimate; the Consus portal is the billing record.
Troubleshooting
401 Unauthorized: x-api-key is missing or wrong. Verify echo $CONSUS_API_KEY returns your key in the same shell you launched pi from, and that the headers."x-api-key" line in models.json is present.
403 Forbidden: A Bearer token reached the gateway. Make sure authHeader is not set to true in your provider block; Consus authenticates only via x-api-key.
400 ... compliance level required: A model id is missing its :level suffix (e.g. claude-opus-4-8 instead of claude-opus-4-8:fedramp-high). Add the level your authorization requires.
400 invalid_request_error mentioning reasoning_effort: A thinkingLevelMap value is outside the accepted set. Use only none, low, medium, high, or xhigh; anything else (such as minimal) is rejected. A level you want to hide should be null, not an invented token.
Invalid models.json schema on launch: Pi validates the file against its schema. The usual cause is a thinkingFormat value outside Pi’s list (use "openai"), an input entry other than text or image, or a thinkingLevelMap key outside off, minimal, low, medium, high, xhigh, max.
400 / thinking-budget errors at high effort: A model’s thinking budget can exceed maxTokens, which some providers reject. Raise maxTokens for that model or lower the reasoning effort.
Model not appearing in /model: models.json didn’t parse. Validate it with python3 -m json.tool ~/.pi/agent/models.json, fix any error, and re-open the picker (Pi reloads the file each time).