Clawdbot 源码解读 1:一个个人 AI 助手的架构设计

56 阅读8分钟

本系列文章将从源码带大家学习最近大火的 Clawdbot 的架构设计,学完后有兴趣的可以参与开源项目。

前言

Clawdbot 是一个开源的「个人 AI 助手」——你可以把它跑在自己的设备上,通过 WhatsApp、Telegram、Slack、Discord 等渠道与它对话,它背后是统一的 Gateway 控制平面和 Pi Agent 运行时。本系列文章将带你从源码层面理解它的设计与实现。

本文是《Clawdbot 源码解读》系列的第一篇,我们会从整体架构入手,建立对项目的全局认知,为后续深入各个模块打基础。

学习目标

  • 理解 Clawdbot 的项目定位和设计理念
  • 掌握整体分层架构和核心组件
  • 熟悉技术栈和源码目录结构
  • 能够搭建开发环境并运行项目

前置知识

  • 了解 Node.js / TypeScript 基础
  • 对 WebSocket、CLI 工具有基本概念即可

一、项目背景与定位

1.1 它是什么?

Clawdbot 的官方描述是:Personal AI Assistant you run on your own devices。核心特点可以概括为:

  • 本地优先:Gateway 和会话数据都在你自己控制的机器上
  • 多渠道统一:同一套助手能力,接入 WhatsApp、Telegram、Slack、Discord、Google Chat、Signal、iMessage、WebChat 以及扩展渠道(Teams、Matrix、Zalo 等)
  • 产品是助手,Gateway 是控制平面:用户感知到的是「一个会回消息的 AI」,而 Gateway 负责连接渠道、路由消息、调度 Agent、管理工具和事件

README 里有一句很关键的话:

The Gateway is just the control plane — the product is the assistant.

也就是说:Gateway 不是产品本身,而是让「助手」能在各个渠道里工作的控制层

1.2 设计理念

从文档和代码结构可以看出几个明确的设计取向:

  1. 单一 Gateway,多客户端
    一个主机上只跑一个 Gateway 进程,所有消息渠道由它统一管理;CLI、macOS 应用、Web UI、iOS/Android 节点都通过 WebSocket 连到同一个 Gateway。

  2. 类型安全与协议约束
    使用 TypeScript 严格模式,协议用 TypeBox 定义 JSON Schema,既有运行时校验,也有类型推导和代码生成(如 Swift 端)。

  3. 可扩展但不臃肿
    核心能力在 src/,渠道和技能通过 extensions/skills/ 扩展,插件依赖与核心分离,避免把一切塞进主包。

  4. 安全默认值
    默认 DM 需要配对、非 main 会话可进沙箱、Gateway 必须配置认证等,都体现「安全优先」的取舍。


二、整体架构:分层视角

我们可以用「从上到下」的视角把系统拆成几层:外部接口 → Gateway 控制平面 → 渠道与路由 → Agent 运行时 → 工具与存储。

2.1 架构全景图

下面这张图概括了各层之间的关系(箭头表示数据流或依赖关系):

graph TB
    subgraph "外部接口层"
        WA[WhatsApp]
        TG[Telegram]
        SL[Slack]
        DC[Discord]
        WC[WebChat]
        EXT[扩展渠道]
    end

    subgraph "Gateway 控制平面"
        WS[WebSocket Server :18789]
        HTTP[HTTP Server]
        AUTH[认证层]
    end

    subgraph "渠道与路由"
        CM[Channel Manager]
        RT[路由引擎]
        SM[Session Manager]
    end

    subgraph "Agent 运行时"
        AR[Agent Runtime]
        AM[Agent 管理]
        WS2[Workspace]
    end

    subgraph "工具与存储"
        BR[Browser]
        CV[Canvas]
        ND[Nodes]
        SK[Skills]
        CFG[配置/会话/凭证]
    end

    subgraph "客户端"
        CLI[CLI]
        MAC[macOS App]
        WEB[Web UI]
    end

    WA --> CM
    TG --> CM
    SL --> CM
    DC --> CM
    WC --> CM
    EXT --> CM

    CM --> RT
    RT --> SM
    SM --> AR
    AR --> AM
    AM --> WS2

    AR --> BR
    AR --> CV
    AR --> ND
    AR --> SK

    WS --> AUTH
    HTTP --> AUTH
    AUTH --> CM
    AUTH --> AR

    CLI --> WS
    MAC --> WS
    WEB --> HTTP

    CM --> CFG
    SM --> CFG

各层职责简述:

层级职责
外部接口层各消息平台(WhatsApp、Telegram 等)及 WebChat,消息从这里进入和发出
Gateway 控制平面WebSocket/HTTP 服务、认证;所有客户端和渠道都经由这里
渠道与路由渠道管理、路由规则、Session Key、配对与白名单
Agent 运行时Pi Agent RPC、多 Agent、工作空间与提示词
工具与存储Browser、Canvas、Nodes、Skills、配置与会话存储

