deeprelay setup pi
Point Pi at deeprelay
Point Pi at deeprelay
Synopsis
Points Pi at deeprelay. After it runs, Pi lists deeprelay's models under the deeprelay provider and sends their requests to deeprelay's OpenAI-compatible /v1/chat/completions endpoint.
What it writes
Setup edits Pi's models.json: ~/.pi/agent/models.json, or models.json in the directory $PI_CODING_AGENT_DIR names. It changes one key, providers.deeprelay, and leaves the rest of the file alone. Comments, formatting and every other provider stay exactly as they were.
{
"providers": {
"deeprelay": {
"baseUrl": "https://api.deeprelay.ai/v1",
"api": "openai-completions",
"apiKey": "!'/usr/local/bin/deeprelay' auth token",
"models": [
{
"id": "deeprelay/deepseek-v4.1-flash",
"name": "deeprelay/deepseek-v4.1-flash",
"input": ["text"],
"contextWindow": 131072,
"maxTokens": 8192,
"reasoning": true,
"thinkingLevelMap": { "off": "none" }
}
]
}
}
}
models holds every model in deeprelay's list of models tested with coding agents, in that list's order. The IDs are exact deeprelay model IDs, because Pi sends them unchanged. contextWindow and maxTokens come from the deeprelay catalog. Setup leaves maxTokens out when the catalog does not list a maximum output.
reasoning and thinkingLevelMap also come from the catalog: from the reasoning effort levels a model accepts. If a model lists any, setup writes "reasoning": true. Pi offers /thinking levels, and asks for thinking, only for models marked this way. If the levels include none, setup also writes "thinkingLevelMap": {"off": "none"}, so /thinking off sends reasoning_effort: "none". Without the map, Pi sends no effort at all for off, and the model reasons at its default. A model that lists no levels gets neither key.
api is openai-completions, Pi's name for the Chat Completions format. baseUrl is the API base setup runs against (--api-base, or DEEPRELAY_API_BASE), always ending in /v1.
Your key never lands in a file
apiKey starts with !, which tells Pi to run the rest as a shell command and use what it prints as the key. The command is the absolute path of this deeprelay binary followed by auth token, so the key stays in the deeprelay credentials file (deeprelay login). It is not in models.json, the setup record or a backup, and there is no shell rc line to add. If you rotate the key, Pi's next request uses the new one.
The path is resolved when you run setup and quoted for the shell, so a path with spaces or quotes works. If you move or reinstall deeprelay somewhere else, run setup again. Run setup from an installed binary, not go run.
Setup uses this form because Pi's own source shows it is safe. Checked on 2026-10-07 against packages/coding-agent/src/core/provider-composer.ts and src/core/resolve-config-value.ts in the Pi repository (github.com/earendil-works/pi): Pi runs a models.json key command on each request and does not cache the result, so a failed run is retried next time. It keeps only the command's standard output, as the key, and discards its error output. If the command fails, Pi's error names the command, not anything it printed, and Pi does not log the key.
Pi gives the command 10 seconds. If deeprelay auth token fails (you are logged out, say), Pi reports that it could not resolve the API key for provider deeprelay. Run deeprelay login and try again.
Modes
- Default: writes the
deeprelayprovider. Asks before writing. --model: writes only that model instead of the curated list. It must exist on deeprelay and support tool calling.--print: writes nothing. It prints the config snippet, so you can merge it into the file yourself.--refresh: rewrites the models list andbaseUrlfrom the current list. It needs an earlier setup, and it shows a diff and backs up the file like setup does.--remove: undoes a previous setup (see below).--force: with--yes, replaces setup's entries even if you edited them (see below).
Setup writes the Chat Completions format only. Pi's anthropic-messages format is not offered, because a side-by-side test on 2026-10-07 found no difference: 32 runs of the same coding tasks through Pi, all correct in both formats, with no errors and the same turns and tokens.
Before anything is written
Setup resolves your key the way deeprelay auth token does: from DEEPRELAY_API_KEY if it is set, or else from the credentials file. It reads the model list from GET /v1/models and checks that each model exists and supports tool calling. It makes no billed call. If the API does not serve a recommended list, setup uses the list built into the CLI and says so.
Setup then shows a key-by-key diff and the undo command, and asks you to confirm. --yes skips the prompt for scripts. If stdin is not a terminal and you did not pass --yes, setup stops without writing. If nothing would change, setup says Pi is already configured.
Setup owns providers.deeprelay as a whole. If you edited it after setup (renamed a model, added a model of your own or changed baseUrl, say), a run asks before replacing your edit. --yes alone leaves the edited entry alone, writes everything else, and exits non-zero. --yes --force replaces it. Keep models of your own in a provider of your own under another name: setup never touches those.
The same applies the first time setup runs on a models.json that already has a hand-written providers.deeprelay whose model list differs from deeprelay's: the run asks, --yes leaves it and exits non-zero, and --yes --force replaces it (--remove then puts your version back).
If the file is not valid JSON or JSONC, setup stops with an error and writes nothing.
Windows is not supported yet; setup says so and writes nothing.
Backups and undo
Before each write, setup copies the existing file into backups/pi/ in the deeprelay config directory (the one holding your credentials file). A later run never overwrites an earlier backup. Setup also records what it added or changed, and the earlier values, in the setup directory next to it. No key is ever in either.
deeprelay setup pi --remove replays that record. providers.deeprelay is deleted if it still holds what setup wrote. If you edited it after setup, it is left alone with a warning. Running --remove again, or when setup never ran, reports "nothing to remove" and exits 0.
Default model
Setup does not change Pi's default model. After it runs, start Pi on a deeprelay model with:
pi --model deeprelay/deeprelay/deepseek-v4.1-flash
Pi reads and splits at the first slash, so the value is deeprelay/ followed by the full model ID. Setup prints this line for the first model on the list; a model covered by your plan comes first. To make it the default, run /model inside Pi, pick a deeprelay model and press Ctrl+S. Pick a single model at setup time with --model.
Examples
# Configure Pi (asks before writing)
deeprelay setup pi
# No prompt
deeprelay setup pi --yes
# Only one model
deeprelay setup pi --model deeprelay/deepseek-v4-pro
# Print the snippet
deeprelay setup pi --print
# Update the model list from the catalog
deeprelay setup pi --refresh
# Replace setup's entries even though you edited them
deeprelay setup pi --refresh --yes --force
# Undo
deeprelay setup pi --remove
deeprelay setup pi [flags]
Options
--force With --yes, replace a setup-owned entry you have edited since the last run
-h, --help help for pi
--model string Use this model instead of the curated list
--print Print the config snippet and export line instead of writing any file
--refresh Re-sync the configured models from the curated list
--remove Undo a previous setup entry by entry
--yes Apply without the confirmation prompt (warnings still print)
Options inherited from parent commands
--api-base string API base URL (override with DEEPRELAY_API_BASE env) (default "https://api.deeprelay.ai/v1")
--debug Enable debug logging to stderr
--no-preflight Skip the plan/credit check before inference requests (override with DEEPRELAY_NO_PREFLIGHT env)
-o, --output string Output format: table|json (default table on TTY, json otherwise) (default "table")
SEE ALSO
- deeprelay setup - Configure coding agents to use deeprelay