Skip to main content
The WattSwarm Docker Compose stack gives you a fully wired local environment in one command. It starts four services: a PostgreSQL 16 database (the kernel’s source of truth for the event log, projections, and decision memory), the wattswarm kernel with its UI console and Iroh-backed P2P bridge, the wattswarm-runtime reference HTTP executor, and a background run worker process that continuously claims and executes queued run steps. All three Rust services use cargo watch with the local source tree bind-mounted, so any code change you save triggers an automatic rebuild and process restart — no manual docker compose restart needed.

Prerequisites

  • Docker Desktop (macOS/Windows) or Docker Engine + Compose plugin (Linux). The docker compose subcommand must be available; v2 Compose is required.
  • The WattSwarm source tree cloned locally:

Default ports

All four ports are overridable via environment variables — see Custom ports below.

Steps

1

Clone the repo and enter the directory

If you have not already cloned the repository, do so now and change into it:
The docker-compose.yml at the root of the repo defines all four services and the two named volumes (wattswarm_pg_data and wattswarm_state_data).
2

Start the full stack

Build images and start all services in detached mode:
Compose starts services in dependency order:
  1. postgres — waits until pg_isready passes its health check.
  2. runtime — waits until /health returns 200.
  3. kernel — waits for both postgres and runtime to be healthy, then runs run init to bootstrap the queue schema, auto-registers the rt executor pointing at http://runtime:8787, and starts the UI server on 0.0.0.0:7788.
  4. worker — starts the background run worker loop with WATTSWARM_P2P_ENABLED=false to prevent conflicts with the kernel over the shared state volume.
Because kernel, runtime, and worker bind-mount the local source tree (.:/app) and run under cargo watch, saving a .rs file automatically triggers a rebuild and clean restart of that container — no image rebuild required during normal development.
First build pulls dependencies and compiles from source. On a typical developer laptop this takes 3–5 minutes. Subsequent builds that change only application code are much faster because the layer cache preserves compiled crate artifacts.
3

Open the kernel console

Once the kernel container is healthy, open the UI console in your browser:
The console gives you point-and-click access to every CLI operation group: node up/down/status, peers, log head/replay/verify, executor add/list/check, task sample/submit/watch/decision/run-real, and knowledge export. It also includes a built-in Quick Start panel with ordered operation steps and a minimal TaskContract reference snippet.For the real swarm dashboard (live task lifecycle map, consensus log, and agent panels):
The swarm dashboard drives real kernel transitions via GET /api/swarm/state and POST /api/swarm/tick, so the panels reflect actual SEL and projection state — not a simulation.
4

Submit a run via the CLI

With the compose stack running, use the CLI from your host machine and point it at the compose PostgreSQL instance with --pg-url. The --kickoff flag moves the run and its steps to QUEUED immediately after creation so the background worker can pick them up.
The command prints a JSON object containing the new run_id. The compose worker container will begin claiming and executing run steps within WATTSWARM_WORKER_POLL_MS milliseconds (default 250 ms).
Submitting a run spec is not sufficient on its own — the run queue requires an active worker process to claim and execute steps. The compose worker service provides that worker automatically. If you run without Compose, start a worker yourself with run worker.
5

Watch the run

Poll the run status and step conclusions using the run_id returned by run submit:
The command prints a pretty-printed JSON view of the run record including current status (PENDING, RUNNING, FINALIZED, FAILED), per-step conclusions, and the aggregated result_json once the run reaches a terminal state. You can also stream the raw event log for a run:

Custom ports

Override any default host port by setting environment variables before docker compose up. All four host-port variables are recognized by the compose file:

P2P and network mode options

When WATTSWARM_UDP_ANNOUNCE_ENABLED=true, the kernel emits an announce payload on startup and listens on WATTSWARM_UDP_ANNOUNCE_PORT (default 37931). Discovered peer IDs are persisted locally so the peers list command and the Peers panel in the console can surface them. To use broadcast instead of multicast:

Worker tuning

The background worker container reads three environment variables that control how aggressively it claims and processes run steps: Example — tighten concurrency and use a shorter poll interval for a low-latency dev loop:
Multiple worker processes can run in parallel against the same PostgreSQL instance — step claiming is designed to be safe under concurrent access without requiring external queue middleware.

UI entrypoints

The console’s Diagnostics panel reads diagnostics/wattswarm_node.jsonl from the state directory and returns structured transport, gossip, backfill, and agent-callback events — useful for multi-node debugging without leaving the browser.

State persistence

The kernel’s node-local state is stored in the named Docker volume wattswarm_state_data, mounted at /var/lib/wattswarm inside the container. Three files drive node identity and startup behavior:On macOS with Docker Desktop these files live inside the VM-managed volume. Access them through the container (docker exec -it wattswarm-kernel cat /var/lib/wattswarm/node_state.json) or copy them out with docker cp wattswarm-kernel:/var/lib/wattswarm/node_seed.hex . — do not rely on the repo-local .wattswarm/ directory for compose-managed state.
Deleting the wattswarm_state_data volume removes node_seed.hex. Because node_id is derived from that Ed25519 seed, your node will receive a new identity on next startup. If the same seed is later introduced into another running node, the registry bootstrap raises a conflict error to prevent duplicate identity registration.