阅读指南¶
这不是 API 手册,也不是把目录树翻译成中文。它是一份以运行时行为为中心的源码地图。
1. 研究基线¶
分析对象是工作区中的 paperclip-master 快照。它有完整源码和依赖清单,但没有 .git 目录,因此无法可靠给出提交 SHA。可以确认的版本事实是:
server、ui、cli、db、shared、adapter-utils与多数 adapter 的package.json版本为0.3.1;- 插件 SDK 的清单版本为
1.0.0; - 部分新包仍处在
0.1.x; - 仓库内同时存在面向用户的
docs/和偏内部设计/运行手册的doc/; - 实际数据库默认实现是 embedded PostgreSQL,而一处较旧架构文档仍写着 PGlite。
因此,本文采用以下证据优先级:
不要把设计稿自动当成现状
doc/plans/ 和部分 SPEC 描述的是目标形态。本文引用它们时会明确写“规格”或“计划”;没有这种标记的行为结论,均以当前源码和测试为依据。
2. 三条推荐路线¶
路线 A:两小时掌握执行内核¶
适合已经做过 Agent loop、只想抓 Paperclip 独特点的读者。
flowchart LR
C1["01 定位"] --> C2["02 分层"] --> C6["06 原子认领"]
C6 --> C7["07 Heartbeat"] --> C9["09 Workspace"]
C9 --> C10["10 授权"] --> C22["22 端到端"]
重点关注:
- checkout 的条件更新与 stale-lock adoption;
- wakeup request 与 heartbeat run 为什么分表;
- run terminalization 为什么必须早于 lease release;
- liveness 不等于“进程还在”;
- responsible user 如何进入授权决策。
路线 B:准备二次开发¶
建议顺序读完 01–14,再按需求选择 15–21。每章末尾的“源码入口”可以作为 IDE 跳转清单。
开始改代码前,至少要理解五个同步面:
packages/db的数据库事实;packages/shared的常量、类型和 Zod 校验;server的路由与服务;ui的 API client、query key 与展示状态;- 迁移、测试、OpenAPI 与文档。
漏掉其中任何一个,通常会造成“编译能过但跨层契约漂移”。
路线 C:评估安全与治理¶
按 03 → 06 → 09 → 10 → 11 → 14 → 15 → 20 阅读。
你会看到 Paperclip 的安全不是单一 RBAC,而是多层相交:
- company scope 防止租户串线;
- actor middleware 建立请求身份;
- membership/grant 决定资源权限;
- trust preset 限制低信任来源;
- issue/run context 限制 task bridge、skill test、watchdog;
- approval 与 budget 在关键动作上设门;
- secret projection 只把需要的值投影进运行环境;
- activity/tool audit 保存决策证据。
3. 章节结构约定¶
大多数章节由以下部分组成:
| 部分 | 作用 |
|---|---|
| 一句话结论 | 先给你可验证的核心判断 |
| 问题与模型 | 从业务约束解释为什么存在该子系统 |
| 数据结构 | 表、字段、状态、索引及其不变量 |
| 源码路径 | route → service → DB/event/adapter/UI 的调用链 |
| 时序/状态图 | 把跨文件行为还原成一个整体 |
| 失败与恢复 | 并发、超时、重试、重启、权限失败的结果 |
| 设计权衡 | 当前实现的优点、代价和已知边界 |
| 可复用经验 | 抽象成与你的项目有关的模式 |
| 源码入口 | 文件和符号索引 |
代码片段会被压缩成“保留语义的伪代码”或很短的真实结构,避免让大段源码遮住控制流。要核对细节,请直接打开对应路径。
4. 如何读路径与符号¶
例如:
server/src/services/issues.ts :: checkout
packages/db/src/schema/issues.ts :: issues
ui/src/context/LiveUpdatesProvider.tsx :: handleLiveEvent
双冒号左侧是仓库相对路径,右侧是建议搜索的符号。对巨型服务,符号搜索比固定行号稳定;对 schema,则优先看字段、索引和 check/unique 条件。
在线核对可从上游仓库进入。由于本文快照没有提交号,上游 master 在未来可能与本文存在差异。
5. 事实、推断与评价¶
本文使用三种语气:
- 事实:“
checkout使用带前置条件的单条UPDATE。”可在代码中直接定位。 - 推断:“把 wakeup 与 run 分表,是为了让请求去重和执行尝试拥有不同生命周期。”这是从 schema 与调用链得到的设计推断。
- 评价:“单进程 EventEmitter 是当前横向扩展的边界。”这是基于实现的工程评价。
出现“我认为”“可以看作”“更像”时,通常是在做推断或评价;其余关键结论会给出源码入口。
6. 先建立六组区分¶
Paperclip 的复杂度很大一部分来自“相似但不能合并”的概念。建议先记住:
| 不要混为一谈 | A | B |
|---|---|---|
| 计划与执行 | Issue:要做什么 | Run:一次执行尝试 |
| 分配与锁 | assignee:责任人 | checkout/execution run:本次占有者 |
| 请求与尝试 | Wakeup request:为什么要唤醒 | Heartbeat run:实际怎么执行 |
| 规划空间与运行空间 | Project workspace:长期根目录 | Execution workspace:某次/某组任务实际运行位置 |
| 展示与决策 | Profile:工具是否可见 | Policy:这次调用能否执行 |
| 输出与交付 | Workspace file:仍在工作目录 | Artifact/work product:可供审查的持久化结果 |
后续章节会反复用到这些边界。
7. 本文不做什么¶
- 不逐个解释所有 React 组件或 REST endpoint;
- 不替代官方安装与运维手册;
- 不把尚未实现的计划包装成现有能力;
- 不评价某个模型或供应商的效果;
- 不声称当前快照代表上游仓库的最新状态。
8. 配合源码阅读的最小工具集¶
# 找符号
rg -n "function checkout|async function enqueueWakeup" server/src
# 找状态常量的所有消费者
rg -n "HEARTBEAT_RUN_STATUSES|ISSUE_STATUSES" .
# 看某个表在哪里被更新
rg -n "update\(issues\)|insert\(heartbeatRuns\)" server/src
# 先看测试名,快速理解边界条件
rg -n "describe\(|it\(" server/src/__tests__/issues-service.test.ts
对 Paperclip 这类服务型 Monorepo,测试名称常常比业务文件中的注释更快暴露真正的不变量。
9. 建议的做笔记方式¶
读每个子系统时维护四栏即可:
例如 checkout:
POST /issues/:id/checkout
| assigneeAgentId / checkoutRunId / executionRunId
| todo|in_progress -> in_progress
| 409 / stale adoption / admin force release
这比照着函数顺序抄摘要更能形成系统模型。
准备好后,从第 01 章:产品定位与拆解方法开始。