# seek PRD v5：代理编排（umbrella）

> 目标版本：seek v0.6.x
> 依赖基础：v0–v4 全部子系统（permission、tool、session JSONL、hooks Registry、checkpoint、keymap、suggested-reply）
> 前置阅读：[PRD v3 umbrella](v3.md) §2（跨柱设计约束——v5 继承）、[PRD v4 umbrella](v4.md) §2（v4 三条新约束——v5 同样继承）、[`docs/comparison.md`](../comparison.md) §10 + 差距汇总 🔴 P0 段。

**本文是 umbrella 文档**——v5 用以补齐 Claude Code 对比表里识别出的最大单一架构缺口：**子代理 + 调度 + worktree 隔离**这一耦合三件套。v5 把它们打包做，是因为分开做会重复造调度面与生命周期管理。

| 柱 | 主题 | Feature PRD | 子里程碑 | 交付状态 |
|---|---|---|---|---|---|
| **G** | 空间维度：子代理 + Worktree 隔离 | [`feature-subagent.md`](feature-subagent.md) | M11.0 + M11.1 | 🚀 v0.6.0 |
| **H** | 时序维度：Cron / Wakeup / Push | [`feature-routines.md`](feature-routines.md) | M11.2 + M11.3 | 🚀 v0.6.1 |

两柱**共享一套编排生命周期**（ctx 传播、goroutine 拥有权、成本归集、子 session 持久化），但用户接口完全不重叠——G 是模型主动 spawn，H 是系统按时间 / 外部事件唤醒。E/F 是 v4 留下的占位符（"待规划"），v5 从 G 起编号以示主题切换。

---

## 1. 动机

走完 v0–v4 后，seek 在**单 agent 单进程**的能力曲线上已对齐 Claude Code 主流形态。但对比文档（§10 + 差距汇总 P0）反复指向同一个**架构维度**的空白：

- **空间维度**——seek 永远只有一个 agent 串行干一切。Claude Code 的 `Agent` 工具让模型可以 spawn 子上下文做**并行研究**（"同时让三个 subagent 查这三个目录"），叠加 `EnterWorktree`/`ExitWorktree` 做**并行实施**（"两个 subagent 各自试一种方案，最后挑一个"）。没有这层，模型的"分而治之"完全靠用户在外部协调。
- **时序维度**——seek 永远是"用户敲完回车才跑"。Claude Code 的 `CronCreate` / `ScheduleWakeup` / `RemoteTrigger` / `PushNotification` 让 agent 摆脱同步会话循环，可定时检查 CI、等外部事件、跑完推送给用户。

两个维度**单独看都不够格做"v5 整版"**，但**绑在一起做才合理**——子代理与定时任务都需要"非主 turn 的执行通道 + 独立成本归集 + 父 session 关系追踪"。分开做会有两份调度面、两份转录隔离逻辑、两套权限传播规则。v5 命名为"代理编排"而非"多 agent"或"调度"，正是因为内核是**同一套**编排基础设施。

**v5 不追**：单点工具缺口（LSP / NotebookEdit / WebSearch / Monitor / 结构化 `ask_user` v2）。它们每个都是独立文件改动，没必要进 umbrella；挂到 v0.6.x dot release 或 v6 按需 ship。

## 2. 跨柱设计约束（继承 v3 / v4，新增 v5 特有六条）

v3.md §2（prefix-cache 字节确定性、复用 Registry、信任前置、`pkg/` 零变更、失败降级）和 v4.md §2（旁路调用不污染主 transcript、闭环数据存最小集、单一开关贯穿全链路）全部在 v5 继续生效，不引入新例外。

v5 特有的六条新约束：

### 2.1 子转录字节隔离

子 agent 拥有**独立的 session JSONL**（路径下沉到 `subagents/<sub-sid>.jsonl`），父 transcript 中**只**保留一条 tool result：`[agent: completed] <summary>`（参考 v3 plan-mode `[plan: approved]` 的 wire-format 契约——前缀确定，扩展项加在闭合 token 之后）。子 transcript 永不 inline 进父字节流——否则父的 prefix cache 会被子的可变 streaming 输出击穿。

