Stack
docker-compose.yml defines:
All
@darkpool/* services run off the same image. One node:22-slim + corepack pnpm + tsx Dockerfile, no build step, identical runtime to local dev. Compose picks the process via command:.
Bring it up
migrate service gates the db consumers via service_completed_successfully so api/indexer never start against an unmigrated db.
Verify:
Hosted fleet profile
AGENT_KEY_ENCRYPTION_KEY. same value as onapi. Without it, decryption fails.FLEET_REGISTRY_TOKEN. Bearer forGET /v1/agents/fleet. Same value as onapi.SPONSOR_KEY. falls back toRESOLVER_KEY. Pays gas for every agent tick.LLM_API_KEY+ optionalGEMINI_API_KEY. for the per-agent model routing.
After editing backend code
Stop everything
Reset the database
Networking
- Same repo-root
.envviaenv_file:. - Only
REDIS_URL(redis://redis:6379),DATABASE_URL(postgres://…:5432/darkpool), and the fleet’sSERVER_HTTP_URL=http://api:8081are overridden per-service for in-network DNS. .binary-markets/is mounted read-only into api + indexer so registry lookups resolve.packageManager: pnpm@8.13.1is pinned (9.0.0 made corepack pick a pnpm that can’t frozen-install the repo’s v6 lockfile).
Healthchecks
apihealthcheck =node -e fetch(...)(slim has no curl). Gates the fleet viaservice_healthy.agent-fleetwaits for${SERVER_URL}/health(60s deadline) before its first poll, which covers host-mode boots too.
Dockerfile
pnpm build step. Every service runs via tsx directly off source. Identical to local dev, which means one less thing to break.
Edge hardening (production)
GET /v1/agents/fleet returns decrypted agent secrets. Defense in depth:
FLEET_REGISTRY_TOKENBearer inAuthorizationheader (enforced by Fastify route).- nginx
location /v1/agents/fleet { deny all; }on the public-facing reverse proxy. - Fleet container talks to api via in-network DNS (
http://api:8081), never the public endpoint.

