The Problem

Running OpenClaw AI chatbots in production means managing Docker containers, per-bot credentials, multi-provider model config, and a dozen chat channels — all by hand. BotMaker wraps that into a web UI with a creation wizard, monitoring dashboard, and container lifecycle management.

What This Does

A two-part app. The backend (src/) is a Fastify server with SQLite for bot metadata, Dockerode for container orchestration, and file-based per-bot secrets. The frontend (dashboard/) is a React + Vite SPA with a multi-step wizard covering templates, personality, toggles, and channel/model config — 28 channel definitions live in dashboard/src/config/channels/, four providers in dashboard/src/config/providers/.

Bot config is generated from templates in src/bots/templates.ts (generateOpenclawConfig, generateSoulMd, generateIdentityMd). Secrets are isolated per bot in src/secrets/manager.ts and mounted read-only into containers.

How It Is Wired

Execution starts at main in src/index.ts:12, which reaches 28 functions and calls buildServer (src/server.ts:81). The shortest path to a side effect: main -> buildServer -> initDb -> createSchema, hitting the database via db.exec in src/db/schema.ts. The shutdown path (main -> shutdown -> listBots) hits the DB via db.prepare. Eleven functions read or write the database; one runs an external command.

The hot functions — change these and the most breaks: getDb (called from 8 places), useWizard (7), wrapDockerError (7), handleResponse (5), getSecretsRoot (5). dashboard/src/config/channels/types.ts is a hub with 31 modules importing it and zero outgoing edges — pure type definitions, but high-blast-radius churn. dashboard/src/types.ts has 15 importers.

File-by-file map: src/bots/store.ts owns bot CRUD, src/services/DockerService.ts owns container lifecycle (11 functions), src/services/ReconciliationService.ts syncs status and cleans orphans, src/db/index.ts owns the SQLite handle, dashboard/src/api.ts is the frontend's HTTP layer, dashboard/src/wizard/context/WizardContext.tsx holds the wizard state machine (5 functions, called from 6 files).

How To Use It

npm install
cd dashboard && npm install && cd ..
npm run dev          # backend with hot reload, port 7100
cd dashboard && npm run dev   # frontend

# Production
npm run build:all
npm start

# Docker
docker compose up -d

Configuration lives in env vars: PORT, DATA_DIR, SECRETS_DIR, OPENCLAW_IMAGE, BOT_PORT_START. Requires Node 20+, Docker, and an openclaw:latest image.

Real-World Use

A team offering per-customer OpenClaw bots: each customer gets an isolated container on its own port. The wizard generates a bot with provider credentials (OpenAI, Anthropic, etc.) and channel tokens (Telegram, Slack, WhatsApp). Secrets land in SECRETS_DIR per bot, mounted read-only — a container compromise doesn't expose other bots' credentials. The dashboard's diagnostics tab shows container stats and lets an operator clean orphaned containers/workspaces.

Code Health & Issues

Static analysis found 7 findings (2 high, 5 medium): hub modules with high blast radius in channels/types.ts and types.ts; 23 duplicated 6-line blocks across 12 files (e.g. BotCard.tsx exists in both components/ and dashboard/); high branching density in src/bots/store.ts (50 branch points over 145 lines); deep nesting in dashboard/src/wizard/pages/Page4Config.tsx (indentation depth 6).

SDLC observations: no CI workflow despite 115 source files; docker-compose.yml runs privileged with the Docker socket mounted and host networking; the Dockerfile bakes SECRETS_DIR as an env var (readable via docker history); node:20-slim is unpinned; no non-root USER; 4 test files against 115 source files (ratio 0.035); missing .editorconfig and .gitattributes.

The Bottom Line

Solid architecture for the problem: clean separation between backend, dashboard, and per-bot secrets, with a genuinely useful wizard. The gaps are operational — no CI, privileged Docker, unpinned images, thin test coverage. Fine for a single-host deployment today; needs hardening before multi-tenant or shared-host use.