Everything you need to verify before taking GoClaw from development to production.
This checklist covers the critical steps to harden, secure, and reliably operate a GoClaw gateway in production. Work through each section top to bottom before going live.
- PostgreSQL 15+ is running with the pgvector extension installed
-
GOCLAW_POSTGRES_DSNis set via environment — never inconfig.json - Connection pool is sized for your expected concurrency
- Database connection pool uses 25 max open / 10 max idle connections (hard-coded) — ensure your PostgreSQL
max_connectionsaccommodates this plus other clients - Automated backups are configured (daily minimum, test restore quarterly)
- Schema is up to date:
./goclaw upgrade --statusshowsUP TO DATE - v3 upgrade: Migrations 37–44 have been applied (subagent tasks, vault tables, evolution tables, edition tables). Run
./goclaw upgradebefore starting the new binary - v3 upgrade: Vault tables exist (
vault_documents,vault_links) — required if any agent has vault enabled - v3 upgrade: Back up the database before upgrading from v2 to v3
# Verify schema status
./goclaw upgrade --status
# Apply any pending migrations (required for v3)
./goclaw upgrade-
GOCLAW_ENCRYPTION_KEYis set to a random 32-byte hex string — back this up. Losing it means losing all encrypted API keys stored in the database. -
GOCLAW_GATEWAY_TOKENis set to a strong random value — required for WebSocket and HTTP auth - Neither secret appears in
config.json, git history, or logs - All provider API keys are set via environment (
GOCLAW_ANTHROPIC_API_KEY, etc.) or added through the dashboard (where they are stored encrypted with AES-256-GCM)
# Generate secrets if you haven't run onboard/prepare-env.sh
export GOCLAW_ENCRYPTION_KEY=$(openssl rand -hex 32)
export GOCLAW_GATEWAY_TOKEN=$(openssl rand -hex 32)Back up
GOCLAW_ENCRYPTION_KEYin a secrets manager (e.g. AWS Secrets Manager, 1Password, Vault). If you rotate it, all encrypted API keys in the database become unreadable.
- TLS termination is in place (nginx, Caddy, Cloudflare, or load balancer) — GoClaw itself does not terminate TLS in standard mode
- Gateway is not exposed directly on a public port without TLS
-
gateway.allowed_originsis set to your actual client origins (empty = allow all WebSocket origins)
{
"gateway": {
"allowed_origins": ["https://your-dashboard.example.com"]
}
}-
gateway.rate_limit_rpmis set (default: 20 requests/minute per user, 0 = disabled) -
tools.rate_limit_per_houris set (default: 150 tool executions/hour per session, 0 = disabled) - Webhook rate limiting is built-in (30 requests/60s per source, max 4096 tracked sources) — no configuration needed
{
"gateway": {
"rate_limit_rpm": 20
},
"tools": {
"rate_limit_per_hour": 150
}
}If agents execute code, review the sandbox settings:
-
sandbox.modeis set:"off"(no sandbox),"non-main"(sandbox subagents only), or"all"(sandbox everything) -
sandbox.memory_mbandsandbox.cpusare tuned for your workload (defaults: 512 MB, 1 CPU) -
sandbox.network_enabledisfalseunless agents explicitly need network access -
sandbox.read_only_rootistrue(default) for immutable container root filesystem -
sandbox.timeout_secis set to a reasonable limit (default: 300s) -
sandbox.idle_hourstuned (default: 24 — removes containers idle longer than this) -
sandbox.max_age_daysset (default: 7 — removes containers older than this)
{
"agents": {
"defaults": {
"sandbox": {
"mode": "non-main",
"memory_mb": 512,
"cpus": 1.0,
"network_enabled": false,
"read_only_root": true,
"timeout_sec": 120
}
}
}
}-
gateway.injection_actionis set to"warn"(default) or"block"— never"off"in production -
tools.exec_approval.securityis"full"(default) — blocks dangerous shell patterns -
agents.defaults.restrict_to_workspaceistrue(default) — prevents path traversal outside workspace - Review
tools.web_fetchdomain allow/deny lists if agents browse the web
- Log output is collected (stdout/stderr) — GoClaw uses structured JSON logging via
slog - Alert on repeated
slog.Warn("security.*")log entries — these indicate blocked attacks or anomalies - Alert on
tracing: span buffer full— indicates the collector is falling behind under load - Uptime monitoring is configured (e.g. ping
/healthor the gateway port) - Consider enabling OTel export for trace-level visibility — see Observability
- Interactive API documentation is available at
/docs(Swagger UI) and/v1/openapi.jsonfor integration testing
- Log rotation is configured if writing to files (use
logrotateor your container runtime's log driver) -
GOCLAW_AUTO_UPGRADE=trueis set only if you accept automatic schema migrations on startup; otherwise upgrade explicitly with./goclaw upgrade - A runbook exists for: restart, rollback, DB restore, and encryption key rotation
- Upgrade procedure is documented and tested — see Upgrading
- Consider creating scoped API keys instead of sharing the gateway token
- API keys support fine-grained scopes:
operator.admin,operator.read,operator.write,operator.approvals,operator.pairing - Keys are hashed (SHA-256) before storage — the plaintext is shown only at creation time
- Set up key rotation policy — keys can be revoked individually without affecting others
// Example: create a read-only key for monitoring
// via dashboard or API
{
"name": "monitoring-readonly",
"scopes": ["operator.read"]
}GoClaw uses lane-based scheduling to limit concurrent agent runs by type:
| Environment Variable | Default | Purpose |
|---|---|---|
GOCLAW_LANE_MAIN |
30 |
Max concurrent main agent runs |
GOCLAW_LANE_SUBAGENT |
50 |
Max concurrent subagent runs |
GOCLAW_LANE_DELEGATE |
100 |
Max concurrent delegated runs |
GOCLAW_LANE_CRON |
30 |
Max concurrent cron job runs |
Tune these based on your server resources and expected load. Lower values reduce memory pressure; higher values improve throughput.
Review these gateway settings for your deployment:
| Setting | Default | Description |
|---|---|---|
gateway.owner_ids |
[] |
User IDs with owner-level access — keep this list minimal |
gateway.max_message_chars |
32000 |
Max user message size before truncation |
gateway.inbound_debounce_ms |
1000 |
Merge rapid consecutive messages (ms) |
gateway.task_recovery_interval_sec |
300 |
How often team tasks are checked for recovery |
-
gateway.owner_idscontains only trusted admin user IDs -
gateway.max_message_charsis appropriate for your use case (lower = less token spend)
For new installations, the onboard command handles initial setup interactively:
./goclaw onboardIt generates encryption and gateway tokens, runs database migrations, and walks you through basic configuration. You can also run prepare-env.sh for non-interactive secret generation.
The doctor command runs a comprehensive check of your environment:
./goclaw doctorIt validates: runtime info, config file, database connection and schema version, provider API keys, channel credentials, external tools (docker, curl, git), and workspace directories.
# Check schema and pending migrations
./goclaw upgrade --status
# Verify gateway starts and connects to DB
./goclaw &
curl http://localhost:18790/health
# Confirm secrets are not exposed in logs
# Look for "***" masking, not raw key values| Issue | Likely cause | Fix |
|---|---|---|
| Gateway refuses to start | Schema outdated | Run ./goclaw upgrade |
| Encrypted API keys unreadable | Wrong GOCLAW_ENCRYPTION_KEY |
Restore correct key from backup |
| WebSocket connections rejected | allowed_origins too restrictive |
Add your dashboard origin to the list |
| Rate limit too aggressive | Default 20 RPM for high-traffic use | Increase gateway.rate_limit_rpm |
| Agents escape workspace | restrict_to_workspace disabled |
Set to true in config |
- Upgrading — how to upgrade GoClaw safely
- Observability — set up tracing and alerting
- Security Hardening — deeper security configuration
- Docker Compose Setup — production compose patterns