CLI for managing isolated OpenClaw agent instances in Docker containers. Each bot gets its own container, workspace, config, and optionally Mattermost, Telegram, or Tailscale integration.
- macOS: OrbStack (recommended) or Docker Desktop
- Linux: Docker Engine or Docker Desktop
- Node.js >= 22
- An API key for Anthropic or OpenAI, a ChatGPT subscription (Codex), or Ollama running locally
git clone <this repo>
cd botdaddy
npm install
npm link # makes `botdaddy` available globallyOr run directly with node bin/botdaddy.js <command>.
# Create a new bot (interactive wizard + apply)
botdaddy create mybot
# Start the bot
botdaddy start mybot
# Follow logs
botdaddy logs mybot
# Open the gateway dashboard in a browser
botdaddy dashboard mybot| Command | Description |
|---|---|
create <name> |
Alias for config |
config <name> |
Create or update a bot — interactive wizard then applies |
apply [name] |
Re-apply botdaddy.json config without re-running the wizard (all bots if no name) |
start [name] |
Start bot container(s) (all bots if no name) |
restart [name] |
Restart bot container(s) (all bots if no name) |
stop [name] |
Stop bot container(s) (all bots if no name) |
logs <name> |
Follow container logs |
ls |
List all bots and their status |
shell <name> |
Open a shell inside the container |
token <name> |
Print the gateway auth token |
dashboard <name> |
Open the gateway dashboard in a browser |
mattermost <name> |
Provision or re-provision Mattermost for a bot |
telegram <name> |
Configure Telegram for a bot |
tailscale <name> |
Configure Tailscale for a bot |
proxy <name> |
Configure a dev server proxy for a bot |
approve <name> <channel> <code> |
Approve a channel pairing code |
rebuild [name] |
Rebuild the base image and recreate bot containers |
destroy <name> |
Stop and remove a bot (optionally delete data) |
botdaddy.json is the source of truth for all bot config (ports, provider, model, channel flags). The apply command reads it and idempotently reconciles everything — files on disk, openclaw.json, and the running container.
botdaddy config mybot → writes botdaddy.json → calls apply
botdaddy apply mybot → reads botdaddy.json → writes .env, openclaw.json, restarts container
See CONFIG-FLOW.md for a full map of where config lives and how it flows.
Select Anthropic in the wizard. You'll be prompted for an API key, which can be saved as a global default or set per-bot.
Default model: anthropic/claude-sonnet-4-6
Select OpenAI in the wizard. You'll be prompted for an API key, which can be saved as a global default or set per-bot.
Default model: openai/gpt-4.1
Use your ChatGPT Pro/Plus subscription instead of a pay-per-use API key. Select OpenAI (Codex subscription) in the wizard — no API key is needed. After starting the bot, authenticate inside the container:
botdaddy shell mybot
openclaw models auth login --provider openai-codexDefault model: openai-codex/codex-mini-latest
The default Ollama model is minimax-m2.5:cloud, which runs on MiniMax's servers through Ollama's cloud API — no GPU required.
1. Install Ollama
curl -fsSL https://ollama.com/install.sh | shOr download from ollama.com.
2. Log in to Ollama
ollama loginThis authenticates with your Ollama account (required for cloud models).
3. Pull the model
ollama pull minimax-m2.5:cloud4. Create a bot
botdaddy create mybot # select "Ollama (local)" as the providerOllama must be running on the host — the container reaches it via host.docker.internal:11434.
# During create:
botdaddy config mybot # answer yes to Mattermost setup
# Or add to an existing bot:
botdaddy mattermost mybotAfter starting the bot, DM it on Mattermost to receive a pairing code, then:
botdaddy approve mybot mattermost <code># During create:
botdaddy config mybot # answer yes to Telegram setup
# Or add to an existing bot:
botdaddy telegram mybotCreate a bot via @BotFather and paste the token when prompted.
Add bots to your Tailscale network so they're reachable from any device on your tailnet. Each bot gets its own node with hostname <namespace>-<name> (e.g. botdaddy-mybot).
# During create:
botdaddy config mybot # answer yes to Tailscale setup
# Or add to an existing bot:
botdaddy tailscale mybotYou'll need a Tailscale auth key or OAuth client secret — generate one at Tailscale admin. The key is saved to ~/.botdaddy/config.json and shared across all bots.
Once started, the bot's gateway is reachable at http://<tailscale-ip>:18789 from any device on your tailnet.
~/.botdaddy/config.json # global defaults (API keys, MM admin token, TS auth key)
botdaddy.json # bot registry — gitignored
bots/<name>/
.env # env vars (gateway token, API key, dev ports, TS auth)
openclaw.json # OpenClaw config (models, channels, gateway)
.tailscale/ # Tailscale state (persists node identity)
.vscode-server/ # VS Code remote server + extensions (persisted)
.cursor-server/ # Cursor remote server + extensions (persisted)
workspace/ # agent workspace (git repo)
memory/ # agent long-term memory
skills/ # seeded skills (agent-browser, coding-agent, marketing, etc.)
agents/ # agent identity and sessions
Each bot's data directory is volume-mounted into its container at /workspace. The .vscode-server and .cursor-server directories are mounted separately into the coder user's home (/home/coder/) so IDE remote connections survive container recreations. Containers run the main process as the coder user (UID 1000) via gosu, with passwordless sudo available when needed.
Every bot is seeded with a set of skills that OpenClaw auto-discovers from the workspace. Skills are synced from seed/skills/ during apply and rebuild.
Agent tools:
- agent-browser — headless browser automation with Chromium
- coding-agent — orchestrate coding agents (Claude Code, Codex, etc.) with PTY and background sessions
- notion — Notion API integration
- trello — Trello board management
Marketing (29 skills from marketingskills):
- Conversion optimization: page-cro, signup-flow-cro, onboarding-cro, form-cro, popup-cro, paywall-upgrade-cro
- Content & copy: copywriting, copy-editing, cold-email, email-sequence, social-content
- SEO & discovery: seo-audit, ai-seo, programmatic-seo, competitor-alternatives, schema-markup
- Paid & distribution: paid-ads, ad-creative
- Measurement: analytics-tracking, ab-test-setup
- Retention: churn-prevention
- Growth: free-tool-strategy, referral-program
- Strategy: marketing-ideas, marketing-psychology, launch-strategy, pricing-strategy, content-strategy, product-marketing-context
The base Docker image is a "kitchen sink" build with everything pre-installed so every bot is ready for any project type.
Languages & runtimes:
- Python 3 with pip and venv
- PHP 8.2, 8.3, 8.4 (via Ondrej Sury PPA) with common extensions (mbstring, xml, curl, zip, mysql, sqlite3, pgsql, gd, intl, bcmath, readline, redis, memcached, xdebug)
- Composer (PHP package manager)
- Node.js (latest LTS via nvm), TypeScript, tsx
Libraries:
- libvips — native image processing for sharp (used by Next.js, Astro)
Database clients:
- PostgreSQL client (
psql) - MySQL client (
mysql) - Redis tools (
redis-cli)
Dev tools:
- Docker CLI + compose plugin (for Docker-out-of-Docker)
- GitHub CLI (
gh) - ripgrep (
rg) and tree - Tailscale (started conditionally at runtime)
Agent tools:
- Claude Code — agentic coding assistant
- agent-browser — headless Chromium for browser automation
PHP 8.4 is the default. Switch versions inside a container:
# Use a specific version directly
php8.2 artisan serve
# Or change the default
update-alternatives --set php /usr/bin/php8.3After modifying the Dockerfile, rebuild all bots:
botdaddy rebuild # rebuild image + recreate all containers
botdaddy rebuild mybot # rebuild image + recreate one container
botdaddy start mybot # start on the new imageBots can spawn sibling containers via the host Docker socket (/var/run/docker.sock). Each bot is allocated a 10-port dev range for this purpose, documented in its workspace TOOLS.md.
Forward a port inside the container to an upstream target, making dev servers accessible via the bot's Tailscale vanity URL or OrbStack domain.
# Add a proxy to an existing bot
botdaddy proxy mybot
# The bot's port 80 will forward to the target (e.g. host.docker.internal:3000)Enabling or disabling the proxy only requires a container restart, not recreation.
Multiple independent BotDaddy stacks can coexist by setting environment variables before running:
BOTDADDY_NAMESPACE=team2 BOTDADDY_BASE_PORT=20000 BOTDADDY_HOME=~/.botdaddy-team2 botdaddy config mybot