OpenClaw 源码深度分析与应用文档

0 阅读19分钟

仓库地址: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-sdkplugin-package-contractmemory-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):

  1. isMainModule 守卫:entry.js 可能被作为共享依赖被 dist/index.js 间接 import。如果没有这个守卫,顶层副作用会第二次触发 runCli,造成"二次启动 gateway + 锁/端口冲突"。这是一个很典型的打包器/入口文件合流陷阱,作者用显式守卫根治了它。
  2. Compile cache (enableCompileCache())、进程 warning filter、normalizeEnv()、Windows argv 归一化、--no-color 规范化 —— 全部在加载业务代码之前做,降低环境差异。
  3. respawn 计划 (buildCliRespawnPlan / attachChildProcessBridge):某些情况下父进程会 spawn 一个干净的自身副本,把 stdio 透传过去。这是 Node 世界处理"需要特定 execArgv"的经典做法。
  4. Version fast path / Help fast path:--version--help 不走完整 CLI 图,直接走 cli/root-help-metadata.js 返回预计算元数据 —— 首屏感知速度优化。
  5. 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.ts lazy 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 生命周期、模型、skill
  • channels.ts —— 渠道操作(启动、登录、状态)
  • commands.ts / config.ts / cron.ts
  • devices.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.tsAJV 编译每一个 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(常量聚合)允许运行时反射协议表面
  • ErrorCodesdiscriminated 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 / modes
  • preauth-hardening.test.ts
  • control-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.tsContextEngine 接口是上下文管理的可插拔契约。它把整个 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 —— 运行时传入提示缓存遥测:retentionlastCallUsageobservation(是否破坏缓存、破坏的原因码: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):

  1. Proxy 拦截每个兼容方法
  2. 第一次调用带 sessionKey / prompt,若失败,从错误链里检测是否包含 legacy key 拒绝信号
  3. detectRejectedLegacyCompatKeysLEGACY_UNKNOWN_FIELD_PATTERNS(一组 regex)匹配 zod / AJV / 字符串消息变体
  4. 命中后把对应字段移除并重试;记住状态避免第二次再撞

这个实现解决了生态演进里最烦的问题: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.tsexec-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.tsauth-profiles.cooldown-auto-expiry.test.ts 一起描绘出一个多 key 限流/故障转移矩阵:key 达上限 → 进入 cooldown → 自动过期 → 重新参与轮换。

7.4 CLI 运行器 & Harness

  • cli-runner.ts + cli-runner/ —— agent 作为 CLI 子进程跑(codexclaude-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 —— 运行期守卫,避免爆 token
  • context-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 through openclaw/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 审批 UI
  • blocks-*.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)、沙箱 host
  • audit-filesystem-windows.ts + windows-acl.ts —— Windows ACL 专属检查
  • audit-gateway-*.ts —— gateway 暴露面、HTTP auth、tools HTTP
  • audit-hooks-routing.ts
  • audit-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 函数返回带 SecurityAuditSeveritySecurityAuditFinding,最终合并为一个 SecurityAuditReport。有 deep vs nondeep 两种模式(audit.deep.runtime.ts / audit.nondeep.runtime.ts),让定期检查与深度扫描分离。

结合 /skills/SKILL.md 里的 security-review skill 和 Gateway 的 approval 机制,OpenClaw 在安全上的工程姿态是:

  1. 默认安全(dangerous-config-flags 要显式开)
  2. 审计可执行(openclaw doctor / security-review skill)
  3. 审批人在回路(exec-approval-* / plugin-approval-*)
  4. 自动修复(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"
  • telegram channel plugin 接收 → gateway → agent
  • agent 调用 summarize skill 读 PDF,然后调用 notion skill 写页
  • 所有文件 I/O 受 security/scan-paths.tsworkspace-skill-escape 检查
  • 需要执行 bash 时,审批请求经 Slack/iOS 推送

模式 3:作为 Claude Code / Codex 的宿主

  • 启动 OpenClaw gateway
  • Claude Desktop 连接 gateway 的 MCP HTTP endpoint(src/mcp/channel-server.tsopenclaw-tools-serve.ts)
  • Claude 获得 OpenClaw 的全部工具目录(bash、file edit、channel send、skill invocation)
  • 双向: OpenClaw 也可以通过 coding-agent skill 调用 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" 即可。


十二、值得学习的工程亮点

  1. 契约即代码(Contract-as-code):src/gateway/protocol/schema.ts 把协议、类型、校验、文档生成统一在一处。AJV compile 的是 schema 对象本身,不依赖独立生成步骤,但可以通过 pnpm config:docs:gen/check 保持文档不漂移。

  2. Lazy boundary 纪律:每一个重型子系统都有 *.runtime.ts,import-cycles / madge 作为 gate。启动代价被分散到"真正使用时"。

  3. 特征边界硬隔离:扩展禁止 deep-import core;core 禁止 deep-import 扩展。tsconfig.package-boundary.paths.json + 自定义架构检查 + CODEOWNERS 协同执行。

  4. "试一次读错误"兼容层 (context-engine/registry.ts:201-249):schema 演进不用全局开关 / 双写,靠运行期探测。

  5. 拆分到"单一失败定位" (server-startup*.tsbash-tools.*.ts):每个文件只负责一个阶段/关注点,事故分析可以直接落到文件。

  6. 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 保持命中"上做优化。

  7. 多 Auth Profile + 故障转移:auth-profiles/*failover-policy.tsapi-key-rotation.ts —— 是商用级的 multi-tenant 友好设计。

  8. 审批在回路,跨设备:exec-approval-ios-push.ts + plugin-approval-* 的组合,不是简单的 "是/否" 弹窗,而是一个协议级的跨终端审批体系。

  9. 安全审计与自动修复:src/security/ 子系统 + security/fix.ts —— 同时提供发现与修复能力。

  10. 测试纪律(AGENTS.md Tests 节):

    • 颗粒"Unit-test pure helpers / contracts; one integration smoke per boundary, not per branch"
    • 禁止宽泛的 importOriginal() / openclaw/plugin-sdk/* partial mock,要加窄的 *.runtime.ts seam
    • 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,它展示了真正生产化所需要的所有"没人爱写但又必须写"的代码


附录:源码阅读路线图

  1. 30 分钟版:README.mdVISION.mdAGENTS.mdsrc/entry.tssrc/gateway/protocol/schema.ts 前 200 行
  2. 2 小时版:追加 src/context-engine/types.tssrc/context-engine/registry.tsextensions/AGENTS.md、某一个 channel 插件(建议 extensions/slack/src/)
  3. 一周版:读 src/gateway/ 完整、src/agents/bash-tools.*.ts + exec-approval-*src/plugins/ 激活链路、src/security/audit*.tsdocs/plugins/ 全部
  4. 真正理解:自己写一个 channel 或 provider 插件,走一遍 pnpm check:changed 闭环