Skip to content

DocsHow-to guides

4 min read · updated

Operate

Keep a decisio server up, know at a glance when it is not, and secure what sits in front of it.

Wait until a server is ready, then read what it serves:

until curl -sf http://127.0.0.1:8000/health > /dev/null; do sleep 5; done
curl -s http://127.0.0.1:8000/health

Run against the CPU stand-in at v0.35.0 on 2026-10-26.

Figure · When the engine dies

A dead engine does not serve again: the server says so, exits, and your supervisor starts a new one.

An error caused by the request itself, such as a 422, does not probe the engine.

Source: docs/running.md "When the engine dies" at the pinned release.

When its engine dies, the server exits with code 70 and leaves the restart to whatever runs it.

SupervisorSettingThe full file
Docker Composerestart: unless-stoppedWith Docker
systemdRestart=on-failure, TimeoutStartSec=infinityOn a cloud GPU
KubernetesrestartPolicy: Always, a liveness probe on /healthOn a cloud GPU
  • Give the first start time. It downloads the weights: allow 45 minutes, as the image’s own health check does.
  • Keep the weights on a volume, so a restart does not download them again.
  • Requests sent while the new server loads are refused, so retry them in your client.
WatchWhereWhat a bad value means
The status of /healthGET /healthanything but 200: alert; 503 means the engine has died
The exit codeyour supervisor70: the engine died and the server ended itself
Server timethe x-decisio-server-ms headerthe server’s time for the request, without the network
Queueingwait in the x-decisio-stages headera growing wait is requests queueing behind the one engine
What answeredthe x-decisio-tasks and x-decisio-adapter headerswhich taught task answered, and the adapter if the server serves one (--adapter)
Certified tasksGET /metricssee Watch for drift

Ask one question and print what it cost:

curl -s -D - -o /dev/null http://127.0.0.1:8000/v1/systemone \
-H 'Content-Type: application/json' \
-d '{"state": "Both charges are 49.00 EUR, same day. Please refund one.", "questions": {"urgent": {"type": "noul"}}}' \
| grep -i '^x-decisio'

Run against the CPU stand-in at v0.35.0 on 2026-10-26. It printed, trimmed to the fields this page uses:

x-decisio-server-ms: 754.3
x-decisio-route: text
x-decisio-stages: prepare=0.7;warm=0.0;engine=753.8;wait=0.0
  • The server runs one engine; concurrent requests queue behind it and are answered in turn, first come, first served, with no queue limit. Batch concurrent requests scores the waiting ones together instead.
  • There are no engine metrics and no structured log: take latency and queueing from the headers, in your client or your proxy’s log.
  • After a deploy, read /health for the model, its checkpoint and revision, and max_model_len with its source.

The figure above is the sequence: the server checks the engine, answers 503, finishes what is in flight, exits with code 70 about 7 seconds after the failing request, and your supervisor starts it again. Once the engine is dead, every request, and /health, answers at once with the reason: {"ok": false, "engine": "dead", "reason": "...", "exit_code": 70}

  • A death between requests turns /health to 503 within a second, before any request arrives.
  • An error caused by the request itself, such as a 422, is answered and does not touch the engine.

4. Keep tasks across restarts and replicas

Section titled “4. Keep tasks across restarts and replicas”
  • One server: start it with --tasks-dir on a volume that outlives the container, and --require-tasks N, as Teach a task shows. One directory belongs to one server.
  • Replicas behind a load balancer: start every one with --task-store on object storage, such as s3://bucket/prefix. A task taught on one replica reaches the others within --task-store-poll-seconds, 5 by default, as the same fitted record, so every replica serves the same numbers.
  • Two teachers at once: a second registration of the same task answers 409 instead of overwriting it; read the task again and send it again.
  • Keep fitting on one replica: start the others with --task-store-readonly and route the task-writing routes to that one.
  • If the store goes away: replicas keep serving what they have, and teaching answers 503 until it is back; /health says so under systemone.task_store.
  1. Keep it on a private network, behind your proxy. The server listens on 127.0.0.1 by default; do not expose it to the internet.
  2. Put authentication, rate limits and request-size limits in the proxy. The server has none.
  3. Restrict the routes that change it to trusted callers: POST /v1/tasks, POST /v1/tasks/import, DELETE /v1/tasks/{id} and the abstention routes.
  4. Do not configure CORS on the proxy for this server: it would let a web page’s browser send requests to it.
  5. Run one server per trust boundary, one for each group of callers that trust each other: its cache and its tasks are shared by every caller.
  6. Leave --debug-readout off. It exposes the model’s raw readouts.
  7. Keep to the latest release: it is the one that receives security fixes.

Report a vulnerability through the repository’s private vulnerability reporting, not a public issue: an acknowledgement comes within 5 working days, an assessment within 15.

  • Scale: many questions, long texts and the settings that move server time.
  • Upgrade: move to a new release without losing your certificates.
  • Troubleshoot: what you see, why, and what to do.