Scout's end-to-end test harness runs four Docker containers — each with systemd as PID 1 — that connect back to a hub running on your host machine. The web dev server also runs on the host, giving you hot reload across the full stack.
Three terminals:
# 1. Hub (push schema on first run)
cd apps/hub
bun --env-file=.env.test run db:push
bun --env-file=.env.test run dev
# 2. Web
cd apps/web
bun --env-file=.env.test run dev
# 3. E2E containers + agents
cd e2e
./scripts/up.shVerify: curl -s http://localhost:3001/health should show "connectedAgents": 4.
Open http://localhost:3000 to use the web UI.
cd e2e
./scripts/down.sh # stop containers, clean state
./scripts/down.sh --volumes # also remove k3s persistent dataHub and web are regular dev processes — Ctrl+C to stop.
Host (your machine)
├── apps/hub → :3001 (Bun, hot reload)
├── apps/web → :3000 (Vite, hot reload)
└── .scout/ → agent PID files + logs
Docker network
├── scout-node-server (systemd + nginx + redis)
├── scout-node-k3s (systemd + k3s single-node cluster)
├── scout-node-docker (systemd + Docker-in-Docker)
└── scout-node-minimal (systemd only, bare ubuntu)
Containers mount the repo read-only at /opt/scout so agents see your local edits without rebuilding. Each agent connects to the hub via ws://host.docker.internal:3001.
| Node | Plugin capabilities | What it tests |
|---|---|---|
node-server |
systemd | Service management (nginx, redis), unit files, journal logs |
node-k3s |
systemd, k8s | Kubernetes workloads, pod logs, scale/restart actions |
node-docker |
systemd, docker | Container lifecycle, image/network inventory, container logs |
node-minimal |
systemd | Bare system — capability auto-discovery fallback |
All nodes also report core system metrics (CPU, memory, disk, network, processes).
SCOUT_TOKEN=test-token-123
SCOUT_DB_PATH=./test.db
SCOUT_PORT=3001
SCOUT_HUB_URL=http://127.0.0.1:3001
The containers use matching env vars set in e2e/compose.yml:
SCOUT_HUB_URL=ws://host.docker.internal:3001
SCOUT_TOKEN=test-token-123
SCOUT_INTERVAL=15
Note: Use
127.0.0.1(notlocalhost) forSCOUT_HUB_URLin the web env. On macOS,localhostmay resolve to IPv6 first and collide with other processes on the same port.
All scripts live in e2e/scripts/ and should be run from the e2e/ directory.
| Script | Usage | Purpose |
|---|---|---|
up.sh [node] |
./scripts/up.sh |
Build images, start containers, launch agents |
down.sh [--volumes] |
./scripts/down.sh |
Stop containers, clean .scout/ state |
logs.sh [node] |
./scripts/logs.sh node-k3s |
Tail agent logs (no args = last 20 lines from all) |
exec.sh <node> [cmd] |
./scripts/exec.sh node-server |
Shell into container (or run a command) |
stop-agents.sh [node] |
./scripts/stop-agents.sh |
SIGTERM agents without tearing down containers |
./scripts/up.sh node-server./scripts/stop-agents.sh node-docker
docker exec -d scout-node-docker /opt/scout/e2e/scripts/run-agent.sh./scripts/exec.sh node-k3s kubectl apply -f /opt/scout/e2e/fixtures/k3s/test-app.yamlThis creates a scout-test namespace with a nginx Deployment (2 replicas), a ClusterIP Service, and a redis StatefulSet.
Agent stdout/stderr is written to .scout/<node-name>.log on the host:
tail -f .scout/node-server.log # from e2e/ directory
# or
./scripts/logs.sh node-server # equivalentPID files at .scout/<node-name>.pid track the agent process inside each container.
The hub uses apps/hub/test.db (SQLite). To reset:
rm apps/hub/test.db
cd apps/hub && bun --env-file=.env.test run db:pushconnectedAgents: 0 after up.sh
Check agent logs: ./scripts/logs.sh. Common causes:
- Hub not running on port 3001
- Schema not pushed (
bun --env-file=.env.test run db:push) - Layer wiring error in agent (check for "Service not found" in logs)
Container stuck on "timeout waiting for systemd"
The container's systemd may report degraded instead of running (usually means a service failed to start). This is usually fine — retry or start the agent manually:
docker exec -d scout-node-docker /opt/scout/e2e/scripts/run-agent.shPort 3000 already in use
Vite auto-increments ports. Kill the stale process: lsof -ti:3000 | xargs kill
Plugin data not appearing
Check for schema validation errors in agent logs (grep "WARN" .scout/<node>.log). Common cause: entity fields set to undefined instead of omitted — Schema.optionalKey rejects explicit undefined.
e2e/
├── compose.yml # Docker Compose services
├── fixtures/
│ └── k3s/test-app.yaml # Sample K8s workload
├── nodes/
│ ├── base.Dockerfile # Ubuntu 24.04 + systemd + bun
│ ├── server.Dockerfile # + nginx + redis
│ ├── k3s.Dockerfile # + k3s
│ ├── docker.Dockerfile # + Docker CE (DinD, VFS driver)
│ └── minimal.Dockerfile # Base only
└── scripts/
├── up.sh
├── down.sh
├── logs.sh
├── exec.sh
├── run-agent.sh
└── stop-agents.sh