03 · 领域模型与公司边界¶
一句话结论: Paperclip 用 Company 作为租户与治理根,用 Goal/Project/Issue 表达意图,用 Agent org 表达责任,再用 Run/Workspace/Artifact 记录执行事实;父子结构、依赖关系和所有权彼此独立。
1. 总体对象图¶
erDiagram
COMPANY ||--o{ AGENT : employs
COMPANY ||--o{ GOAL : owns
COMPANY ||--o{ PROJECT : owns
COMPANY ||--o{ ISSUE : owns
COMPANY ||--o{ MEMBERSHIP : governs
COMPANY ||--o{ BUDGET_POLICY : constrains
COMPANY ||--o{ APPROVAL : reviews
AGENT o|--o{ AGENT : manages
GOAL o|--o{ GOAL : decomposes
GOAL ||--o{ PROJECT : aligns
PROJECT ||--o{ ISSUE : contains
ISSUE o|--o{ ISSUE : decomposes
ISSUE ||--o{ HEARTBEAT_RUN : executes
ISSUE ||--o{ DOCUMENT : explains
ISSUE ||--o{ WORK_PRODUCT : delivers
HEARTBEAT_RUN o|--o| EXECUTION_WORKSPACE : uses
图中最值得注意的是多个递归关系:Agent 汇报树、Goal 目标树、Issue 工作树。它们长得相似,但约束和用途不同。
2. Company:租户、编号和治理根¶
companies 表不仅有名称和描述,还保存:
status;issuePrefix与issueCounter,用于生成如PAP-123的稳定标识;- 预算与累计支出字段;
- 单附件上限;
- 默认 responsible user;
- 是否要求新 Agent 经 Board 审批;
- interaction governance 与 branding。
Company 同时承担四个角色:
- 数据分区键:业务查询第一过滤条件;
- 命名空间:Issue identifier、技能、工具连接和插件配置;
- 治理范围:membership、permission grant、预算和审批;
- 事件频道:实时事件按 company 订阅。
因此,“关联 ID 存在”不够,服务还会验证关联对象是否属于同一 Company。
3. Goal:保存“为什么”¶
Goal 有 level、status、parentId 和可选 ownerAgentId。它形成递归目标树,并可通过 project/issue 关联向下传播。
Goal 的价值不是做另一套标签,而是让 Agent context 能带上祖先目标。任务描述回答“做什么”,目标链回答“为什么”。
4. Project:轻量规划容器¶
Project 保存名称、状态、lead agent、goal 关联和环境/工作区策略。它刻意不等同于 Git repository:
- 可以没有代码;
- 可以有多个 project workspace;
- 可以代表运营、设计或内容项目;
- execution workspace policy 只是执行默认值,不改变其规划身份。
这个决定避免把“一个 repo”“一个交付目标”“一个运行目录”错误合并。
5. Issue:系统中最密集的聚合¶
issues 表承载了远多于任务标题的事实,可以按六组理解。
5.1 结构与对齐¶
companyId、projectId、goalId;parentId:工作分解树;projectWorkspaceId:选定的长期 workspace。
5.2 工作状态¶
status:backlog/todo/in_progress/in_review/done/blocked/cancelled;workMode:standard/ask/planning/skill_test;priority、review policy、started/completed/cancelled timestamps。
5.3 责任与执行锁¶
assigneeAgentId或assigneeUserId;checkoutRunId;executionRunId;executionAgentNameKey、executionLockedAt。
责任人、checkout 持有者和实际执行 run 分开保存,允许系统表达“仍由 A 负责,但 A 的上一轮已结束,新一轮正在接管”。
5.4 来源与幂等¶
originKind、originId、originRunId、originFingerprint;requestDepth;- routine、recovery、watchdog、productivity review 等系统来源。
这些字段让自动化创建的 Issue 可以被去重、识别和排除自触发。
5.5 执行策略¶
- adapter/model/runtime overrides;
- execution policy 与 state;
- workspace preference/settings;
- monitor 和 liveness 相关字段。
5.6 信任与责任归属¶
sourceTrust:输入来源的信任元数据;responsibleUserId:Agent 行为最终由哪个人类责任主体承接;unblockDescriptor:blocked 时可路由的解除路径。
这六组字段解释了 issues.ts 和 routes/issues.ts 为什么会变成巨型文件:Issue 是规划、执行、治理和恢复的交点。
6. 三种图不能混用¶
6.1 父子图:分解¶
parentId 回答“这个子任务属于哪个更大的任务”。父任务完成与否、子任务是否自动完成,由业务规则和 workflow 决定。
6.2 Blocker 图:依赖¶
issue_relations 中的 blocks 回答“B 是否必须等待 A”。它不是父子关系:兄弟任务、跨树任务也可以形成 blocker。
6.3 Org 图:管理与升级¶
agents.reportsTo 回答“谁管理谁”,用于 delegation、direct-report 权限、completion wake 和升级链。
flowchart LR
subgraph WorkTree["工作分解树"]
P["父 Issue"] --> C1["子 Issue A"]
P --> C2["子 Issue B"]
end
subgraph Dependency["依赖图"]
C1 -->|blocks| C2
end
subgraph Org["组织图"]
CEO --> CTO --> ENG
end
如果把三张图合成一张,系统会出现典型错误:父任务被误当 blocker、经理自动获得任意任务写权、取消上游被误判为依赖满足。
7. Agent:配置、组织身份和运行状态¶
agents 表可按三层理解:
| 层 | 代表字段 | 含义 |
|---|---|---|
| 组织身份 | name、role、title、reportsTo、capabilities | 它在公司里是谁 |
| 执行配置 | adapterType、adapterConfig、runtimeConfig、defaultEnvironmentId | 怎样运行它 |
| 控制状态 | status、budget/spend、pause/error、permissions、lastHeartbeatAt | 现在能否运行 |
状态包括 active、paused、idle、running、error、pending_approval、terminated。但“状态是 active”并不等价于“可立即唤醒”;invokability 还会检查 Company、预算、adapter、树暂停、环境等条件。
7.1 汇报树不是唯一授权来源¶
reportsTo 支持 delegation 和特定直系汇报场景,但真正授权还要结合:
- company membership role;
- principal permission grants;
- 资源 membership;
- task/skill/watchdog scope;
- responsible user 的可用权限;
- trust preset。
这是一套混合 RBAC + ABAC,而不是“老板可以做一切”。
8. Human、Agent 与 responsible user¶
Company membership 可以指向 user 或 agent。请求 actor 也可能是 board、agent、system 或 plugin。
为什么还需要 responsibleUserId?因为 Agent 的执行最终应能映射到一个人类责任主体,尤其在工具连接、密钥、审批和私有资源访问中。
可以把授权看成集合相交:
这避免某个高权限 Agent API key 脱离任务与人类责任上下文后成为万能 token。
9. Run 与 Session:尝试和连续性¶
heartbeat_runs 记录一次尝试,包含:
- 状态、来源、开始/结束时间;
- adapter/session/model 信息;
- usage/cost/result/log/process metadata;
- retry 关系和调度时间;
- liveness 分类;
- context snapshot。
agent_task_sessions 则以 company + agent + adapter + task key 保持可恢复会话。一次 session 可以跨多个 run,多个 run 不应共享同一条“当前执行事实”。
flowchart LR
S["Task Session"] --> R1["Run 1"]
S --> R2["Run 2"]
S --> R3["Run 3"]
R1 -->|"resume state"| R2 -->|"resume state"| R3
10. Workspace 也是领域对象¶
Project workspace 是稳定根;execution workspace 是实际执行位置;environment 是执行能力载体;environment lease 表示某次 run 对能力的占用。
这组对象让系统不必假设:
- 代码一定在 Server 本机;
- 每个任务一定创建 Git 分支;
- 一个 Issue 只能运行一次;
- workspace 清理可以靠进程退出顺便完成。
第 09 章会详细展开。
11. 证据对象:不要只看最终状态¶
Paperclip 把不同证据分开保存:
activity_log:谁对什么实体做了什么;heartbeat_run_events:执行流中的结构化事件;cost_events/finance_events:用量与账务;documents/ revisions / annotations:可审阅文本;- attachments/assets:持久化文件;
- work products:PR、preview、artifact、workspace file 等交付摘要;
- external objects:GitHub 等外部系统对象映射。
因此状态查询、历史审计和产物浏览可以使用不同读模型。
12. 删除与归档语义¶
关系使用多种策略:
- Company 删除通常级联业务数据,但实际删除能力受 deployment/config 保护;
- Agent 被移除时,历史记录多使用
set null保留证据; - 插件、连接、技能和部分成员更偏向 disable/archive,而非抹去;
- terminal Issue 保留全部 run/activity/document 历史。
这体现“运行系统里的历史比干净外键更重要”。
13. 可复用经验¶
- 多 Agent 系统应先选清楚租户/治理根,所有对象显式归属。
- 父子分解、依赖 DAG、组织汇报树必须分开建模。
- 责任人、checkout owner 和 execution lock 不应塞进一个
owner字段。 - Run 表达一次尝试,Session 表达跨尝试连续性。
- 交付状态、执行成功与输出证据应能独立查询。
- 自动化生成的对象要保存 origin 和 fingerprint,才能可靠去重与防自触发。
源码入口¶
packages/db/src/schema/companies.tspackages/db/src/schema/goals.tspackages/db/src/schema/projects.ts、project_workspaces.tspackages/db/src/schema/agents.tspackages/db/src/schema/issues.ts、issue_relations.tspackages/db/src/schema/heartbeat_runs.ts、agent_task_sessions.tspackages/shared/src/types/issue.ts、agent.ts、heartbeat.ts
下一章进入运行组合根:04 · 服务启动与请求生命周期。