██████╗██╗ █████╗ ██╗ ██╗██████╗ ███████╗
██╔════╝██║ ██╔══██╗██║ ██║██╔══██╗██╔════╝
██║ ██║ ███████║██║ ██║██║ ██║█████╗
██║ ██║ ██╔══██║██║ ██║██║ ██║██╔══╝
╚██████╗███████╗██║ ██║╚██████╔╝██████╔╝███████╗
╚═════╝╚══════╝╚═╝ ╚═╝ ╚═════╝ ╚═════╝╚══════╝
██████╗██╗ █████╗ ██╗ ██╗
██╔════╝██║ ██╔══██╗██║ ██║
██║ ██║ ███████║██║ █╗ ██║
██║ ██║ ██╔══██║██║███╗██║
╚██████╗███████╗██║ ██║╚███╔███╔╝
╚═════╝╚══════╝╚═╝ ╚═╝ ╚══╝╚══╝
Your local agent CLI, delivered to your phone via Telegram.
ClaudeClaw is not a chatbot wrapper. It runs Claude Code on your Mac, Linux, or Windows machine and pipes the result back to your Telegram chat. Everything that works in your terminal (your skills, your tools, your context) works from your phone.
Eight surfaces, one bot, one machine. Telegram for chat, the dashboard for everything else, war room for live multi-agent conversation (text or voice), Mission Control for queued work, Scheduled for recurring runs, Hive Mind to see what every agent has been doing. Everything is local: SQLite database, Node bot, optional dashboard. No cloud, no telemetry, no per-message API calls beyond the model itself.
DISCLAIMER — Provider support. Setup configures Claude as the agent provider. This release also introduces runtime support for OpenCode, Gemini CLI, the Codex ACP adapter, and custom ACP commands; those are gated behind
ENABLE_ACP=truein.envand can be enabled post-setup via the dashboard Settings page ornpm run provider:setup(or by editingstore/main-config.json).Non-Claude providers are experimental and new. Different models interpret prompts differently — some will treat a casual chat message as a request to run shell commands or modify files. To keep that surprise contained, conversational Telegram and dashboard chat with non-Claude providers is restricted to read-only tools (
Read,Grep,Glob) by default. Mission tasks, scheduled jobs, and the war-room flows are unaffected. If a non-Claude provider isn't behaving the way you expect, switch back to Claude.
ClaudeClaw has two tiers of features. The core features work out of the box with just a Telegram bot token. The experimental features are opt-in and require additional setup.
Everything below works with TELEGRAM_BOT_TOKEN, ALLOWED_CHAT_ID, and one authenticated agent provider. ClaudeClaw itself does not need extra feature API keys unless you enable the experimental features below.
| Feature | What it does |
|---|---|
| Text messaging | Full local agent access from your phone. All tools, all skills. |
| Photos and documents | Send a photo or PDF, your agent reads and analyzes it |
| Session persistence | Context carries across every message, even after restarts |
| Memory system | SQLite-backed memory that learns about you over time |
| Scheduled tasks v2 | Cron with plain-English descriptions, visual time picker, edit/pause/resume/delete |
| Web dashboard | Live monitoring, theme + UI scale + accent personalization, workspace name |
| Mission Control | Kanban with custom column widths, drag-drop reassign, auto-assign via Gemini, history drawer |
| Multi-agent | Run specialist agents (research, comms, content, ops, meta) in parallel |
| Agent creation wizard | 3-step flow from BotFather token to running agent — directly in the dashboard |
| Custom agent avatars | Upload PNG/JPEG/WebP per agent, or fall back to Telegram profile photo, or to bundled art |
| Hive Mind | Cross-agent activity log with 2D and 3D anatomical brain views, lobe-hover stats, per-agent pie chart |
| Agent files editor | Edit each agent's CLAUDE.md from the dashboard with full SQLite-backed version history |
| All your skills | Every skill in ~/.claude/skills/ auto-loads |
| File sending | Your agent can create and send files back to you |
| Voice output (macOS) | Uses say + ffmpeg locally, no API key needed |
These are powerful but require extra API keys or services. Each one has its own setup section below.
| Feature | What you need | Notes |
|---|---|---|
| Voice input | GROQ_API_KEY (free) |
Transcribes your voice notes via Whisper |
| Voice output (cloud) | ElevenLabs, Gradium, or Kokoro | Higher quality than macOS say |
| Video analysis | GOOGLE_API_KEY |
Gemini analyzes videos you send |
| Memory consolidation | GOOGLE_API_KEY |
Gemini detects patterns across conversations |
| War Room (voice) | GOOGLE_API_KEY + Python venv |
Live voice boardroom with your agent team via Gemini Live (no Deepgram, no Cartesia) |
| War Room (text) | none extra | Multi-agent text group chat with agent rail, /standup, /discuss, ad-hoc rosters, sticky-addressee follow-ups |
| Standup roster picker | none extra | Drag-reorder, toggle, cap, and rotate /standup speakers from the dashboard |
| Live Meetings (Daily.co) | DAILY_API_KEY |
Send an agent into a Daily.co video room with a Pika avatar that speaks in real time |
| WhatsApp bridge | Puppeteer + QR scan | Highly experimental. Read/send WhatsApp from Telegram |
Follow these steps in order. The whole thing takes about 5 minutes.
| Requirement | Notes |
|---|---|
| Node.js 20+ | Check: node --version. Download at nodejs.org |
| Git | Check: git --version. If you've never used git, also run the two commands below |
| Claude Code | Authenticate via claude login (any plan), or set ANTHROPIC_API_KEY for pay-per-token. Other ACP providers (OpenCode, Gemini CLI, Codex adapter, custom) are an experimental opt-in — see the provider disclaimer above. |
| Telegram account | Any existing account works |
First time using git? Run these two commands first (use your own name and email):
git config --global user.name "Your Name"
git config --global user.email "you@example.com"Without this, git operations will fail with a confusing error about missing identity.
macOS users: After starting ClaudeClaw for the first time, your Mac may show "Node wants to access..." permission dialogs. You need to click Allow on each one or the bot will silently hang. Keep an eye on your Mac screen during the first run.
Using Claude Code? ClaudeClaw can run the claude CLI, so any Claude plan works (Free, Pro, Max). However, complex multi-step tasks (building skills, debugging code, multi-agent work) perform significantly better on Opus. If you're on the Free or Pro plan and Claude struggles with a task, the model matters. Sonnet is fast but often can't handle the kind of agentic work ClaudeClaw enables. Max ($100 or $200) with Opus is the recommended Claude Code experience.
Want to try a non-Claude provider? OpenCode, Gemini CLI, Codex, and custom ACP commands are supported as an experimental opt-in. See the provider disclaimer near the top of this README for how to enable them after setup.
New to the terminal? Download Warp, it's a modern terminal with AI built in. If you hit any OS-level issues during setup (permissions, missing tools, PATH problems), type /agent in Warp and describe what went wrong. It will walk you through fixing it. This alone will save you hours of Googling.
That's it for hard requirements. Everything else (voice, video, WhatsApp) is optional and the setup wizard will ask about them.
You need a bot token from Telegram. This is what ClaudeClaw uses to send and receive messages.
- Open Telegram and search for @BotFather
- Send
/newbot - Follow the prompts, give it a name and a username (e.g.
MyAssistantBot) - Copy the token BotFather gives you, it looks like
1234567890:AAFxxxxxxx
Keep this token handy for the next step.
git clone https://github.com/earlyaidopters/claudeclaw-os.git
cd claudeclaw-os
npm installnpm run setupThe wizard walks you through everything interactively:
- Checks your environment (Node, Claude CLI, builds if needed)
- Configures Claude as the agent provider
- Asks which features you want (voice, video, War Room, WhatsApp)
- Sets up your Telegram bot token and auto-detects your chat ID
- Configures security: PIN lock, emergency kill phrase, idle auto-lock
- Creates your
CLAUDE.mdpersonality file from a template - Collects API keys only for the features you selected
- Optionally sets up specialist agents (custom or from templates)
- Offers to start the bot immediately when done
Prefer to let Claude handle it? After cloning,
cdinto the repo, runclaude, and paste:I just cloned ClaudeClaw. Please read README.md and set me up completely. install deps, configure .env, help me get any API keys I need, and set up the background service for my OS.
The setup wizard detects your chat ID automatically. When it asks you to message your bot on Telegram, just send any message and press Y. It picks up your chat ID via the Telegram API.
If you skipped this step during setup, the bot will auto-detect your chat ID the first time you message it and save it to .env for you.
The wizard offers to start the bot at the end. If you said yes, it's already running. Otherwise, run npm start. Then send any message. Try:
What can you do?
or
Check my calendar for today
or just start talking. Claude is running on your machine, with access to your files, the web, and every skill you've installed.
You probably want ClaudeClaw running automatically, not manually in a terminal.
macOS: the setup wizard installs a launchd agent. Or manually:
# After running npm run setup, it's already installed.
# Logs:
tail -f /tmp/claudeclaw.logLinux: the setup wizard installs a systemd user service:
systemctl --user status claudeclaw
journalctl --user -u claudeclaw -fWindows: two supported paths. WSL2 is smoother, native works too.
- WSL2 (recommended):
wsl --install -d Ubuntuin an elevated PowerShell, reboot, clone ClaudeClaw inside the Ubuntu filesystem (not/mnt/c), then follow the Linux steps above. Keep~/.claude/inside WSL2. - Native Windows: the setup wizard registers a per-user Scheduled Task that runs at logon (no admin rights required). Manage it with:
Logs are in
schtasks /Query /TN "com.claudeclaw.main" schtasks /End /TN "com.claudeclaw.main" schtasks /Run /TN "com.claudeclaw.main" schtasks /Delete /TN "com.claudeclaw.main" /F
logs\main.log. Same for each agent atlogs\<agent-id>.log. - PM2 fallback (native Windows) if the scheduled task route doesn't work:
npm install -g pm2 pm2 start dist/index.js --name claudeclaw pm2 save && pm2 startup
Caveats on native Windows:
- The War Room voice feature expects a POSIX Python venv. If you need voice, use WSL2.
better-sqlite3is a native module. Ifnpm installfails, install Visual Studio Build Tools (C++ workload) and retry. WSL2 skips this.- macOS-only TTS (
say) is off; use ElevenLabs for voice replies instead.
npm run statusOutput looks like:
✓ Node v22.3.0
✓ Agent provider: Claude Code (ACP providers available behind ENABLE_ACP)
✓ Bot token: @YourBotName
✓ Chat ID: 1234567890
✓ Voice STT: Groq (configured)
⚠ Voice TTS: not configured
✓ Service: running (PID 12345)
✓ Memory DB: 47 memories stored
─────────────────
All systems go.
When a new version is released, update in 5 commands:
cd claudeclaw-os # go to your ClaudeClaw directory
git pull # pull the latest code
npm install # install any new dependencies
npm run migrate # apply any pending migrations
npm run build # recompile TypeScriptThen restart the bot (Ctrl+C and npm start, or restart the background service).
Do not point Claude at the GitHub URL to read updates. Claude works with local files, so you need the repo cloned on your machine. git pull is how you stay current.
Upgrading from V1? If you heavily customized V1, start fresh with V2 and copy over your .env and any CLAUDE.md customizations. If you kept V1 mostly stock, git pull will work.
ClaudeClaw is designed to run on a local Mac or Linux box. Most setup paths assume you've installed and authenticated Claude Code on the host (claude login), you have a writable filesystem for SQLite + Obsidian + skill caches, and the process restarts mean "your machine reboots". If you want to host it on Railway, Fly, Render, Hetzner, or any other VM/container platform, two things break by default.
ClaudeClaw starts Claude Code as a subprocess. A fresh container has no ~/.claude/ auth files, so the subprocess exits immediately and ClaudeClaw retries forever. The CLI normally reads your Max-plan OAuth credentials from ~/.claude/.credentials.json, which is created by claude login on the host.
Pick one of:
- Long-lived OAuth token (Max plan). On your local machine run
claude setup-token. It prints a token that does not expire on its own. Set it on your cloud host asCLAUDE_CODE_OAUTH_TOKEN=<token>. Redeploy. - API key (pay per token). Get a key from console.anthropic.com. Set
ANTHROPIC_API_KEY=<key>. This bypasses your subscription and bills per request.
If you've opted into ACP providers (see the disclaimer at the top), the equivalent applies: install the provider command in the container or VM and configure its credentials there before starting ClaudeClaw. OpenCode needs opencode auth login plus a default model; Gemini CLI needs its own auth and runs through gemini --acp; Codex needs the Codex CLI authenticated with codex; custom ACP providers need the command and args available on PATH. ClaudeClaw only stores the provider type, model/settings, or custom command; it does not copy model-provider keys into .env.
ClaudeClaw stores conversation history, extracted memories, scheduled tasks, WhatsApp Web session keys, Slack tokens, and audit logs in store/claudeclaw.db on disk. Most cloud platforms wipe the filesystem on every redeploy. Without a persistent volume mount you lose the SQLite database, which means:
- Every redeploy resets memory and session history
- WhatsApp Web reauthorizes (requires scanning the QR again)
- Scheduled tasks vanish
- Mission Control queue drops
Mount a persistent volume at the project root (/app on Railway, a Fly volume on Fly, etc.) so store/ survives restarts. If your platform doesn't offer persistence, ClaudeClaw will work as a stateless bot but the memory and messaging features won't behave the way they do locally.
- CPU/RAM: each query starts a Claude Code subprocess (or your configured ACP provider subprocess if enabled). 512 MB minimum, 1 GB recommended.
- Outbound network: needs to reach
api.telegram.org, the Anthropic API (or your configured ACP provider's endpoint), and any optional services you enable (Gemini, ElevenLabs, Slack, etc.). - launchd / systemd: skip the background-service step in setup. Your platform manages the process.
- Cloudflare Tunnel: if you want the dashboard public, the cloud platform's own URL will already be public. You don't need the tunnel.
If your platform refuses to run the bot at all (binary missing, npm install failing in the container, etc.), open an issue with the platform name and the build log. Cloud deployment isn't the supported path, but we'll help where we can.
See the feature table at the top of this README. Core features work with zero extra API keys. Experimental features are opt-in.
Most users only need a Telegram bot token. Everything below the Telegram section is optional and only needed for experimental features.
Model-provider credentials are handled by the agent provider itself:
- Claude Code (default): use
claude loginfor subscription/OAuth auth (any plan), or setANTHROPIC_API_KEYif you want pay-per-token billing.
The ACP providers below are an experimental opt-in (see the provider disclaimer near the top of this README). Once you set ENABLE_ACP=true in .env, switch providers via the dashboard Settings page or npm run provider:setup.
- OpenCode: configure provider keys in OpenCode itself with
opencode auth login. If you want to use GLM, Qwen, DeepSeek, local providers, or another OpenCode-supported provider, set that API key and default model in OpenCode before starting ClaudeClaw. ClaudeClaw does not store those keys in.env. - Gemini CLI: configure Gemini CLI separately. ClaudeClaw starts
gemini --acp; Gemini handles its own model and auth. - Custom ACP: configure the provider and its API keys outside ClaudeClaw, then save the ACP command and args via the dashboard Settings page or
npm run provider:setup. - Codex ACP adapter: ClaudeClaw includes the
codex-acpadapter and uses it to connect to your locally signed-in Codex CLI. Runcodexonce in your terminal first to confirm your Codex account is authenticated. This is adapter-based support, not native Codex ACP.
Get it: @BotFather → /newbot. free, instant.
What it does: Transcribes your voice notes using Whisper before passing them to Claude.
Get it: console.groq.com. free tier, no card needed.
Model: whisper-large-v3
| Alternative | Cost | Notes |
|---|---|---|
| Groq (default) | Free | Fastest to set up |
| OpenAI Whisper | ~$0.006/min | Swap transcribeAudio() in src/voice.ts |
| AssemblyAI | Free tier | More features |
| Local Whisper.cpp | Free | No API, runs on your Mac. needs code change |
What it does: Converts Claude's responses to audio in your cloned voice.
Get it: elevenlabs.io → clone your voice under "Voice Lab" → copy the Voice ID string.
Model: eleven_turbo_v2_5
Tuning: Edit src/voice.ts if the cloned voice sounds off:
stability: 0.5 (higher = more consistent but robotic)
similarity_boost: 0.75 (higher = closer to you but can distort)
| Provider | Cost | Notes |
|---|---|---|
| ElevenLabs (primary) | Free tier + paid | Best cloning quality |
| Gradium AI (built-in alternative) | Free tier (45k credits/mo) | Add GRADIUM_API_KEY + GRADIUM_VOICE_ID to .env |
| macOS say + ffmpeg (built-in fallback) | Free | No API key. works offline. Set TTS_VOICE in .env to change voice |
| OpenAI TTS | ~$0.015/1k chars | Good quality, no cloning. needs code change |
| Google Cloud TTS | Free tier | More robotic. needs code change |
The TTS cascade tries ElevenLabs first, falls back to Gradium, then to macOS say. Configure whichever providers you want. even just the local fallback works fine.
What it does: Analyzes videos you send using Gemini. Also handles images, audio, function calling, structured output, and code execution via the gemini-api-dev skill.
Get it: aistudio.google.com → "Get API key". free tier.
Skill to install: The gemini-api-dev skill is published by Google at:
- Skill docs: github.com/google-gemini/gemini-skills/.../gemini-api-dev/SKILL.md
- Repo: github.com/google-gemini/gemini-skills
- Install: copy the
gemini-api-devfolder into~/.claude/skills/
The skill reads GOOGLE_API_KEY from the environment automatically.
What it does: Bypasses your Max subscription and uses pay-per-token billing instead when the active provider is Claude Code.
When to use it: Server deployments, or if you want zero ambiguity about billing. The Max plan assumes "ordinary individual usage". an always-on bot can hit limits faster than expected.
Get it: console.anthropic.com
What it does: Lets an ACP provider call whichever model provider you choose, such as GLM, Qwen, DeepSeek, Gemini, local providers, or any other provider supported by that ACP command.
Where to configure it: In the provider, not ClaudeClaw. For OpenCode:
opencode auth login
opencode models
npm run provider:setupUse opencode auth login to add the provider API keys, opencode models to confirm the model IDs available to OpenCode, and npm run provider:setup to tell ClaudeClaw to use OpenCode.
For Gemini CLI, authenticate and configure Gemini first, then select Gemini:
gemini
npm run provider:setupFor Codex, install/authenticate the Codex CLI first, then run codex once in your terminal to confirm it works. ClaudeClaw includes the @zed-industries/codex-acp package and launches the bundled codex-acp adapter for you, so you normally do not need to install a separate codex-acp binary globally.
For a custom ACP provider, install and authenticate that provider first, then select "Custom ACP" and enter the command and args. The dashboard Settings page can save provider-specific model ids, thinking levels, and speed options when the provider advertises them through ACP session/configuration. Access/sandbox mode is not exposed as a setting: ClaudeClaw runs providers in full-access mode when the ACP provider offers it, because this is an autonomous local assistant.
ClaudeClaw ships with bundled Gmail and Google Calendar skills that work great out of the box. This is an optional alternative if you want broader Google Workspace access from a single tool.
Google released an official CLI that covers Drive, Gmail, Calendar, Sheets, Docs, Chat, Admin, and every other Workspace API in one tool. It's dynamically built from Google Discovery Service and includes 40+ agent skills out of the box.
Repo: github.com/googleworkspace/cli
What's a CLI, and how is it different from a skill or MCP?
There are three ways Claude can interact with external services. They all achieve similar things, but work differently under the hood:
| What it is | How Claude uses it | |
|---|---|---|
| CLI (Command Line Interface) | A program you install on your machine that runs commands in the terminal. Think of it like a text-based app. | Claude runs terminal commands like workspace drive list or workspace gmail send through the Bash tool. It's the same as if you typed those commands yourself. |
| Skill | A markdown file (.md) that teaches Claude how to do something specific, usually by combining CLI commands, API calls, or code into a workflow. |
Claude reads the skill file and follows its instructions. ClaudeClaw's bundled Gmail skill, for example, tells Claude which Python scripts to run and how to format the output. |
| MCP (Model Context Protocol) | A server that runs in the background and gives Claude access to tools directly, without going through the terminal. | Claude calls MCP tools natively, like calling a function. No terminal commands needed. It's the most seamless option but requires a running MCP server. |
In short: a CLI is a tool you run in the terminal, a skill is a set of instructions that tells Claude how to use tools, and an MCP is a live server that gives Claude direct access to tools. They can all do similar things, just with different tradeoffs in setup and flexibility.
What it gives you beyond the bundled skills:
- Google Drive (upload, download, search, share)
- Sheets and Docs (read, write, create)
- Chat (send messages, manage spaces)
- Admin (user management, org units)
- Every other Workspace API, auto-discovered
When to use it: If you want your assistant to interact with Google Workspace services beyond email and calendar, or if you prefer a single unified CLI over individual skills.
Setup: Follow the install instructions in the repo, then reference it in your CLAUDE.md so your assistant knows it's available.
Sending a voice note transcribes it and executes it as a command. The reply comes back as text by default: not audio.
To get a voice reply back from a specific voice note, say one of these anywhere in your message:
"respond with voice" "respond via voice" "respond in voice"
"send me a voice note" "send a voice back" "voice reply"
"reply with voice" "reply via voice"
To toggle voice replies on permanently for all messages, send /voice. Send it again to turn it off. Resets on restart.
Voice output uses a cascade of TTS providers. If the first one fails, it tries the next:
- ElevenLabs (primary). best quality, voice cloning
- Gradium AI (alternative). free tier with 45k credits/month
- macOS
say+ ffmpeg (local fallback), no API key needed, works offline on Mac
If all TTS providers fail, it falls back to text automatically.
Voice note sent
↓
.oga file downloaded → renamed .ogg (Groq requires this)
↓
Groq Whisper → transcribed text
↓
Check for voice-back trigger phrases
├── found → Claude runs → TTS cascade → audio reply
│ (ElevenLabs → Gradium → macOS say)
└── not found → Claude runs → text reply
Want full voice conversations? The War Room (experimental) lets you have live voice meetings with your agent team using Gemini Live. No Deepgram or Cartesia needed. The recommended setup is just
GOOGLE_API_KEY. See the War Room section below.
Send a photo with or without a caption. Caption becomes the instruction. No caption. Claude describes what it sees.
Any file Claude Code can open: PDFs, code, markdown, CSV, plain text. Caption is the instruction.
ClaudeClaw downloads the video to workspace/uploads/ and tells Claude to analyze it with the gemini-api-dev skill. Without GOOGLE_API_KEY, Claude receives the file path but can't understand the content. Telegram caps downloads at 20MB.
Ask your agent to create a file (PDF, spreadsheet, image, text) and send it to you. It creates the file on your machine, includes a [SEND_FILE:/path] marker in its response, and the bot sends it as a Telegram attachment. Works with any file type up to 50MB.
"Write a haiku about AI and send it to me as a text file"
"Create a PDF summary of my meeting notes and send it"
"Generate a chart of monthly revenue and send the image"
Claude can also send photos inline using [SEND_PHOTO:/path], and attach captions via [SEND_FILE:/path|caption text]. Multiple files in a single response are sent in order. If a file doesn't exist, you get an error message instead of a crash.
Provider sessions carry context across messages. ClaudeClaw namespaces session ids by provider, so switching between Claude, OpenCode, Gemini, Codex, and custom ACP starts or resumes the right provider session instead of mixing histories. Send /newchat to start fresh.
Every skill in ~/.claude/skills/ loads on every session. Call them directly (/gmail check inbox) or describe what you want. Claude routes automatically if you've listed the skill in CLAUDE.md.
Everyday commands:
| Command | What it does |
|---|---|
/help |
List all available commands |
/stop |
Cancel the current agent query mid-execution. works from Telegram and the dashboard |
/model |
Switch Claude model for this chat when the active provider is Claude. For all providers, the dashboard Settings page is the main model picker |
/provider |
Show the active provider and where its model/thinking settings are selected |
/voice |
Toggle voice replies on/off for all messages. When off, voice notes still get transcribed and executed. replies just come back as text |
/newchat |
Wipe the active provider session and start fresh. Use when context gets stale or the conversation window is filling up |
/respin |
Pull the last 20 conversation turns back into a fresh session. Run this right after /newchat to keep recent context without the full token weight |
/memory |
Show what the bot remembers about you (recent memories from SQLite) |
/forget |
Clear the session ID only. Memories stay and decay naturally over time |
Integrations:
| Command | What it does |
|---|---|
/wa |
Open the WhatsApp interface. shows recent chats, pick one to read and reply |
/slack |
Open the Slack interface, same flow as WhatsApp |
/dashboard |
Get a clickable link to the live web dashboard |
Security:
| Command | What it does |
|---|---|
/lock |
Lock the session immediately. Requires PIN to unlock. Only works when PIN is configured. |
/status |
Show current security status: PIN enabled, locked/unlocked, idle timeout, kill phrase |
Setup (one-time):
| Command | What it does |
|---|---|
/start |
First message to the bot, confirms it's running |
/chatid |
Shows your Telegram chat ID for the ALLOWED_CHAT_ID setting in .env |
All built-in commands are registered in Telegram's command menu, so you get autocomplete when you type /.
Any skill in ~/.claude/skills/ that has user_invocable: true in its SKILL.md frontmatter automatically shows up in Telegram's / command menu. No code changes needed -- just drop a skill folder in and restart the bot.
For example, if you install the bundled tldr skill:
cp -r skills/tldr ~/.claude/skills/tldrThe next time the bot starts, /tldr appears in Telegram's autocomplete alongside the built-in commands. The description shown in the menu comes from the skill's description field in its frontmatter.
How it works: On startup, ClaudeClaw scans ~/.claude/skills/ for folders containing a SKILL.md with valid YAML frontmatter. If user_invocable: true is set, the skill's name and description are registered with Telegram's setMyCommands API alongside the built-in commands. Telegram allows up to 100 commands total.
Important: Telegram aggressively caches the command menu on mobile. After installing a new skill and restarting the bot, you may need to fully close Telegram (swipe it away from your app switcher, not just minimize) and reopen it before the new / commands appear.
Any /command not in the built-in list (like /todo, /gmail, /tldr) passes through to Claude and routes to whatever matching skill you have installed.
Context windows fill up over long conversations. When things start feeling off or Claude starts missing context:
- Send
/newchatto start a completely fresh session - Send
/respinimmediately after
/respin pulls the last 20 conversation turns from the database and feeds them back into the new session as context. Claude sees what you discussed recently without carrying the full token weight of the old session. It's like a soft restart.
The pulled-in turns are marked as historical context (not new messages), so Claude treats them as background rather than active conversation.
Send /slack to enter Slack mode. It works like the WhatsApp interface:
/slack list recent conversations (unread first)
1 open conversation #1, show last 15 messages
r <text> reply to the open conversation
r 2 <text> quick-reply to conversation #2 without opening it
Type anything that isn't a number or r <text> to exit Slack mode and return to normal Claude.
A live web page that shows you everything happening inside your assistant: what tasks are scheduled, what it remembers, how much you're spending, and whether it's healthy. You open it from Telegram with one tap.
When you start ClaudeClaw, a small web page starts running alongside the bot. It reads directly from the same database the bot uses and shows you the data in real time.
Here's what happens when you use it:
- You send
/dashboardin Telegram: the bot replies with a clickable link - You tap the link: a web page opens in your browser with four live panels
- The page updates itself every 60 seconds: no need to refresh manually
By default, this web page only works on the same computer running the bot. If you want to open it from your phone while you're out, you can add a free tunnel (explained below).
Nothing leaves your machine. The dashboard reads your local database and shows it to you. No data is sent to any cloud service.
At the top of the dashboard, a summary stats bar gives you an at-a-glance overview:
| Stat | What it shows |
|---|---|
| Messages | Total conversation turns today across all agents |
| Agents | How many agents are currently running vs. configured |
| Cost Today | Total API spend for the day |
| Memories | Total memories stored in the system |
Below that, the dashboard is organized into panels:
| Panel | What it shows you |
|---|---|
| Agents | Status cards for every configured agent. Shows live/off status, model, today's turns and cost. Click a card to see recent conversation, hive mind activity, and Start/Stop/Delete controls. + New Agent button opens a 3-step wizard to create and activate a new agent directly from the dashboard. |
| Hive Mind | A real-time activity feed showing what each agent has been doing, with timestamps and color-coded agent names. Includes a privacy blur toggle. |
| Tasks | Unassigned mission tasks waiting to be routed. Create tasks with a title and prompt, then either drag them to an agent column or click Auto-assign to let Gemini classify and route them automatically. |
| Mission Control | A kanban board with one column per agent. Shows running and recently completed tasks per agent. Click History to open a paginated drawer of all completed tasks with full results. Completed tasks stay visible for 30 minutes, then move to history. |
| Scheduled Tasks | Recurring cron tasks. Shows status, next run countdown, last result. Pause, resume, or delete directly. |
| Memory Landscape | Total memories, consolidation insights, importance distribution chart. Sections for fading memories (salience < 0.5) and recently retrieved. Tap to browse all memories in a drill-down drawer. Includes a 30-day memory creation timeline. |
| System Health | Context window gauge (green/yellow/red), session age, compaction count, connection status for Telegram, WhatsApp, and Slack. |
| Tokens & Cost | Today's spend, all-time cost, 30-day cost timeline chart, cache hit rate chart. |
The dashboard also has a live chat overlay: a floating chat button that opens a real-time conversation panel. You can send messages to Claude directly from the dashboard and see responses stream in via SSE (Server-Sent Events). It shows tool progress in real time and has a stop button to abort queries mid-execution. Messages sent from the dashboard are also relayed to your Telegram chat.
On your phone it's a single scrollable page. On a computer it splits into two columns automatically.
Open your terminal and paste this command:
node -e "console.log(require('crypto').randomBytes(24).toString('hex'))"It prints a long random string like a3f8c2d1e5b794.... this is your dashboard password. Copy it. You'll need it in the next step.
Open the .env file in your ClaudeClaw folder. (This is the same file where your Telegram token and other keys live. Open it with any text editor. TextEdit on Mac, Notepad on Windows, or whatever your terminal editor is.)
Add this line:
DASHBOARD_TOKEN=paste_the_long_string_here
That's the only setting you need. There are two optional ones you can ignore for now:
DASHBOARD_PORT=3141 # the dashboard uses port 3141 by default. only change this if something else on your computer already uses that port
DASHBOARD_URL= # leave this blank for now. you only fill this in if you set up phone access (Step 5 below)
Save the file.
npm run build
npm startYou should see a log line that says Dashboard server running. If you don't, double-check that DASHBOARD_TOKEN is in your .env.
The easiest way: send /dashboard to your bot in Telegram. It replies with a clickable link. Tap it. Done.
Or open your browser and go to:
http://localhost:3141/?token=YOUR_TOKEN&chatId=YOUR_CHAT_ID
Replace YOUR_TOKEN with the password from Step 1, and YOUR_CHAT_ID with the ALLOWED_CHAT_ID from your .env.
You're done. The dashboard now works on the machine running the bot.
If that's all you need, stop here. The next step is only if you want to access the dashboard from your phone while away from home.
Right now the dashboard only works when you're on the same computer. To open it from your phone (or anywhere), you need a "tunnel". a free service that securely connects your computer to the internet without opening any ports.
Option A: Quick tunnel (free, takes 2 minutes, but the link changes every time you restart)
Best for trying it out:
# Install the tunnel tool (Mac)
brew install cloudflare/cloudflare/cloudflared
# On Linux, use: curl -L https://github.com/cloudflare/cloudflared/releases/latest/download/cloudflared-linux-amd64 -o /usr/local/bin/cloudflared && chmod +x /usr/local/bin/cloudflaredStart the tunnel:
cloudflared tunnel --url http://localhost:3141It prints a URL like https://something-random.trycloudflare.com. Copy that URL, open your .env file, and set:
DASHBOARD_URL=https://something-random.trycloudflare.com
Restart the bot (npm run build && npm start). Now when you send /dashboard in Telegram, the link works from your phone.
Downside: The URL changes every time you restart the tunnel. You'll need to update .env each time.
Option B: Permanent URL (free, but you need to buy a cheap domain for $5-12/year)
This gives you a URL that never changes. like https://dash.mysite.com. You need a domain registered through Cloudflare. Go to dash.cloudflare.com → Domain Registration → Register Domain. Cheapest options: .work, .xyz, .site (around $5-12/year).
Once you have a domain, run these commands one at a time:
# 1. Install the tunnel tool (skip if you already did this)
brew install cloudflare/cloudflare/cloudflared
# 2. Log in to Cloudflare (this opens your browser: pick your domain when asked)
cloudflared tunnel login
# 3. Create a tunnel (remember the ID it prints: you'll need it)
cloudflared tunnel create claudeclaw
# 4. Connect your domain to the tunnel (replace with your actual domain)
cloudflared tunnel route dns claudeclaw dash.yourdomain.comNow you need to create a config file. Open your terminal and paste:
nano ~/.cloudflared/config.ymlThis opens a text editor in the terminal. Paste the following (replace the two placeholder values with what the tunnel create command printed):
tunnel: YOUR_TUNNEL_ID
credentials-file: /Users/yourname/.cloudflared/YOUR_TUNNEL_ID.json
ingress:
- hostname: dash.yourdomain.com
service: http://localhost:3141
- service: http_status:404Save and exit (in nano: press Ctrl+X, then Y, then Enter).
Start the tunnel:
cloudflared tunnel run claudeclawUpdate your .env:
DASHBOARD_URL=https://dash.yourdomain.com
Restart the bot. Your permanent dashboard URL is now live.
First time? The secure certificate can take 1-5 minutes to activate on a brand new domain. If your browser shows an error page, wait a couple minutes and refresh.
To make the tunnel start automatically when your computer boots:
brew services start cloudflaredMoving to a new machine later? Copy two files from the old machine: ~/.cloudflared/config.yml and the .json credentials file next to it. Run cloudflared tunnel run claudeclaw on the new machine. Same URL, no changes needed.
- The dashboard link contains your password. Treat it like you'd treat a password. Don't screenshot the address bar and post it somewhere. The dashboard can only show data (nobody can change or delete anything through it), but your task details and memory content would be visible.
- If the bot stops, the dashboard stops. They run together. Restart the bot and the dashboard comes back automatically.
- Quick tunnel links are temporary. If you used Option A and restart the tunnel tool, you get a new URL and the old one stops working. Option B (permanent URL) doesn't have this problem.
- For extra security: Cloudflare Access (free for up to 50 users) can add a login page in front of the dashboard, so even if someone finds the URL they'd need to authenticate. This is optional. the token alone is fine for personal use.
Dashboard API reference (for developers)
All endpoints require ?token=YOUR_TOKEN. Per-user endpoints also need &chatId=YOUR_CHAT_ID.
| Endpoint | Returns |
|---|---|
GET / |
Dashboard HTML page |
GET /api/tasks |
All scheduled tasks |
GET /api/memories?chatId= |
Memory stats, fading list, top accessed, timeline |
GET /api/memories/list?chatId=§or=&limit=&offset= |
Paginated memory drill-down |
GET /api/health?chatId= |
Context gauge, session stats, connections |
GET /api/tokens?chatId= |
Cost stats, 30-day timeline, cache rate |
GET /api/info |
Bot name, username, PID |
GET /api/chat/stream |
SSE stream for real-time chat events (user messages, assistant responses, tool progress) |
GET /api/chat/history?chatId=&limit=&beforeId= |
Paginated conversation history |
POST /api/chat/send |
Send a message from the dashboard ({"message": "..."}) |
POST /api/chat/abort |
Abort the current agent query |
The dashboard adapts to how you read code, not the other way around. Settings → Appearance:
| Knob | What you can change |
|---|---|
| Color theme | Dark / light / auto. Drives the entire SPA, not just one panel. |
| Custom hex accent | Pick from six preset accents (mint / amber / cyan / pink / lavender / blue) or paste your own #hex. Live-previews across highlights, focus rings, badges, brain glow, and chart strokes. |
| UI scale | Compact / cozy / comfortable. Changes font size and spacing globally — doesn't break any layout because every measurement uses the same scale variable. |
| Workspace name | Rename the sidebar header. Useful if you run multiple ClaudeClaw installs (work / personal). |
| Sidebar sections | Collapse the sections you don't use so the rail is shorter on small screens. |
| Mission column order + widths | Drag the columns; reorder by name; persist per-install. |
Everything writes to dashboard_settings via PATCH /api/dashboard/settings — JSON-validated, byte-capped (4 KB), scoped to an explicit allowlist of keys. A malformed payload bounces with a 400 and a specific error message rather than silently saving and breaking the next read.
Requires a Slack User OAuth Token. This connects to your workspace so ClaudeClaw can read and send messages on your behalf.
- Go to api.slack.com/apps
- Click the green Create New App button (top right)
- In the popup, choose From scratch (not "From an app manifest")
- Fill in:
- App Name: anything you want (e.g.
ClaudeClaw) - Pick a workspace: select the Slack workspace you want to connect
- App Name: anything you want (e.g.
- Click Create App
You'll land on the Basic Information page for your new app.
This is the critical step. You need to add permissions so the app can read and send messages as you.
-
In the left sidebar, click OAuth & Permissions
-
Scroll down past "OAuth Tokens for Your Workspace" until you see the Scopes section
-
You'll see two subsections: Bot Token Scopes and User Token Scopes
-
Ignore Bot Token Scopes entirely. Click Add an OAuth Scope under User Token Scopes
-
Add each of these scopes one at a time (click Add an OAuth Scope, type the name, select it):
Scope Description channels:historyView messages and other content in public channels channels:readView basic information about public channels in a workspace chat:writeSend messages on a user's behalf groups:historyView messages and other content in private channels groups:readView basic information about private channels im:historyView messages and other content in direct messages im:readView basic information about direct messages mpim:historyView messages and other content in group direct messages mpim:readView basic information about group direct messages search:readSearch a workspace's content users:readView people in a workspace After adding all 11, your User Token Scopes section should show all of them listed.
- Scroll back up to the top of the OAuth & Permissions page
- Under OAuth Tokens for Your Workspace, click Install to Workspace
- Slack will show a permissions screen listing everything the app can do
- Click Allow
- You'll be redirected back to the OAuth & Permissions page
- You'll now see a User OAuth Token field with a token that starts with
xoxp- - Click Copy to copy the token
- Open your
.envfile in the ClaudeClaw project directory - Add the token:
SLACK_USER_TOKEN=xoxp-your-token-here - Restart ClaudeClaw
Send /slack in your Telegram chat. You should see a numbered list of your recent Slack conversations with unread counts.
If you get "Slack not connected", double-check:
- The token starts with
xoxp-(notxoxb-which is a bot token) - The
.envfile has no extra spaces around the=sign - You restarted ClaudeClaw after adding the token
ClaudeClaw ships with a Slack CLI at dist/slack-cli.js and a matching skill in skills/slack/. To use Slack via natural language from any Claude Code session:
cp -r skills/slack ~/.claude/skills/slackThen just say "check my slack" or "message Jane on slack saying hey" and Claude handles the rest.
cd /path/to/claudeclaw
node dist/slack-cli.js list # List conversations with unread counts
node dist/slack-cli.js list --limit 10 # Limit results
node dist/slack-cli.js read <channel_id> # Read messages from a conversation
node dist/slack-cli.js send <channel_id> "message" # Send a message
node dist/slack-cli.js send <channel_id> "reply" --thread-ts 1234.5678 # Thread reply
node dist/slack-cli.js search "jane" # Find conversations by nameThe War Room is where you bring multiple agents into one conversation. Three modes share the same dashboard surface:
- Text mode — async multi-agent group chat with
/standup,/discuss, ad-hoc rosters, and an MSN-style status rail. No extra setup, no API keys. - Voice mode — live voice boardroom over Gemini Live. Talk, get spoken replies in each agent's distinct voice.
- Live Meetings — send a Pika-avatar agent into a Daily.co video room as a real participant.
The text war room is the easiest way to pull your full team into one thread. Open the dashboard, click War Room → Text → New text meeting, and you've got a multi-agent group chat with full transcript and per-agent rail.
Three slash commands shape how the room behaves:
| Command | What it does |
|---|---|
/standup |
Every enabled agent in the standup roster speaks once, in order. Status update format. |
/discuss <topic> |
Same roster, but framed as a discussion of <topic> rather than a status check. |
/standup @meta @research |
Ad-hoc roster — only the named agents run. Saved roster is ignored for this run. |
You can also @-mention a single agent (@research what trends should I know about?) and the team chimes in only when relevant — gated by a lightweight classifier that decides whether each non-mentioned agent has something to add.
Rotation queue. When more agents are enabled than the per-turn cap (default 8), the over-cap agents queue and rotate on the next /standup call so every agent eventually speaks. The standup config page footnotes this whenever the queue is non-empty.
Hive logging. Every primary reply lands in the cross-agent hive_mind table as action='warroom_reply'; intervener replies log as action='warroom_chime_in'. Replies under 25 chars and legacy meetings (no chat_id) are filtered out. This is what populates the Hive Mind brain views and the per-agent activity rails.
Dashboard → War Room → Standup opens the roster editor. From here you decide:
- Order — drag-reorder the agent list. The first slot is the primary leader of every
/standuprun. - In / out — toggle which agents participate. Disabled rows stay in the list (so you don't lose your order) but are skipped at runtime.
- Cap — slider 1..8 (the orchestrator's
SLASH_HARD_CAP). The header readsX will speak · Y in rotation · Z disabledso you always know what the next call will look like.
Saved to dashboard_settings.standup_config and read by pickSlashRoster() in the orchestrator. Ad-hoc @-mention rosters skip this config entirely for the duration of one command.
The voice war room is a live boardroom you join from the browser. You speak, Gemini Live processes your voice natively (speech-to-speech), and agents respond with their own voices. You can pin a specific agent for direct conversation, or use "hand-raise" mode where Gemini automatically routes your questions to the best agent.
What you need:
GOOGLE_API_KEY(Google AI Studio, free tier works)- Python 3.10+ with a virtual environment
WARROOM_ENABLED=truein your.env
Default setup (Gemini Live mode): Gemini handles both speech recognition and voice synthesis natively with sub-second latency. No Deepgram, no Cartesia, no extra voice API keys. Just your Google API key.
Setup:
# 1. Create the Python virtual environment
python3 -m venv warroom/.venv
source warroom/.venv/bin/activate
pip install -r warroom/requirements.txt
# 2. Add to your .env
WARROOM_ENABLED=true
GOOGLE_API_KEY=your-google-ai-studio-key
# 3. Rebuild and restart
npm run build
npm startAccess: Open the dashboard and click "War Room" in the navigation. The interface has a cinematic intro, agent sidebar with click-to-pin, live mic waveform, and transcript view.
Modes:
- Direct mode: Talk to one pinned agent. Click a different agent card to switch.
- Auto mode (hand-raise): Gemini listens and routes each question to the best agent automatically. You'll see a hand-up animation on the agent card that's answering.
Voices: Each agent has a distinct Gemini voice (configurable via the dashboard voice settings). The voice config lives in warroom/voices.json.
Entrance music: The War Room can play background music during the cinematic intro. Upload any mp3 via the "upload" link in the War Room sidebar. The file saves to warroom/music.mp3 (gitignored) and plays at low volume, fading out when the session connects. No music ships by default.
Legacy mode: If you prefer the original stitched pipeline (Deepgram STT + Claude + Cartesia TTS), set WARROOM_MODE=legacy and provide DEEPGRAM_API_KEY + CARTESIA_API_KEY. This has higher latency (~10s per turn) but runs the full Claude Code stack per utterance.
Rebuilding the Pipecat client bundle: If you modify warroom/client.js, rebuild with:
npm run build:warroom-clientThis feature is experimental. It works, but it uses Puppeteer to drive a headless browser session with WhatsApp Web. It can break when WhatsApp updates their web client, requires a QR code scan to authenticate, and the session can expire. Use at your own risk.
No API key needed. Uses your existing WhatsApp account via Linked Devices.
npx tsx scripts/wa-daemon.tsA QR code prints. Open WhatsApp → Settings → Linked Devices → scan within 30 seconds. Session saves to store/waweb/. you only scan once.
/wa list 5 most recent chats (unread first)
1 open chat #1, show last 10 messages
r <text> reply to the open chat
r 2 <text> quick-reply to chat #2 without opening it
When someone messages you on WhatsApp:
📱 John Smith. new message
/wa to view & reply
No content is forwarded automatically. You pull it on demand.
Messages you send via the bot go into a wa_outbox SQLite table. The daemon's outbox poller (every 3 seconds) picks them up and delivers them. If the daemon is temporarily down, messages queue and deliver when it comes back.
All WhatsApp message bodies are encrypted at rest using AES-256-GCM before being written to the database. Even if someone accesses store/claudeclaw.db directly, message content is unreadable without the encryption key in your .env.
Messages are also automatically deleted after 3 days: The retention sweep runs on startup and every 24 hours, covering wa_messages, wa_outbox, and wa_message_map. This is enforced in code and cannot be bypassed without modifying runDecaySweep() in src/memory.ts.
The store/ directory (database, WhatsApp session, logs) is gitignored with multiple layers of protection. It will never be committed to the repo.
ClaudeClaw has a structured memory system that extracts, consolidates, and recalls knowledge across all sessions. Everything is automatic.
Every time you send a message, Claude resumes the same session using a stored session ID, so conversation history carries across messages without you re-sending anything. If you've opted into an ACP provider, the same model applies: ClaudeClaw stores sessions in separate per-provider namespaces so switching providers doesn't cross-contaminate session IDs.
Use /newchat to start a completely fresh session when you want a clean slate.
After each conversation turn, Gemini Flash evaluates whether the exchange contains anything worth remembering long-term. If it does, it extracts structured data: a summary, entities, topics, connections to other memories, and an importance score (0.0 to 1.0). Only memories scoring 0.5+ are saved. This filters out noise like "ok thanks" or command acknowledgments.
Each memory also gets a vector embedding for semantic search.
Importance tiers and decay:
| Importance | What gets this score | Daily decay | Approximate lifespan |
|---|---|---|---|
| 0.8 - 1.0 | Core identity, critical rules, strong preferences | 1% per day | ~460 days |
| 0.5 - 0.7 | Useful context, standing decisions, workflows | 2% per day | ~230 days |
| Below 0.5 | Not saved (filtered at extraction) | n/a | n/a |
| Pinned | Anything you mark as permanent | No decay | Forever |
Memories that are actually useful in conversations get a salience boost (+0.1 per use). Memories that surface but aren't relevant get penalized (-0.05). This feedback loop means the system learns what matters over time.
Before every message, five parallel searches build your memory context:
- Semantic vector search: finds memories similar in meaning to your message (cosine similarity > 0.3)
- High-importance recall: recent memories with importance >= 0.5
- Consolidation insights: patterns detected across multiple memories (e.g., "User consistently prefers X over Y")
- Team activity: what other agents have done in the last 24 hours (from the Hive Mind)
- Conversation history recall: triggered when you say things like "remember when" or "what did we discuss"
The results are deduplicated and prepended to your message as a block Claude sees:
[Memory context]
Relevant memories:
- [0.8] User prefers short bullet replies over long paragraphs
- [0.6] Working on YouTube channel rebrand this week
Insights:
- User has strong communication preferences: concise, no fluff
[Team activity]
- [comms] 2h ago: Processed weekly email digest
[End memory context]
A background process finds patterns across unconsolidated memories: themes, contradictions, and connections. When a newer memory contradicts an older one, the older memory is superseded (importance reduced, marked as outdated). Consolidation insights surface in the memory context block.
Requires GOOGLE_API_KEY in your .env (Gemini Flash, costs ~$0.03/day).
/memory show the most recent memories stored for this chat
/forget clear the current session (memories keep decaying naturally)
High-importance memories (0.8+) trigger a Telegram notification when saved, giving you a chance to pin them. Pinned memories never decay.
src/memory-ingest.ts: controls what gets extracted and the importance threshold:
// The Gemini extraction prompt defines what's worth remembering
// Importance threshold (default: 0.5) filters low-value memoriessrc/db.ts: controls decay constants:
// importance >= 0.8: 0.99 multiplier (1% daily decay)
// importance >= 0.5: 0.98 multiplier (2% daily decay)
// pinned = 1: no decay
// Deleted when salience < 0.05While Memory is what each agent remembers about you, Hive Mind is what every agent can see about each other. Every meaningful action by any agent — a war-room reply, a finished mission task, a tool call, a scheduled run — lands in one shared hive_mind table. The dashboard turns that table into a real-time activity feed and a brain visualization you can hover.
The flow is the same regardless of which agent fires:
- Source. Some agent does something — finishes a task, replies in the war room, calls a tool.
- Write.
logToHiveMind()inserts a row withagent_id,chat_id,action,summary, optional artifacts. - Stream. The dashboard's SSE channel broadcasts the new row to every open tab.
- Render. The brain dispatches: 3D mode parents a new dot to the right lobe and fires a synapse arc; 2D mode increments the lobe's counter and pulses its glow.
- Output. You see it in the rail, on the brain, and in the per-agent activity panels.
Some replies are filtered out so the brain stays signal-rich: war-room replies under 25 chars (catches "ok" / "noted"), legacy meetings with no chat_id, and retry replays where the assistant insert was a no-op.
The 3D view is a real anatomical cerebrum mesh from the NIH 3D Print Exchange, rendered in WebGL via Three.js. On top of the mesh:
- Cortex glow uses
EffectComposer + UnrealBloomPassso the brain pulses subtly with overall activity. - Activity dots are parented to the brain group — one per
hive_mindrow, positioned by lobe, invisible until filtered in. - Synapse arcs fire on every new entry: a curved line from the prior lobe to the new one, deduplicated via a
seenEntryIdsSet, capped at 24 concurrent arcs so memory stays bounded. - Hover a lobe and a tooltip pops with the entry count and a per-agent pie chart breaking down which agents drove that lobe's activity.
- The slider that used to filter visible agents is repurposed as a glow intensity knob for screenshots and demos.
The whole scene runs in BrainGraph3D.tsx at 60fps with a side-three-quarter camera angle so you can see all four lobes without rotating.
The 2D view is a fallback for tabs where WebGL is unavailable, or when you'd rather not run a Three.js scene. It draws into an HTML5 <canvas> with the same data source:
- A cerebrum silhouette with frontal / parietal / temporal / occipital lobes, gyri textured as bezier curves, and a soft inner shadow per region.
- Activity dots placed inside each lobe shape, fading with row age.
- Lobe stats panel on hover: entry count plus the same per-agent breakdown the 3D brain shows.
The 2D view repaints instantly on filter changes and is significantly lighter on the GPU. Use whichever feels right; the data is identical.
The Hive Mind page has a blur toggle that hides every summary while preserving counts, agent badges, and timestamps. Use it before screen-sharing or screenshots if your activity logs name internal projects you don't want visible.
Tell Claude what you want, in plain language:
Every Monday at 9am, summarize AI news from the past week and send it to me
Every weekday at 8am, check my calendar and inbox and give me a briefing
Every 4 hours, check for new emails from clients and flag anything urgent
Claude creates the task via CLI; the dashboard's Scheduled page becomes the day-to-day control surface.
- Plain-English descriptions. Every task shows its cron parsed back into something readable:
Every weekday at 9:00 AM,Every 4 hours,On the 1st of each month at 9:00 AM. No more decoding0 8 * * 1-5in your head. - Visual time-of-day picker. Click any task to edit. Pick the days of the week (M T W T F S S), pick the hour and minute on a wheel, and the editor writes the cron back for you.
- Edit prompts and assignments. Change the prompt, the schedule, or the agent assignment without recreating the task. Edits are live — the next run uses the new values.
- Per-agent scoping. Every task has an agent tag (
@main,@comms,@research, ...) and runs inside that agent's process, scoped to its memory and skills. - Inline pause / resume / delete. Buttons live on each row. Bulk-select with the checkbox column to delete a stack at once.
- Last-result snippet. Click the chevron on a row to see the last execution's output and timestamp without leaving the page.
- Privacy blur toggle. Hides task prompts before you screen-share or screenshot — the rest of the page stays visible.
node dist/schedule-cli.js list
node dist/schedule-cli.js create "summarize AI news" "0 9 * * 1"
node dist/schedule-cli.js pause <id>
node dist/schedule-cli.js delete <id>| Cron pattern | Meaning |
|---|---|
0 9 * * 1 |
Every Monday at 9am |
0 8 * * 1-5 |
Every weekday at 8am |
0 9 1 * * |
First of the month at 9am |
0 */4 * * * |
Every 4 hours |
0 7 * * * |
Every day at 7am |
Mission Control lets you create one-shot tasks and assign them to any agent from the dashboard or via Telegram.
- Create a task from the dashboard (click + New Task in the inbox column) or tell your main agent: "have research look into X"
- The task appears in the Inbox column on the dashboard, unassigned, with a priority pill
- Assign it by dragging it to an agent column, clicking Auto-assign for a single task, or Auto-assign all to bulk-route every unassigned task in one shot
- The target agent picks it up within 60 seconds, executes it, and sends the result to your Telegram chat
- Completed tasks linger in the agent's column for 30 minutes (so you can re-read the result inline), then move to the History drawer where they're paginated and searchable
The kanban is fully customizable. Use the Layout menu in the column header to:
| Preset | What it does |
|---|---|
| Uniform | Every column the same width — best for screenshots and first-time scans |
| Fit | Each column sized to its widest task title — best for long task names |
| Reset | Back to the default proportions |
You can also drag any column border to resize it manually. Order and widths persist per workspace via dashboard_settings.mission_column_order and mission_column_widths — no re-arranging on every reload.
Click any inbox card to open the task details modal: full prompt, priority, creation timestamp, and a single-click reassign drop-down. Useful when you've forgotten what's queued and want to triage without dragging things around.
When you click Auto-assign, Gemini Flash reads the task prompt and matches it against your agent descriptions (from their agent.yaml files). A task about "draft a reply to John's email" routes to the comms agent. A task about "research competitors" routes to the research agent. Costs about $0.0001 per classification. Auto-assign all runs the same classifier in bulk for every unassigned task in the inbox.
Your main agent can create mission tasks for other agents. Just say things like:
- "have research look into the top competitors in AI coding"
- "get ops to update the Stripe pricing"
- "ask comms to draft a reply to that partnership email"
The main agent creates the task via CLI and responds immediately. The target agent picks it up asynchronously.
node dist/mission-cli.js create --agent research --title "Competitor analysis" "Full prompt here"
node dist/mission-cli.js list
node dist/mission-cli.js result <id>
node dist/mission-cli.js cancel <id>Omit --agent to create an unassigned task (assign from dashboard).
Mission tasks go through the same FIFO message queue as user messages and scheduled tasks. They can never collide with an active conversation. Each task runs in a fresh session and has a 10-minute timeout.
ClaudeClaw ships with SQLite and creates everything automatically on first run: No migrations, no setup, no external database server. File lives at store/claudeclaw.db.
Schema:
sessions -- Claude Code session IDs, one per chat per agent
memories -- Structured memories with importance, salience, embeddings
memories_fts -- Virtual FTS5 table, auto-synced via triggers
consolidations -- Insights synthesized across memories (patterns, contradictions)
scheduled_tasks -- Cron-scheduled recurring tasks (per agent)
mission_tasks -- One-shot async tasks for Mission Control
conversation_log -- Full conversation turns (per agent, used by /respin)
token_usage -- Per-turn token counts and cost tracking
hive_mind -- Cross-agent activity log
inter_agent_tasks -- Real-time delegation tracking (@agent: syntax)
wa_message_map -- Maps Telegram message IDs to WhatsApp chats
wa_outbox -- Queued outgoing WhatsApp messages
wa_messages -- Incoming WhatsApp message history (encrypted, 3-day retention)
slack_messages -- Slack message history (encrypted, 3-day retention)Encryption: WhatsApp and Slack message bodies are encrypted with AES-256-GCM before storage. The key lives in your .env as DB_ENCRYPTION_KEY. Raw SELECT queries on the body column will return ciphertext. Use the app's read functions to get decrypted content.
Retention: Messages in wa_messages, wa_outbox, wa_message_map, and slack_messages are auto-deleted after 3 days by runDecaySweep().
Inspect it directly:
sqlite3 store/claudeclaw.db
SELECT summary, importance, salience FROM memories ORDER BY created_at DESC LIMIT 10;
SELECT * FROM scheduled_tasks;
SELECT title, status, assigned_agent FROM mission_tasks ORDER BY created_at DESC;
SELECT agent_id, action, summary FROM hive_mind ORDER BY created_at DESC LIMIT 10;
SELECT * FROM sessions;CLAUDE.md is loaded into every ClaudeClaw session. It's the personality and context file, and setup also creates an AGENTS.md symlink for tools that look for that filename. Edit CLAUDE.md to make ClaudeClaw yours.
The sections that matter most:
Personality rules: Be specific. "No em dashes, ever" and "don't narrate what you're about to do, just do it" change behavior on every single message.
Who you are: What you do, your projects, your context. The more specific, the less you have to explain per message.
Your environment: File paths Claude should be able to reach without being told: your Obsidian vault, project directories, anything you reference regularly.
Skills table: Maps skill names to trigger phrases. This teaches Claude to invoke them automatically when you describe a task.
Message format: How responses should look in Telegram: tight and scannable, summary-first for long outputs, how to handle task lists.
ClaudeClaw gets more useful the more context you give it. Each layer compounds on the last. Your CLAUDE.md is the foundation, skills add capabilities, and your file system becomes the knowledge base. The more you invest in these layers, the less you explain per message and the more your agents can do autonomously.
Here's how to think about it if you're a business owner:
This is the base. Every session loads it. Tell Claude about your business, your role, your tools, your preferences. Open Claude Code in your terminal and try:
Update my CLAUDE.md with this context:
- I run [your business]. We sell [products/services].
- My team is [size], mostly in [locations/timezones].
- I use [tools: Stripe, Notion, Slack, etc.] daily.
- When I say "check revenue" I mean Stripe + Gumroad combined.
- My writing style: [direct, casual, formal, etc.].
- Never [thing you hate in AI output].
Claude can read any file on your machine. Organize key business docs where agents can find them:
Create a ~/Business folder structure for my ClaudeClaw agents:
- ~/Business/SOPs/ for standard operating procedures
- ~/Business/Templates/ for email templates, proposals, contracts
- ~/Business/Clients/ for client briefs and notes
- ~/Business/Products/ for pricing, feature lists, positioning docs
Then update my CLAUDE.md to reference these paths so agents
know where to look without being told.
If you use Obsidian, point your vault path in CLAUDE.md and agents will search it automatically.
Each skill you install is a new capability every agent inherits. Start with the basics and add more as you need them:
Install these skills into ~/.claude/skills/:
- gmail (email triage, drafting, sending)
- google-calendar (scheduling, availability checks)
- agent-browser (web research, form filling, scraping)
Then test: send "check my email" to your bot on Telegram.
The skill catalog is at github.com/anthropics/claude-code/tree/main/skills. Community skills work too. Anything in ~/.claude/skills/ auto-loads for every agent.
Once you have context and skills, specialist agents multiply your throughput:
| Agent | Handles | You stop doing |
|---|---|---|
| comms | Email triage, Slack replies, DM responses | Inbox scanning |
| research | Market research, competitor tracking, trend reports | Manual googling |
| content | Drafts, social posts, scripts | First-draft writing |
| ops | Calendar, billing, task management | Admin work |
Each agent gets its own 1M context window, its own CLAUDE.md personality, and access to every skill you've installed.
Each layer makes the others more powerful:
- CLAUDE.md alone: Claude knows who you are but can't do much
- + Files: Claude can reference your SOPs, templates, and client notes
- + Skills: Claude can send emails, check your calendar, browse the web
- + Agents: Four specialists working in parallel, each with full context
- + Scheduled tasks: Agents running autonomously on a cron (daily email triage, weekly reports)
- + Memory: Every interaction teaches the system. It remembers client preferences, project history, your patterns
You don't need everything on day one. Start with CLAUDE.md and one skill. Add layers as you feel the gaps.
The startup banner is in banner.txt at the project root. Replace it with anything or leave it empty. It's read fresh on every start.
ClaudeClaw auto-loads every skill in ~/.claude/skills/. Install a skill by copying its folder there.
ClaudeClaw ships with ready-to-use skills in the skills/ directory. Copy any of these to activate them:
# Gmail: read, triage, reply, send, create filters
cp -r skills/gmail ~/.claude/skills/gmail
# Google Calendar: schedule meetings, check availability, send invites
cp -r skills/google-calendar ~/.claude/skills/google-calendar
# Slack: list conversations, read messages, send replies
cp -r skills/slack ~/.claude/skills/slack
# TLDR: summarize conversations and save as notes
cp -r skills/tldr ~/.claude/skills/tldrGmail + Calendar require Google OAuth credentials. See .env.example for the variables and each skill's SKILL.md for one-time setup instructions (create a Google Cloud project, enable the API, download credentials, run auth once).
Slack requires a User OAuth Token. See the Slack setup section above for step-by-step instructions.
todo. read tasks from Obsidian or text filesagent-browser. browse the web, fill forms, scrape datamaestro. run multiple tasks in parallel with sub-agents
For video analysis:
gemini-api-dev. published by Google, handles video/image/audio/text- Docs: github.com/google-gemini/gemini-skills/.../gemini-api-dev/SKILL.md
- Install: copy the
gemini-api-devfolder to~/.claude/skills/
Browse more: github.com/anthropics/claude-code
| Variable | Required | Description |
|---|---|---|
TELEGRAM_BOT_TOKEN |
Yes | From @BotFather |
ALLOWED_CHAT_ID |
Yes | Your chat ID. send /chatid to get it |
ANTHROPIC_API_KEY |
No | Claude Code pay-per-token instead of Max subscription |
GROQ_API_KEY |
No | Voice input. console.groq.com |
ELEVENLABS_API_KEY |
No | Voice output. elevenlabs.io |
ELEVENLABS_VOICE_ID |
No | Your ElevenLabs voice ID string |
GOOGLE_API_KEY |
No | Gemini. aistudio.google.com |
SLACK_USER_TOKEN |
No | Slack User OAuth Token (starts with xoxp-) |
GOOGLE_CREDS_PATH |
No | Path to Google OAuth credentials.json (default: ~/.config/gmail/credentials.json) |
GMAIL_TOKEN_PATH |
No | Path to Gmail OAuth token (default: ~/.config/gmail/token.json) |
GCAL_TOKEN_PATH |
No | Path to Calendar OAuth token (default: ~/.config/calendar/token.json) |
DASHBOARD_TOKEN |
No | 48-char hex token for dashboard access |
DASHBOARD_PORT |
No | Dashboard port (default: 3141) |
DASHBOARD_URL |
No | Public URL if using Cloudflare Tunnel |
CLAUDE_CODE_OAUTH_TOKEN |
No | Override which Claude account is used |
ACP provider keys are intentionally not listed here. Add them in OpenCode, Gemini CLI, Codex, or your custom ACP provider; ClaudeClaw reads only the active provider type/command.
npm run setup # Interactive setup wizard
npm run provider:setup # Switch between OpenCode, Gemini, custom ACP, Codex, and Claude Code
npm run status # Health check. env, bot, DB, service
npm run build # Compile TypeScript → dist/
npm start # Run compiled bot (production)
npm run dev # Run with tsx, no build needed (development)
npm test # Run test suite (vitest)
npm run test:e2e # Run local Playwright dashboard tests with fake providers
npm run typecheck # Type-check without compilingFor Claude Code, it's a grey area, but signs point to yes for personal use. Anthropic's Agent SDK (@anthropic-ai/claude-agent-sdk) is a published, official package. Boris Cherny (Anthropic) has indicated the Agent SDK can be used for personal usage with a Claude subscription. When the active provider is Claude Code, ClaudeClaw uses this SDK path.
How the Claude Code provider works: The Agent SDK's query() spawns the claude binary as a child process. That subprocess manages its own auth from ~/.claude/. ClaudeClaw never reads or transmits your token. It runs Claude Code and reads the output, identical to typing claude -p "message" in a terminal.
How ACP providers work: ClaudeClaw starts an ACP command and talks to it over the Agent Client Protocol. Built-in presets currently include opencode acp, gemini --acp, and the bundled codex-acp adapter. OpenCode, Gemini, Codex CLI, or your custom ACP provider owns auth, API keys, and model availability. Configure auth before selecting the provider in ClaudeClaw; model, thinking, and speed preferences can be saved from the dashboard when the provider supports those ACP settings.
| ClaudeClaw | Token-extraction tools | |
|---|---|---|
Runs the official claude CLI |
✅ | ❌ |
Auth stays in ~/.claude/ |
✅ | ❌ |
| Uses Anthropic-published SDK | ✅ | ❌ |
| Single-user, personal machine | ✅ | ❌ |
| Anthropic telemetry intact | ✅ | ❌ |
What's clearly not OK: Tools that extract your OAuth token and make API calls with it from third-party code, or impersonate Claude Code without running it.
For server or multi-user deployments, set ANTHROPIC_API_KEY to use pay-per-token billing. This removes any ambiguity since you're paying directly for usage.
ClaudeClaw has multiple security layers. Some are always on, others are opt-in. The setup wizard (npm run setup) configures all of them interactively.
These protections are active in every ClaudeClaw installation, no configuration needed.
| Layer | What it does |
|---|---|
| Chat ID restriction | ALLOWED_CHAT_ID locks the bot to a single Telegram account. Messages from any other user are silently dropped. |
| Private chat only | The bot rejects all group chats. Only private (1-on-1) conversations are accepted. |
| Audit logging | Every action (messages, commands, delegations, lock/unlock, blocked attempts) is recorded to the audit_log table in SQLite with timestamps, agent ID, and chat ID. |
| DB file permissions | The store/ directory is set to 0700 and all database files to 0600 on startup (owner-only access). |
| Message encryption | WhatsApp and Slack message bodies are encrypted with AES-256-GCM before being written to the database. The key is stored in .env (gitignored). |
| Message auto-purge | A 3-day retention sweep runs on startup and every 24 hours, deleting all message data from wa_messages, wa_outbox, wa_message_map, and slack_messages. |
Full-access execution. This is an autonomous local assistant, so provider turns run without interactive tool approval. Claude Code uses permissionMode: 'bypassPermissions'; ACP providers run in full-access mode when they advertise an access/sandbox config option. The agent can execute tools such as shell commands, file reads, and web requests without confirmation. This is safe only when the bot is locked to your chat ID on your own machine. Do not expose it to untrusted users.
PIN lock adds a session gate. When enabled, the bot starts locked and ignores all messages until you send the correct PIN.
| Behavior | Detail |
|---|---|
| Startup | Bot starts locked. Send your PIN as a regular message to unlock. |
/lock |
Locks the session immediately. |
/status |
Shows current security status (locked/unlocked, idle timeout, kill phrase). |
| Idle auto-lock | If IDLE_LOCK_MINUTES is set, the session re-locks after that many minutes of inactivity. |
The PIN is stored as a salted SHA-256 hash. The plaintext never touches disk.
Set EMERGENCY_KILL_PHRASE to a unique phrase. Sending it immediately stops all ClaudeClaw launchd/systemd services and force-exits the process. This is a hard stop, not a lock. Use it if something goes wrong and you need everything shut down now.
The setup wizard can generate one for you, or you can choose your own.
| Variable | Required | Description |
|---|---|---|
ALLOWED_CHAT_ID |
Yes | Your Telegram chat ID. Bot ignores all other users. |
DB_ENCRYPTION_KEY |
Yes | AES-256 key for message field encryption. Auto-generated on first run. |
SECURITY_PIN_HASH |
No | Salted SHA-256 hash of your PIN. Format: salt:hash. Setup wizard generates this. |
IDLE_LOCK_MINUTES |
No | Auto-lock after N minutes of inactivity. Only active when PIN is set. |
EMERGENCY_KILL_PHRASE |
No | Phrase that immediately kills all agents and exits. |
sqlite3 store/claudeclaw.db \
"SELECT datetime(created_at,'unixepoch'), action, detail FROM audit_log ORDER BY created_at DESC LIMIT 20;"Or view it in the dashboard via the API: GET /api/audit?limit=50.
WhatsApp daemon runs on localhost only. The wa-daemon HTTP API (port 4242) and Chrome DevTools Protocol (port 9222) bind to 127.0.0.1. They are not accessible from outside your machine, but any local process can reach them.
notify.sh is called by Claude. The notification script sends Telegram messages via curl. Since Claude has full shell access, it can call this script with any content. This is by design (progress updates), but prompt injection via external content could theoretically cause unexpected messages.
Bot doesn't respond
- Check
ALLOWED_CHAT_IDmatches the number from/chatid - Check logs:
tail -f /tmp/claudeclaw.log - Run
npm run statusfor a full health check - Verify Claude auth:
claude --version - macOS: Check if your Mac is showing "Node wants to access..." permission dialogs. The bot hangs until you click Allow. This is easy to miss if your Mac screen is off or in the background.
Setup fails at bracket placeholders
CLAUDE.mdships with[BRACKETED]placeholder values like[YOUR NAME]and[YOUR ASSISTANT NAME]- These must be replaced before the bot can work properly
- The setup wizard opens
CLAUDE.mdin your editor for this, but if you skip it or your editor doesn't save, edit it manually: openCLAUDE.mdin any text editor, find/replace all[BRACKETED]values with your actual info - You do not need to fill in every bracket. At minimum:
[YOUR ASSISTANT NAME],[YOUR NAME], and[PATH TO CLAUDECLAW](the full path to your claudeclaw directory)
Git errors during setup
- "Please tell me who you are". run
git config --global user.name "Your Name"andgit config --global user.email "you@email.com" - Git needs these set once, globally, before it can do anything
Can't access the internet / "break out"
- ClaudeClaw runs Claude Code locally. If the agent says it can't access the internet, first verify Claude works in a normal terminal session: run
claudeand ask it to search the web. - If you've opted into an ACP provider, verify that provider works directly too: OpenCode →
opencode, confirm the configured model works and provider API keys are set. Gemini →geminiand confirm auth. Codex →codexand confirm your account/session. Custom ACP → run the command directly.
Voice notes return an error
GROQ_API_KEYmust be in.envand the bot restarted after adding it
Voice replies not working
- Both
ELEVENLABS_API_KEYandELEVENLABS_VOICE_IDmust be set - Voice ID is a string like
21m00Tcm4TlvDq8ikWAM, not the voice name - Either
/voicemode must be on, or say "respond with voice" in your message
WhatsApp not connecting
wa-daemonmust be running separately:npx tsx scripts/wa-daemon.ts- QR code expires after ~30s. kill and restart the daemon if it timed out
- To force re-authentication, delete
store/waweb/and restart the daemon
"409 Conflict: terminated by other getUpdates request"
- Two instances running. Kill the old one:
kill $(cat store/claudeclaw.pid)
Session feels off or confused
- Send
/newchatfor a fresh start
File downloads fail
- Telegram caps downloads at 20MB. this is a Telegram API limit, not a ClaudeClaw one
"Do I need the mega prompt / Rebuild_Prompt.md?"
No. There is no separate prompt to execute and no Rebuild_Prompt.md file. CLAUDE.md is the main instruction file, and setup also creates AGENTS.md as a symlink for tools that expect that filename. You personalize it once (replace the [BRACKETED] placeholders with your info) and forget about it. Just clone the repo, run setup, and go. When you git pull updates, your personalized .env stays untouched.
"Does this use Claude Remote?"
No. ClaudeClaw has nothing to do with Anthropic's Remote product. It runs Claude Code locally on your own machine (Mac, Linux, or Windows via WSL2) — the local claude CLI — and pipes results to Telegram. If you've opted into an ACP provider, that's also a local command (opencode acp, gemini --acp, codex-acp, or your custom ACP command). No cloud VMs, no remote sessions.
"Does this work on Windows?"
Yes, two ways. WSL2 is the smoothest (install WSL2, clone ClaudeClaw inside the WSL filesystem, run the normal Linux setup). Native Windows also works: the setup wizard registers a per-user Scheduled Task at logon (no admin rights), and agent activate/deactivate uses schtasks under the hood. War Room voice still needs WSL2 because the Python stack is POSIX-only.
"What is GOOGLE_API_KEY for?" Video analysis via Google Gemini. It is not for Gmail or Google Calendar (those use separate OAuth credentials via the gmail and google-calendar skills). Get it free at aistudio.google.com.
"Should I watch the Claude Code video first?" Recommended but not required. The video covers how Claude Code works under the hood, which helps you understand what ClaudeClaw is actually doing. But you can set up ClaudeClaw first and watch it later.
"How do I update when a new version drops?"
cd claudeclaw-os && git pull && npm install && npm run migrate && npm run build then restart. See Updating ClaudeClaw above.
"Telegram formatting looks broken / not formatting properly" ClaudeClaw converts Claude's Markdown to Telegram-safe HTML (bold, italic, code blocks, links). Telegram's formatting support is limited compared to a full web page. If something looks off, it's usually Telegram's rendering, not a bug. For very long or complex responses, the formatting is intentionally kept simple to avoid Telegram parse errors.
"Can I add extra security like 2FA?"
ALLOWED_CHAT_ID restricts the bot to your Telegram account, which is the default security layer. Community members have added Google Authenticator (TOTP) for tiered permissions (read-only vs elevated actions with time-limited re-auth). This isn't built in yet, but it's a straightforward addition to handleMessage() in src/bot.ts if you want that extra layer.
flowchart TD
Phone["Telegram App"] -->|message| TGAPI["Telegram Bot API"]
TGAPI -->|long-poll| Bot["bot.ts\n(grammy)"]
Bot -->|voice note| STT["Groq Whisper\nTranscription"]
Bot -->|photo / doc / video| DL["Media Download\nworkspace/uploads/"]
STT --> Handler
DL --> Handler
Bot -->|text| Handler["handleMessage()"]
Handler -->|"5-layer retrieval"| Mem["Memory Layer\nVector + FTS5 + Gemini"]
Mem -->|context block| Agent
Handler -->|"@agent: syntax"| Orch["orchestrator.ts\nAgent delegation"]
Orch -->|route to agent| Agent
Agent["agent.ts\nClaude Agent SDK"] -->|spawns subprocess| CC["claude CLI\n~/.claude/ auth"]
CC -->|loads| Config["CLAUDE.md\n+ ~/.claude/skills/"]
CC -->|uses| Tools["Bash · Web · MCP\nFile system · APIs"]
CC -->|result| Agent
Agent --> Format["Format + Split\nMarkdown to HTML"]
Format -->|reply| TGAPI
Sched["Scheduler\ncron + mission tasks"] -->|every 60s| Agent
WA["WhatsApp daemon\n:4242"] --> Bot
Dashboard["Dashboard\nHono + SSE"] --> Bot
Mission["Mission Control\nTasks inbox + kanban"] --> Sched
DB[("SQLite\nstore/claudeclaw.db")] --- Mem
DB --- Sched
DB --- WA
DB --- Dashboard
DB --- Mission
Gemini["Gemini API\nextraction + auto-assign"] --- Mem
Gemini --- Mission
claudeclaw/
│
│ ← Files you'll actually touch
├── CLAUDE.md ← START HERE: your assistant's personality and context
├── banner.txt ← ASCII art shown on startup. edit or replace freely
├── .env ← Your API keys (created by setup wizard, gitignored)
│
│ ← Configuration and setup
├── .env.example Template for .env. shows all available variables
├── claudeclaw.plist macOS LaunchAgent template (setup wizard uses this)
├── package.json npm scripts and dependencies
├── tsconfig.json TypeScript compiler config
│
│ ← Bot source code (src/)
├── src/
│ ├── index.ts Main entrypoint. starts everything
│ ├── bot.ts Handles all Telegram messages (text, voice, photo, etc.)
│ ├── agent.ts Provider orchestration wrapper around the agent engine
│ ├── agent-engine/ Normalized provider engine: Claude SDK + ACP adapters
│ ├── agent-config.ts Loads agent YAML configs and CLAUDE.md templates
│ ├── orchestrator.ts Agent delegation routing (@agent: syntax)
│ ├── db.ts SQLite database. all tables and queries
│ ├── memory.ts 5-layer context injection and memory feedback
│ ├── memory-ingest.ts Gemini-powered memory extraction from conversations
│ ├── memory-consolidate.ts Pattern detection across memories (every 30 min)
│ ├── embeddings.ts Vector embeddings for semantic memory search
│ ├── gemini.ts Gemini API client (extraction, classification)
│ ├── scheduler.ts Cron + mission task runner. checks every 60 seconds
│ ├── schedule-cli.ts CLI for managing scheduled tasks
│ ├── mission-cli.ts CLI for creating/managing mission tasks
│ ├── voice.ts Voice transcription (Groq) and synthesis (ElevenLabs)
│ ├── media.ts Downloads files from Telegram, cleans up after 24h
│ ├── slack.ts Slack API client (conversations, messages, send)
│ ├── slack-cli.ts CLI wrapper for Slack (used by the slack skill)
│ ├── whatsapp.ts WhatsApp client via whatsapp-web.js
│ ├── dashboard.ts Web dashboard server (Hono + API routes + token auth)
│ ├── dashboard-html.ts Dashboard HTML/CSS/JS (Tailwind + Chart.js, no build step)
│ ├── state.ts Shared state and SSE event emitter
│ ├── message-queue.ts Per-chat FIFO queue (prevents session collisions)
│ ├── config.ts Reads .env safely (never pollutes process.env)
│ ├── env.ts Low-level .env file parser
│ ├── obsidian.ts Obsidian vault context injection (per agent)
│ └── logger.ts Structured logging via pino
│
│ ← Skills (copy to ~/.claude/skills/ to activate)
├── skills/
│ ├── gmail/SKILL.md Gmail inbox management
│ ├── google-calendar/ Calendar events, invites, availability
│ └── slack/SKILL.md Slack conversations and messages
│
│ ← Scripts (scripts/)
├── scripts/
│ ├── setup.ts Interactive setup wizard. run with: npm run setup
│ ├── status.ts Health check. run with: npm run status
│ ├── notify.sh Sends a Telegram message from the shell (used by Claude)
│ └── wa-daemon.ts WhatsApp daemon. run separately for WhatsApp bridge
│
│ ← Runtime data (auto-created, gitignored)
├── store/
│ ├── claudeclaw.db SQLite database. created automatically on first run
│ ├── claudeclaw.pid Tracks the running process to prevent duplicates
│ └── waweb/ WhatsApp session. scan QR once, persists here
│
└── workspace/
└── uploads/ Telegram media downloads. auto-deleted after 24 hours
The only files you need to edit to get started:
CLAUDE.md. fill in your name, what you do, your file paths, your skills.env. add your API keys (the setup wizard does this for you)
Everything else runs without modification.
This is a core feature, not experimental. Setting up multiple agents is straightforward and one of the most powerful things about ClaudeClaw.
What are agents? Instead of one bot doing everything, you can spin up specialist bots. Each one is its own Telegram chat with its own personality, its own context window, and its own focus area. Think of it like having a small team of people, each in their own DM thread on your phone.
How it works in plain English: Each agent is just another Telegram bot running the same ClaudeClaw code, but with a different personality file (CLAUDE.md) and a different Telegram token. They all share your machine, your database, and your skills. The main agent can delegate work to specialists, and they ping you back on Telegram when they're done.
ClaudeClaw can run specialist agents alongside the main bot. Each agent is its own Telegram bot with its own personality, its own Claude Code session, and its own chat on your phone.
Example setup: Comms, Content, Ops, and Research agents, each with a pop-art avatar generated via Gemini.
Your main ClaudeClaw bot does everything. That's powerful but also means one long conversation, one context window, and one personality trying to handle email, research, billing, and content all at once.
Agents let you split the work:
| What | Main bot | Specialist agents |
|---|---|---|
| Context window | Shared across all tasks | Each gets its own 1M window |
| Personality | General purpose | Focused CLAUDE.md per role |
| Model | Opus (default) | Sonnet (cheaper, fast enough for routine work) |
| Scheduled tasks | All fire in one process | Scoped per agent |
| Obsidian context | Optional | Auto-injected from assigned vault folders |
| Cost | Full Opus pricing | Sonnet by default, /model opus when needed |
All agents share your machine, your SQLite database, your global skills (~/.claude/skills/), and your .env secrets. A hive mind table lets agents log what they did so any agent (or the main bot) can see cross-agent activity.
This is 100% optional. npm start with no flags works exactly like before. Zero breaking changes.
Think about the roles that make sense for your workflow. Here are the templates we ship:
| Template | What it handles | Default model |
|---|---|---|
comms |
Email, Slack, WhatsApp, YouTube comments, community forums, LinkedIn DMs | Sonnet |
content |
YouTube scripts, LinkedIn posts, carousels, trend research | Sonnet |
ops |
Calendar, billing, Stripe, Gumroad, admin, task management | Sonnet |
research |
Deep web research, academic sources, competitive intel | Sonnet |
You can start with one and add more later. Or use the blank _template and define your own role entirely.
Open the dashboard's Agents page and click + New Agent. The wizard walks you through three gated steps:
- Template. Pick
comms,content,ops,research, or a blank template. Each loads a defaultCLAUDE.mdyou can edit later. The agent ID is debounced-validated against existing agents so you can't collide. - Token. Paste your BotFather token. The wizard hits Telegram's
getMeto validate the token in real time and shows the bot's username and profile photo on success. - Activate. Reviews the agent name, model, token env var, and any optional Obsidian config. Clicking Activate writes
agent.yamland.env, installs the launchd plist, and starts the agent.
A side panel during step 2 includes a copy-to-clipboard /newbot template and inline screenshots of the BotFather flow if you've never done this before. After the agent is running you can edit its CLAUDE.md or upload a custom avatar without leaving the dashboard.
If you'd rather do it by hand, open Telegram and message @BotFather:
- Send
/newbot - Choose a name (e.g., "MyName Comms", "MyName Ops")
- Choose a username ending in
_bot(e.g.,yourname_comms_bot) - Copy the token BotFather gives you
Repeat for each agent you want. Keep the tokens handy.
npm run agent:createIt walks you through the same template selection, bot creation, token setup, and a test start — same code path as the dashboard, just terminal-driven.
Every agent gets an avatar that surfaces in the dashboard, war room rail, agent cards, and Daily.co video tiles. The resolver has a fixed priority order so the same image shows up everywhere — no per-surface drift:
- Mutable user-owned. A PNG/JPEG/WebP you uploaded via the dashboard. Stored at
STORE_DIR/avatars/main.png(for main) orresolveAgentDir(id)/avatar.png(for sub-agents). - Bundled meet variant.
warroom/avatars/<id>-meet.png, used only when an agent joins a Daily.co video tile (ctx.context === 'meet'). This is the version optimized for the small circular video frame. - Bundled default art.
warroom/avatars/<id>.png, the curated pop-art that ships with the repo. - Telegram fallback. If none of the above exist for a sub-agent, the resolver hits
getMe → getFileonce and caches the bot's profile photo. A.no-avatarflag stops it from re-attempting for 24h on misses.
Upload from the dashboard's Agents page — the PUT handler magic-byte-sniffs every file (so a hostile rename can't slip an HTML page past the filter), enforces a 5 MB cap, and serializes concurrent writes via a per-agent mutex. ETags are mtime+size-based so the moment a new file lands on disk every open dashboard tab revalidates.
HTTP contract (avatar endpoints, all JSON-shaped errors):
| Status | When |
|---|---|
400 {"error":"invalid id"} |
id fails the [a-z0-9_-]+ regex |
404 {"error":"agent not found"} |
id valid, but no agent.yaml exists for that agent (and id is not main) |
204 |
agent exists, resolver returned null (no mutable, no bundled, no Telegram). Caller renders initials. |
200 + ETag |
file resolved, served with correct Content-Type (PNG / JPEG / WebP sniffed at serve time) |
For each agent, you need two files in agents/<name>/:
agent.yaml -- the agent's config:
name: Comms
description: Email, Slack, WhatsApp, YouTube comments, community forums, LinkedIn
telegram_bot_token_env: COMMS_BOT_TOKEN
provider:
type: opencode
# Optional: auto-inject open tasks from your Obsidian vault
obsidian:
vault: /path/to/your/obsidian/vault
folders:
- Inbox/
- Client Work/
read_only:
- Daily Notes/CLAUDE.md -- the agent's personality and instructions:
# Comms Agent
You handle all human communication on the user's behalf.
[... focused instructions for this role ...]Add the bot token to .env:
COMMS_BOT_TOKEN=1234567890:AAFxxxxxxxxxxxxxxxxxxxxxxx
You have two options: run agents in foreground terminals (great for testing), or install them as persistent background services with launchd (recommended for daily use).
Open a new terminal tab for each agent:
npm start -- --agent comms # Terminal 1
npm start -- --agent content # Terminal 2
npm start -- --agent ops # Terminal 3
npm start -- --agent research # Terminal 4Each will show:
ClaudeClaw agent [comms] online: @yourname_comms_bot
Your main bot keeps running in its own terminal as usual (npm start). Close the terminal and the agent dies.
What is launchd? On macOS, launchd is the system's built-in service manager (like systemd on Linux). It starts your agents automatically when you log in, and if an agent crashes, launchd restarts it within 30 seconds. No open terminals needed. Your agents just run.
Why this is better than running terminals:
- Agents survive reboots -- they start automatically when you log in
- Agents auto-restart on crash -- if one dies, launchd brings it back
- No open terminal tabs -- they run invisibly in the background
- One command installs everything -- main bot + all agents at once
Install all agents with one command:
bash scripts/install-launchd.shThis script:
- Builds the project (
npm run build) - Removes any stale/orphaned agents from previous installs
- Copies each agent's
.plistconfig to~/Library/LaunchAgents/ - Loads them into launchd (they start immediately)
- Verifies all agents are running and shows their PIDs
After installation you'll see:
com.claudeclaw.main: running (PID: 12345)
com.claudeclaw.comms: running (PID: 12346)
com.claudeclaw.content: running (PID: 12347)
com.claudeclaw.ops: running (PID: 12348)
com.claudeclaw.research: running (PID: 12349)
All agents installed and running.
Useful commands after install:
# Check which agents are running
launchctl list | grep claudeclaw
# View logs for a specific agent
tail -f logs/main.log
tail -f logs/comms.log
# Restart a single agent (e.g., after code changes)
launchctl unload ~/Library/LaunchAgents/com.claudeclaw.comms.plist
launchctl load ~/Library/LaunchAgents/com.claudeclaw.comms.plist
# Restart ALL agents after a rebuild
npm run build
for agent in main comms ops content research; do
launchctl unload ~/Library/LaunchAgents/com.claudeclaw.$agent.plist 2>/dev/null
launchctl load ~/Library/LaunchAgents/com.claudeclaw.$agent.plist
done
# Remove all agents (stop everything)
npm run uninstallHow the plist files work: Each agent has a .plist file in the launchd/ directory that tells macOS how to run it. These are XML config files that specify the command, working directory, environment variables, and log paths. You shouldn't need to edit them unless you're adding a custom agent -- the install script handles everything.
Logs: Each agent writes stdout and stderr to logs/<agent-name>.log. These files grow over time; you can safely truncate them with > logs/comms.log if they get large.
Linux users: launchd is macOS-only. On Linux, use systemd or run agents with pm2 / screen / tmux. The same npm start -- --agent comms command works everywhere.
Open each agent's chat in Telegram and send /start. They'll respond with their name and role. From there, use them like you use the main bot -- voice notes, photos, files, slash commands -- everything works.
Every agent runs the exact same createBot() code path as the main bot. There's no "lite" agent mode -- they inherit everything with zero extra config:
- Voice notes (STT via Groq, TTS via ElevenLabs/Gradium/macOS say)
- Photo, document, and video handling (including Gemini video analysis)
- File sending (
[SEND_FILE:...]markers) - All built-in slash commands: /newchat, /respin, /voice, /model, /memory, /stop, /wa, /slack
- All global skills from
~/.claude/skills/(auto-discovered and registered in each bot's Telegram command menu) - Memory system (FTS5 search, salience decay) -- isolated per agent
- Context window tracking and compaction warnings
- WhatsApp and Slack integration
Inheritance works like this: agents and the main bot share the same compiled codebase (dist/), the same SQLite database, the same .env secrets, and the same global skills directory (~/.claude/skills/). Each agent just has its own Telegram bot token, its own CLAUDE.md personality, and its own session state.
This means when you:
- Install a new skill to
~/.claude/skills/-- every agent picks it up on restart, including its/slashcommand in Telegram's menu - Change code and rebuild (
npm run build) -- every agent picks up the changes on restart - Add a new
.envvariable -- every agent can use it on restart
Restarting agents after changes:
Agents load code and skills at startup. Rebuilding dist/ or adding skills doesn't hot-reload running processes. You need to restart:
# Rebuild first
npm run build
# If running via launchd (recommended): reload each agent
for agent in main comms ops content research; do
launchctl unload ~/Library/LaunchAgents/com.claudeclaw.$agent.plist 2>/dev/null
launchctl load ~/Library/LaunchAgents/com.claudeclaw.$agent.plist
done
# If running in terminals: Ctrl+C each agent, then restart
npm start -- --agent comms
npm start -- --agent content
# Or re-run the install script (rebuilds + restarts everything)
bash scripts/install-launchd.shNote: After restarting, Telegram may cache the old command menu for a few minutes. Force-close and reopen Telegram on your phone to see updated / commands immediately.
If you use Obsidian, agents can be assigned vault folders. Open tasks (- [ ] lines) from those folders are automatically prepended to every message -- the agent just knows what's on your plate without you having to say anything.
# In agent.yaml
obsidian:
vault: ~/ObsidianVault
folders:
- Client Work/ # agent can read and reference
- Inbox/
read_only:
- Daily Notes/ # reference onlyWhat the agent sees before every message:
[Obsidian context]
Client Work//
Open: Send proposal to Acme Corp (Acme Deal)
Open: Follow up on invoice #42 (Billing)
Inbox//
Open: Get back to Brock about podcast (Podcast Invite)
[End Obsidian context]
Scanned every 5 minutes (cached), only open tasks, only from assigned folders. Lightweight -- typically 200-500 tokens.
When an agent completes a meaningful action, it logs it to the shared hive_mind table. Any agent can query what others have done:
SELECT agent_id, action, summary, datetime(created_at, 'unixepoch')
FROM hive_mind ORDER BY created_at DESC LIMIT 20;The dashboard shows the hive mind feed in real-time across all agents.
Cron jobs belong to the agent that creates them. A task created in the comms agent only fires in the comms agent's process:
# Create a task for the comms agent
node dist/schedule-cli.js create "check youtube comments" "0 */4 * * *" --agent comms
# List tasks for a specific agent
node dist/schedule-cli.js list --agent commsWhen agents are configured, the dashboard adds panels at the top:
- Summary Stats Bar -- messages today, active agents count, today's cost, total memories
- Agent Status Cards -- each agent with a color-coded status (live/offline), model, today's turns and cost
- Hive Mind Feed -- timestamped cross-agent activity table, color-coded by agent, with full summary text that wraps cleanly
All existing dashboard panels (tasks, memory, health, tokens, chat) continue to work as before.
There are three ways to create an agent. Pick whichever fits your workflow.
Click "+ New Agent" in the Agents section of the dashboard. The wizard walks you through three steps:
- Basics -- pick an agent ID, display name, description, model, and template
- Connect Telegram -- the wizard suggests a bot name and username for BotFather, then you paste the token. It validates the token live against the Telegram API and shows the resolved
@usernameon success. - Activate -- creates the agent directory, writes
agent.yamlandCLAUDE.md, saves the bot token to.env, generates a launchd/systemd service config, and optionally starts the agent immediately.
Available templates: comms, content, ops, research, and blank (the default _template). The template dropdown is populated from agents/ on disk, so any custom template directories you add will appear automatically.
The agent-create-cli handles everything non-interactively. Useful for scripting or when the dashboard isn't running.
# Create and activate in one shot
node dist/agent-create-cli.js \
--id analytics \
--name "Analytics" \
--description "Data analysis and reporting" \
--template research \
--token "123456789:ABCdef..." \
--activate
# Validate a token without creating anything
node dist/agent-create-cli.js --validate --token "123456789:ABCdef..."
# List available templates
node dist/agent-create-cli.js --templates
# Get suggested BotFather names for an ID
node dist/agent-create-cli.js --suggest --id analyticsFlags:
| Flag | Required | Description |
|---|---|---|
--id |
Yes | Lowercase identifier (letters, numbers, hyphens, underscores) |
--name |
Yes | Display name shown in the dashboard and logs |
--description |
Yes | What this agent does |
--token |
Yes | Telegram bot token from @BotFather |
--model |
No | Claude model (default: claude-sonnet-4-6) |
--template |
No | Template to clone from (default: _template) |
--activate |
No | Install launchd/systemd service and start immediately |
The CLI validates the bot token against the Telegram API before creating anything. If validation fails, it exits with a non-zero code and no files are written.
If you prefer full control, create the files yourself:
# 1. Copy the template
cp -r agents/_template agents/myagent
# 2. Edit the personality
vim agents/myagent/CLAUDE.md
# 3. Create agent.yaml from the example
cp agents/myagent/agent.yaml.example agents/myagent/agent.yaml
vim agents/myagent/agent.yaml
# 4. Create a bot via @BotFather, add token to .env
echo "MYAGENT_BOT_TOKEN=your_token_here" >> .env
# 5. Build and start
npm run build
npm start -- --agent myagentWith the manual approach you also need to create launchd/systemd configs yourself if you want the agent to run as a background service. The dashboard wizard and CLI handle this automatically.
Use any image generation tool (Gemini, DALL-E, Midjourney) to create pop-art or branded avatars for your agents. Set them via the Telegram Bot API:
curl -X POST "https://api.telegram.org/bot<TOKEN>/setMyProfilePhoto" \
-F 'photo={"type":"static","photo":"attach://file"}' \
-F "file=@assets/agent-comms.png"5 Node.js processes (main + 4 agents) use ~500MB RAM total at idle. Each runAgent() call spawns a separate Claude Code subprocess that exits when done. SQLite WAL mode handles concurrent access from all processes with no contention.
To completely remove ClaudeClaw OS (services, config, database, temp files):
npm run uninstall
cd .. && rm -rf claudeclaw-osThis stops all background services, removes ~/.claudeclaw, clears the SQLite database and session data, and wipes temp files. The final rm -rf deletes the repo itself.
The same runAgent() pattern in src/agent.ts works on any channel:
- NanoClaw: WhatsApp, isolated Linux containers
- OpenClaw: Telegram, WhatsApp, Slack, Discord, iMessage, Signal, and more
- TinyClaw: ~400 lines of shell, Claude Code + tmux, zero dependencies
ClaudeClaw OS is source-available under the ClaudeClaw OS Community Commercial License, see LICENSE.md. It is not MIT and not open source. Use is limited to active Early AI-dopters community members.























