Skip to main content
HQ’s default Compose stack has seven services that work together. The UI runs on its own; the other six are gateway services that run agents, process data, and handle event-driven plugins. The gateway runs OpenClaw 6.6 as its agent runtime.

ui

Next.js dashboard. Renders the workspace — agents, CRM, tasks, knowledge, routines, settings — and writes to Supabase through server actions. Port 3000.

gateway

Agent runtime host. Runs OpenClaw 6.6, Chrome/Chromium, XFCE desktop, noVNC, and the files API. This is where agents live. Port 18790 (files API). noVNC runs inside the container and is proxied through the UI — no host port needed.

dispatcher

Inbox daemon. Watches agent_inbox_items for new work, filters to agents on the local gateway, checks budget status, and wakes agents through OpenClaw. Includes burst-aware batch sizing, inbox dedup, and exponential backoff for unprovisioned agents (v0.2.2). See Inbox dispatch.

runner

Command daemon. Watches agent_commands, leases commands for the local gateway, executes lifecycle and auth operations, and reports results back to Supabase.

embedder

Knowledge indexing daemon. Runs FastEmbed locally with the BGE embedding model pre-loaded in the image. Indexes pending knowledge items into searchable knowledge chunks. Override the model via EMBEDDER_MODEL env var — non-default models download on first boot. Uses memory-aware batch sizing — reads /proc/meminfo and throttles (or pauses) when available RAM is low to prevent OOM on small instances.

file-processor

File processing daemon. Leases uploaded knowledge files (PDF, DOCX, XLSX, CSV, PPTX, TXT), extracts plain text, and triggers embedding. Runs independently so file processing doesn’t block other gateway operations. Uses memory-aware batch sizing (same mechanism as the embedder) to stay safe on constrained hosts.

plugin-runner

Plugin daemon. Watches the hq_plugin_event_queue for events emitted by SQL triggers and dispatches them to enabled plugins — local Python handlers or remote webhook endpoints with HMAC signatures. See Plugins.

Shared state

The gateway, dispatcher, and runner containers share the gateway-state Docker volume (mounted at /home/openclaw/.openclaw). This volume holds OpenClaw config, the bare git repo, agent worktrees, browser profiles, and auth state. The embedder uses gateway-embedding-cache for downloaded local embedding models, so restarts reuse the cached BGE files. The runner additionally mounts /var/run/docker.sock so it can restart sibling containers when needed.
For single-host installs, start everything with docker compose --profile gateway up -d. For multi-host setups, run docker compose up -d ui separately from the gateway services. See Add a gateway.

Shared modules

Several gateway daemons share helper modules that aren’t standalone services but affect behavior across the stack.

Gateway backup (gateway_backup.py)

Handles automatic backup and restore of gateway state (~/.openclaw/) to Supabase Storage. Used by:
  • entrypoint.sh — restores on boot (if no local state exists), backs up on SIGTERM.
  • command_runner.py — exposes backup_gateway as a command action triggered from the UI.
  • Keepalive scripts — backs up before extending sandbox timeout.
Backups are gzipped tarballs uploaded to a gateway-backups storage bucket, keyed by gateway ID and timestamp. Chrome profile data (OAuth sessions, cookies, local storage) is included but regeneratable caches are excluded to keep archives small (~6 MB vs ~180 MB unfiltered). Retention keeps the 5 most recent backups per gateway and prunes anything older than 7 days. Restore tries backups newest-first and falls back to the next if an archive is corrupt. CLI usage inside the container:

Sentry initialization (sentry_init.py)

Shared Sentry setup for all gateway daemons. Each daemon calls init_sentry("daemon_name") at startup. Sentry is only active when both conditions are met:
  1. SENTRY_DSN environment variable is set.
  2. RUNTIME_MODE is hosted or e2b.
Self-hosted instances never send telemetry. When active, the module tags every event with gateway_id, tenant_id, daemon_name, and runtime_mode. A before_send filter drops noisy transient errors (closed connections, WebSocket handshake failures, timeouts, connection refused) to keep the Sentry project clean. Daemons import capture(exc) to report exceptions — the function is a safe no-op when Sentry is unavailable.

Memory pressure (memory_pressure.py)

Provides memory-aware batch sizing for the embedder and file-processor daemons. Reads MemAvailable from /proc/meminfo on each processing cycle and adjusts the effective batch size: When processing is paused due to critical memory pressure, the module creates a dashboard notification so operators know the gateway is throttled. Notifications are rate-limited to one every 10 minutes. On non-Linux hosts (macOS dev environments), /proc/meminfo is unavailable and the module falls back to the full configured batch size.