跳转至

Paperclip 源码拆解

从一个任务如何被创建、认领、唤醒、执行、治理、恢复并最终交付出发,读懂一个多 Agent 控制平面的完整工程实现。

22 个主题章节 · 111 个数据库 schema 文件 · 1,229 个测试文件 · 全链路 Mermaid 图解

开始阅读 :material-arrow-right: 查看上游源码

研究对象

本站基于本地 paperclip-master 快照进行静态源码分析。快照没有 .git 元数据;核心包清单版本为 0.3.1。本文优先相信实际代码,其次才是仓库内文档,因此会主动标出两者不一致之处。

为什么值得拆 Paperclip

很多 Agent 项目停留在“调用模型 + 工具循环”。Paperclip 处理的是更难的后一半:当几十个不同运行时的 Agent 共同工作时,怎样让任务不被重复领取、上下文可以续接、预算能真正止损、权限不会越界、失败后仍有恢复路径,而且人随时能介入。

它的价值不只在某个框架或 API,而在一组能迁移到其他 Agent 系统的工程命题:

  • 任务所有权如何成为数据库事实,而不是 Prompt 中的一句约定;
  • 一次唤醒如何成为可持久化的运行记录,并具备排队、合并、重试与取消语义;
  • 执行环境如何和规划对象解耦,既支持本地目录,也支持 worktree、SSH 与远程 sandbox;
  • 权限、审批、预算和工具风险如何进入执行热路径,而不是事后审计;
  • 进程退出、服务器重启、静默运行与悬空任务如何被系统性收敛;
  • 前端如何消费高频运行事件,又不把服务端和浏览器拖进刷新风暴。

全站路线图

flowchart LR
  A["产品与领域模型"] --> B["API 与数据契约"]
  B --> C["Issue 原子认领"]
  C --> D["Heartbeat 执行闭环"]
  D --> E["Adapter 与 Workspace"]
  E --> F["权限与治理"]
  F --> G["实时 UI 与扩展系统"]
  G --> H["恢复、测试与发布"]
  H --> I["端到端源码追踪"]
模块 你会得到什么 代表章节
产品与建模 理清“控制平面”边界、公司/目标/项目/任务/Agent 的关系 01–03
接口与状态 看懂服务启动、共享契约、Issue 状态机和原子 checkout 04–06
执行内核 逐步追踪 wakeup、run、session、adapter、workspace 07–09
安全治理 理解 actor、RBAC/ABAC、审批、预算、成本、审计 10–11
数据与体验 看懂 Drizzle/PostgreSQL 与 WebSocket/React Query 的协作 12–13
可扩展能力 分析插件、MCP、密钥、Skills、Teams 与自动化 14–17
交付与运维 研究文档/产物、CLI、部署、恢复、CI 与发布 18–21
综合串联 用一条真实任务时序把所有部件重新拼起来 22

规模画像

这不是一个“几个文件的 Demo”。对快照进行静态计数后,可以看到它已经具备大型 TypeScript 产品的形态:

指标 数量 说明
TypeScript / TSX 文件 3,202 UI、Server、CLI、Packages 合计
测试文件 1,229 单测、集成、E2E、脚本契约测试
Markdown 文件 408 用户文档、设计稿、计划、技能与团队模板
SQL 文件 214 其中 210 个位于 Drizzle migrations 目录
数据库 schema 文件 111 每个文件通常对应一组强相关表
Server 路由文件 58 REST、认证、OpenAPI、工具网关等
Server 业务服务文件 216 不含测试文件
UI 源文件 1,278 页面、组件、API client、context 与工具函数

最能说明复杂度的不是文件数量,而是核心文件的体积:heartbeat.ts 约 1.9 万行,routes/issues.ts 约 1.2 万行,issues.ts 约 9 千行,tool-access.ts 约 7.8 千行。本文不会按文件从头复述,而会把这些巨型服务拆成可理解的状态机和时序。

本站的拆解方式

每章尽量回答同一组问题:

  1. 它解决什么问题? 先给业务约束,不从类名和函数名开始。
  2. 数据事实放在哪里? 指出表、字段、唯一索引或状态常量。
  3. 请求如何走? 从 route 追到 service、transaction、event 和 UI cache。
  4. 为什么这样设计? 解释并发、幂等、故障恢复和安全边界。
  5. 代价是什么? 标出巨型服务、单机事件总线、规格与实现漂移等现实限制。
  6. 能复用什么? 把 Paperclip 的实现提炼成其他 Agent 系统可采用的模式。

文中所有“源码入口”均使用仓库相对路径和符号名。在线上游分支可能继续变化,因此比固定行号更耐用。

先记住四条主线

Company → Goal → Project → Issue → Run → Work Product

规划对象与执行对象分开:Issue 表达意图,Run 表达一次尝试,Work Product 表达可验证输出。

assigneeAgentId + checkoutRunId + executionRunId

谁负责、哪次运行取得 checkout、哪次运行持有执行锁是三个相关但不同的问题。

Wakeup Request → Heartbeat Run → Adapter → Workspace → Liveness → Recovery

唤醒不是直接 spawn();它先被持久化、去重、排队,再进入一套带清理和恢复的生命周期。

Actor → Authorization → Budget/Approval → Mutation → Activity Log

每次关键动作都要回答:谁做、能不能做、是否要人批、是否超预算、怎样留下证据。

适合谁读

  • 在做 Agent orchestration、coding agent 平台或 AI 内部工具的工程师;
  • 想把“Prompt 约定”升级成“可验证系统不变量”的架构师;
  • 需要评估 Paperclip 二次开发、插件开发或部署风险的团队;
  • 想系统学习 TypeScript Monorepo、Express、React Query、Drizzle 与 PostgreSQL 的读者。

如果只想快速了解,读第 01、02、06、07、10、22 章即可;如果准备改代码,建议按顺序读完并配合源码导航图。


下一步:阅读指南会说明如何选择路线、怎样核对源码,以及本站对“事实、推断、规格”的标注约定。