Deployment

Configure alineod, run it as a Docker container, and connect it to OpenSandbox.

alineod is a single Bun process with two SQLite files and a working directory. It holds no in-memory state that can't be rebuilt, so the process — or its container — can be restarted or recreated freely (see Crash recovery).

Configuration

VariableDefaultDescription
ALINEOD_PORT4600HTTP + SSE listen port.
ALINEOD_DB_PATH./data/alineod.dbalineod's own state: the append-only swarm ledger and the agents/handles tables derived from it.
ALINEOD_SDK_LEDGER_PATH./data/alineod-sdk-ledger.dbThe SDK's sandbox ledger (sandbox, exec, and checkpoint events), shared by every agent alineod drives.
ALINEOD_WORK_DIR./data/alineod-workSpec files handed to spawn(), and stored agent results.
ALINEOD_PROMPT_INACTIVITY_MS180000If a turn's stream produces nothing for this long, alineod follows the turn by polling instead.
ALINEOD_TURN_MAX_MS1800000How long a polled turn may keep running (paused time excluded) before it's ended with partial output.
ALINEOD_CATCH_UP_POLL_MS2000Interval between state polls while following a turn.
ALINEOD_STATE_PROBE_TIMEOUT_MS5000Bound on one state poll, so an unresponsive agent can't stall alineod.
ALINEOD_RESUME_BRIDGE_TIMEOUT_MS10000After a resume, how long to wait for the agent's harness to answer before restarting it.

OpenSandbox connection settings come from alineo.config.json in the working directory, exactly as for the SDK and CLI. Model-provider keys (NVIDIA_API_KEY, ANTHROPIC_API_KEY, …) are read from alineod's own environment wherever a spec's env references them as ${VAR}.

Fixed limits, set in apps/alineod/config.ts:

  • Socket idle timeout: 255 s (Bun's maximum — its ~10 s default would kill SSE and long-polls).
  • SSE heartbeat: every 10 s.
  • GET /agents/:id/result?wait= is capped at 240 s.

Docker

The image builds the whole monorepo (alineod depends on the SDK workspace packages), so build from the repo root:

docker build -f apps/alineod/Dockerfile -t alineod .

docker run --rm -p 4600:4600 \
  --add-host host.docker.internal:host-gateway \
  -e ALINEO_SERVER_URL=http://host.docker.internal:8080 \
  -e NVIDIA_API_KEY=nvapi-... \
  -v alineod-data:/data \
  alineod

Or with Compose:

NVIDIA_API_KEY=nvapi-... docker compose -f apps/alineod/docker-compose.yml up --build

The entrypoint writes /data/alineo.config.json from these variables before starting the server:

VariableDescription
ALINEO_SERVER_URLOpenSandbox server URL.
ALINEO_USE_SERVER_PROXYRoute sandbox traffic through the OpenSandbox server (true).
ALINEO_API_KEYOpenSandbox API key, if the server requires one.

All state lives under /data — keep it on a volume.

Networking

alineod talks to OpenSandbox over HTTP only. It does not need the Docker socket: OpenSandbox creates the agent containers, not alineod.

Server proxy URLs and the eip

In server-proxy mode, OpenSandbox hands back sandbox URLs built from its own configured eip. If that is http://localhost:8080, those URLs won't resolve from inside the alineod container. Either put alineod on the same Docker network as OpenSandbox with a routable eip, or run the container with --network host (the same as running alineod bare on the host).

alineod has also been run against an OpenSandbox server using gVisor (runsc) as its secure container runtime; nothing in alineod depends on the runtime.

The protocol spec

The wire contract is defined once, as Zod schemas in apps/alineod/src/schema.ts. The running daemon serves an interactive OpenAPI document at /openapi, and the schemas can be emitted to files for client generation:

cd apps/alineod
bun run spec    # writes specs/alineod/openapi.json and specs/alineod/events.schema.json