Skip to content

Connect a client

Any client that speaks the OpenAI Chat Completions API (or the Responses API) can use ignis. Three settings are all it needs: a base URL, an API key if you set one, and a model id.

Where the client runs Base URL
On the same machine http://127.0.0.1:8000/v1
In a container started with -p 8000:8000 the same, on the host’s address

The server listens on 127.0.0.1:8000 by default (--server-bind, IGNIS_SERVER_BIND), so another machine reaches it only if you bind a wider address; the container image binds 0.0.0.0:8000 (Model and server). The routes are listed in The API; /v1/docs/ on the running server is the generated reference.

With no key set, /v1 needs none, and any value a client insists on sending is accepted. To require one:

ignis-server --server-api-key sk-... # or IGNIS_SERVER_API_KEY=sk-...
ignis-server --server-api-key auto # generate one and print it

Clients then send Authorization: Bearer sk-...; a request without it is refused 401 and loads nothing. The Playground’s static pages and /v1/docs/ stay open. /ui/metrics is behind the key like /v1 (Access).

The id a request names is the served id: qwen3.8-27b unless you started another model. GET /v1/models shows it first (data[0], active: true). A request that names no model is served by the loaded one, which is what the Playground does. A request that names another model the server lists switches the server to it; see the caution below.

Terminal window
curl http://127.0.0.1:8000/v1/chat/completions \
-H 'Content-Type: application/json' \
-H "Authorization: Bearer $IGNIS_SERVER_API_KEY" \
-d '{"model":"qwen3.8-27b","messages":[{"role":"user","content":"Hello"}],"max_tokens":256}'

Drop the Authorization header when no key is set. Streaming, the agent lane and the Responses API are in the examples.

from openai import OpenAI
client = OpenAI(base_url="http://127.0.0.1:8000/v1", api_key="sk-...")
reply = client.chat.completions.create(
model="qwen3.8-27b",
messages=[{"role": "user", "content": "Hello"}],
max_tokens=256,
)
print(reply.choices[0].message.content)
import OpenAI from "openai";
const client = new OpenAI({ baseURL: "http://127.0.0.1:8000/v1", apiKey: "sk-..." });
const reply = await client.chat.completions.create({
model: "qwen3.8-27b",
messages: [{ role: "user", content: "Hello" }],
max_tokens: 256,
});
console.log(reply.choices[0].message.content);

With no key set on the server, api_key / apiKey still has to be a non-empty string for the SDK; ignis ignores it.

Both SDKs honour Retry-After on a 503. That is how a client rides out engine_full (every lane busy) and model_switching: the header is 1 to 60 seconds, 60 being the most the OpenAI SDK waits (The API). The Responses API works through responses.create, and its WebSocket mode through responses.connect (Responses).

A request field ignis cannot honour is a 400 naming it in param, not a silent drop; if an SDK sends one, that error says which (Chat completions).

Point the agent’s OpenAI-compatible provider at the base URL above, give it the key if you set one, and name the served id as its model. For opencode, a provider in opencode.json:

{
"$schema": "https://opencode.ai/config.json",
"provider": {
"ignis": {
"npm": "@ai-sdk/openai-compatible",
"name": "ignis (local)",
"options": { "baseURL": "http://127.0.0.1:8000/v1" },
"models": { "qwen3.8-27b": { "name": "Qwen3.8-27B", "tool_call": true } }
}
},
"model": "ignis/qwen3.8-27b",
"small_model": "ignis/qwen3.8-27b"
}

With a key, add "apiKey": "{env:IGNIS_SERVER_API_KEY}" to options. Both model and small_model name the same id, for the reason below.

Two things matter for agents:

  • Subagents. A request can state its lane as class: "agent" or as an @agent suffix on the model name (qwen3.8-27b@agent). An agent request never displaces an interactive one when the KV pool is full (KV pool).
  • Long reasoning. Absent max_tokens, a request generates at most --model-default-max-tokens (38,912) tokens, reasoning included, and ends with finish_reason: "length" at that point (Chat completions).

The same holds for any front end that picks ids from GET /v1/models, which lists every servable model.

Add ignis as an OpenAI-compatible connection with the base URL above (and the key). The front end then lists the models from GET /v1/models: the loaded one first, then every model a request naming it would switch to.

The Playground never causes this: its chat and Decide requests name no model, and it switches only when you ask it to (Load on the Server view, the image tools, the model picker under the prompt box) (Get a model, Switching models).