Install
openclaw skills install openclaw-dual-agentRun two OpenClaw agents simultaneously — a paid Anthropic agent and a free agent using either OpenRouter or local Ollama models. Trigger phrases: multi-agent...
openclaw skills install openclaw-dual-agentRun a paid Anthropic agent and free OpenRouter agent side by side with separate Telegram bots.
Create two Telegram bots via @BotFather and extract chat IDs:
curl https://api.telegram.org/bot{TOKEN}/getUpdates | jq '.result[0].message.chat.id'
Authenticate agents:
# Run interactively — avoids exposing keys in shell history
openclaw onboard
⚠️ Never pass API keys directly on the CLI (e.g.
--anthropic-api-key ...) — it exposes them in shell history. Always useopenclaw onboardinteractively. Credential files (auth-profiles.json,openclaw.json) should bechmod 600.
Configure openclaw.json with two agents, separate bindings, and Telegram accounts.
Verify setup:
openclaw doctor
openclaw sessions cleanup \
--store /Users/YOUR_USERNAME/.openclaw/agents/main/store \
--enforce --fix-missing
openclaw restart
agentDir, workspace, and model config.accountId in bindings directs Telegram messages to the correct agent.provider/modelid format (e.g., anthropic/claude-sonnet-4-6).auth-profiles.json in each agent's directory.Adding a free agent:
/Users/YOUR_USERNAME/.openclaw/agents/free-agent/agentopenclaw.json with model.primary: "openrouter/..."auth-profiles.json with OpenRouter API key in agent's directoryaccountId (e.g., "tg2")openclaw restartSwitching models:
Edit openclaw.json agent's model.primary and fallbacks with valid provider/id strings.
Masking secrets for logs:
cat ~/.openclaw/openclaw.json | \
jq '.channels.telegram.accounts |= map_values(.botToken = "[REDACTED]")'
Instead of OpenRouter, run your second agent on a local Ollama model — free, private, and locally-hosted. The default config uses a hybrid approach with OpenRouter cloud fallback for reliability. For fully offline operation, see "Fully Offline Config" below.
macOS:
# Install via Homebrew
brew install ollama
# Or download from https://ollama.ai
Start Ollama:
# In a dedicated terminal, keep it running
ollama serve
Pull a model (choose one based on your needs):
# Google Gemma 4 26B — good balance of capability and speed (17GB)
ollama pull gemma4:26b
# Meta Llama 3.3 70B — very capable, excellent reasoning (43GB)
ollama pull llama3.3:70b
# Qwen 2.5 32B — strong coding and multilingual (20GB)
ollama pull qwen2.5:32b
# Mistral 7B — fast and lightweight, good for quick responses (4GB)
ollama pull mistral:7b
Add the agent entry to openclaw.json (e.g., id: "ayo"):
{
"id": "ayo",
"name": "Ayo",
"workspace": "/Users/YOUR_USERNAME/.openclaw/workspace-ayo",
"agentDir": "/Users/YOUR_USERNAME/.openclaw/agents/ayo/agent",
"model": {
"primary": "ollama/gemma4:26b",
"fallbacks": [
"openrouter/free"
]
},
"heartbeat": {
"every": "1h",
"model": "openrouter/free"
}
}
Key points:
ollama/modelname:tag (e.g., ollama/gemma4:26b, ollama/llama3.3:70b)auth-profiles.json required.ollama serve in a terminal before the gateway startsollama pull modelname:tag before configuring (the model must exist locally)openrouter/free for fallback and heartbeat — this means prompts and context MAY route to OpenRouter cloud. See below for fully offline config.accountId (e.g., "tg_ollama") to route messages to AyoIf you want a truly local, offline-only Ollama agent with no external provider calls:
{
"id": "ayo",
"name": "Ayo",
"workspace": "/Users/YOUR_USERNAME/.openclaw/workspace-ayo",
"agentDir": "/Users/YOUR_USERNAME/.openclaw/agents/ayo/agent",
"model": {
"primary": "ollama/gemma4:26b",
"fallbacks": []
},
"heartbeat": {
"every": "1h",
"model": "ollama/gemma4:26b"
}
}
This config uses ONLY local Ollama models — no cloud provider traffic for primary, fallback, or heartbeat.
After config change:
# Verify no errors
openclaw doctor
# Restart the gateway
openclaw gateway restart
| ❌ Wrong | ✅ Correct | Issue |
|---|---|---|
gemma4:26b:local | ollama/gemma4:26b | Invalid format; always use provider/model:tag |
gemma4:26b | ollama/gemma4:26b | Without prefix, OpenClaw won't route to Ollama |
ollama/kimi-k2.5:cloud | openrouter/kimi-k2.5:cloud | Cloud models don't belong in Ollama fallbacks |
| Model not pulled | ollama pull gemma4:26b | Gateway fails silently if model doesn't exist locally |
If you see "Invalid input" errors in openclaw doctor, check the model.primary format — it must start with ollama/.
references/config-reference.md — Full openclaw.json, bindings, and auth-profiles.json examplesreferences/troubleshooting.md — Common errors, fixes, and Node.js compatibility notes