Docs

Junie CLI

Junie CLI takes a custom endpoint as a JSON file, not a settings screen. Nine lines in $JUNIE_HOME/models/kunavo.json and junie --model custom:kunavo is running Claude and GPT through one key — with the helper traffic pointed somewhere cheap.

Junie CLI takes a custom endpoint as a JSON profile in $JUNIE_HOME/models/, where baseUrl is the complete endpoint URL and fasterModel decides where its helper traffic lands.

$JUNIE_HOME/models/kunavo.json — or .junie/models/kunavo.json
{
  "id": "claude-sonnet-5",
  "baseUrl": "https://api.kunavo.com/v1/chat/completions",
  "displayName": "Kunavo",
  "providerName": "Kunavo",
  "apiType": "OpenAICompletion",
  "apiKey": "${KUNAVO_API_KEY}",
  "fasterModel": {
    "id": "claude-haiku-4-5"
  }
}
baseUrl is the complete endpoint, path and all. JetBrains states it plainly: “The baseUrl is used as the complete endpoint URL — Junie does not append a path to it,” and tells you to “set it to the full endpoint for your chosen apiType”. So this field is neither the origin nor the /v1 root that most clients want — it is https://api.kunavo.com/v1/chat/completions. Stopping at https://api.kunavo.com/v1 is the single most likely way to get a 404 out of an otherwise correct profile.
A missing environment variable fails the whole profile, not the request. apiKey and extraHeaders values take $${VAR_NAME} references, and JetBrains documents the failure mode exactly: “If a referenced environment variable is not set, the profile fails to load and Junie reports an error identifying the missing variable.” Export KUNAVO_API_KEY before starting Junie — the profile is read at load time, not at first request, so a shell that lost the export shows up as a profile that vanished from /model rather than as a 401.
fasterModel is where Junie sends work you did not ask for. JetBrains describes it as “The model used for internal helper tasks like summarizing context or classifying tasks”, and says that if primaryModel or fasterModel “is not explicitly defined, they inherit the top-level properties”. A profile with no fasterModel block therefore bills its housekeeping at your main model's rate. The one-line override above is the whole fix, and it is why the block is in the minimal config rather than in an appendix.
This profile is derived from JetBrains' published schema, read on the date below. Kunavo has not run Junie CLI against its endpoint — not a session, not a streamed turn, not a tool round-trip, and no client build has been pinned and accepted. A published setup page is not a test, and nothing here should be read as one. The curl below is the part you can settle in ten seconds; how Junie behaves on top of it is between you and JetBrains.

Step by step

  1. Create a key at /app/keys and copy it — it is shown once. Export it as KUNAVO_API_KEY in the shell you will start Junie from, or put a literal key in the file instead; JetBrains notes that “Values without any $${...} reference are used as-is”.
  2. Save the JSON above as $JUNIE_HOME/models/kunavo.json for your account, or .junie/models/kunavo.json to share it with a repository. The filename without .json becomes the profile id — that is what makes the selector below read custom:kunavo.
  3. Set id to the model id you actually want. It is described as “The model identifier as expected by the API endpoint”, so a Kunavo slug from the table below goes straight in; the ids are resolved at the endpoint, not inside Junie.
  4. Start Junie and pick the profile: junie --model custom:kunavo, or the /model command in an interactive session. Custom models “appear in the model selection list after the built-in providers”.
  5. Give it a task that edits a file rather than a greeting. Junie is an agentic client and leans on tool calling for almost everything it does, so a first run that reads and writes something tells you far more than a single reply does.

Checked against JetBrains’ Custom LLMs page for Junie 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.

This is the short version. The full walkthrough — model choice, what a real session costs, and the failure modes — is in Junie CLI vs Claude Code — the endpoint-boundary comparison.

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 Junie CLI.

# 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 idKunavo in / outWhere it fits in Junie CLI
claude-sonnet-5$2.00 / $10.00the primaryModel for ordinary work — tasks that edit files
claude-opus-5$2.00 / $10.00a plan that would be expensive to get wrong, pinned per session
claude-haiku-4-5$0.40 / $2.00the fasterModel role: summarizing context, classifying tasks
gpt-5-6-sol$2.00 / $12.00a second opinion from another family — a second profile, same key
Billing is per token from a prepaid balance with no monthly fee — see billing. On repeated context — which is most of what an editor or a chat client sends — prompt caching moves the bill more than the model choice does.

