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 Claude Opus 4.8, Claude Sonnet 4.5, and GPT-5.4, all with ITAR authorization on AWS GovCloud Bedrock. Opus 4.8 is authorized for ITAR only, so it uses the standalone:itar ID.
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’s Claude Sonnet 4.5 or GPT-5.4 with ITAR authorization on AWS GovCloud Bedrock; with the All models example it’s 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 (use the system role), supportsStrictMode: false, and thinkingFormat: "reasoning_effort" so reasoning is expressed as a reasoning_effort value.
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 every reasoning model uses the same thinkingLevelMap to translate Pi’s levels onto that set: off maps to none (turns reasoning off where the provider allows it), minimal maps to low, and the rest map to themselves. xhigh is honored only by models that advertise it (GPT-5.4 here); on the others the gateway clamps it down to that model’s maximum tier rather than erroring, so the one shared map is correct everywhere. Non-reasoning models (for example Gemini 3.1 Pro) omit both fields.
models[].contextWindow / maxTokens
: The model’s input context window and the maximum output tokens Pi requests per turn.
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. xhigh is fine on any model, since the gateway clamps it down to a model’s maximum tier.
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).