Skip to content

CoeOS box — the router

Your tools see a single model called CoeOS; behind it, the box sends each request to the model that benchmarked best on that kind of work, with your keys, and nothing leaves your network unless you pointed it there.

CoeOS is the AI operating system: Nemo, the desktop client, plus the CoeOS box, the router. This page is about the box (Odyssai-eu/coeos-box); it describes the code as it is, not a roadmap.

The box is a gateway with one address and two APIs, OpenAI-compatible and Anthropic-compatible. For each request it picks a competence axis, looks up the model your TMB Settings assign to it, and relays the call, with your keys, to the provider hosting that model: a local OdyssAI-X engine or a cloud endpoint. It does no inference itself.

TermWhat it is
Competence axisA benchmarked category of work: python, debug, legal_rgpd, creative, plan_spec, reasoning, fast_tools and the rest of the 18 competence axes of your TMB Settings.
TMB SettingsThe recipe: which model serves each axis, plus the regime (cloud / local), the default axis and the decider. One file ships with the box (TMB Settings — 100 % Cloud (best-of-all)); you can write your own.
ProviderWho hosts a model: openrouter (cloud, key required), odyssai (a local OpenAI-compatible engine such as OdyssAI-X, no key), or any provider you declare with an api_base and a key.

How the axis is chosen, in order:

  1. An explicit x-coeos-axis: <axis> header. The agent knows what it is doing; the box obeys.
  2. The decider, a small model you configure in the settings. Until you do, requests without an explicit header go to the default axis.
  3. The default axis (default_axis, code_general in the shipped file).

You can also name a model explicitly instead of CoeOS: or:<org/model> for OpenRouter, or a logical name from your registry.

Prerequisites: Docker, or Python 3.10 or newer.

Terminal window
git clone https://github.com/Odyssai-eu/coeos-box.git && cd coeos-box
docker compose up -d --build
curl -s http://localhost:4600/health

The box listens on 4600 and serves the same surface on 4800, where agent clients look for a control plane. /health reports ok, axes_bound, axes_servable and providers_ready; a fresh box answers "status": "setup" until a provider is ready, which is normal, not a fault. The console is at http://<host>:4600/dashboard.

Without Docker: pip install . then coeos-box (--host, --port, --console-port; 0 disables the second port).

Configuration lives in coeos-config.json (COEOS_CONFIG; in Docker /data/coeos-config.json on the ./data volume) next to the accounts database. Provider keys are encrypted at rest (Fernet) with COEOS_MASTER_KEY or a coeos-master.key file (mode 0600) generated beside the database; keep it out of the image and out of git.

