Daily Recap - 每日工作整理
将所有机器上的 Agent 会话整理为一份主题聚合的日报,写入 Obsidian 工作日志或个人日记。
nmem 是 source of truth:多台机器上的会话通过 nmem 同步,覆盖全部机器的全部会话。会话的唯一来源是 nmem,不区分本地/远程。
流程:选日 + 列举候选 → 归类审查(唯一人工门) → 收集 + 聚合 → 条件核验(静默)→ 写入 + 一行报告。执行期保持安静,只在归类审查和写入报告两处出声。
流程
1. 选日 + 列举候选
确定目标工作日:工作日窗口以 CST 04:00 为界 [工作日 04:00, 次日 04:00),凌晨 00:00-04:00 的会话归前一工作日。"总结哪个工作日"以 12:00 为界(<12:00 昨天 / ≥12:00 今天),由脚本按 recap 时刻自动选择。
cd <skill目录> && uv run --script scripts/extract_today.py
拿到 date 后回显一行:「整理目标工作日:{date}(脚本自动选择,改期用 --date)」。整理历史日期才显式传 --date YYYY-MM-DD。
列举候选(nmem 是唯一来源):
nmem threads list --limit 200 --json | uv run --script scripts/extract_today.py --filter
脚本按 UUID v7 时间戳(线程 id 前 48 位 = 会话开始时间毫秒戳,见 CONTEXT.md「线程 ID 时间戳」)把线程分成三组:
candidates:窗口内非机器线程——进入归类审查machine:窗口内机器会话,按标题族分组(advisoradvisor 镜像 /subagent子代理任务 /recap上一轮 recap 自身及子代)——默认跳过,跳过必留痕:归类审查消息里带一行计数备注(如「另跳过 31 条机器会话:advisor×16、子代理×12、上轮 recap×3」);用户点名可捞回excluded:窗口外线程——不处理
机器标题族在脚本里维护;新形态的机器会话照常进候选,确认后补进脚本。
分页:nmem threads list 排序不是严格日期序(按导入批次混杂),--offset 递增翻页,每页管道 --filter,直到连续多页无窗口内候选才停;翻页范围在归类审查消息里一行带过。
其余过滤:消息数 <10 的候选多为测试探针,聚合成一行备注(数量 + 特征),不逐条进表。留痕原则:窗口内每个线程要么进候选表、要么在备注里有据可查——包括机器会话与 stub,不允许静默消失。
空集:candidates 为空时告知「目标工作日没有会话记录」并终止。不得用「当前会话应在窗口内」反证——12:00 前跑 recap 时目标工作日是昨天,当前会话必然在窗口外,反证前提恒不成立。
降级:nmem CLI 连接失败/超时(退出码非 0,stderr 报 connecting/timeout)→ Hard stop,见 references/recovery-guide.md。
2. 归类审查(HITL · 唯一人工门)
把 candidates 整理为候选条目表,直接按主题域分组,机器/stub 跳过备注随表附上:
| # | 会话主题 | 主题域 | 去向 | 理由 |
|---|---|---|---|---|
| 1 | HPC 巡检 | genome-assembly | 工作日志 | 之江实验室日常工作 |
| 2 | 双语 HTML 转换 | learn-mattpocock | 不记录 | 个人练习,无产出变化 |
去向:工作日志 · 个人日记 · 不记录
呈现给用户确认——这是全程唯一的人工交互。用户修正去向或标记跳过后,仅批准的条目进入下一步。
3. 收集 + 聚合
3a. 扇出 recap-collector 收集事件
批准后按主题域扇出(一个主题域一个 collector,包揽该主题下所有会话;主题域超过 6 个也先全部收集——合并发生在 3b,不预先砍)。collector 读 nmem 线程,蒸馏成事件(选骨架、填字段、带来源指针),返回结构化文本证据包。写入由主 agent 独占。
collector 的角色、统一接口与降级策略见
agents/recap-collector.md;task 按references/collector-task-template.md填充(主题域 / 目标工作日 / 技能目录 / 会话清单 / 重点核实项,不传去向)。
异常处置(不静默、不硬写、不打断):
- collector 发现窗口外线程或读取失败:跳过并记入「遗留」清单
- 会话未完成但内容有效(如 CI 修复在结论落地前截断):标注「未完成」,只写已确认的部分,不把未验证的意图写成既成事实
- 某批准主题域整体无法落地:写入报告里点名,补不补由用户决定
3b. 聚合写作
collector 返回的事件(非会话摘要)是输入。对批准条目做主题聚合:
- 语义相近的事件合并到同一主题域
- 同一主题下的多个事件 → 1 个标题 + 子 bullet 展开
- 每个子 bullet 1-2 行,只写结论和决策
- 排序:部署/功能交付在前,基础设施/配置在后,探索/学习最后
- 不超过 6 个主题域(理想 3-5 个);无零散单事件段落
事件骨架(collector 已选型填字段,成文时照此展开):
- 功能(实现了功能):功能名称 + 核心特性 + 关键技术决策
- 修复(修复了问题):问题 + 根因 + 修复方式
- 决策(做了决策):决策内容 + 理由 + 放弃的替代方案
- 调研(调研了方案):调研对象 + 结论 + 选型判断(为什么选 A 不选 B)
- 部署(部署/配置):环境 + 关键参数 + 验证结果
- 验证(验证假设/回答问题):原始问题 + 验证方法 + 结论 + 下一步含义
学到什么:事件带可复用结论(根因/选型判断/下一步含义/决策理由)才点出;纯交付(功能/部署)无可复用结论不硬编。
数据密集判定:bullet 含可核对的具体数字/参数/验证结果 = 数据密集,触发第 4 步核验;纯定性(决策理由、调研结论)跳过。按 3b 输出 bullet 判定。
写作规则:
- 来源可追溯(硬约束):每条 bullet 能追到证据包来源(
thread_id#消息index)。写不出来源的句子不写——不写「根据习惯」「一般来说」这类无来源内容。 - 按主题聚合:按主题域组织而非按时间平铺;证据不足的主题域剔除或补收集,不带病进写入。
- 去掉流程噪音:不写 agent 操作日志与内部项目标签——会话全景表、消息量、Git 提交、验证流程、阶段标记、配置路径,以及内部项目标签(map/ticket/issue 编号、里程碑、生命周期阶段)。写「产出了什么结论」,不写「完成了什么任务」。
输出模板(标题层级遵循 references/diary-rules.md 变体规则,文件名已含日期,文件内一级标题是主题/子系统,不重复日期标题):
# 主题域(work: 子系统名 / personal: 主题标题)
- 关键事件 bullet...
- 关键事件 bullet...
4. 条件核验(静默)
对数据密集 bullet 扇出核验 subagent:对着证据包原文逐条核对数字、百分比、公式、口径;纯定性 bullet 跳过。
agent: reviewer;task = 证据包原文 + 待核验 bullet 清单(每条含声称的数字和来源出处)- 核验报告逐条给出结论(一致 / 修正为 X,依据来源 Y)
- 不一致 → 按来源静默修正(数字、口径以来源为准),修正处数记入写入报告;来源无法裁决的条目从终稿剔除并记入报告。不打断用户。
5. 写入 + 一行报告
变体:按候选表去向定 work/personal(规则见 references/diary-rules.md;混合内容拆分分别写入)。
日记上下文:
cd <skill目录> && uv run --script scripts/obsidian-helper.py --vault <work|personal> --date YYYY-MM-DD
输出 DIARY_PATH/DATE、RECENT(近期 2-3 篇日记,了解写作风格)、TODAY(今日日记全文;不存在时自动从模板创建)。始终传 --date(用第 1 步的目标工作日)。首次配置:CONFIG_MISSING=true 时按打印的示例创建 ~/.config/cnife-skills/obsidian-diary.json,询问用户 vault 根目录后填入,重新运行脚本。
补全式整合写入:先读后写,基于 TODAY 全文补全不覆盖——已有章节末尾追加 bullet,不重写已有内容;新章节插到已有章节之后,按重要性排序;用 Edit(patch)工具写入。
一行报告(就此收尾,不再请用户读终稿):「已写入 {变体} 日记({date})」;有核验修正或遗留项时追加一句(如「核验修正 2 处」「遗留:1 条读取失败未纳入」)。准确性兜底 = 来源可追溯 + 静默核验 + 用户日常浏览时顺手改。
参考
- 收集任务模板 ->
references/collector-task-template.md - 日记格式规则 ->
references/diary-rules.md - 故障恢复 ->
references/recovery-guide.md