状态写到磁盘,活过压缩
「State that survives compression — because it's outside the conversation.」
TodoWrite 和 Task 有什么区别?
s03 的 TodoManager 也能列任务——但它存在内存里。s06 讲的 auto_compact 一触发,messages[] 被替换成 summary,TodoManager 的状态就跟着没了(因为它是 in-memory)。
s07 的 Task 不一样:每个 task 是一个 .tasks/task_42.json 文件。context 被压也好、进程重启也好、agent 被换掉也好——只要磁盘文件还在,任务就还在。
# .tasks/task_12.json { "id": 12, "subject": "Refactor auth middleware", "description": "Extract JWT logic to shared module", "status": "pending", "blockedBy": [8, 11], # 必须先完成 #8 和 #11 "owner": "" }
选择规则:临时待办(做完这次就忘)用todo;持久任务(跨会话保留、有依赖)用task。
blockedBy · 依赖图的脾气
blockedBy 是一个 task id 列表——必须这些都 completed 之后,当前 task 才「可执行」。
s07 的实现有一个精巧的细节:完成一个 task 时,它会自动从所有其他 task 的 blockedBy 列表里移除自己。
def _clear_dependency(self, completed_id: int): # Scan every task, remove completed_id from their blockedBy for f in self.dir.glob("task_*.json"): task = json.loads(f.read_text()) if completed_id in task.get("blockedBy", []): task["blockedBy"].remove(completed_id) self._save(task)
这样 agent 不需要维护一张独立的 "什么 task unblocked 了" 表——只要遍历 .tasks/,找 status=="pending" and not blockedBy 的就是现在可执行的。
依赖图交互
下面这个 widget 给你一个 5 个 task 的依赖图。点 "complete",看 blockedBy 自动更新,哪些 task 变成「可执行」(绿色高亮)。
经过压缩还能活吗?
s06 讲过 auto_compact 会把 messages[] 换成一条 summary。但 task 不受影响,因为它在磁盘。测试一下:让 agent 做了 5 个 task,压缩掉对话后,它扫一下 .tasks/,原地能继续。