Service Openclaw - thekaveh/atlas GitHub Wiki
Open-source AI agent for messaging platforms with web-based administration dashboard.
The OpenClaw service provides an LLM-backed agent that connects to messaging apps:
-
Messaging channels: WhatsApp, Telegram, Discord, Slack, Signal and others (upstream
docs/channels/index.mdin the image). iMessage needs a signed-in Mac running theimsgbridge. - Workspace files: Read, create, and manage files in a dedicated workspace
-
Skills: Bundled skills include
githubandgog(Google Calendar, Gmail, Drive). They need theghandgogbinaries, which the pinned image (2026.6.10) does not contain. - Web Dashboard: Browser-based admin panel for configuration and approvals
- Multi-Provider LLM: Models come through LiteLLM (Β§2). Direct Anthropic and OpenAI keys are optional overrides (Β§4.3).
OpenClaw runs as a single gateway process that:
- Serves the web dashboard on the configured gateway port. The container-mode stack default is 63076; localhost mode uses
OPENCLAW_LOCALHOST_PORTand defaults to 63065 unless you point it at OpenClaw's native/default 18789. - Manages messaging platform connections (bridge) on the configured bridge port. The container-mode stack default is 63077.
- Stores configuration in
~/.openclaw/directory - Stores workspace files in
~/.openclaw/workspace/
OpenClaw reaches models through LiteLLM. The container gets LITELLM_API_KEY (the LiteLLM master key), which OpenClaw's bundled litellm provider reads. Its default base URL http://localhost:4000 does not resolve in the container. openclaw-init therefore sets models.providers.litellm.baseUrl to http://litellm:4000 when it is unset. It keeps an operator value and does not patch a JSON5 config (see below). OpenClaw does not read LITELLM_BASE_URL.
Select models from the litellm provider. Its built-in default litellm/claude-opus-4-6 works only if LiteLLM serves a model with that name. You can also point the openai provider at LiteLLM (Β§7). Keep OPENCLAW_OPENAI_API_KEY empty then, or a real OpenAI key goes to LiteLLM. OPENCLAW_OPENAI_API_KEY and OPENCLAW_ANTHROPIC_API_KEY bypass LiteLLM (Β§4.3).
Container Mode Initialization: When running in container mode, an openclaw-init container runs first to:
- Set correct volume permissions (uid 1000/node) on config and workspace volumes
- Pre-configure the gateway for non-loopback binding (
gateway.controlUi.dangerouslyAllowHostHeaderOriginFallback)
OpenClaw accepts JSON5 (comments, trailing commas), but jq does not. openclaw-init leaves a config that jq cannot parse unpatched and logs a warning. Set models.providers.litellm.baseUrl and gateway.controlUi.dangerouslyAllowHostHeaderOriginFallback in that file yourself.
The gateway container starts with --bind lan to listen on all interfaces (required for Docker networking).
Step 1: Configure source
Edit .env:
OPENCLAW_SOURCE=containerStep 2: Start the stack
./start.shOr use CLI override:
./start.sh --openclaw-source containerStep 3: Access the dashboard
Open http://localhost:${OPENCLAW_GATEWAY_PORT} (default 63076) or http://openclaw.localhost:${KONG_HTTP_PORT} (via Kong; default port 63000).
Step 4: Run onboarding (from the repository root)
Use the active Atlas env file: .env by default, or ATLAS_ENV_FILE.
The command uses the bootstrapper dependencies through uv and preserves the project nameβs spelling.
PROJECT_NAME=$(
PYTHONPATH=bootstrapper uv run --project bootstrapper python - <<'PYPROJECT'
import sys
from core.config_parser import ConfigParser, DEFAULT_PROJECT_NAME
parser = ConfigParser(root_dir=".")
if not parser.env_file_path.is_file():
sys.exit("The active Atlas env file does not exist.")
env = parser.parse_env_file()
print(env.get("PROJECT_NAME") or DEFAULT_PROJECT_NAME, end="")
PYPROJECT
) || exit 1
docker exec -it "${PROJECT_NAME}-openclaw-gateway" openclaw onboardNote:
- OpenClaw is disabled by default - you must explicitly enable it
- First run requires onboarding to configure messaging channels; the bundled
litellmprovider is pre-pointed at the gateway byopenclaw-init
Step 1: Install OpenClaw
# Requires Node.js 22+
npm install -g openclawStep 2: Run onboarding
openclaw onboard --install-daemonStep 3: Start the gateway
openclaw gateway --port 63065Step 4: Start the stack with OpenClaw localhost
./start.sh --openclaw-source localhostOr edit .env:
OPENCLAW_SOURCE=localhost
# Optional: if your local OpenClaw runs on its native/default 18789 instead:
# OPENCLAW_LOCALHOST_PORT=18789
# (URL is derived as http://host.docker.internal:18789 at compose-render time.)OPENCLAW_SOURCE=disabled| Variable | Description | Default |
|---|---|---|
OPENCLAW_SOURCE |
Service source (container, localhost, disabled) | disabled |
OPENCLAW_IMAGE |
Docker image | ghcr.io/openclaw/openclaw:2026.6.10 |
OPENCLAW_GATEWAY_PORT |
Gateway HTTP port | 63076 |
OPENCLAW_BRIDGE_PORT |
Bridge port | 63077 |
OPENCLAW_GATEWAY_TOKEN |
Bearer token for the gateway API and dashboard; generated into .env at startup when empty and kept afterwards |
generated |
OPENCLAW_SCALE |
Container replicas (set by bootstrapper) | 0 |
By default, OpenClaw uses these configuration and environment settings for LiteLLM:
| Setting | Description | Default |
|---|---|---|
models.providers.litellm.baseUrl |
Provider URL in openclaw.json; openclaw-init sets it only when unset and keeps operator values |
http://litellm:4000 (in-network) |
LITELLM_BASE_URL |
Compatibility environment value; OpenClaw does not read it |
http://litellm:4000 (in-network) |
LITELLM_API_KEY |
Bearer key for LiteLLM (equals LITELLM_MASTER_KEY) |
auto-generated |
These keys let OpenClaw call a provider directly, without LiteLLM. Use them for a separate budget or key, or for a model that LiteLLM does not serve.
| Variable | Description | Default |
|---|---|---|
OPENCLAW_ANTHROPIC_API_KEY |
Anthropic API key for OpenClaw | Empty by default; set only to bypass LiteLLM with a dedicated OpenClaw key |
OPENCLAW_OPENAI_API_KEY |
OpenAI API key for OpenClaw | Empty by default; set only to bypass LiteLLM with a dedicated OpenClaw key |
| Variable | Description | Default |
|---|---|---|
OPENCLAW_LOCALHOST_PORT |
Host port of a native OpenClaw (its own slot, separate from OPENCLAW_GATEWAY_PORT). Set it to 18789 if your local OpenClaw uses its native default port. Compose derives the URL http://host.docker.internal:${OPENCLAW_LOCALHOST_PORT}. |
63065 |
OpenClaw gets LLM access from the always-on LiteLLM gateway (variables in Β§4.2βΒ§4.3):
-
Default path (LiteLLM): the bundled
litellmprovider (key fromLITELLM_API_KEY, base URL set byopenclaw-init) or a repurposedopenaiprovider (Β§7) calls the gateway. LiteLLM routes to every Ollama, OpenAI, Anthropic or OpenRouter upstream that the stack enables. Use the model IDs that LiteLLM serves (for exampleollama/qwen3.8:latest,gpt-4o,claude-sonnet-4-6). -
Anthropic override: set
OPENCLAW_ANTHROPIC_API_KEYin.envto call Anthropic directly. When it is unset, OpenClaw reaches Anthropic only through LiteLLM. -
OpenAI override: set
OPENCLAW_OPENAI_API_KEYin.envto call OpenAI directly. When it is unset, OpenClaw does not inherit the stack-wideOPENAI_API_KEY.
Provider selection. OpenClaw uses the provider named in the selected model id (litellm/<model>, anthropic/<model>, openai/<model>). An override key takes effect only when you select a model from that provider. To keep every request on LiteLLM (budget tracking, spend logs), select litellm/ models and leave both OPENCLAW_*_API_KEY overrides empty.
The OpenClaw gateway includes a built-in web dashboard for administration:
-
Direct access:
http://localhost:${OPENCLAW_GATEWAY_PORT}(default 63076) -
Via Kong:
http://openclaw.localhost:${KONG_HTTP_PORT}(default port 63000)
The dashboard provides:
- Chat interface for interacting with the agent
- Configuration management
- Execution approvals
- Channel status monitoring
Security: The dashboard is an admin surface and requires OPENCLAW_GATEWAY_TOKEN (read it with the parser helper in Β§7). Atlas generates the token at startup when it is empty, because the gateway refuses to bind to the LAN without a token.
Run OpenClaw CLI commands inside the container.
From the repository root, define the helper and read the values before the remaining commands.
It uses the bootstrapper dependencies through uv and reads the active Atlas env file.
The default file is .env; use ATLAS_ENV_FILE for a custom file:
env_get() {
PYTHONPATH=bootstrapper uv run --project bootstrapper python - "$@" <<'PYENV'
import sys
from core.config_parser import ConfigParser
parser = ConfigParser(root_dir=".")
if not parser.env_file_path.is_file():
sys.exit("The active Atlas env file does not exist.")
key = sys.argv[1]
fallback = sys.argv[2] if len(sys.argv) == 3 else ""
value = parser.parse_env_file().get(key) or fallback
if not value:
sys.exit(f"Set a nonempty {key} in the active Atlas env file.")
print(value)
PYENV
}
PROJECT_NAME=$(env_get PROJECT_NAME atlas) || exit 1
OPENCLAW_GATEWAY_PORT=$(env_get OPENCLAW_GATEWAY_PORT 63076) || exit 1
OPENCLAW_GATEWAY_TOKEN=$(env_get OPENCLAW_GATEWAY_TOKEN) || exit 1
# Run onboarding
docker exec -it "${PROJECT_NAME}-openclaw-gateway" openclaw onboard
# Point OpenClaw's OpenAI provider at LiteLLM (base URL and gateway key)
docker exec -it "${PROJECT_NAME}-openclaw-gateway" openclaw config set models.providers.openai.baseUrl "http://litellm:4000/v1"
docker exec -it "${PROJECT_NAME}-openclaw-gateway" sh -c 'openclaw config set models.providers.openai.apiKey "$LITELLM_API_KEY"'
# Check health
docker exec -it "${PROJECT_NAME}-openclaw-gateway" openclaw doctor
# View gateway status
docker exec -it "${PROJECT_NAME}-openclaw-gateway" openclaw gateway probe
# Read the gateway token
env_get OPENCLAW_GATEWAY_TOKENUse the env_get helper and PROJECT_NAME from Β§7.
# Direct health check
curl http://localhost:${OPENCLAW_GATEWAY_PORT}/healthz
# Deep health check (the container's environment supplies the token)
docker exec ${PROJECT_NAME}-openclaw-gateway sh -c 'node openclaw.mjs health --token "$OPENCLAW_GATEWAY_TOKEN"'Runs OpenClaw gateway in a Docker container.
Best for: Standard deployment, messaging app integrations
Resources: Atlas sets no memory limit and has not measured the gateway's memory use. Upstream's 2 GB guidance applies to building the image, which Atlas does not do.
Setup: Automatic via docker-compose
Connects to OpenClaw running natively on the host machine.
Best for: Development, custom configurations, persistent settings
Resources: Node.js 22+, npm
Setup: Manual β see Β§3.2 (openclaw gateway --port 63065, or set OPENCLAW_LOCALHOST_PORT to your port).
No OpenClaw agent (default).
Best for: When messaging agent functionality is not needed
Impact: No messaging platform integration available
-
LiteLLM β the gateway container waits for
litellmto be healthy (depends_on). No other service requires OpenClaw.
See Β§5.
- OpenClaw Documentation
- OpenClaw Docker Guide
- LiteLLM Gateway β the OpenAI-compatible front door OpenClaw points at by default
-
Hermes Agent β the agent runtime.
HERMES_ENDPOINTandHERMES_API_KEYare set in this container, but no OpenClaw-to-Hermes bridge exists yet. - OpenClaw GitHub Repository
Support tier: experimental β Capability contract declared; no cited cold-start, workflow, or upgrade qualification run yet (evidence at v0.1.0).
| Capability | Status | Verification | Notes |
|---|---|---|---|
| LiteLLM-backed messaging agent gateway | partial | tested | Atlas injects the LiteLLM key, and openclaw-init points the bundled litellm provider at http://litellm:4000 when its baseUrl is unset. Messaging channels and approvals require onboarding and are not exercised against live platforms. |
| Container and operator-host sources | partial | tested | Atlas initializes and runs the container source, while localhost mode only resolves an existing operator-managed gateway and cannot guarantee its version, onboarding, or supervision. |
| Direct cloud-provider overrides | partial | tested | Optional OpenClaw-specific Anthropic or OpenAI keys can bypass LiteLLM, which also bypasses Atlas gateway accounting and centralized provider routing. |
| OpenClaw gateway authentication | partial | tested | OPENCLAW_GATEWAY_TOKEN, generated at startup, protects the gateway API and dashboard; the CORS-only Kong route adds no Atlas authentication of its own. Direct gateway ports are loopback-only by default; an operator who deliberately publishes them remotely must secure that exposure separately. |
| Agent configuration and workspace persistence | partial | tested | Config and workspace data persist in local named volumes, with no MinIO sharing, backup workflow, replication, or tenant-isolated workspace topology. |
| Hermes and n8n message bridges | stubbed | tested | Hermes endpoint variables are injected and OpenClaw webhooks are documented, but Atlas ships no live forwarding implementation between OpenClaw, Hermes, or n8n. |
| Untrusted agent command isolation | not-supported | documented | OpenClaw can manage files and execute commands from messaging workflows, while Atlas configures no mandatory sandbox runner or per-channel authorization policy. |
Problem: EACCES: permission denied, open '/home/node/.openclaw/openclaw.json'
Solution:
- The
openclaw-initcontainer should fix this automatically on startup - If it persists, set
PROJECT_NAMEas in Β§7 and run:docker run --rm -v ${PROJECT_NAME}-openclaw-config:/data alpine chown -R 1000:1000 /data - Restart the gateway:
docker restart ${PROJECT_NAME}-openclaw-gateway
Problem: OpenClaw container fails to start
Solution:
- Check logs (set
PROJECT_NAMEas in Β§7):docker logs ${PROJECT_NAME}-openclaw-gateway - Verify image is available:
docker pull ghcr.io/openclaw/openclaw:2026.6.10 - Ensure ports 63076/63077 (the gateway and bridge defaults;
OPENCLAW_GATEWAY_PORT/OPENCLAW_BRIDGE_PORT) are free - Check
docker logsfor an exit code 137 (out of memory) and give Docker more memory if you see it
Problem: OpenClaw doesn't see any models
Solution:
-
Verify LiteLLM is healthy:
curl http://localhost:63040/health/liveliness(63040 is the defaultLITELLM_PORT) -
List the models LiteLLM serves. From the repository root, read the active file through the bootstrapper dependencies with
uv:PYTHONPATH=bootstrapper uv run --project bootstrapper python - <<'PYMODELS' import subprocess import sys from core.config_parser import ConfigParser parser = ConfigParser(root_dir=".") if not parser.env_file_path.is_file(): sys.exit("The active Atlas env file does not exist.") env = parser.parse_env_file() key = env.get("LITELLM_MASTER_KEY", "") if not key: sys.exit("Set a nonempty LITELLM_MASTER_KEY in the active Atlas env file.") port = env.get("LITELLM_PORT") or "63040" subprocess.run( ["curl", "-H", f"Authorization: Bearer {key}", f"http://localhost:{port}/v1/models"], check=True, ) PYMODELS
-
Check the provider config (
baseUrlmust behttp://litellm:4000; setPROJECT_NAMEas in Β§7):docker exec ${PROJECT_NAME}-openclaw-gateway openclaw config get models.providers.litellm. Checkmodels.providers.openaionly if you repurposed it (Β§7). -
Confirm that
LITELLM_API_KEYis set in the OpenClaw container environment -
For Ollama models, set
LLM_PROVIDER_SOURCEto anollama-*value (notnone), so LiteLLM has an Ollama upstream
Problem: Web dashboard returns errors
Solution:
- Check the health endpoint:
curl http://localhost:63076/healthz(defaultOPENCLAW_GATEWAY_PORT) - Wait for startup (20s start period)
- If using Kong, verify hosts file:
./start.sh --setup-hosts - Sign in with
OPENCLAW_GATEWAY_TOKENfrom.env; it is always required
Problem: Port 63076 (gateway) or 63077 (bridge) is occupied
Solution:
# Use different base port
./start.sh --base-port 64000
# Or check what's using the port
lsof -i :63076| Service | Category | Status |
|---|---|---|
| litellm | llm | optional: openclaw-init sets models.providers.litellm.baseUrl when unset; an operator value is kept |
| Service | Category |
|---|---|
| kong | infra |

Open the full-size diagram for a full-screen view.
-
openclaw β hermes β Why: OpenClaw is positioned as a channel adapter (40+ messaging surfaces); Hermes is the programmable agent runtime already in the stack. The compose file already passes
HERMES_ENDPOINT/HERMES_API_KEYβ only the bridge wiring is missing. Mechanism: OpenClaw skill or webhook plugin forwarding inbound messages tohttp://hermes:8642/v1/chat/completions; replies posted back via OpenClaw'ssendRPC. Effort: medium. Confidence: high. -
openclaw β n8n β Why: OpenClaw webhooks name n8n as a main trigger. n8n gives non-developers a visual way to connect messaging events to stack workflows. Mechanism: n8n HTTP Request node β
POST http://openclaw-gateway:18789/webhooks/<route>withAuthorization: Bearer <route-secret>. Effort: small. Confidence: high. -
openclaw β minio β Why: Workspace files, voice notes, and media attachments live only in the
openclaw-workspaceDocker volume β not addressable by other stack services. Mechanism: configure S3 backend withendpoint=http://minio:9000, dedicatedopenclawbucket alongside the existingMINIO_BUCKET_*set. Effort: small. Confidence: medium. -
openclaw β doc-processor β Why: OpenClaw handles chat PDF and Office attachments poorly. doc-processor (Docling) produces structured Markdown and chunks that the rest of the stack uses. Mechanism: custom OpenClaw skill posting attachments to
${DOCLING_ENDPOINT}/v1/document/convert; persist markdown to workspace + MinIO. Effort: medium. Confidence: high. -
openclaw β weaviate β Why: OpenClaw lists "memory search across persistent knowledge bases" but has no backend wired; Weaviate is the stack's vector DB. Mechanism: skill or MCP server bridging to
http://weaviate:8080/v1/objects(REST) or:50051(gRPC); embedding via LiteLLM's embeddings endpoint. Effort: medium. Confidence: medium. -
openclaw β searxng β Why: OpenClaw ships web-search tools with multiple providers but defaults to commercial APIs; SearXNG is the stack's privacy-preserving metasearch. Mechanism: set OpenClaw's web-search provider to a custom HTTP backend pointing at
${SEARXNG_INTERNAL_URL}/search?format=json&q=.... Effort: small. Confidence: medium.
- Honcho (details) β Headline: hosted/self-hostable user-memory store explicitly listed as an OpenClaw memory-engine backend. Wires into: hermes, backend, local-deep-researcher.
- MCP CLI / external MCP server support β Why pursue: lets OpenClaw use any MCP server (Neo4j, Weaviate, GitHub) over stdio, SSE or streamable HTTP. RAG and graph tools then need no bespoke skills. Effort: medium.
- Webhooks plugin (inbound TaskFlow trigger) β Why pursue: standard surface for n8n/CI/external triggers; auth model already defined. Effort: small.
- Sandbox runners (Docker/SSH backends) β Why pursue: non-main sessions can run tools in Docker sandboxes β meaningfully safer than current host-bound execution. Effort: medium.
-
Local TTS/STT providers β Why pursue: stack already runs
tts-providerandstt-provider; swap OpenClaw's cloud STT/TTS for local providers to keep voice fully on-device. Effort: small. - Memory engines (Honcho / QMD search) β Why pursue: persistent cross-session memory currently absent. Effort: medium.
- S3 / object-storage backend β Why pursue: wire workspace + media to MinIO for cross-service file sharing. Effort: small.