Skip to content

Docker / container mode

A container running a single Runtime Host is called a worker cell. The canonical container layout lives in projects/matrix-worker/ (Dockerfile, docker-compose, entrypoint, README). This page describes how the Host behaves when it is the principal process inside a container.

What ships today

  • projects/matrix-worker/Dockerfile — Node 22 base, hivecast from the registry, agent CLIs, openssh-server, default MATRIX_HOME=/root/.matrix.
  • projects/matrix-worker/docker-compose.yml — one worker on host port 3200 -> container 3100, 2200 -> container 22.
  • projects/matrix-worker/entrypoint.sh — starts SSH and the Host, mounts user credentials read-only.
bash
cd projects/matrix-worker
docker compose up -d                       # one worker
docker compose up -d --scale worker=3      # three workers

Each worker is one Host instance with its own <host-home> inside the container.

Bind-host detection

The .deb postinst — used inside containers built from the package, not the worker Dockerfile above — auto-detects when it is running in a container and binds to 0.0.0.0 instead of 127.0.0.1:

bash
# build-deb-installer.js:291-296
if [ -z "${HIVECAST_BIND_HOST:-}" ]; then
  HIVECAST_BIND_HOST="127.0.0.1"
  if [ -f /.dockerenv ] || grep -qaE "(docker|containerd|kubepods)" /proc/1/cgroup 2>/dev/null; then
    HIVECAST_BIND_HOST="0.0.0.0"
  fi
fi

The same logic runs against the nats-server.conf so NATS is reachable from outside the container if the operator chose to publish port 4222.

Two-Runtime Dev Topology in containers

A single worker can run both shells: matrix-web as the platform shell on a known port, and matrix-edge as the Device shell on another. The repo's CLAUDE.md § "Two-Runtime Dev Topology" gives the full recipe:

bash
# Inside the container
hivecast install --home /root/.matrix --no-start
hivecast start   --home /root/.matrix --no-default-runtimes

matrix up @open-matrix/matrix-web --serve --port 5001 \
  --runtime-id WEB --env hivecast --startup auto --restart always

matrix up @open-matrix/matrix-edge --serve --port 5002 \
  --runtime-id EDGE --env hivecast --startup auto --restart always

Publish 5001 and 5002 (or pick others) in docker-compose.yml.

Worker Bootstrap Gotchas

The worker bootstrap surfaced real Hosting bugs during the codex two-runtime replication. The repo AGENTS.md § "Worker Bootstrap Gotchas" is the authoritative checklist; key items as they relate to the Host:

  • Stale dist/ across branch switches. The Host runs built artifacts. pnpm build after every git switch or expect ghost behavior.
  • auth.mode: public-session requirement. Browser-served packages (matrix-web, matrix-edge) need the Host's host.json auth.mode set to public-session for unauthenticated browser sessions to work.
  • NATS port mismatch in fresh installs. Wrapper installs use ports 4270/4271. The .deb uses 4222/4223. Both are valid; do not mix configs across them.
  • --port patch dependency. matrix up --port was added in a recent patch; older Hosts ignored it silently.
  • 0.0.0.0 vs 127.0.0.1 bind. Container detection above handles the default; if you override host.json manually, double-check.
  • HTTP 200 is not proof. Always read the browser console and the runtime stderr log; an HTTP 200 from matrix-web does not mean a NATS WS handshake completed. See Runtime health.
  • Serial-only Docker rebuilds. docker compose build parallelism races for the registry. Build serially.

What you need on the host filesystem

The compose file mounts:

  • ./credentials/nimbletec.json -> /root/.matrix/credentials.json (NATS credentials from a previous hivecast login).
  • ~/.claude/.credentials.json -> /root/.claude/.credentials.json (Claude API).
  • ~/.codex/auth.json -> /root/.codex/auth.json (Codex API).

Everything else is generated inside the container.

See also