Docs
Oh My Pi
Oh My Pi keeps its providers in one YAML file. Three lines under a name you choose — baseUrl, api, apiKey — and omp is routing to Claude, GPT and Gemini through a single key, with the model list fetched rather than typed.
A provider block in ~/.omp/agent/models.yml — baseUrl, api, apiKey — points Oh My Pi at Kunavo, and discovery fills the model list from GET /v1/models.
providers:
kunavo:
baseUrl: https://api.kunavo.com/v1
api: openai-completions
apiKey: KUNAVO_API_KEY # an env-var name; literal text also works
discovery:
type: openai-models-list # reads GET /v1/models
# Prefer a fixed list to a discovered one? Drop the discovery block and
# declare ids instead. Omitted metadata defaults to a 128,000-token context
# window and a 16,384-token output limit, so set the real numbers from
# /models when they differ.
#
# models:
# - id: claude-sonnet-5
# name: Claude Sonnet 5
# contextWindow: ...
# maxTokens: .../v1. omp documents baseUrl as the “Endpoint root” and openai-completions as “OpenAI-compatible Chat Completions”, and its own 404 troubleshooting entry reads “Generic OpenAI-compatible base URLs commonly end in /v1”. Every custom-provider example on both pages ends the same way. “Commonly” is their hedge, not a guarantee — but Kunavo serves /v1/chat/completions, so https://api.kunavo.com/v1 is the root that produces it. This is the opposite of the Anthropic-style clients, which want the bare origin.authHeader out on this route. omp documents it as being for a gateway that “specifically needs Authorization: Bearer injected as an ordinary header”, and notes that “standard provider clients already apply their normal authentication scheme” — which the OpenAI-compatible client does, and Kunavo accepts. Add it only if you see a 401 that the curl below does not reproduce.curl below is the part you can settle in ten seconds; the rest is between you and omp.Step by step
- Create a key at
/app/keysand copy it — it is shown once. - Export it as
KUNAVO_API_KEYin the shell that starts omp. omp resolvesapiKeyas an environment-variable name first and falls back to treating the text as the literal key, so a typo in the variable name loads quietly and fails at the first request. A value beginning with!is run as a shell command instead — that is the 1Password-style route. - Put the block above in
~/.omp/agent/models.yml. The provider id —kunavohere — is yours to choose and becomes the first half of every selector. - Run
omp models kunavoto load the file and list just this provider. A YAML or schema problem printsmodels.yml validation failedand the field that failed;omp models refresh kunavoforces a fresh discovery call instead of using the cached catalog. - Exercise it with an exact selector:
omp -p --model kunavo/claude-sonnet-5 "Reply with only OK". Then startomp, type/model, and assign the id you want to Default — the model hub reloadsmodels.ymlwhen it opens./switchchanges only the current session.
Checked against omp's Providers page on September 21, 2026. Third-party settings move; if a field name here no longer matches what you see, that page is the authority, not this one.
Verify before you debug the client
One request settles whether a failure is the endpoint, the key, or the configuration file. If this returns JSON, the same base URL and key work in Oh My Pi.
# Settles whether a failure is the endpoint, the key, or the client.
curl -sS https://api.kunavo.com/v1/models \
-H "Authorization: Bearer sk-kn-..."Which model id to put in the field
Every text model is reachable as a model id — the live list is GET /v1/models, and the catalog with prices is on the models page. Rates are USD per 1M tokens, input / output.
| Model id | Kunavo in / out | Where it fits in Oh My Pi |
|---|---|---|
claude-sonnet-5 | $2.00 / $10.00 | the default role — the model most sessions actually run on |
claude-opus-5 | $2.00 / $10.00 | the plan role, where a wrong plan costs more than the tokens |
claude-haiku-4-5 | $0.40 / $2.00 | the smol role: triage, summaries, the calls that never stop |
gpt-5-6-sol | $2.00 / $12.00 | a second opinion from another family, same provider block |
Discovery: which type, and what lands in the picker
omp offers six discovery.type values and two of them look right for a gateway. Only one is. proxy is documented for “a mixed OpenAI/Anthropic proxy whose model rows advertise supported_endpoint_types”, and it derives each model's wire from that field. Kunavo's GET /v1/models does not publish it, so under proxy every row would fall back to the provider-level api — or, with none set, be dropped. openai-models-list, documented as “a generic OpenAI-compatible GET /v1/models endpoint”, is the one to use, and it is why the block above keeps api: openai-completions: omp's rule is that “except for proxy, discovery requires provider-level api”.
One consequence worth knowing before you open the picker. Kunavo's model list is the whole enabled catalog, so a discovered provider surfaces image, video and music ids alongside the chat ones, and the chat transport cannot call those. Kunavo publishes context_length on chat rows — which is the field omp's generic discovery reads after max_model_len, per its models documentation — but omits it on the media rows, so those arrive with omp's 128,000-token default rather than a real number. If you want a short, correct picker, drop the discovery block and declare the three or four ids you actually use.
omp can also speak anthropic-messages, and Kunavo answers /v1/messages. This page does not print a config block for that pairing: the two pages cited here settle the base-URL form for the OpenAI-compatible route and say nothing about how a trailing /v1 is treated on the Anthropic one, and the whole point of a config block is that a reader can paste it. If you go that way,disableStrictTools: true is the documented answer to tool calls failing with a 400 on an Anthropic-compatible endpoint.
FAQ
How do I add a custom API provider to Oh My Pi?
Everything happens in ~/.omp/agent/models.yml. Add a key under `providers:` — the name is yours and becomes the provider half of the selector — and give it baseUrl, api and apiKey, which is the order omp's own "Add a custom provider" example uses. Either list the models by hand under `models:` or add a `discovery:` block and let omp fetch them. Then run `omp models <your-provider-id>` to confirm the file loaded, and select a model with `omp --model <provider>/<model-id>` or the /model hub inside a session.
Does the Oh My Pi baseUrl need /v1 at the end?
For an OpenAI-compatible endpoint, yes. omp calls baseUrl the endpoint root and appends the route for the api family you declare, so `api: openai-completions` means it asks for chat completions under whatever root you gave it. Its own troubleshooting note for a 404 says generic OpenAI-compatible base URLs commonly end in /v1, and every custom-provider example in its documentation does. Kunavo serves /v1/chat/completions, so the root to write is https://api.kunavo.com/v1 — a missing /v1 shows up as a 404 or an "unsupported endpoint", not as an authentication error.
Where does Oh My Pi look for the API key, and what wins?
An apiKey in models.yml is resolved in three steps: a value starting with ! is run as a shell command and its trimmed stdout is used, otherwise omp looks for an environment variable with exactly that name, and if there is none it treats the text itself as the key. That last fallback is the trap — a misspelled variable name loads without complaint and fails at the first request. In the wider precedence order a models.yml key beats stored OAuth, which omp documents as deliberate, so a key supplied for a gateway is not overwritten by an upstream login.
Which discovery type should a gateway use in omp?
openai-models-list, not proxy, unless the gateway advertises supported_endpoint_types on each model row — that field is what proxy reads to decide whether a model goes to /v1/messages or /v1/chat/completions, and without it models fall back to the provider-level api or are dropped. Kunavo's /v1/models does not publish that field, so the generic OpenAI list is the right type, and omp requires a provider-level api for every discovery type except proxy. Run `omp models refresh <provider>` to force a fresh fetch rather than using the cached catalog.
Has Kunavo tested Oh My Pi against its endpoint?
No. What was checked, on September 21 2026, is omp's own documentation — the field names, their order, the key-resolution rule and the discovery types are quoted from it, and two details were checked against Kunavo's own /v1/models route rather than assumed. No omp session has been run against api.kunavo.com here, and no claim is made about streaming, tool round-trips or model routing inside the client. The one thing that can be settled in isolation is whether the endpoint and key work at all, which the curl on this page does.