The other two apiType values Kunavo answers

apiType names a request format, not a vendor, and Junie accepts four values: OpenAICompletion, OpenAIResponses, Google and Anthropic. Kunavo serves three routes, so two of the other three values have a matching baseUrl here — and because Junie appends no path, changing the format means changing the URL in the same edit:

  1. "apiType": "OpenAICompletion" with https://api.kunavo.com/v1/chat/completions — the profile above, and the one this page recommends because the route is the most widely exercised of the three.
  2. "apiType": "Anthropic" with https://api.kunavo.com/v1/messages — Kunavo answers the Messages format on that path.
  3. "apiType": "OpenAIResponses" with https://api.kunavo.com/v1/responses.

Which of the three Junie drives best for a given model is exactly the kind of question a runtime test answers and a documentation read does not, so this page does not rank them beyond that first line. Pick one, keep the URL and the apiType in step, and if a key-set profile comes back 401, make the credential explicit rather than guessing at Junie's header: JetBrains documents apiKey only in the negative — “If omitted, requests are sent without an Authorization header” — and never states the scheme used when it is present. extraHeaders is documented as “additional HTTP headers to include in every request” and takes the same $${VAR} references, which makes "extraHeaders": {"Authorization": "Bearer $${KUNAVO_API_KEY}"} the unambiguous form.

FAQ

How do I add a custom provider to Junie CLI?

Junie CLI reads custom providers from JSON profiles rather than from a settings screen. Put a file in $JUNIE_HOME/models/ for your account or .junie/models/ inside a project; the filename without the .json extension becomes the profile id. The required keys are id, baseUrl and apiType, with apiKey, displayName, providerName, extraHeaders, extraBody, temperature, maxContextLength, primaryModel and fasterModel optional. Then select it with `junie --model custom:<id>` or the /model command — custom models appear in the list after the built-in providers.

Does Junie CLI's baseUrl need /v1 or the full path?

The full path. JetBrains states that the baseUrl is used as the complete endpoint URL and that Junie does not append a path to it, and tells you to set it to the full endpoint for your chosen apiType. For an OpenAICompletion profile against Kunavo that is https://api.kunavo.com/v1/chat/completions — not the origin, and not the /v1 root that clients like Kilo Code want. Both example profiles in JetBrains' own documentation carry a complete path for the same reason.

Why does Junie say a profile failed to load with a missing environment variable?

Because apiKey and extraHeaders values support ${VAR_NAME} references, and JetBrains documents that if a referenced environment variable is not set, the profile fails to load and Junie reports an error naming the missing variable. Resolution happens when the profile is loaded, so the symptom is the profile disappearing from the model list rather than a failed request. Export the variable before starting Junie, or replace the reference with a literal value.

Can Junie CLI use its own BYOK key with a gateway like Kunavo?

The BYOK screen and a custom profile are two different routes. JetBrains' BYOK page covers connecting a named provider — OpenAI, Anthropic, Google, xAI, OpenRouter or GitHub Copilot — through /account or "Use your own API key" on the welcome screen, and states that all usage is billed by the provider with no JetBrains AI subscription required. An endpoint that is not on that list, Kunavo included, goes in as a custom LLM profile instead, which is the JSON file on this page. Bringing your own key is a Junie CLI capability: JetBrains' plugin documentation states it is not supported via the Junie plugin.

Why is Junie calling a model I did not select?

Junie splits a profile into two roles, and fasterModel is documented as the model used for internal helper tasks such as summarizing context or classifying tasks. If you do not define that block, JetBrains states that the roles inherit the top-level properties — so the helper traffic runs on your primary model and bills at its rate. Setting fasterModel.id to a cheaper id, as in the profile on this page, is the lever; the top-level baseUrl, apiType and apiKey are inherited by both roles, so only the id has to change.

Has Kunavo tested Junie CLI?

No. What was checked, on September 21 2026, is JetBrains' own Custom LLMs documentation — the field names, their order, the accepted apiType values and the complete-endpoint rule are quoted from it. Kunavo has not installed Junie CLI, pinned a build or sent a request through it, and makes no claim here about streaming, tool round-trips or model routing inside the client. The one thing you can settle in isolation is whether the endpoint and key work at all, which the curl on this page does.