派生规则：父调用 `agent` 工具的 ChatRequest 看到的是确定性的 tool schema bytes + 子返回 summary；中间过程（子的 system prompt、tool calls、reasoner 思考）一律不进父 messages[]。

### 2.2 子转录可独立 resume，但默认不挂入父 List()

子 session JSONL 走标准 `internal/session` 包格式（schema_version=2），使得 `seek -resume <sub-sid>` 可单独续传一个子 agent；但 `seek -list` 默认只列父 session，子 session 通过 `--include-subagents` 显式展开。理由：用户感知里"我有 5 个 session"应等于"我跑了 5 次主对话"，而非被子任务噪声放大。

### 2.3 权限单调收紧

`permission.Policy` 在 spawn 子 agent 时**只能向下传**，不能向上松：

- **Preference**：parent=`PrefYolo` 可生子 `Yolo/Ask/Deny`；parent=`PrefAsk` 不可生 `Yolo`；parent=`PrefDeny` 子只能 `Deny`。
- **Workflow**：parent=`WorkflowPlanAnalyze` **强制**子 `PlanAnalyze`（只读不可破）；parent=`WorkflowPlanExecute` 默认子继承同态，但子可显式声明 `PlanAnalyze`（更严）；parent=`WorkflowNone` 子默认 `None`，可显式声明任何 Workflow。

实现：新增 `Policy.Spawn(restriction) (*Policy, error)` 方法，编译期约束；`agent` 工具的 LLM schema **不暴露**任何"提升权限"的参数。这是 v0 permission R1 双轴模型的自然延伸——pref/workflow 两个轴在父→子方向上各自只能单调收紧。

### 2.4 成本同账户归集

子 agent 的 token usage（cache_hit / miss、prompt / completion 分桶）由子拥有独立 `cache.Tracker` 跑自己的 `Record(...)`，**父 Tracker 通过 `AdoptChild(child *Tracker)` 持有子引用**——`Cumulative()` / `CumulativeCost()` 在读取自身 turns 后追加遍历 `children`。状态栏显示的费用 == 父 + 全部活跃/已完成子之和。

为什么选 `AdoptChild` 而非给 `Record` 加 `parentSid` 参数：（a）现有所有 caller 零改动；（b）子 Tracker 可独立 `Summary()` / 独立写入子 session header，无需感知父；（c）resume 路径只需"是否 adoption 过"一个 flag，避免双重计数（§ feature-subagent §3.7 + 风险表）。

### 2.5 时序触发零常驻进程（柱 H）

定时任务**不引入** seek 自己的后台 daemon。触发模型走两条腿：

- 每次 `seek` 启动时扫一遍 `~/.seek/cron/jobs.jsonl`，对 `next_run_at <= now()` 的条目立刻在 detached goroutine 中触发；
- 提供 `seek cron tick` 子命令，用户可挂 launchd / systemd / cron / Task Scheduler 这些**OS 级**调度器（每分钟跑一次 `seek cron tick`）。

理由：常驻 daemon 与 seek 的"单二进制零依赖"卖点直接冲突；OS 级调度器已经免费提供进程拉起，seek 只负责"被拉起后执行什么"。Remote trigger 同样走**文件桥**（`~/.seek/cron/triggers/<id>.json`）而非 socket 监听——简单、跨平台、可审计、与 Windows 兼容。

### 2.6 编排状态全部 transcript-外存

cron job 定义、子 session 父子索引、push 历史——全部走专用文件（`~/.seek/cron/`、`~/.seek/projects/<id>/subagents.jsonl`），**不**进 session JSONL。

理由：v3 plan-mode 的 transcript 事件溯源能成立，是因为 plan 状态是**单会话内事件序列**；v5 的编排状态是**跨会话 / 跨进程**的，transcript 不是 single source of truth，硬塞会让 `-resume` 行为变得不可预测。CLAUDE.md "Reconstruct state from transcript, don't persist parallel state files" 的限定语境是 plan-mode 那种"事件源自 LLM 调用"，不适用于"事件源自 OS 级调度器"。

## 3. 跨柱集成视图

### 3.1 Prefix cache 影响审计

