仓库地址:github.com/openclaw/op… 分析时间:2026-04-23 · HEAD
b09aed82分析范围:仓库结构、核心子系统、关键契约与 API、扩展与应用模式
一、项目定位与设计哲学
OpenClaw 官方自述为 "the AI that actually does things": 一个运行在用户自有设备上、面向多消息渠道、能实际执行任务(而不仅是问答)的个人 AI 助手。
它的历史可以追溯到作者个人项目 Warelay → Clawdbot → Moltbot → OpenClaw, 典型的作者驱动项目演化。VISION.md 清楚地陈述了项目取舍:
- 核心保持精简(core stays lean),能力通过插件交付
- 安全是显式权衡:强默认不阉割能力,把危险路径暴露为操作者可控开关
- 终端优先 —— 不做掩盖安全决策的"便利封装"
- 插件优先分发:新能力先进 ClawHub,不进 core
- MCP 通过
mcporter桥接,core 不内建 MCP 运行时
这一套哲学决定了仓库的工程形态:一个以"控制面 Gateway + 可插拔 Provider/Channel + 会话/上下文引擎"为骨架的编排系统,而不是一个"大而全的 Agent 框架"。
二、仓库鸟瞰
规模:14,900+ 文件,500+ 分支。TypeScript ESM monorepo,用 pnpm workspaces 管理。
顶层主要目录:
| 目录 | 角色 |
|---|---|
| src/ | 核心 TS 运行时(Gateway、Agents、Channels、Plugins、Context Engine、Security) |
| packages/ | 面向第三方的包:plugin-sdk、plugin-package-contract、memory-host-sdk |
| extensions/ | 内建插件(Provider + Channel),100+ 个,含 anthropic, openai, telegram, slack, whatsapp, imessage 等 |
| skills/ | 内建 "skill" 集合(宏/工具脚本化能力),如 coding-agent, mcporter, notion, obsidian |
| ui/ | Web 前端(Vite + React) |
| apps/ | 各平台伴生 App(macOS / iOS / Android / Windows shared) |
| docs/ | 产品/概念/插件/提供商/安装 文档 |
从 AGENTS.md 可以读出非常强的分层边界纪律:
- Core(
src/**)必须对扩展不可知,不能为某个 bundled plugin 写特殊情况 - Extension 只能经由
openclaw/plugin-sdk/*、manifest、注入的 runtime helpers 和api.ts/runtime-api.ts本地桶(barrel)跨越边界 - 扩展禁止深入
src/**、其它扩展的src/** - Gateway protocol 改动视为契约变更:先做向后兼容,不兼容需要版本化、文档化并驱动客户端跟进
这种硬边界通过 lint 规则 / 架构门(pnpm check:architecture)、import-cycles、TS 项目引用、tsconfig.package-boundary.*.json 等机制来实际落地。
三、启动路径:从 CLI 到 Gateway
OpenClaw 是终端优先的,入口是 src/entry.ts。它只做一件事:启动 CLI,但做得非常谨慎。
关键设计点(entry.ts:38–131):
isMainModule守卫:entry.js 可能被作为共享依赖被dist/index.js间接 import。如果没有这个守卫,顶层副作用会第二次触发runCli,造成"二次启动 gateway + 锁/端口冲突"。这是一个很典型的打包器/入口文件合流陷阱,作者用显式守卫根治了它。- Compile cache (
enableCompileCache())、进程 warning filter、normalizeEnv()、Windows argv 归一化、--no-color规范化 —— 全部在加载业务代码之前做,降低环境差异。 - respawn 计划 (
buildCliRespawnPlan/attachChildProcessBridge):某些情况下父进程会spawn一个干净的自身副本,把 stdio 透传过去。这是 Node 世界处理"需要特定execArgv"的经典做法。 - Version fast path / Help fast path:
--version和--help不走完整 CLI 图,直接走cli/root-help-metadata.js返回预计算元数据 —— 首屏感知速度优化。 - Lazy CLI 图:
import("./cli/run-main.js").then(({ runCli }) => runCli(argv)),真正的 Commander 命令树是按需加载的。
src/index.ts 是库入口(给三方/SDK 消费者用):它通过 let ... = await import("./library.js") 做按需绑定 —— 作为 main 时不触发,作为库 import 时才绑定。这避免了 CLI 用户承担库 API 的加载代价。
src/library.ts 则演示了一套一致的 lazy-boundary 模式:
let replyRuntimePromise: Promise<typeof import("./auto-reply/reply.runtime.js")> | null = null;
function loadReplyRuntime() {
replyRuntimePromise ??= import("./auto-reply/reply.runtime.js");
return replyRuntimePromise;
}
export const getReplyFromConfig: GetReplyFromConfig = async (...args) =>
(await loadReplyRuntime()).getReplyFromConfig(...args);
每个重量级子系统都有专门的 *.runtime.ts 懒加载边界。AGENTS.md Code Style 节强调:
Do not mix static and dynamic import for same module in prod path. Use dedicated
*.runtime.tslazy boundary.
这不是风格洁癖:混合静态 + 动态 import 会让 bundler 把"懒加载"优化成"静态内联",导致启动时 load 整张图,甚至触发死循环或重复副作用。专门的 *.runtime.ts 是一个防守性的架构边界。
四、Gateway:控制面的核心
src/gateway/ 是整个系统的控制面。它是 OpenClaw 所有客户端(CLI、Web UI、iOS/macOS/Android App、node 节点)与 agent/channel 运行时之间的 WebSocket/HTTP 枢纽。
4.1 协议层 src/gateway/protocol/
src/gateway/protocol/schema.ts 是整个协议的真理源(single source of truth),并由多个子 schema 模块聚合(见 schema/index.ts):
agent.ts/agents-models-skills.ts—— agent 生命周期、模型、skillchannels.ts—— 渠道操作(启动、登录、状态)commands.ts/config.ts/cron.tsdevices.ts/nodes.ts—— 设备配对、分布式节点exec-approvals.ts/plugin-approvals.ts—— 危险命令/插件动作的人审审批sessions.ts—— 会话创建/发送/压缩/分支/恢复wizard.ts—— 首次运行向导frames.ts——RequestFrame/ResponseFrame/EventFrame帧protocol-schemas.ts——PROTOCOL_VERSION与总线
src/gateway/protocol/index.ts 用 AJV 编译每一个 schema 为校验器:
const ajv = new (AjvPkg as unknown as new (opts?: object) => import("ajv").default)({
allErrors: true, strict: false, removeAdditional: false,
});
export const validateRequestFrame = ajv.compile<RequestFrame>(RequestFrameSchema);
formatValidationErrors 把 AJV 的 additionalProperties 等错误展开成可读消息(特别是不合法字段会打印 at /path: unexpected property 'xyz'),这对协议调试非常关键。
值得记一笔的是:这里有近 200 个 exported validator —— 每一个 JSON-RPC/WS 方法都有对应 params/result schema,意味着:
- 客户端侧可以用同一份 schema 校验
ProtocolSchemas(常量聚合)允许运行时反射协议表面ErrorCodes用 discriminated unions / closed codes 表达错误(AGENTS.md:"Runtime branching: prefer discriminated unions / closed codes over freeform strings")
这是契约优先、向前兼容工程学的教科书例子:你没有办法"偷偷"加一个字段 —— 必须先加 schema、过 AJV、过客户端。AGENTS.md 里直接写了:
Gateway protocol changes are contract changes: additive first; incompatible needs versioning/docs/client follow-through.
4.2 服务端组装
src/gateway/ 下以 server-*.ts 命名的文件高度拆分(>60 个),每个文件只负责一个 concern:
server-startup.ts/server-startup-early.ts/server-startup-plugins.ts/server-startup-post-attach.ts—— 分阶段启动,让测试和事故诊断可以定位到"哪一阶段失败"server-channels.ts—— 渠道管理server-chat.ts/server-chat.agent-events.test.ts—— 聊天事件流server-cron.ts—— 计划任务server-discovery.ts—— 插件 / 能力发现server-runtime-services.ts—— 全局运行时服务注入server-restart-sentinel.ts/server-restart-deferral.test.ts—— 安全重启协议server-shared-auth-generation.ts/shared-auth.test-helpers.ts—— 共享 token 轮转
亮点:server.impl.ts 是 composition root;周围一大票分片文件是 concerns。这是一个把 "god file" 问题用 水平拆分 解的范例。
4.3 HTTP surface
除了 WebSocket 主协议,还有若干 HTTP 子面:
mcp-http.ts—— 作为 MCP server 对外暴露(给 Claude Desktop、其他 MCP client 消费)openai-http.ts/openresponses-http.ts—— 对外伪装成 OpenAI-兼容 API(含/v1/responses适配)embeddings-http.ts/models-http.ts/tools-invoke-http.ts—— 标准子端点sessions-history-http.ts—— 会话史外部读写
这意味着 OpenClaw Gateway 本身既是 MCP server,也是 OpenAI-API 兼容端点;第三方工具连接它就像连一个本地模型服务。
4.4 认证与安全
server.auth.*.test.ts 列表显示认证表面非常丰富:
browser-hardening/control-ui/default-token/modespreauth-hardening.test.tscontrol-ui-csp.ts—— 控制 UI 的 CSP 头origin-check.ts—— 跨源校验control-plane-rate-limit.ts—— 控制面速率限制known-weak-gateway-secrets.ts—— 主动拒绝弱凭据role-policy.ts/method-scopes.ts—— 方法级细粒度权限
node-invoke-system-run-approval*.ts 是一个特别值得注意的设计:系统命令执行(system-run)必须过 approval match,匹配不到显式允许就要走审批链。exec-approval-ios-push.ts 甚至把审批请求推送到 iOS 原生 App 的通知里 —— 把"危险动作→人工授权"这件事做成跨设备体验,而不是一个本地 yes/no。
五、Plugin 系统:二分层 SDK
src/plugin-sdk/ 是对外的公共契约,src/plugins/ 是内部的 loader / registry / activation。
5.1 插件 SDK(src/plugin-sdk/)
这里导出的是第三方编写插件时看到的全部面板。ls 下的文件名讲故事:
channel-contract.ts(见下)agent-runtime.ts/agent-harness.ts—— agent 对接approval-*—— 审批能力(approver、handler、client、delivery、native、renderer、reply)browser-*—— 浏览器控制(CDP 桥、facades、host inspection)memory-core*/memory-host-core.ts—— memory 插件是专用槽位(single-slot,只能一个生效,见 VISION)account-core.ts/channel-lifecycle.core.ts/image-generation-core.ts—— 各领域契约
插件契约故意窄。以 channel-contract.ts 为例,它只 re-export 精心选择的类型,不暴露 src/channels/** 的任何具体实现:
export type {
BaseProbeResult, BaseTokenResolution,
ChannelAgentTool, ChannelAccountSnapshot,
ChannelApprovalAdapter, ChannelApprovalCapability,
ChannelCommandConversationContext,
...
} from "../channels/plugins/types.public.js";
这就把 channel 实现细节(src/channels/plugins/types.core.ts)锁死在 core 里,只暴露 public 类型 —— 插件作者无法依赖内部形状。
5.2 插件 loader / registry(src/plugins/)
一些重要文件:
activation-planner.ts+activation-source-config.ts—— 根据配置计算"该激活哪些插件",纯函数可测bundle-manifest.ts+bundled-plugin-metadata.ts—— 内建插件 manifest(openclaw.plugin.json)读取bundle-mcp.ts—— 把 MCP servers 打包为插件bundled-capability-runtime.ts/capability-provider-runtime.ts—— 能力(capability)注册active-runtime-registry.ts—— 运行期活动插件表
AGENTS.md 一句总结其方向:
Plugin architecture direction: manifest-first control plane; targeted runtime loaders; no hidden paths around declared contracts; broad mutable registries are transitional.
也就是说,manifest 是先于运行时的 control plane;运行时只做 manifest 声明过的事。这允许 UI 在不执行任何插件代码的情况下列出能力、推导配置、做 setup/doctor 流程。
5.3 能力槽(slots)
配置里 config.plugins.slots 是一组"只能有一个实现"的专用槽。比如 src/context-engine/registry.ts:469–535 解析 context engine:
const slotValue = config?.plugins?.slots?.contextEngine;
const engineId = slotValue?.trim() || defaultSlotIdForKey("contextEngine");
注册分两层:核心可信路径 registerContextEngineForOwner(id, factory, owner) 和 公共 SDK 路径 registerContextEngine(id, factory)。后者使用特殊的 PUBLIC_CONTEXT_ENGINE_OWNER,不能声明 core 槽、也不能强制刷新已注册实现(注释写明:"caller's identity is not authenticated")。这是防止第三方插件绑架 core 槽位的简单而有效的办法。
此外,如果 slot 指定的 engine 解析失败(未注册 / factory 抛错 / 契约违反),非默认 engine 会静默降级到默认 engine,只有默认 engine 自身失败才让错误逃逸 —— 生产可用性的典型保险。
六、Context Engine:上下文如何管理
src/context-engine/types.ts 的 ContextEngine 接口是上下文管理的可插拔契约。它把整个 agent 会话生命周期拆成若干 hook:
| 方法 | 作用 |
|---|---|
bootstrap? | 会话初始化,可以选择导入历史 |
maintain? | bootstrap / 成功 turn / compact 后的维护 |
ingest | 单条消息入库 |
ingestBatch? | 按 turn 批量入库 |
afterTurn? | turn 完成后的持久化、触发 background compaction 决策 |
assemble | 按 token 预算组装模型上下文(核心) |
compact | 在预算或阈值下压缩上下文 |
prepareSubagentSpawn? / onSubagentEnded? | subagent 生命周期 |
dispose? | 释放资源 |
值得留意的几个类型:
ContextEngineInfo.turnMaintenanceMode:"foreground" | "background"—— 允许 engine 声明 turn 维护工作是否可以丢到后台ContextEnginePromptCacheInfo—— 运行时传入提示缓存遥测:retention、lastCallUsage、observation(是否破坏缓存、破坏的原因码:cacheRetention/model/streamStrategy/systemPrompt/tools/transport)TranscriptRewriteRequest—— engine 不直接改会话 DAG,而是请求 runtime 做 branch-and-reappend 式的消息替换
这是一个非常成熟的设计:engine 做"决策"(什么该留、什么可删),runtime 做"写入"(如何在 DAG 上体现)。第三方 engine 不可能破坏 session 存储一致性。
Legacy sessionKey 兼容的高级戏法
src/context-engine/registry.ts:251–300 实现了一个很有趣的兼容层。新版 ContextEngine 契约中,某些方法不再接受 sessionKey / prompt 字段(用 sessionId 替换)。老版 engine 会因为 zod/AJV unrecognized_keys 报错。
兼容包装逻辑(wrapContextEngineWithSessionKeyCompat):
- 用
Proxy拦截每个兼容方法 - 第一次调用带
sessionKey/prompt,若失败,从错误链里检测是否包含 legacy key 拒绝信号 detectRejectedLegacyCompatKeys用LEGACY_UNKNOWN_FIELD_PATTERNS(一组 regex)匹配 zod / AJV / 字符串消息变体- 命中后把对应字段移除并重试;记住状态避免第二次再撞
这个实现解决了生态演进里最烦的问题:schema 变了,但你既没有 dry-run 能力也没有标记位。OpenClaw 的做法是"试一次,读错误,学会"。
委托到内建 compaction
src/context-engine/delegate.ts 提供 delegateCompactionToRuntime:第三方 engine 如果只想做"什么时候压缩"的策略、不想重写整个 compaction 算法,可以直接调这个函数委托给 compactEmbeddedPiSessionDirect(pi-agent-core 的内置实现)。buildMemorySystemPromptAddition 更进一步 —— 让非 legacy engine 也能复用 memory/wiki prompt 指导。
这组接口是"open/closed"的范本:核心算法开放复用,策略开放替换。
七、Agents 子系统:能执行真事
src/agents/ 是 OpenClaw 从"聊天机器人"变成"能真做事"的地方。文件数量巨大(数百个),按关注点归类:
7.1 Bash 与命令执行
bash-tools.*.ts 是整个项目最敏感的部分。它被切成了接近 30 个小文件,每个负责一个执行面:
bash-tools.exec.ts+bash-tools.exec-runtime.ts—— 核心执行bash-tools.exec-host-node.ts/exec-host-gateway.ts/exec-host-shared.ts—— 选择 host(node vs gateway)bash-tools.exec.pty.ts/exec.pty-cleanup.ts/exec.pty-fallback.ts—— PTY 支持与回退bash-tools.exec-approval-request.ts/exec-approval-followup.ts—— 每一次 exec 都可能要过审批bash-tools.exec.path.test.ts/exec.script-preflight.test.ts—— PATH 欺骗防护 + 预检bash-tools.process-send-keys.ts/process.supervisor.test.ts—— 后台进程控制
这套拆分是从安全事件里学来的。你只要扫一眼 exec-host-node.test.ts 和 exec-host-gateway.test.ts 会发现同一个"exec"的语义在两种 host 下要求是严格一致的 —— 如果有偏差就是越权面。
7.2 Apply Patch
apply-patch.ts + apply-patch-update.ts —— 实现的是模型返回 patch 补丁格式的合并。和 codex / claude-cli 的 patch 协议一致。
7.3 模型提供商层
anthropic-transport-stream.ts/anthropic-payload-log.ts/anthropic-payload-policy.ts—— Anthropic 原生传输,带 payload 采样日志 + 策略(哪些字段脱敏)anthropic-vertex-stream.ts—— GCP Vertex 变体chutes-oauth.ts/github-copilot-token.ts/copilot-dynamic-headers.ts—— 多种 OAuth/token 路径auth-profiles/*.ts+auth-profiles.ts+ 大量auth-profiles.*.test.ts—— 多 auth profile 轮换、冷却、读只读同步、round-robin、last-used 排序
api-key-rotation.ts 与 auth-profiles.cooldown-auto-expiry.test.ts 一起描绘出一个多 key 限流/故障转移矩阵:key 达上限 → 进入 cooldown → 自动过期 → 重新参与轮换。
7.4 CLI 运行器 & Harness
cli-runner.ts+cli-runner/—— agent 作为 CLI 子进程跑(codex、claude-cli等)cli-session.ts/cli-session-history.ts—— session 跨进程持久化harness/目录 +harness-runtimes.ts—— 把模型 CLI 包进 harness,插入 stdin/stdout、审批、超时、重启cli-watchdog-defaults.ts—— 默认 watchdog 参数
7.5 压缩 & 上下文窗口防护
compaction.ts+ 大量compaction.*.test.ts—— 多种 compaction 路径(real conversation、identifier policy、retry、summarize fallback、token sanitize、tool result details)context-window-guard.ts—— 运行期守卫,避免爆 tokencontext-cache.ts+cache-trace.ts—— prompt cache 追踪
7.6 失败与容错
failover-error.ts / failover-policy.ts / configured-provider-fallback.ts —— 多 provider 级别的故障转移策略(主模型失败 → 备模型)。
7.7 其他关键点
codex-native-web-search.ts—— 原生 codex web-search 工具适配embedded-agent.ts+embedded-pi-lsp.ts+embedded-pi-mcp.ts—— 嵌入式 PI agent(作 subagent)glob-pattern.ts+docs-path.ts—— 文件导航基础gpt5-prompt-overlay.ts/google-thinking-compat.ts—— 针对特定模型家族的 prompt 覆盖层
八、Extensions:100+ 插件的实现面
extensions/ 目录是一个 bundled plugin 博物馆,每个子目录 = 一个插件,同时也是给外部插件作者的 reference implementation。
8.1 Provider(模型)插件
anthropic, openai, google, deepseek, moonshot, xai, qwen, mistral, groq, cloudflare-ai-gateway, litellm, openrouter, vercel-ai-gateway, amazon-bedrock, anthropic-vertex, microsoft-foundry, nvidia, huggingface, ollama, lmstudio, sglang, vllm, ...
每个 provider 自己拥有:
- 认证 / onboarding(不进 core)
- catalog 选择逻辑
- 特定的 tool schema 改写 / replay policy / payload patch
- stream wrapper chain
extensions/AGENTS.md 里有一条明确规则:
Before adding a new provider-local
wrapStreamFn,buildReplayPolicy,normalizeToolSchemas,inspectToolSchemas, or compat patch helper, check whether the same behavior already exists throughopenclaw/plugin-sdk/*. 两个以上 provider 复用同一套就必须抽出共享 helper 并同时迁移两边。
这是一个对抗 copy-paste 腐烂的明确规定。
8.2 Channel 插件
telegram, slack, discord, whatsapp, imessage, signal, matrix, bluebubbles, feishu, line, mattermost, msteams, nostr, synology-chat, nextcloud-talk, tlon, twitch, webhooks, zalo, qqbot, ...
这些插件实现 src/plugin-sdk/channel-contract.ts 的契约。以 extensions/slack/src/ 为例,一个典型 channel 插件包括:
channel.ts+channel.setup.ts+channel.test.ts—— 主实现accounts.ts+accounts.runtime.ts—— 账号管理actions.*.ts—— 消息动作(read、download-file、blocks 等)approval-handler.runtime.ts/approval-native.ts—— native 审批 UIblocks-*.ts—— Slack Block Kit 渲染doctor.ts—— 健康诊断(每个 channel 都必须有 doctor)directory-config.ts/directory-live.ts—— 用户目录同步draft-stream.ts—— 流式草稿预览:在外部消息平台里,像 "正在输入..." 那样实时更新exec-approvals.ts/group-policy.ts—— 群组策略format.ts—— 平台特定格式
8.3 Tool / Service 扩展
brave, duckduckgo, exa, tavily, firecrawl, perplexity, searxng, deepgram, elevenlabs, runway, fal, comfy, voyage, openai-whisper, openai-whisper-api, ...
这些都是对外部服务的封装,同样以插件形式存在,没有一个进 core。
8.4 特殊:opencode / codex / kilocode
opencode, opencode-go, codex, kilocode, kimi-coding —— 把别的 coding agent(opencode、codex 等)包装为 OpenClaw 的 provider。也就是说,OpenClaw 可以用 opencode 作为下层执行 agent。
九、Skills:给 LLM 的宏指令
skills/ 目录下每个子目录有一个 SKILL.md(spec)。skill 是 LLM 可以指令级调用的可复用工具脚本,典型例子:
coding-agent—— 把 claude-code / codex 作为子 agent 调用(recursion)mcporter—— MCP 桥notion,obsidian,bear-notes,apple-notes,apple-reminders,things-mac,trello—— 生产力工具1password—— 凭据访问(需审批)taskflow+taskflow-inbox-triage—— 任务流github,gh-issues—— GitHub 集成spotify-player,sonoscli,openhue—— 家居/媒体控制peekaboo—— macOS 截图/识别camsnap,video-frames—— 视频/相机sherpa-onnx-tts,openai-whisper,songsee,voice-call—— 语音healthcheck,session-logs,model-usage—— 可观测性nano-pdf,summarize,gifgrep,blogwatcher,weather,xurl,wacli—— 杂项工具skill-creator—— 用来创建其他 skill
VISION 明确说:新 skill 应该先进 ClawHub,而不是仓库 core。
十、Security:深度与广度兼备
src/security/ 是单独的安全子系统。audit.ts 是总入口;分面文件非常细:
audit-channel-*.ts—— 每个 channel 的 DM 策略、账户元数据、readonly 判定audit-config-*.ts—— config 文件权限、include 权限、符号链接audit-exec-*.ts—— 安全二进制名单(exec-safe-bins)、沙箱 hostaudit-filesystem-windows.ts+windows-acl.ts—— Windows ACL 专属检查audit-gateway-*.ts—— gateway 暴露面、HTTP auth、tools HTTPaudit-hooks-routing.tsaudit-loopback-logging.ts—— 回环日志audit-plugin-code-safety.ts/audit-plugin-readonly-scope.ts/audit-plugins-trust.ts—— 插件代码安全audit-sandbox-browser.ts+audit-sandbox-docker-config.ts—— 沙箱检查audit-workspace-skill-escape.ts—— skill 越界dangerous-config-flags.ts—— 危险配置标记dangerous-tools.ts—— 危险工具清单external-content.ts—— 外部内容来源审计safe-regex.ts—— ReDoS 防护scan-paths.ts/skill-scanner.ts—— 安全扫描器secret-equal.ts—— 恒时比较防止 timing 攻击fix.ts—— 自动修复发现的问题
所有 collect*Findings 函数返回带 SecurityAuditSeverity 的 SecurityAuditFinding,最终合并为一个 SecurityAuditReport。有 deep vs nondeep 两种模式(audit.deep.runtime.ts / audit.nondeep.runtime.ts),让定期检查与深度扫描分离。
结合 /skills/SKILL.md 里的 security-review skill 和 Gateway 的 approval 机制,OpenClaw 在安全上的工程姿态是:
- 默认安全(
dangerous-config-flags要显式开) - 审计可执行(
openclaw doctor/ security-review skill) - 审批人在回路(
exec-approval-*/plugin-approval-*) - 自动修复(
security/fix.ts)
十一、关键应用场景与集成模式
模式 1:个人多设备助手
iPhone (iOS App) ─┐
macOS (mac App) ──┤── pair ──► OpenClaw Gateway (Mac/Linux)
Android (APK) ──┤ │
│ ├── Telegram / Slack / iMessage …
Node CLI ─────────┘ └── MCP clients (Claude Desktop)
- 所有终端通过 pairing 协议(
device-pair-*)连到一个 Gateway - Gateway 对外既是 WebSocket(原生 protocol),也是 MCP server / OpenAI 兼容 API
- 审批请求通过 iOS push (
exec-approval-ios-push.ts) 送到手机批
模式 2:消息渠道上的 "实际做事" 助手
- 用户在 Telegram 发 "把这个 PDF 总结然后发到 Notion"
telegramchannel plugin 接收 → gateway → agent- agent 调用
summarizeskill 读 PDF,然后调用notionskill 写页 - 所有文件 I/O 受
security/scan-paths.ts和workspace-skill-escape检查 - 需要执行 bash 时,审批请求经 Slack/iOS 推送
模式 3:作为 Claude Code / Codex 的宿主
- 启动 OpenClaw gateway
- Claude Desktop 连接 gateway 的 MCP HTTP endpoint(
src/mcp/channel-server.ts→openclaw-tools-serve.ts) - Claude 获得 OpenClaw 的全部工具目录(bash、file edit、channel send、skill invocation)
- 双向: OpenClaw 也可以通过
coding-agentskill 调用 Claude CLI / codex 作为子 agent
模式 4:第三方扩展 OpenClaw
开发一个新 provider:
// my-provider/src/index.ts
import { definePlugin } from "openclaw/plugin-sdk/plugin-entry";
import { ChannelRuntimeSurface } from "openclaw/plugin-sdk/channel-contract";
// 不得 import "openclaw/src/**"
manifest(openclaw.plugin.json)先声明能力,core 读 manifest 后决定是否激活 —— 无代码执行发现。
开发一个新 context engine:
import { registerContextEngine } from "openclaw/plugin-sdk/...";
import { delegateCompactionToRuntime } from "openclaw/plugin-sdk/...";
registerContextEngine("my-engine", async () => ({
info: { id: "my-engine", name: "My Engine" },
async ingest(p) { /* 写入自己的存储 */ },
async assemble({ sessionId, tokenBudget, prompt }) {
/* 我自己的 retrieval 策略 */
return { messages, estimatedTokens };
},
async compact(p) {
return delegateCompactionToRuntime(p); // 委托内建 compaction
},
}));
然后在 config.plugins.slots.contextEngine = "my-engine" 即可。
十二、值得学习的工程亮点
-
契约即代码(Contract-as-code):
src/gateway/protocol/schema.ts把协议、类型、校验、文档生成统一在一处。AJV compile 的是 schema 对象本身,不依赖独立生成步骤,但可以通过pnpm config:docs:gen/check保持文档不漂移。 -
Lazy boundary 纪律:每一个重型子系统都有
*.runtime.ts,import-cycles/madge作为 gate。启动代价被分散到"真正使用时"。 -
特征边界硬隔离:扩展禁止 deep-import core;core 禁止 deep-import 扩展。
tsconfig.package-boundary.paths.json+ 自定义架构检查 + CODEOWNERS 协同执行。 -
"试一次读错误"兼容层 (context-engine/registry.ts:201-249):schema 演进不用全局开关 / 双写,靠运行期探测。
-
拆分到"单一失败定位" (
server-startup*.ts、bash-tools.*.ts):每个文件只负责一个阶段/关注点,事故分析可以直接落到文件。 -
Prompt-cache 是一等公民:
ContextEnginePromptCacheObservation有专门的"cache broke 原因码"。运行时不仅追踪缓存命中率,还能告诉你为什么没命中。AGENTS.md 明确 "deterministic ordering for maps/sets/registries/plugin lists/files/network results before model/tool payloads. Preserve old transcript bytes when possible." —— 整个系统在"让 prompt cache 保持命中"上做优化。 -
多 Auth Profile + 故障转移:
auth-profiles/*、failover-policy.ts、api-key-rotation.ts—— 是商用级的 multi-tenant 友好设计。 -
审批在回路,跨设备:
exec-approval-ios-push.ts+plugin-approval-*的组合,不是简单的 "是/否" 弹窗,而是一个协议级的跨终端审批体系。 -
安全审计与自动修复:
src/security/子系统 +security/fix.ts—— 同时提供发现与修复能力。 -
测试纪律(AGENTS.md Tests 节):
- 颗粒"Unit-test pure helpers / contracts; one integration smoke per boundary, not per branch"
- 禁止宽泛的
importOriginal()/openclaw/plugin-sdk/*partial mock,要加窄的*.runtime.tsseam OPENCLAW_TEST_PROJECTS_TIMINGS测试分片时序记录,做到自适应 shard 均衡
十三、批判与权衡
阅读门槛高。仅 src/agents/ 就有上百个 bash-tools.*、auth-profiles.*、cli-runner.*、compaction.*。文件划得过细会拉高认知摩擦 —— 你需要跨十几个文件才能读懂一次 bash exec 的全链路。这是"单一失败定位"的代价。
Channel 数量膨胀。100+ extension 里有不少是作者早期探索的产物(Tlon、Nostr、Synology Chat 等),VISION.md 已经在"What We Will Not Merge"里明确不再接受重复包装。意味着扩展列表不等于"都值得用"。
没有官方的第三方插件市场(ClawHub 仍在建设中)。目前大多数能力内嵌。
文档与代码的同步靠纪律。docs/.generated/*.sha256 是 baseline,但"代码改了 → 文档漂移"在 100k+ LOC 级别很难完全避免。
核心技术栈深度绑定 TS / Node 22+ / pnpm。移植到 deno/bun 会很痛(尽管 VISION 提到支持 Bun,但 AGENTS.md 注 "keep Node and Bun paths working" 本身说明这不是自动的)。
十四、总结
OpenClaw 的源码值得被当成一份TypeScript 大型系统工程指南来读。它不是"又一个 Agent 框架",而是一个:
- 以 Gateway 为控制面、以 Protocol 为契约的个人 AI 编排系统
- 插件/Channel/Provider/Skill 四种一等扩展单元,用公共 SDK + manifest-first 严格解耦
- 把"能真做事"必须面对的所有硬问题(多 provider auth、token rotation、compaction、prompt cache、审批、沙箱、跨设备 pairing、Windows/macOS/Linux/iOS/Android)作为一等公民
- 以安全默认 + 显式高权限开关 + 审计/修复链路为安全模型,而不是 "trust and hope"
- 架构边界用 lint/ts 项目引用/madge cycle/arch 门 物理强制,不靠口头约定
对于想学习大型 LLM 应用如何在工程化层面写出来的开发者,它是目前最丰富的开源样本之一:比起炫目的"agent 框架"DSL,它展示了真正生产化所需要的所有"没人爱写但又必须写"的代码。
附录:源码阅读路线图
- 30 分钟版:README.md → VISION.md → AGENTS.md → src/entry.ts → src/gateway/protocol/schema.ts 前 200 行
- 2 小时版:追加 src/context-engine/types.ts、src/context-engine/registry.ts、extensions/AGENTS.md、某一个 channel 插件(建议 extensions/slack/src/)
- 一周版:读
src/gateway/完整、src/agents/bash-tools.*.ts+exec-approval-*、src/plugins/激活链路、src/security/audit*.ts、docs/plugins/全部 - 真正理解:自己写一个 channel 或 provider 插件,走一遍
pnpm check:changed闭环