后续文章会逐层展开,这里先建立「分层」和「数据流」的印象即可。

2.2 核心数据流(一句话版)

  • 入站:某渠道收到用户消息 → Channel Manager → 路由解析出 Agent 和 Session Key → Session Manager 取/建会话 → Agent 执行 → 可选调用工具 → 生成回复。
  • 出站:回复经格式化后交给对应渠道发送回用户。
  • 控制:CLI / macOS / Web 等客户端通过 WebSocket 调用 agentsendconfig 等方法,并订阅 agentpresencehealth 等事件。

三、技术栈与工程约束

3.1 技术选型

package.json 和工程配置可以看出:

  • 语言与模块:TypeScript,ESM("type": "module"),Node 22+。
  • 包管理:pnpm,monorepo(根目录 + ui + extensions/*)。
  • 构建tsc 输出到 dist/,另有 A2UI 打包、协议代码生成等脚本。
  • 质量:Vitest 测试,oxlint/oxfmt 做 lint 和格式化。

关键依赖里能看到「渠道 + Agent + 工具」的痕迹,例如:

  • 渠道:@whiskeysockets/baileys(WhatsApp)、grammy(Telegram)、@slack/bolt、discord 相关等。
  • Agent:@mariozechner/pi-agent-corepi-aipi-coding-agent 等。
  • 工具与基础设施:playwright-coreexpresshonowscroner 等。

入口和二进制在 package.json 里是这样暴露的:

{
  "main": "dist/index.js",
  "bin": {
    "clawdbot": "dist/entry.js"
  },
  "exports": {
    ".": "./dist/index.js",
    "./plugin-sdk": "./dist/plugin-sdk/index.js",
    "./plugin-sdk/*": "./dist/plugin-sdk/*"
  }
}

也就是说:你执行 clawdbot 时,实际跑的是 dist/entry.js,而库入口和插件 SDK 通过 exports 对外提供。

3.2 源码目录结构(高层)

在仓库根目录下,和「读源码」最相关的目录大致如下(只列顶层和代表性子目录):

clawdbot/
├── src/                    # 核心源码
│   ├── entry.ts            # CLI 可执行入口(见下节)
│   ├── index.ts            # 库入口
│   ├── cli/                # CLI 命令与程序结构
│   ├── config/             # 配置加载、类型、会话等
│   ├── gateway/            # Gateway 服务器、协议、认证
│   ├── channels/          # 渠道抽象、注册表、会话等
│   ├── routing/           # 路由解析
│   ├── agents/             # Agent 运行时、工具注册等
│   ├── commands/          # 具体命令实现(如 agent、send)
│   ├── auto-reply/         # 自动回复与消息分发
│   ├── browser/            # 浏览器工具
│   ├── plugins/            # 插件加载
│   ├── plugin-sdk/         # 插件 SDK
│   ├── infra/              # 环境、端口、二进制、日志等
│   ├── telegram/           # Telegram 实现
│   ├── discord/            # Discord 实现
│   ├── slack/              # Slack 实现
│   ├── web/                # Web 渠道 / WebChat 相关
│   └── ...
├── extensions/             # 渠道与能力扩展(如 msteams、matrix)
├── skills/                 # 技能(SKILL.md + 脚本等)
├── apps/                   # macOS / iOS / Android 应用
├── ui/                     # Web Control UI
├── docs/                   # 文档
└── scripts/                # 构建、发布等脚本

读源码时建议的「第一站」:

  • 入口与 CLIsrc/entry.tssrc/cli/run-main.tssrc/cli/program/
  • Gatewaysrc/gateway/server.impl.tssrc/gateway/server/
  • 渠道路由src/channels/registry.tssrc/routing/
  • Agentsrc/agents/src/commands/agent.js(或对应 TS)

四、程序入口:从 entry.ts 到 CLI

用户执行 clawdbot 时,系统实际执行的是编译后的 dist/entry.js。理解入口有助于后面理解「配置何时加载、Gateway 何时启动」。

4.1 入口文件做了什么?

src/entry.ts 做了几件「在真正跑 CLI 之前」的事:

  1. 设置进程标题
    process.title = "clawdbot",方便在进程列表里识别。

  2. 抑制 Node 实验性警告
    若未设置 NODE_OPTIONS 中的 --disable-warning=ExperimentalWarning,会设置环境变量并 respawn 当前进程(用新的 Node 进程重新执行当前参数),这样用户无需自己配 NODE_OPTIONS。若已设置或设置了 CLAWDBOT_NO_RESPAWN,则不再 respawn。

  3. 处理 --no-color
    若传入该参数,会设置 NO_COLOR / FORCE_COLOR,影响后续输出是否带颜色。

  4. Windows 下规范化 argv
    normalizeWindowsArgv(process.argv) 会去掉 Windows 下可能混入的 node.exe 路径等,保证 Commander 解析的是「用户输入的参数」。

  5. Profile 解析
    使用 parseCliProfileArgs / applyCliProfileEnv 处理 profile(如 --profile dev),若有 profile 会改写环境变量并更新 process.argv

  6. 动态加载并运行 CLI
    最后通过 import("./cli/run-main.js") 得到 runCli,并执行 runCli(process.argv)。真正的命令解析、子命令注册、插件注册都在 run-main 和后续的 program 里完成。

下面这段是入口里「不 respawn 时」的执行路径(保留原逻辑,仅作注释说明):

// src/entry.ts(节选)

process.title = "clawdbot";
installProcessWarningFilter();

if (process.argv.includes("--no-color")) {
  process.env.NO_COLOR = "1";
  process.env.FORCE_COLOR = "0";
}

// ... ensureExperimentalWarningSuppressed() / normalizeWindowsArgv ...

if (!ensureExperimentalWarningSuppressed()) {
  const parsed = parseCliProfileArgs(process.argv);
  if (!parsed.ok) {
    console.error(`[clawdbot] ${parsed.error}`);
    process.exit(2);
  }
  if (parsed.profile) {
    applyCliProfileEnv({ profile: parsed.profile });
    process.argv = parsed.argv;
  }

  import("./cli/run-main.js")
    .then(({ runCli }) => runCli(process.argv))
    .catch((error) => {
      console.error("[clawdbot] Failed to start CLI:", ...);
      process.exitCode = 1;
    });
}

抓住这几点即可:入口只做环境与参数准备,不解析具体子命令;子命令和 Gateway 的启动都在 run-main 及其下游

4.2 入口与 index 的区别

  • dist/entry.js:对应 src/entry.ts,是 bin.clawdbot 的入口,面向「命令行使用」。
  • dist/index.js:对应 src/index.ts,是库入口(require/import('clawdbot')),会导出配置、会话、回复等能力,供其他模块或脚本使用。

写「源码解读」或做二次开发时,若关心「用户敲一条命令发生了什么」,就从 entry.ts 追起;若关心「如何在代码里调 Clawdbot 的能力」,就从 index.ts 和其导出看起。


五、快速搭建开发环境

5.1 环境要求

  • Node.js:≥ 22.12.0(见 package.jsonengines
  • 包管理:pnpm(推荐,与仓库脚本一致)

5.2 克隆、安装、构建

git clone https://github.com/clawdbot/clawdbot.git
cd clawdbot

pnpm install
pnpm build

若需要 Control UI,可能还需执行:

pnpm ui:build

(具体以仓库根目录的 README 或脚本说明为准。)

5.3 运行 CLI

开发时常用:

# 使用编译后的 dist(需先 pnpm build)
node dist/entry.js --help

# 或使用仓库提供的脚本(可能通过 tsx 直接跑 TS)
pnpm clawdbot --help

验证 Gateway 时(需已配置认证等):

pnpm clawdbot gateway run --verbose

在另一终端可执行:

pnpm clawdbot gateway status

5.4 如何「顺着」源码读下去

  1. 从入口到子命令
    src/entry.tssrc/cli/run-main.tssrc/cli/program/build-program.ts / command-registry,看一条命令(如 gateway run)是如何被注册和调用的。

  2. 从文档到代码
    docs/concepts/architecture.md 描述 Gateway 与客户端、Node 的关系;docs/gateway/protocol.md 描述协议。对照 src/gateway/ 下的实现读,会更容易。

  3. 从测试到用法
    很多模块配有 *.test.ts,例如 src/gateway/*.test.tssrc/channels/*.test.ts。测试里往往有「最小可运行」的调用示例,适合用来理解 API 和流程。

  4. 善用搜索
    确定一个概念(如 sessionKeyresolveAgentRoute)后,在 src/ 里搜索,可以快速找到定义和使用点,再结合调用栈理解层次。


六、总结与下一篇预告

6.1 本文要点

  • Clawdbot 是「个人 AI 助手」,产品是助手本身,Gateway 是控制平面,负责渠道、路由、Agent 和工具。
  • 架构:外部接口 → Gateway(WS/HTTP + 认证)→ 渠道与路由 → Agent 运行时 → 工具与存储;客户端通过 WebSocket 连到同一 Gateway。
  • 技术栈:TypeScript ESM、Node 22+、pnpm monorepo;入口二进制是 dist/entry.js,库入口是 dist/index.js
  • 入口src/entry.ts 负责进程标题、Node 警告抑制、argv 规范化、profile,然后加载 run-main 执行真正的 CLI。
  • 读源码:先建立「分层 + 数据流」的图景,再按入口 → CLI → Gateway → 渠道/路由 → Agent 的顺序,结合文档和测试读。

6.2 下一步

下一篇将专门讲 CLI 系统:命令如何注册、如何解析、如何与 Gateway 和配置交互,并会跟踪一条具体命令(如 clawdbot gateway run)的完整执行路径。这样你就能把「用户输入」和「进程内调用」串起来,形成更清晰的代码地图。


参考资源