# 🦞 Clawdbot Architecture Deep Dive > A comprehensive technical breakdown of Clawdbot's codebase, prompting system, and internal architecture. --- ## High-Level Overview Clawdbot is a **TypeScript/Node.js application** (v22.12+) that acts as a universal gateway between messaging platforms and AI agents. Think of it as a sophisticated message router with an embedded AI brain. ``` ┌─────────────────────────────────────────────────────────────────┐ │ MESSAGING CHANNELS │ │ Discord │ Telegram │ WhatsApp │ Signal │ iMessage │ Slack │ └─────────────────────────────┬───────────────────────────────────┘ │ ▼ ┌─────────────────────────────────────────────────────────────────┐ │ GATEWAY SERVER │ │ - WebSocket control plane (ws://127.0.0.1:18789) │ │ - HTTP server (control UI, Canvas, OpenAI-compat endpoints) │ │ - Session management │ │ - Cron scheduler │ │ - Node pairing (iOS/Android/macOS) │ └─────────────────────────────┬───────────────────────────────────┘ │ ▼ ┌─────────────────────────────────────────────────────────────────┐ │ AGENT LAYER │ │ - Pi coding agent (embedded via @mariozechner packages) │ │ - System prompt generation │ │ - Tool definitions & policy enforcement │ │ - Sub-agent spawning │ │ - Model routing (Anthropic, OpenAI, Gemini, Bedrock, etc.) │ └─────────────────────────────────────────────────────────────────┘ ``` --- ## Directory Structure ``` /opt/homebrew/lib/node_modules/clawdbot/ ├── dist/ # Compiled JavaScript (~800 files) │ ├── agents/ # Agent runtime, tools, system prompt │ ├── gateway/ # Gateway server implementation │ ├── channels/ # Channel plugin system │ ├── cli/ # CLI commands │ ├── config/ # Configuration loading/validation │ ├── browser/ # Playwright browser automation │ ├── cron/ # Scheduled jobs │ ├── memory/ # Semantic memory search │ ├── sessions/ # Session management │ ├── plugins/ # Plugin SDK │ ├── infra/ # Infrastructure utilities │ └── ... ├── docs/ # Documentation (~50 files) ├── skills/ # Built-in skills (~50 SKILL.md packages) ├── extensions/ # Channel extensions ├── assets/ # Static assets └── package.json # Dependencies & scripts ``` --- ## Core Components ### 1. Entry Point (`dist/entry.js`) The CLI entry point that: - Sets `process.title = "clawdbot"` - Suppresses Node.js experimental warnings - Handles Windows path normalization - Loads CLI profiles - Dispatches to `cli/run-main.js` ```javascript #!/usr/bin/env node process.title = "clawdbot"; installProcessWarningFilter(); // Handle profile args, then bootstrap CLI import("./cli/run-main.js") .then(({ runCli }) => runCli(process.argv)) ``` ### 2. Gateway Server (`dist/gateway/server.impl.js`) The heart of Clawdbot — a single long-running process that owns: | Subsystem | Purpose | |-----------|---------| | Config loader | Reads/validates `~/.clawdbot/clawdbot.yaml` | | Plugin registry | Loads channel & tool plugins | | Channel manager | Manages Discord/Telegram/WhatsApp connections | | Session manager | Isolates conversations, tracks history | | Cron service | Scheduled jobs & reminders | | Node registry | Mobile/desktop node pairing | | TLS runtime | Secure connections | | Control UI | Browser dashboard at `:18789` | | Health monitor | Gateway health & presence | **Key Gateway Files:** - `server-channels.js` — Channel connection lifecycle - `server-chat.js` — Message → Agent routing - `server-cron.js` — Scheduled jobs & reminders - `server-bridge-*.js` — WebSocket control plane methods - `server-http.js` — HTTP endpoints - `server-providers.js` — Model provider management ### 3. Agent System (`dist/agents/`) This is where the AI "brain" lives. #### System Prompt Generation (`system-prompt.js`) The `buildAgentSystemPrompt()` function dynamically constructs the system prompt based on runtime context: ```typescript export function buildAgentSystemPrompt(params) { // Sections built dynamically: const lines = [ "You are a personal assistant running inside Clawdbot.", "", "## Tooling", // ... tool availability list "", "## Tool Call Style", // ... narration guidelines "", "## Clawdbot CLI Quick Reference", // ... CLI commands "", ...buildSkillsSection(params), // Available skills ...buildMemorySection(params), // Memory recall instructions ...buildDocsSection(params), // Documentation paths ...buildMessagingSection(params), // Messaging guidelines ...buildReplyTagsSection(params), // [[reply_to_current]] etc. // ... "## Runtime", buildRuntimeLine(runtimeInfo), // Model, channel, capabilities ]; // Inject project context files for (const file of contextFiles) { lines.push(`## ${file.path}`, "", file.content, ""); } return lines.filter(Boolean).join("\n"); } ``` **System Prompt Sections:** | Section | Purpose | |---------|---------| | Tooling | Lists available tools with descriptions | | Tool Call Style | When to narrate vs. just call tools | | CLI Quick Reference | Gateway management commands | | Skills | Available SKILL.md files to read | | Memory Recall | How to use memory_search/memory_get | | Self-Update | Config/update restrictions | | Model Aliases | opus, sonnet shortcuts | | Workspace | Working directory info | | Documentation | Docs paths | | Reply Tags | Native reply/quote syntax | | Messaging | Channel routing rules | | Silent Replies | NO_REPLY handling | | Heartbeats | HEARTBEAT_OK protocol | | Runtime | Model, channel, capabilities | | Project Context | AGENTS.md, SOUL.md, USER.md, etc. | The final prompt is **~2000-3000 tokens** depending on configuration. #### Tools System (`dist/agents/tools/`) Each tool is a separate module with schema definition and handler: | Tool | File | Purpose | |------|------|---------| | `exec` | `bash-tools.exec.js` | Shell command execution (54KB!) | | `process` | `bash-tools.process.js` | Background process management | | `browser` | `browser-tool.js` | Playwright browser control | | `canvas` | `canvas-tool.js` | Present/eval/snapshot Canvas | | `cron` | `cron-tool.js` | Scheduled jobs & reminders | | `gateway` | `gateway-tool.js` | Self-management (restart, update) | | `message` | `message-tool.js` | Cross-channel messaging | | `nodes` | `nodes-tool.js` | Mobile node camera/screen/location | | `sessions_list` | `sessions-list-tool.js` | List sessions | | `sessions_history` | `sessions-history-tool.js` | Fetch session history | | `sessions_send` | `sessions-send-tool.js` | Send to another session | | `sessions_spawn` | `sessions-spawn-tool.js` | Spawn sub-agent | | `session_status` | `session-status-tool.js` | Usage/cost/model info | | `agents_list` | `agents-list-tool.js` | List spawnable agents | | `web_search` | `web-search.js` | Brave API search | | `web_fetch` | `web-fetch.js` | URL content extraction | | `image` | `image-tool.js` | Vision model analysis | | `memory_search` | `memory-tool.js` | Semantic memory search | | `memory_get` | `memory-tool.js` | Read memory snippets | | `tts` | `tts-tool.js` | Text-to-speech | **Tool Policy Enforcement (`pi-tools.policy.js`):** Tools are filtered through multiple policy layers: 1. Global policy (`tools.policy` in config) 2. Provider-specific policy 3. Agent-specific policy 4. Group chat policy 5. Sandbox policy 6. Sub-agent policy ```typescript const isAllowed = isToolAllowedByPolicies("exec", [ profilePolicy, providerProfilePolicy, globalPolicy, globalProviderPolicy, agentPolicy, agentProviderPolicy, groupPolicy, sandbox?.tools, subagentPolicy, ]); ``` #### Pi Integration (`dist/agents/pi-*.js`) Clawdbot embeds [Pi coding agent](https://github.com/badlogic/pi-mono) as its core AI runtime: ```json // Dependencies from package.json: { "@mariozechner/pi-agent-core": "0.49.3", "@mariozechner/pi-ai": "0.49.3", "@mariozechner/pi-coding-agent": "0.49.3", "@mariozechner/pi-tui": "0.49.3" } ``` **Key Pi Integration Files:** | File | Purpose | |------|---------| | `pi-embedded-runner.js` | Spawns Pi agent sessions | | `pi-embedded-subscribe.js` | Handles streaming responses | | `pi-embedded-subscribe.handlers.*.js` | Message/tool event handlers | | `pi-embedded-utils.js` | Utilities for Pi integration | | `pi-tools.js` | Tool definition adapter | | `pi-tools.policy.js` | Tool allowlist/denylist | | `pi-tools.read.js` | Read tool customization | | `pi-tools.schema.js` | Schema normalization | | `pi-settings.js` | Pi agent settings | ### 4. Channel Plugins (`dist/channels/plugins/`) Each messaging platform is a plugin: ``` channels/plugins/ ├── discord/ # Discord.js integration ├── telegram/ # grammY framework ├── whatsapp/ # Baileys (WhatsApp Web protocol) ├── signal/ # Signal CLI bridge ├── imessage/ # macOS imsg CLI ├── bluebubbles/ # BlueBubbles API ├── slack/ # Slack Bolt ├── line/ # LINE Bot SDK ├── mattermost/ # WebSocket events ├── googlechat/ # Google Chat API └── ... ``` **Channel Plugin Interface:** Each plugin implements: - `connect()` — Establish connection - `disconnect()` — Clean shutdown - `send()` — Deliver messages - `onMessage()` — Handle incoming messages - Channel-specific actions (reactions, polls, threads, etc.) **Channel Registry (`dist/channels/registry.js`):** ```typescript // Plugins register themselves registerChannelPlugin({ id: "discord", displayName: "Discord", connect: async (config) => { ... }, send: async (message) => { ... }, // ... }); ``` ### 5. Skills System (`skills/`) Skills are self-contained instruction packages that teach the agent how to use external tools: ``` skills/ ├── github/SKILL.md # gh CLI usage ├── gog/SKILL.md # Google Workspace CLI ├── spotify-player/SKILL.md # Spotify control ├── weather/SKILL.md # wttr.in integration ├── bear-notes/SKILL.md # Bear notes via grizzly ├── apple-notes/SKILL.md # memo CLI ├── apple-reminders/SKILL.md # remindctl CLI ├── obsidian/SKILL.md # Obsidian vault management ├── notion/SKILL.md # Notion API ├── himalaya/SKILL.md # Email via IMAP/SMTP ├── openhue/SKILL.md # Philips Hue control ├── camsnap/SKILL.md # RTSP camera capture └── ... ``` **Skill Loading Flow:** 1. System prompt includes skill descriptions in `` 2. Agent scans descriptions to find matching skill 3. Agent calls `read` tool to load SKILL.md 4. Agent follows instructions in SKILL.md **Skill File Structure:** ```markdown # SKILL.md - [Tool Name] ## When to use Description of when this skill applies. ## Commands ```bash tool-name command --flags ``` ## Examples ... ``` ### 6. Memory System (`dist/memory/`) Semantic search over workspace memory files: **Memory Files:** - `MEMORY.md` — Root memory file - `memory/*.md` — Dated logs, research intel, project notes **Memory Tools:** - `memory_search` — Semantic vector search using `sqlite-vec` - `memory_get` — Read specific lines from memory files ```typescript // memory-search.js import SqliteVec from "sqlite-vec"; async function searchMemory(query: string, options: SearchOptions) { // Embed query const embedding = await embedText(query); // Vector similarity search const results = await db.query(` SELECT path, line_start, line_end, content, vec_distance_cosine(embedding, ?) as distance FROM memory_chunks ORDER BY distance LIMIT ? `, [embedding, options.maxResults]); return results; } ``` ### 7. Session Management (`dist/gateway/session-utils.js`) Sessions isolate conversations and track state: **Session Key Format:** ``` {channel}:{accountId}:{chatId} discord:main:938238002528911400 telegram:main:123456789 whatsapp:main:1234567890@s.whatsapp.net ``` **Session State:** - Conversation history - Model override (if any) - Reasoning level - Active tool calls - Sub-agent references **Session Files:** ``` ~/.clawdbot/sessions/ ├── discord-main-938238002528911400.json ├── telegram-main-123456789.json └── ... ``` --- ## Message Flow ``` 1. User sends message on Discord/Telegram/WhatsApp/etc. │ ▼ 2. Channel plugin receives message - Parses sender, chat ID, content - Handles media attachments - Checks mention gating (groups) │ ▼ 3. Gateway routes to session - Resolves session key - Loads/creates session - Checks activation rules │ ▼ 4. Session loads context: - System prompt (generated dynamically) - Project context files (AGENTS.md, SOUL.md, USER.md) - Conversation history - Tool availability │ ▼ 5. Pi agent processes with configured model - Anthropic (Claude) - OpenAI (GPT-4, o1, etc.) - Google (Gemini) - AWS Bedrock - Local (Ollama, llama.cpp) │ ▼ 6. Agent may call tools - Tool policy checked - Tool executed - Results fed back to agent - Loop until done │ ▼ 7. Response streamed/chunked back - Long responses chunked for Telegram - Markdown formatted per channel - Media attachments handled │ ▼ 8. Channel plugin delivers message - Native formatting applied - Reply threading if requested - Reactions/buttons if configured ``` --- ## Configuration Config lives at `~/.clawdbot/clawdbot.yaml`: ```yaml # Model Providers providers: anthropic: key: "sk-ant-..." openai: key: "sk-..." google: key: "..." # Default Model defaultModel: "anthropic/claude-sonnet-4-5" # Channel Configs discord: token: "..." defaultModel: "anthropic/claude-opus-4-5" telegram: token: "..." whatsapp: enabled: true # Agent Config agent: workspaceDir: "~/.clawdbot/workspace" agents: main: workspaceDir: "~/.clawdbot/workspace" # Tool Policies tools: exec: security: "full" # full | allowlist | deny host: "sandbox" # sandbox | gateway | node browser: profile: "clawd" # Cron Jobs cron: jobs: - id: "daily-standup" schedule: "0 9 * * *" text: "Good morning! What's on the agenda?" # Gateway Settings gateway: port: 18789 token: "..." ``` **Config Schema:** Full schema at `dist/protocol.schema.json` (~80KB of JSON Schema) --- ## Key Dependencies ```json { // AI Agent Core "@mariozechner/pi-agent-core": "0.49.3", "@mariozechner/pi-ai": "0.49.3", "@mariozechner/pi-coding-agent": "0.49.3", // Messaging Channels "discord-api-types": "^0.38.37", "grammy": "^1.39.3", "@whiskeysockets/baileys": "7.0.0-rc.9", "@slack/bolt": "^4.6.0", "@line/bot-sdk": "^10.6.0", // Browser Automation "playwright-core": "1.58.0", "chromium-bidi": "13.0.1", // Vector Search "sqlite-vec": "0.1.7-alpha.2", // Image Processing "sharp": "^0.34.5", "@napi-rs/canvas": "^0.1.88", // TTS "node-edge-tts": "^1.2.9", // Scheduling "croner": "^9.1.0", // HTTP/WebSocket "hono": "4.11.4", "ws": "^8.19.0", "undici": "^7.19.0", // Schema Validation "zod": "^4.3.6", "@sinclair/typebox": "0.34.47", "ajv": "^8.17.1" } ``` --- ## Key Architectural Decisions ### 1. Single Gateway Process One process owns all channel connections to avoid session conflicts (especially WhatsApp Web which only allows one active session). ### 2. Pi as Core Runtime Leverages Pi coding agent's battle-tested: - Tool streaming - Context management - Multi-provider support - Structured output handling ### 3. Dynamic System Prompt Built at runtime based on: - Available tools (policy-filtered) - Available skills - Current channel - User configuration - Project context files ### 4. Plugin Architecture Everything is pluggable: - Channels (Discord, Telegram, etc.) - Tools (exec, browser, etc.) - Hooks (voice transcription, media processing) - Skills (external instruction packages) ### 5. Session Isolation Each conversation gets isolated: - History - Model settings - Tool state - Sub-agent references ### 6. Sub-agent Spawning Complex tasks spawn isolated sub-agents that: - Run in separate sessions - Have restricted tool access - Report back when complete - Can be monitored/killed ### 7. Multi-Layer Tool Policy Security through depth: - Global policy - Provider policy - Agent policy - Group policy - Sandbox policy - Sub-agent policy --- ## File Counts | Category | Count | |----------|-------| | Compiled JS files | ~800 | | Documentation files | ~50 | | Skill packages | ~50 | | Channel plugins | ~12 | | Tool implementations | ~25 | **Total package size:** ~1.5MB (minified JS + assets) --- ## Development ```bash # Clone and install git clone https://github.com/clawdbot/clawdbot cd clawdbot pnpm install # Build pnpm build # Run dev gateway pnpm gateway:dev # Run tests pnpm test # Lint pnpm lint ``` --- ## Resources - **GitHub:** https://github.com/clawdbot/clawdbot - **Docs:** https://docs.clawd.bot - **Discord:** https://discord.com/invite/clawd - **Skills Marketplace:** https://clawdhub.com --- *Generated by Buba, 2026-02-06*