| 新机制 | 来源 | 是否进父 transcript | 是否影响父 cache |
|---|---|---|---|
| Spawn 子 agent | 柱 G | 是（一条 tool result `[agent: completed] <summary>`，bytes 确定） | 否（与现有 tool result 同形） |
| 子 agent 流式输出 | 柱 G | 否（走独立 JSONL） | 否 |
| Worktree 创建/销毁 | 柱 G | 是（`[worktree: created path=... branch=...]` / `[worktree: cleaned]`） | 否（确定性 bytes） |
| Cron 触发的新 session | 柱 H | N/A（新顶层 session，无父 transcript） | — |
| `schedule_wakeup` 调用 | 柱 H | 是（`[schedule: waking at <iso8601>]` tool result） | 否 |
| Push 通知发送 | 柱 H | 否（OS notification 外发，无 in-prompt 副作用） | 否 |

**净结论**：v5 对父 cache 的扰动等同于"用户主动调用一个工具拿到确定性结果"，与现有 `webfetch` / `git` 同量级。子 agent 自身的 cache 曲线独立于父。

### 3.2 共享配置目录（v5 新增）

```
~/.seek/
├── cron/
│   ├── jobs.jsonl                              # 柱 H：cron 定义
│   ├── runs/<run-id>.jsonl                     # 柱 H：每次触发的运行记录
│   └── triggers/<id>.json                      # 柱 H：远程触发文件桥
└── projects/<id>/
    ├── subagents.jsonl                         # 柱 G：子 session 父子关系索引
    └── sessions/<sid>/subagents/<sub-sid>.jsonl  # 柱 G：子 session 转录
```

git ref 命名空间（沿用 v3 checkpoint 的 `refs/seek/` 主空间）：

```
refs/seek/worktrees/<sub-sid>          # 柱 G：worktree base ref
```

### 3.3 新增 slash / CLI 命令

| 命令 | 来源 | 作用 |
|---|---|---|
| `/agents` | 柱 G | TUI 内列出当前 session 已 spawn 的子 agent 与状态 |
| `/cron` | 柱 H | TUI 内列/启/停定时任务（CLI 同名命令的薄包装） |
| `seek subagent {list,resume,kill}` | 柱 G | CLI 管理子 session |
| `seek cron {create,list,delete,run,tick}` | 柱 H | CLI 管理定时任务，`tick` 用于 OS 调度器挂载 |

### 3.4 与 v3 checkpoint（柱 A）的交互

Worktree spawn 时自动在父 turn 起点打一次 git checkpoint（复用 v3 柱 A）。即使子 agent 在 worktree 里执行破坏性操作并最终 commit 回主分支，父也可一键 `/undo` 撤回整个 turn。failure-degraded 路径：非 git 仓库时 worktree 工具直接 deny，与 checkpoint 的同样降级语义对齐。

### 3.5 与 v4 D（suggested-reply）的交互

子 agent **完全不启用** `predicted_next` 旁路链路——只主 turn 触发预测。理由：预测语境是"用户接下来会说什么"，子 agent 没有真人用户在场。这是 v4 §2.3 "单一开关贯穿全链路"的自然推论：`suggest_reply` 仅在 root agent runner 上为 true。

### 3.6 与 hooks Registry（v3 柱 B）的交互

子 agent 的工具调用**默认走父 session 的 hooks Registry**——`pre_tool` deny / `post_tool` observer / audit log 一视同仁。理由：用户在 `hooks.toml` 里写"禁止 `rm -rf`"是项目级安全策略，子 agent 不能绕过。例外开关 `agent.bypass_hooks: true` 不在 v5 提供，留到柱 G 一段时间反馈再说。

## 4. 总体实现计划

