Pi.
Pi is a deliberately small terminal agent: a minimal shell that adapts to how you work instead of imposing how it works. It speaks the OpenAI format, so NaN goes in as one more provider.
It installs with curl -fsSL https://pi.dev/install.sh | sh, or on Windows with powershell -c "irm https://pi.dev/install.ps1 | iex".
You can skip all of this
The NaN CLI writes this configuration for you: Setup tab, e to paste your key, space to mark Pi, c to apply.
Configuration
Declare the provider
In ~/.pi/agent/models.json:
{
"providers": {
"nan": {
"baseUrl": "https://api.nan.builders/v1",
"api": "openai-completions",
"apiKey": "sk-your-key",
"compat": { "supportsDeveloperRole": true },
"models": [
{
"id": "deepseek-v4-flash",
"name": "DeepSeek V4 Flash",
"reasoning": true,
"input": ["text", "image"],
"contextWindow": 1048576,
"maxTokens": 32768
},
{
"id": "glm5.3-flash",
"name": "GLM 5.3 Flash",
"reasoning": true,
"input": ["text", "image"],
"contextWindow": 1048576,
"maxTokens": 32768
},
{
"id": "qwen3.8-flash",
"name": "Qwen 3.8 Flash",
"reasoning": true,
"input": ["text", "image"],
"contextWindow": 1048576,
"maxTokens": 32768
},
{
"id": "mimo-v2.6-flash",
"name": "Xiaomi MiMo V2.6 Flash",
"reasoning": true,
"input": ["text", "image"],
"contextWindow": 1048576,
"maxTokens": 32768
},
{
"id": "gemma4",
"name": "Gemma 4",
"reasoning": true,
"input": ["text", "image"],
"contextWindow": 262144,
"maxTokens": 65536
},
{
"id": "qwen3.6",
"name": "Qwen 3.6",
"reasoning": true,
"input": ["text", "image"],
"contextWindow": 262144,
"maxTokens": 65536
},
{
"id": "glm5.3",
"name": "GLM 5.3 (premium)",
"reasoning": true,
"input": ["text", "image"],
"contextWindow": 1048576,
"maxTokens": 32768
}
]
}
}
}This is the config for the 7 LLM models NaN serves: deepseek-v4-flash, glm5.3-flash, qwen3.8-flash, mimo-v2.6-flash, gemma4, qwen3.6 and glm5.3. It is the same set the NaN CLI writes, and the same one the OpenCode page publishes.
api: "openai-completions" is what tells Pi which format to speak. maxTokens is the ceiling for one answer, not the context. It is the same figure the OpenCode block publishes as limit.output, because it answers the same question.
Make it the default
In ~/.pi/agent/settings.json:
{
"defaultProvider": "nan",
"defaultModel": "glm5.3-flash"
}This step is not optional
Without defaultProvider and defaultModel, Pi keeps using its factory provider and what you get is a 401. It is the most common failure when connecting it, and the error message does not say this file is the problem.
Try it
piAsk it for something short. If it answers, it is going out through the cluster. You can switch models mid-session without leaving the agent.
Recommended model
glm5.3-flash for coding work. deepseek-v4-flash for everything else, which also has the widest quota on the cluster.
Known issues
- The key is written in the file.
models.jsonlives in your home directory, so it does not usually end up in a repository, but keep it in mind if you sync your configuration between machines. maxTokensis not the context. It is the ceiling for each answer. Reasoning comes out of that same budget, so if you ask for long reasoned answers, raise it.- The models you declare are the ones you get. Pi does not ask the cluster what is available: it shows whatever is on the list.
mimo-v2.6-flashgoes in without its audio, andglm5.3without its audio and video. Pi’s schema accepts"text"and"image"forinputand nothing else, and a third value does not fail that one model: Pi refuses the whole file, every other provider in it included. Both models still take them through the API, just not from inside Pi.glm5.3needs a key on the premium tier. It is on the list so that a member who has it can see it. Without that tier the answer is a401, which is explained in Choose your model.