As long as no key exists, the instance is open (convenient on localhost). From the first key issued, /v1/*, /admin/* and the console require a token, and administration requires an admin account, so create your first user with --admin or you lock yourself out:

Terminal window
python -m coeos.accounts create-user alice --admin --mode byok
python -m coeos.accounts issue-key alice --name laptop # prints ck_… once
python -m coeos.accounts list
python -m coeos.accounts revoke ck_1234

Tokens authenticate by SHA-256; an encrypted copy stays in the vault so the operator can read them back from the console. COEOS_API_KEY (in docker-compose.yml) is an alternative bootstrap, honoured as an implicit admin token.

Two account modes: byok, the account brings its own provider keys (PUT /v1/me/providers/{pid}), or platform, it uses the operator’s key. A non-admin account never falls back to the operator’s global key. Per-account quotas, requests per minute and tokens per day (COEOS_RPM_DEFAULT, COEOS_DAY_TOKENS_DEFAULT, or set-limits <user> --rpm N --day-tokens N), are counted locally (Usage tab, GET /v1/usage).

The odyssai provider ships empty and keyless; the address is yours to give:

Terminal window
curl -X PUT http://localhost:4600/admin/providers/odyssai \
-H 'content-type: application/json' \
-d '{"api_base":"http://<your-engine>:8000/v1"}'

Or use Providers in the console. The box sends OdyssAI-X the one reasoning flag it listens to (enable_thinking) and strips internal fields before relaying.

  • OpenRouter: paste the key in the console (Providers) or set OPENROUTER_API_KEY at first start.
  • Any OpenAI-compatible provider:
Terminal window
curl -X POST http://localhost:4600/admin/providers \
-H 'content-type: application/json' \
-d '{"id":"myprovider","label":"My provider","api_base":"https://api.example.com/v1","api_key":"…"}'

In Settings, import the shipped file or compose your own (PUT /admin/coeos with the file’s JSON does the same). One axis is one line, { "key": "python", "label": "Python / scripts", "model": "<registry id>" }. The registry (models) gives each model its name, provider and native id: "or": "moonshotai/kimi-k3" for OpenRouter, "endpoint": … for a local or declared provider. Routing table shows which model answers each axis and through which provider; Army lists the resolved fleet; PUT /admin/mapping/axis/{axis} reassigns one axis.

The shipped file is 100 % cloud. A 100 % local profile is composed by hand: declare your engine, register your models, assign them to axes. A hand-written setting needs nothing from us; that is tested.

One address, one token, one model.

Terminal window
export OPENAI_BASE_URL=http://<host>:4600/v1
export OPENAI_API_KEY=ck_…
ToolSetting
OpenAI SDK, Aider, Continue, Cline…base_url = http://<host>:4600/v1, model = CoeOS
Claude Code, Anthropic SDKANTHROPIC_BASE_URL=http://<host>:4600, key = your ck_ token; /v1/messages and count_tokens are translated (Opus/Sonnet names go to the router, Haiku names to the fast axis)
curlbelow
Terminal window
curl "$OPENAI_BASE_URL/chat/completions" \
-H "authorization: Bearer $OPENAI_API_KEY" \
-H 'content-type: application/json' \
-d '{"model":"CoeOS","messages":[{"role":"user","content":"Review this contract against the GDPR…"}]}'

Force the axis when the agent knows the step (faster, and safer): -H 'x-coeos-axis: legal_rgpd'.

Know who answered: read the x-coeos-axis, x-coeos-model and x-coeos-provider response headers; the Logs tab keeps them.

Reasoning: pass enable_thinking (or thinking / reasoning, per your SDK); the box translates it to each provider’s field name. If a model refuses no-think (“reasoning is mandatory”), the box replays without the flag instead of failing, flags it in an x-coeos-thinking header on non-streaming calls, and never swaps the model.

Nothing leaves your machine except the request to the provider you chose: no telemetry, no kill-switch, no mandatory call to us. Nine tests in tests/test_sovereignty.py fail if any of these gives way:

  • no notion of licence, expiry or activation anywhere in the code;
  • a box cut off from us still routes;
  • the only outbound addresses are your providers and, optionally, a settings channel you can switch off (COEOS_UPDATES_DISABLED=1);
  • an unreachable settings server is a non-event;
  • usage is metered for you, never reported;
  • what leaves the box contains none of your data;
  • you can reassign every axis without our tables, and a hand-written setting needs nothing from us.

Guardian, the confidential-content detector, is a separate sidecar; see its page.

SymptomLikely causeFix
503 on every axisthe axis’s model points to a provider with no address or no keyRouting table shows the failing axis; set api_base / the key, or reassign the axis
429 on one axisfree tier of a cloud modelreassign the axis to a paid or local model
empty answer from a local reasoning modelno-think was sent under the wrong field namemake sure the provider is odyssai (which gets enable_thinking) or declared with the right thinking_field
401 after creating a keythe instance locked itself (by design)use the ck_ token
403 admin key requiredthe token belongs to a non-admin accountissue a key for a user created with --admin
the console shows no local modelno api_base on odyssaisee “A local engine” above
AreaEndpoints
InferencePOST /v1/chat/completions, POST /v1/messages, POST /v1/messages/count_tokens, GET /v1/models, GET /v1/me, GET /v1/usage
Discovery (public)GET /health, GET /.well-known/coeos.json (profile and version), GET /.well-known/inference-engine.json (capability contract), GET /endpoints
Administration (admin token)/admin/providers[/{pid}] (declare, address, keys), /admin/providers/{pid}/test, /admin/platform/providers[/{pid}] (platform keys), /admin/coeos (import settings), /admin/settings*, /admin/mapping[/axis/{axis}], /admin/keys*, /admin/usage, /admin/army, /admin/coeos/decisions

This page follows the box guide at version 0.23.0.