| 子 ms | 内容 | 估时 | 所属 feature | 发版 | 状态 |
|---|---|---|---|---|---|
| **M11.0** | 子代理核心：`agent` 工具 + 子 session JSONL 路径 + `Policy.Spawn` + `cache.Tracker` 父子归集 + `/agents` 渲染 + `seek subagent` CLI | ~5 天 | feature-subagent | v0.6.0 | 🚀 已交付 |
| **M11.1** | Worktree 集成：`enter_worktree` / `exit_worktree` 工具 + `agent` 的 `isolation: "worktree"` 选项 + 自动清理 + 与 v3 checkpoint 联动 | ~3 天 | feature-subagent | v0.6.0 | 🚀 已交付 |
| **M11.2** | Cron 骨架：`seek cron` CLI + `jobs.jsonl` schema + tick 扫描器 + 启动时自动 tick + run 记录 | ~3 天 | feature-routines | v0.6.1 | 🚀 已交付 |
| **M11.3** | Wakeup + Push：`schedule_wakeup` 工具 + OS notification 适配（macOS `osascript` / Linux `notify-send` / Windows toast — Windows 当前 no-op，BurntToast 适配延后 v0.6.x dot）+ 文件触发桥 | ~3 天 | feature-routines | v0.6.1 | 🚀 已交付 |
| **M11.4** | 集成测试（含并发 -race）+ pitfall 记录 + 文档（README + book chapter + comparison doc 同步 + `docs/guide-cron.md`） | ~2 天 | umbrella（本文） | v0.6.1 收尾 | 🚀 已交付 |
| **合计** | | **~16 天** | | | |

**发版两段**：

- **v0.6.0**：M11.0 + M11.1（subagent + worktree）—— 用户体感最大，单独 ship 立刻补齐"模型可分裂"这一架构差距。
- **v0.6.1**：M11.2 + M11.3 + M11.4（routines + 收尾）

**并行可行性**：柱 G 与柱 H 在代码层零冲突——除共享 `internal/cache.Tracker` 改造与可能抽出的 `internal/orchestrator`（ctx / goroutine 生命周期 helper），其他全部落各自包。建议**同一人**先推 G 再推 H，避免两份 orchestrator 抽象提前定型成不兼容形态。

**测试纪律**（继承 CLAUDE.md "test the failure modes" 规范）：

- 子 agent 中途 ctx 取消时的 transcript 落盘 + 父 cumulative cost 正确性
- worktree dirty 状态下 `exit_worktree` 的 prompt / 拒绝路径
- cron tick 与 seek 启动 race（两个 seek 进程同时跑同一 job 应去重）
- OS notification 在三平台缺失对应可执行文件时的降级（写 stderr 不阻塞）
- subagent 转录损坏时父 session 仍可正常 resume

## 5. 与 v4 的关系

- **v4 D（suggested-reply, M10.0）已 ship**——v5 子 agent 默认禁用预测旁路依赖于 `suggest_reply` 开关位置已稳定。
- v5 不重构 v4——v4 §2.1"旁路 LLM 调用不污染主 transcript"的隔离原则是 v5 §2.1 子 agent 隔离的直接先例；v5 在更强场景（递归而非平级旁路）下复用同一原则。
- v4 §6 列出的 backlog 中"MCP 客户端嵌入"、"TUI 多面板"未进 v5——前者作为独立 feature PRD 已有设计稿，与编排正交；后者待 v5 ship 后再看是否被 `/agents` 渲染压力推上来。

## 6. 后续柱候选（仅 brainstorm，不承诺）

v5 ship 完成后浮现的下一柱候选：

- **子代理 type registry 开放给 skill 系统**——`.skill.md` frontmatter 可声明 `subagent_type: review`，社区可分发专精 agent（如 code-reviewer、security-reviewer）
- **跨 worktree 合并辅助**——并行 subagent 各自改了 worktree 后，工具自动 cherry-pick / 三方合并到主分支
- **Routines TUI 面板**——`/cron` 进入交互视图，显示 next_run / 上次状态 / 累计 token 消耗
- **可选 Webhook server**——`seek serve` 子命令把文件触发桥升级为 HTTP 端点（用户主动开，不强制；保留"零常驻"作为默认）
- **单点工具收尾包**：LSP / NotebookEdit / WebSearch / Monitor / 结构化 `ask_user v2`——这些没进 v5 umbrella，但每个独立可 ship，可在 v0.6.x dot release 中按需推进

backlog 不是 commitment。M11.0 ship 完看用户对子 agent 的真实使用率再排序。
