跳转至

阅读指南

预计 8–12 分钟阅读路线证据标注版本边界

这不是 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。

因此,本文采用以下证据优先级:

可执行代码 / schema / 测试
        > 当前操作文档与 runbook
        > 设计规格与计划文档
        > README 中的产品叙事

不要把设计稿自动当成现状

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 跳转清单。

开始改代码前,至少要理解五个同步面:

  1. packages/db 的数据库事实;
  2. packages/shared 的常量、类型和 Zod 校验;
  3. server 的路由与服务;
  4. ui 的 API client、query key 与展示状态;
  5. 迁移、测试、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 章:产品定位与拆解方法开始。