这本书给谁看,看完能明白什么
如果你每天在两三个 AI 工具之间切换干活,到了晚上却说不清"今天到底做完了哪些事、哪些是 AI 说做完了其实没做完、明天从哪接着来",这本书就是为你写的。
先说我是谁。我叫 Bin哥,日常同时用 Codex、Claude Code 和 Hermes 三个 AI 工具,在两台电脑之间来回切。过去五个星期,我让这些工具自动把每一次会话记进同一本"任务账本":到今天为止,账本里有 917 张任务卡、两千七百多条不可变事件,覆盖 49 个项目。这本书讲的就是这套东西:它为什么存在、怎么记账、怎么判断一句话算不算任务、怎么装到你自己的电脑上、以及它二十天里出过的每一个故障。
这是这本白皮书的第三版。前两版(v1.0、v2.0)写的是"让 Agent 自己写账"的方案:在每个工具的系统提示词里塞一段账本协议,让 AI 一边干活一边调用命令登记任务。那套方案能跑,但两个问题一直没解决:AI 有时忘了记,记账的话还会污染它干正事的上下文。2026 年 9 月 16 日起,我把记账整个从 AI 身上卸了下来,改成一个独立的本机服务。这一版讲的就是卸下来之后的样子。
看完你能明白的五件事
- 为什么聊天记录和待办清单都当不了任务系统,"账本"补的是哪个空。
- 一句话进到系统里之后经过了哪几道手,最后是谁决定它算不算一个任务。
- "AI 说做完了"和"真的做完了"在账本里怎么区分,五种状态各自代表什么。
- 账本落在磁盘上是什么样,为什么坏了能重建,为什么两台电脑不会打架。
- 怎么用 Codex 或 Claude Code 把它装到自己电脑上,装完怎么知道它真的在记。
三条写作原则
- 只说验证过的事。书里每一张截图、每一条任务卡、每一个数字,都能在我的账本和项目仓库里找到原文件。哪些是本机跑过的、哪些只是隔离测试通过、哪些还在规划,我分开写。
- 不承诺做不到的事。它不能保证一条都不漏,也不能替你判断交付质量。哪里有边界,第 10 章写清楚。
- 每个技术词都翻译成人话。第一次出现时给一个生活里的类比,书末有一张术语对照表。
按顺序读最好,因为后一章会用前一章的概念。每章末尾有一个"你现在试试",是十分钟以内能做完的小动作。着急的话,先看第 2、4、7 章:它是什么、最难的判断怎么做、怎么装。只想装不想懂原理的,直接看第 7、8 章,装完再回头看。
聊天记录为什么不能当任务系统?
AI 工作从对话开始,但交付从来不落在对话里。它落在代码、文档、图片、网页、命令和别的系统里。对话能解释来龙去脉,却回答不了几个最要紧的问题。
五个聊天记录答不上来的问题
- 今天正式承诺了哪些工作?一段对话里可能有三件事、两句闲聊、一次改主意。哪些算数?
- 哪些只是讨论?"要不要把这个也改了"和"把这个改了",在聊天里长得几乎一样。
- 同一个需求有没有被记两遍?你在 Codex 里说过一次,换到 Claude 又说了一次。
- 实现、测试、用户验收分别到了哪一步?AI 说"已完成",是代码写完了,还是测试过了,还是你看过了?
- 换电脑、换工具之后从哪里继续?家里的 Mac mini 做到一半,公司的笔记本上一点痕迹都没有。
传统的待办工具也补不上这个空。它只保存标题和截止时间,不会自动记下这件事是哪个工具、哪台设备、哪个会话里冒出来的,更不会记下完成的证据。反过来,如果把每句话都变成待办,噪声比信息多。
一个真实的日子
下面这张图是我写这段话时,工作空间首页显示的当天任务看板。
这 40 条里有凌晨 Codex 自动跑的日复盘,有我在 Claude Code 里排查一个技能报错的三轮对话,有家里那台电脑上修复账本服务的六条任务,还有早上盯盘的一条。它们分散在三个工具、几十个会话里。如果没有这本账,我需要翻十几个聊天窗口才能拼出这张表;有了它,这张表是自动长出来的。
"AI 说做完了"是最大的坑
做这套系统之前,我最常遇到的不是漏记,而是假完成。AI 在回复末尾写一句"任务已完成,所有测试通过",我信了,第二天发现测试根本没跑,或者跑了没过。
所以账本的核心设计是一句话:用证据决定完成度,不用 AI 的语气决定。"代码写完""测试通过""你看过了""另一台电脑也同步了"是四层不同的证据,账本里对应不同的状态。第 5 章专门讲。
会话:你和一个 AI 工具从打开窗口到关掉之间的这一段对话。一个会话里可以有好几件事。
来源:这条记录是从哪个客户端来的,比如 Codex、Claude Code、Hermes。它说的是"哪个工具",不是"谁触发的":Codex 半夜自动跑的任务,来源仍然是 Codex。
设备:哪台电脑。来源和设备是两个独立维度,同一个工具在两台电脑上是两条不同的轨迹。
打开昨天用得最多的那个 AI 工具,翻昨天的对话,试着回答上面五个问题。给自己计时。我第一次做这件事花了二十多分钟,还漏了一条。这二十分钟,就是这本账每天替你省下的时间。
任务账本是什么:对话与交付之间的一本账
一句话定义:任务账本是加在"你跟 AI 说话"和"AI 交出东西"之间的一层记录。它自动把对话里的工作请求变成任务卡,用不可变的事件记录每一次变化,再用证据而不是语气决定这件事做没做完。
它做到的五个"不"
| 承诺 | 意思 | 靠什么做到 |
|---|---|---|
| 不漏 | 你在任何一个接入的工具里提出的工作请求,都会落到账本里 | 每个工具装三个薄 Hook,只负责把你的话和 AI 的最终回复投递给本机服务;服务掉线时先存本地,恢复后补交 |
| 不重复 | 同一件事在同一个会话里不会变成两张卡 | 服务端有"新建复核"和"返工关联"两道独立判断,宁可写明"延续自哪张卡"也不建近义卡 |
| 不假完成 | AI 说"完成"不等于账本上"已完成" | 完成必须带结构化证据引用;"待验证"专门留给需要你拍板的两种情况 |
| 可跨端、跨设备 | 换工具、换电脑,任务轨迹接得上 | 每条记录都带来源、设备、会话、项目四个维度;两台电脑各写各的事件文件,靠 Git 手动合并 |
| 可恢复 | 缓存、日报、看板坏了都能重建 | 权威数据是按天分片的不可变事件文件,其他全是从它算出来的视图 |
一张真实的任务卡
先看它长什么样,再讲道理。这是 2026 年 9 月 24 日凌晨三点五十一分,我在家里那台电脑的 Codex 里说了一句"排查一下已完成任务追加备注为什么还报 409"之后,账本自动生成的卡:
把这张卡拆开看,一共回答了七个问题:
# TASK-20260924-035110:排查已完成任务追加备注仍报409并放开状态校验 - 状态:已完成 ← 现在到哪一步了 - 项目:task-ledger ← 这是哪个项目的事 - 创建来源:Codex / 参与来源:Codex ← 从哪个工具来的 - 创建设备:silence_mini_pro ← 在哪台电脑上 - 创建时间:2026-09-24T03:51:10+08:00 - 最近更新:2026-09-24T03:52:32+08:00 ## 目标 延续自 TASK-20260924-033452(支持状态修改免校验并加二次确认): 排查追加备注时仍报"账本服务 409"的原因…… ← 这件事到底要做什么 ## 证据 人工状态调整 进行中→已完成:用户于本会话明确确认任务已完成; 账本定向测试 49 项、Wiki 定向测试 26 项通过…… ← 凭什么说做完了 证据引用: - file:/…/task-ledger-server/acceptance/97752aea-….json ← 证据在哪个文件
这张卡不是 AI 写的,也不是我写的。它是服务根据两条事件(一条"登记"、一条"流转到已完成")自动渲染出来的 Markdown 文件。改它没用,改了下次重建还会变回去。真正的账在事件里,第 6 章讲。
五种状态,一个都不多
| 状态 | 含义 | 常见误解 |
|---|---|---|
| 待开始 | 明确存在这件事,但还没有任何执行信号 | 不是"我打算做",是"已经登记、还没动手" |
| 进行中 | 已经开始与这件事相关的工作 | AI 回复了一半、你还在追问,都算进行中 |
| 待验证 | 东西交出来了,但有一个确定的下一步必须由你决定,或有一项实质风险必须由你确认 | 不是"AI 不确定就丢给你";模型自己拿不准,不许转嫁成你的验收 |
| 已完成 | 任务范围内的工作做完了,并留下了证据和决策来源 | 不需要你再说一遍"通过";范围外的建议不阻止完成 |
| 阻塞 | 做到一半停了,缺你的信息、授权或重新安排才能继续 | 一次工具报错但 AI 自己修好了,不算阻塞 |
"会话关了""AI 没回话""账本服务挂了"都不是任务状态,是运行状态。归档、放弃也不伪装成已完成。这五个状态从 v1.0 到 v3.0 一个字没改,改的是"什么时候进哪个状态"的规则,第 5 章讲。
任务卡:一张 Markdown 文件,一件事一张,编号是创建时间。它是给人看的投影,不是账本本身。
事件:账本里真正的"账"。每发生一件事(登记、流转、纠错)就多一个小文件,写了就不改,改用新事件覆盖旧结论。
证据引用:写在任务里的一条"去哪能查到"的指针,格式固定:文件、命令、测试、提交、网址、验收记录六种。纯文字的"测试通过"不算证据。
拿昨天做过的一件事,按上面那张卡的七个问题手写一张。写到"证据引用"那一行时停一下:你能不能给出一个别人打开就能核对的位置?写不出来的那件事,很可能就是你以为做完了、其实没做完的那件。
它是怎么记账的:薄 Hook、账本服务、模型判断、规则落账
你不需要看懂代码,但要知道一句话从你嘴里出来到变成账本里的一行,中间经过了哪几道手,以及每道手能做什么、不能做什么。这决定了它出问题时你去哪里找。
四道手,各管一件事
- 薄 Hook:只送信,不判断。每个接入的工具装三个钩子,分别在"你发出一条消息""AI 给出最终回复""会话结束"时触发。它们把这三样东西打包投递到本机服务,然后立刻退出。它不调用模型、不往你的对话里塞任何话、不阻止 AI 回复。服务不在线就把信存进本地暂存目录,服务恢复后每 5 秒自动补交一次。
- 账本服务:先收下,再排队。服务收到信先写进本机数据库,返回"已收到"。这一步不等模型。之后一个串行的"工人"按发生时间把信一封封取出来,找到同会话最近的几条上下文和还没完成的候选任务,交给下一道手。
- 模型:只给建议,不动账。模型看到的是一份脱敏过的输入:这条消息、同会话最近八条上下文、候选任务列表。它只能回答五种动作之一:不记录、新建任务、延续某任务、建议状态变化、请求人工复查。它不能返回命令、不能读文件、不能自己写账本。第 4 章专门讲它怎么判断。
- 规则与状态机:决定落不落账。模型的建议要过几道确定性的关卡:任务编号必须是候选里真实存在的;时序不能比人工决定更旧;状态迁移必须合法;完成必须带证据。全过了,服务才调用原来的账本命令行工具写事件、刷新任务卡、日报和看板,然后逐文件核对写入结果一致,这一封信才算"已应用"。
一条消息的真实旅程
还是第 2 章那张卡。它背后是两个事件文件,我把关键字段抄出来:
事件 1 register(登记)
happened_at : 2026-09-24T03:51:10+08:00
origin : codex
device_id : silence_mini_pro
event_id : codex:b95f0843-…:step:000001 ← 由 Codex 会话里的原生 ID 派生,重发不会重记
task.status : 进行中
task.goal : 延续自 TASK-20260924-033452(…):排查追加备注时仍报 409 的原因……
事件 2 transition(流转)
happened_at : 2026-09-24T03:52:32+08:00
event_id : codex:14a93ea2-…:0
status : 已完成
evidence_refs :
- file:/…/task-ledger-server/acceptance/97752aea-….json ← 人工验收回执
从我在 Codex 里说话,到第一个事件落盘,中间是:Hook 投递(毫秒级)→ 服务入库 → 工人取出 → 模型判断这是一条"延续"→ 新建复核确认 → 规则校验通过 → 调用原命令行登记。第二个事件是我在看板上点了"已完成",走的是人工命令通道,不经过模型。
为什么要把记账从 AI 身上卸下来
v2.0 的做法是让 AI 自己记账:在 Codex 的 AGENTS.md 和 Claude 的 CLAUDE.md 里各放一段账本协议,要求 AI 在第一次调用工具之前先登记任务、结束时按格式汇报状态。Hook 负责兜底。跑了一个月,我发现三个绕不过去的问题:
- 每条消息都被注入一段账本上下文,AI 干正事的注意力被分走
- AI 偶尔忘了记、记错卡,Hook 兜底规则又太粗
- Codex 的 Stop 钩子会阻断回合等记账完成,用起来卡
- 换一个工具就要改一份提示词,三端三套规则
- AI 的提示词里没有一个字跟记账有关,它只干活
- 判断集中在服务端一份提示词里,改一处三端同时生效
- Hook 异步投递,两秒超时,失败放行,业务不受影响
- 模型只给建议,规则和证据决定写不写,能审计、能重放
切换是 2026 年 9 月 16 日到 18 日之间完成的:先让 Hermes 一端以"影子模式"只看不写,确认采集没问题后切正式写入;再接 Claude Code、Cowork 插件和 Codex。切换前把三个工具里的旧协议全部备份、退役。这里有一个数字值得记住:裁掉工具调用和子 Agent 事件之前,它们占服务里事件总量的九成,而工人根本不用它们。三个 Hook 就够了。
八条设计原则
- 采集、判断、存储、展示分四层,每层能单独换掉。
- 同一件实质任务只有一个主编号;延续和返工写在目标里,不建近义卡。
- 任何状态结论都要能回到具体证据。
- 不可变事件优于共享大文件;两台电脑各写各的文件,不改对方的。
- 客户端来源和物理设备是两个独立维度。
- 模型只给结构化建议,确定性规则决定是否执行;不给模型任何命令执行和文件读取权限。
- 不确定时保守:不错误合并、不虚构完成、不把模型的犹豫转嫁成你的验收。
- Git 永远由人手动操作;本地提交、远端同步、目标机验收分开陈述。
Hook(钩子):AI 工具在特定时刻(你发消息、它回完话、会话结束)自动执行的一段小命令。"薄"的意思是它只做投递,一两秒内一定退出。
服务:一个常驻在你电脑上的小程序,监听本机的一个端口,只有本机能访问。可以原生跑,也可以装在 Docker 里。
Worker(工人):服务里负责一封封处理来信的那个循环。只有一个,串行处理,所以不会两条消息同时改一张卡。
spool(暂存箱):服务不在线时 Hook 把信写到本地的一个目录,服务上线后自动补交。
幂等:同一封信送两次,账本只记一次。靠信封上的稳定编号做到。
影子模式 / 正式模式:影子只判断不写账,用来观察;正式才真的写。新装先跑影子。
不用装任何东西。回想你最近一次让 AI"记住这个任务"的经历:它是怎么记的?记在哪?你能在对话之外找到那条记录吗?如果答案是"在它的回复里",那就是第 1 章说的聊天记录,不是账。
最难的一件事:这句话是不是任务?
整套系统里最难、改得最多的,就是这一个判断。"帮我查一下"是任务,"谢谢"不是,"继续"看情况。我为它改了九版提示词,加了三道复核,最后还加了一道程序闸门。这一章讲它怎么判,以及为什么要这么多道。
模型只能回答五种动作
| 动作 | 意思 | 什么时候用 |
|---|---|---|
| NOOP | 不记录 | 寒暄、致谢、单纯的确认、凭常识就能答的一般问答、你明确说"这条别记"、工具自己生成的内部提示词 |
| CREATE_TASK | 新建任务 | 你在要求 AI 针对你的项目、数据、文件或系统做事,而且候选里没有它该续接的任务 |
| LINK_TO_TASK | 延续某任务 | 这条消息是某个候选任务的补充、返工或继续 |
| PROPOSE_STATUS | 建议状态变化 | 只对 AI 的最终回复和会话结束事件使用:建议某任务进入已完成、待验证或阻塞 |
| REQUEST_REVIEW | 请求人工复查 | 只对最终回复和会话结束使用,且必须写明缺什么信息;用户消息永远不许用它 |
判断分两步,顺序不能反:第一步只看这句话在不在要求 AI 干活,问句也算("查一下有没有……"就是任务),反馈缺陷也算("还是报错"是在要求继续处理)。第二步才决定记到哪里:明确是某个候选的补充才延续,否则新建。"候选为空"只说明不能延续,绝不是不记录的理由。
九版提示词:两天里改了什么
这份提示词现在有九千五百多字。它不是一次写成的,是被真实的误判逼出来的。下面这张表是它的进化史,每一行背后都有一份验证报告。
| 日期 | 版本 | 被什么逼出来 | 改了什么 |
|---|---|---|---|
| 09-17 凌晨 | v2 | 切到服务后第一次真实运行 | 三态收口、同会话有界上下文 |
| 09-17 上午 | v3 | Codex 接入后"不记账":空候选和问句式请求全被判成不记录 | 先判是不是任务,再决定关联;加杂音过滤,工具内部会话送模型前就丢掉 |
| 09-17 中午 | v4 + 新建复核 | 有未完成任务时误建新卡 | 要新建时追加一次独立确认;"未记录复查"页面上线 |
| 09-17 下午 | v5 + 复核 v2 | 同会话换了件事,被续接到旧卡 | 明确要求新建、宣布下一步、点名别的卡,一律新建;"同一项目"不是延续理由 |
| 09-17 下午 | v6 | 漏记比误建更不可接受 | "宁可多建不漏建":判不了就新建,结束必须收口 |
| 09-17 14:30 | v7 + NOOP 二次验证 | v6 上线 15 分钟,"谢谢""好的"也建卡,被否决 | 非任务话术不建卡;判 NOOP 先不落账,结合上下文再验一次 |
| 09-17 15:09 | v8 + 复核 v3 + 二次验证 v2 | 同一项目里再安排的事总被记到旧卡上,任务名看不出做了什么 | 延续也新建:新卡名字写清实际要做的事,目标以"延续自 TASK-…"开头 |
| 09-18 | v9(现行) | 普通交付被挂成"待验证",把模型的不确定变成了我的验收负担 | 完成优先:范围内做完就已完成;待验证只留两种情况 |
| 09-22 | v9 + TypeSafe 闸门 | "不记录"这个出口是整条链路里唯一可能漏建的地方 | 判 NOOP 后再问一个校准概率,分三档处理 |
三道复核,各堵一个口
- 新建复核:会话里还有未完成任务、模型却要新建时,再独立问一次"真的是新任务吗"。两次意见不一致时不丢记录,降级为续接到复核指出的那张卡,并留审计。
- NOOP 二次验证:模型判"不记录"时先不落账,把上下文补全再验一次。"继续""先改 1"这种短消息接在一段工作后面,二次验证会把它捞回来。两次都判非任务的,留在"未记录复查"页面,我随时可以点一下"这其实是任务"改判。
- 返工关联:要新建的任务如果紧跟着一张刚完成的卡,再问一次"是不是对它的返工"。是就在目标前加"返工自 TASK-…",旧卡不动。
最后一道闸门:把"不记录"再问一遍
二次验证靠的还是同一个模型,它拿不准的时候我没有第二种意见。所以 2026 年 9 月 22 日我加了一道程序闸门:模型判 NOOP 时,再问 TypeSafe 的 System One 模型一个是非题,"结合上下文,这条消息是否在要求 Agent 针对用户的项目、数据、文件或系统做事"。它返回的不是一段话,是一个校准过的概率。程序按阈值分三档:
| 概率 | 处理 | 省了什么 / 防了什么 |
|---|---|---|
| ≤ 0.15 | 接受不记录,跳过二次验证 | 省一次模型调用 |
| 0.15 到 0.80 之间 | 维持原样,由二次验证定夺 | 不改变既有行为 |
| ≥ 0.80 | 一律落账为新任务;二次验证说"不是任务"或调用失败都被推翻 | 堵住唯一可能漏建的出口 |
这两个阈值不是抄文档的,是在我自己的标注样本上测出来的:真实工作请求落在 0.82 到 0.97,客套和一般问答落在 0.02 到 0.11,两类完全分开,同一套样本跑两遍波动不超过 0.05。闸门只能把"不记录"改成"记录",不能反过来;关掉它或它调用失败,链路和没装闸门时一模一样。换一台电脑部署必须重测阈值,因为下限一旦高过你自己真实请求的最低概率,就会漏建。
提示词每改一版,都要在一份标注样本上跑真实模型,连续三次结果一致才上线。这份样本现在有四十多条,全部来自线上真实误判,比如:
- "好的,谢谢"(有未完成任务时)→ 应判不记录
- "继续"(候选为空、接在一段工作后面)→ 应判新建
- "那 Projects 目录呢"(有候选)→ 应判延续,新卡名要写成"盘点 Projects 目录并给出归档方案"
- "开始进入第 3 步的任务"→ 应判新建,不是延续
- Codex 自动生成的安全分类提示词(一万多字)→ 应在送模型前被过滤
样本要保持真实量级。有一次一条内部提示词样本被截到 175 字,评测通过了,线上却判错,因为真实输入有一万一千字。
三道复核加一道闸门,防的是系统性漏建和误建,不是零误差。线上每天还是会有个位数的"未记录复查"项和"待审核"项,这是设计上留给人的口子,不是故障。没有模型的部署(比如你先不配 API Key)不走这些兜底,全靠审核队列人工处理。
分类器:给每条消息贴"是不是任务、记到哪"标签的那个模型调用。本书里就是 DeepSeek 加一份提示词。
NOOP:英文 no operation,"什么都不做"。这里就是"不记录"。
候选任务:同一个会话里还没完成的任务列表,模型只能从里面挑编号,不能编。
校准概率:一个 0 到 1 的数,0.9 真的意味着"十次里大概九次是"。普通模型自报的"置信度"不是这个东西,只能当参考。
评测集:一份人工标好正确答案的样本,改提示词后拿它跑一遍看对错。
从你最近的 AI 对话里抄五条你自己说的话,包括至少一句"谢谢"和一句"继续"。给每条标上:不记录、新建、延续。然后问自己:如果只看这一句、不看前文,你还标得出来吗?标不出来的那几条,就是为什么必须把上下文一起送给模型。
任务的一生:五态、收口、返工与人工改判
第 2 章说了五种状态是什么,这一章说什么时候进哪个状态、谁有权让它进、以及 AI 判错了你怎么改回来。这些规则是我用了一个月才定下来的,中间反转过两次。
合法的迁移只有这几条
待开始 → 进行中 / 已完成 / 阻塞 进行中 → 待验证 / 已完成 / 阻塞 待验证 → 进行中 / 已完成 / 阻塞 阻塞 → 进行中 已完成 → (没有普通迁出;返工请新建任务并写"返工自")
这张表从 v1.0 起就没变过,账本的命令行工具会拒绝任何不在表里的迁移。变的是下面三件事。
收口:会话结束时,进行中的任务必须有个去处
AI 给出最终回复、或会话结束时,服务会把这个会话里还在进行中的任务逐个"收口",进入三个状态之一:
| 收口到 | 条件(现行 v9 规则,2026-09-18 起) |
|---|---|
| 已完成(默认) | 任务范围内的工作已经交付。分析、方案、整理、修复交出来了就算;报告里提到风险、免责声明、没跑范围外的测试,都不自动变成待验证;交付后附带"如果需要还可以做 X"是另一个可能的任务,不阻止当前这条完成。 |
| 待验证(仅两个例外) | ① 交付已完成,但有一个确定的下一步动作必须由你决定是否或如何继续,比如部署包做好了、要不要上线;② 交付存在明确且实质的风险,必须由你确认才能采用,比如删除或迁移前的不可逆影响。理由必须写清你要决定什么。 |
| 阻塞 | 任务没做完,已经中断,必须由你提供信息、授权或重新安排才能继续。理由必须写清未完成的部分和恢复条件。 |
这条规则反转过一次。9 月 17 日的版本是"判不了就转待验证",结果两天里大量普通交付都挂着"待验证",我每天要点几十次"验收"。9 月 18 日改成"完成优先":模型自己拿不准,不许转嫁成我的验收;缺交付信息就保留原状态并记一条记账异常。这两条例外之外,一律已完成。
换任务:先关旧卡,再开新卡
同一个会话里,你说完一件事又说另一件,是最常见的场景,也是最容易串卡的地方。现行规则(2026-09-21 起):
- 模型确认这是一条新任务(新建或延续都算)。
- 服务先把同一来源、设备、会话、项目下其它未完成的任务收口为已完成,并核验写入成功。这一步失败不能跳过,也不能先建新卡。
- 旧卡全部落定之后,才登记新卡。系统会记一条"由新任务触发收口",不伪装成人工验收。
这条规则也反转过。9 月 17 日先做的是"先建后关",9 月 21 日发现暂存箱重放时会串卡,才改成"先关后建"。旧卡收口失败不许跳过,补投的事件按发生时间排序,每一轮的最终回复只能绑定这一轮登记的卡。
延续和返工:都新建,关系写进目标
这是 9 月 17 日下午定下来的,也是对 v2.0 的一个明确改变。v2.0 里"同义改述、追问、补充"会续接到原卡、往目标里追加一句。跑了几天发现两个毛病:旧卡目标越拖越长,看板上看不出后来做了什么;同一项目里再安排的事全被塞进旧卡。现在:
也新建一张卡。任务名由模型结合上下文写清实际要做的事,比如"盘点 Projects 目录并给出归档方案";目标由程序加前缀"延续自 TASK-…(原任务名):"。旧卡按换任务规则收口。
对刚完成的卡反馈缺陷、要求修改,新建一张卡,目标前缀"返工自 TASK-…:"。旧卡保持已完成,失败的那次尝试留在历史里。
第 2 章那张卡就是一条延续:上一张卡做的是"支持状态修改免校验并加二次确认",我接着说"追加备注还是报 409",系统新建了这张,目标第一句写明了它从哪来。
证据:完成必须能指回去
"已完成"这个状态是账本里最贵的,它必须带至少一条结构化的证据引用,六种之一:
| 类型 | 写法 | 校验 |
|---|---|---|
| file | file:/绝对路径 | 文件必须存在 |
| command | command:命令 | exit=0 | artifact=输出文件 | 必须引用实际存在的输出工件 |
| test | 同 command | 同上 |
| commit | commit:提交号 | 当前仓库能查到 |
| url | url:地址 | 格式合法 |
| acceptance | acceptance:回执文件 | 管理端接受的人工验收,会生成一份仓库外的回执文件 |
证据还分层级:AI 自己声明的(declared)、设备采集到的退出码和文件摘要(device_reported)、服务能独立核对的(independently_verified)、你亲手验收的(user_accepted)。层级高不代表覆盖全部:文件哈希证明文件存在且完整,不证明测试真的跑过。纯文字的"测试通过"从 v2.0 起就不能单独完成一个任务。
人工改判:你永远有最后一票
AI 判错了怎么办?三个入口,都留审计、都写不可变事件、都不许覆盖你更晚的决定:
- 看板上直接改状态(2026-09-24 起):任务详情页可以把状态改成五态里任意一个,已完成的任务也可以只追加一条备注。改状态前有一次二次确认;进入已完成时自动记一条管理员确认回执,不要求你再补业务证据。
- "未记录复查":模型判为不记录的用户消息都列在这里,点一下"这其实是任务"就重新判定建卡,这条样本自动进评测收件箱。
- "待审核"队列:只剩两类东西:缺项目、会话或正文的输入,以及账本写入故障。可以新建、关联或忽略。
还有一条硬规则:人工决定优先于任何迟到的自动判定。一条旧的 AI 回复晚到了,它的状态建议如果比你的人工操作还早,进审核,不覆盖。
2026-09-24 上午,我发现 TASK-20260924-035110 明明做完了,看板上还显示进行中。原因是上一轮只把项目开发记录标了完成,正式账本里这张卡只有登记事件、没有完成事件,两类文件不自动同步。我在看板上把它改成已完成,服务走管理接口提交了一条人工命令:命令号 97752aea…,正式事件 codex:14a93ea2-…:0,操作结果 applied。任务卡、数据库、时间线和看板四处回读一致。这就是第 2 章那张卡第二条事件的来历。
收口:一轮对话结束时,给这轮里还开着的任务一个明确的去处,不让它永远停在进行中。
串卡:这一轮的回复被记到了上一轮的卡上,或者反过来。
回执:你在看板上点"验收"之后,服务写在仓库外的一个小文件,记录谁、什么时候、对哪张卡说了"通过"。它就是那条 acceptance 类型的证据。
审计:服务对每一步(收到、判断、复核、落账、人工改判)都留一条带时间和原因的记录,出了问题能顺着查。
回想最近一次 AI 告诉你"已完成"而你后来发现没完成的事。按本章的规则,它当时应该进哪个状态?大概率是"已完成,但证据引用是空的"。这就是为什么完成必须带证据,而且证据不能是一句话。
账本长什么样:事件、任务卡、日报、看板
账本不是一个数据库,是一个目录。目录最底下是一堆写了就不改的小文件,上面的一切都是从它们算出来的。这一章带你看这个目录,再看它长在屏幕上是什么样。
磁盘上的样子
AI_OS/Tasks/ ├── Ledger/ │ ├── events/ ← 权威数据:主任务不可变事件,按天分片 │ │ ├── 2026-08-20/ │ │ ├── … (到今天 36 天,2770 个文件,11 MB) │ │ └── 2026-09-24/ │ │ ├── 034ef040…6621a4.json (文件名 = 事件 ID 的 SHA-256) │ │ └── … │ ├── link-events/ ← 项目双链与设备交接事件 │ ├── registry-events/ ← 来源 / 设备注册事件 │ ├── schema.json、cutover-v2.json ← 版本标记 │ └── deletion-backups/ ← 纠错删除前的备份 ├── TASK-20260924-035110-排查已完成任务追加备注仍报409并放开状态校验.md ├── TASK-…(一件事一张,到今天 915 张) ← 可读投影,跟踪进 Git ├── Daily/2026-09-24.md ← 日报,本机生成 ├── STATUS.generated.md ← 本机看板文本 └── .task-ledger.sqlite3 ← 缓存,不进 Git ~/.local/share/task-ledger-server/ ← 服务自己的东西,全部在仓库外 ├── service.sqlite3 (收件箱、作业队列、审计) ├── spool/ (离线暂存) ├── acceptance/、decisions/ (验收回执、模型判定凭据) └── local/8765.log (运行日志)
分层:谁是真的账,谁是算出来的
| 数据 | 位置 | 进 Git | 角色 |
|---|---|---|---|
| 主任务事件 | Tasks/Ledger/events/ | 是 | 权威。写了不改,纠错用新事件 |
| 双链、注册事件 | Tasks/Ledger/link-events/、registry-events/ | 是 | 项目绑定、设备交接、来源与设备登记的权威 |
| 任务卡 | Tasks/TASK-*.md | 是 | 给人看、给看板读的投影;可重建 |
| 日报、生成状态页 | Tasks/Daily/、STATUS.generated.md | 否 | 本机视图;可重建 |
| 本机缓存 | Tasks/.task-ledger.sqlite3 | 否 | 运行缓存;可重建 |
| 服务数据 | 仓库外 | 否 | 队列、审计、模型记录、回执;备份要单独做 |
这个分层是 v2.0 定下来的,v3.0 完全保留。服务接管之后有一条硬合同:相同初始状态、相同输入下,原命令行工具、原生服务、Docker 服务写出来的 JSON 和 Markdown 必须逐字节一致。服务只是换了个地方执行原来的写入逻辑,没有另建一套账。
两台电脑怎么不打架
每台电脑跑自己的服务、写自己的事件文件(文件名是事件 ID 的哈希,天然不撞),任务卡由各自重建。同步靠我手动 Git:离开一台之前提交推送,到另一台先拉取再重建视图。Hook 和服务从不碰 Git。同一张卡一次只在一台电脑上继续;绑定了项目的卡还有"活动设备"门禁,要换电脑得先交接。
这套办法适合一个人或一个小团队串行协作。多人同时编辑同一件事,Git 能保存事件,不能替你解决语义冲突。真到那一步要换带身份和事务的服务端,第 10 章有说明。
长在屏幕上的样子:任务大盘
账本本身是文件,看它得有个界面。下面是我工作空间里的"任务看板",它直接读账本文件,人工改状态时经服务写回。
服务自己的管理页
两个界面分工明确:任务大盘看结果,管理页修机器。你装好之后,第一天大概率只用管理页确认"它在记",一周之后就只看大盘了。
两种后端:自己的账本,和别人的
服务支持两种存储后端,配置一个变量切换:
继续驱动我原有的账本命令行工具和上面那套目录,行为逐字节不变。适合已经有 AI_OS 账本的人,也就是我自己。
服务自带一个 SQLite 账本,不需要 AI_OS、不需要原命令行工具;可以选择把每张任务卡另存一份只读 Markdown。两种后端过同一份合同测试。第 7 章装的是这个。
不可变事件:写下就不能改的记录。要纠错就再写一条"上一条作废",历史全留着。
投影 / 重建:从事件算出任务卡、日报、看板的过程。它们是"算出来的",所以坏了可以重算。
分片:按天分目录、按事件分文件,而不是一个大 JSON。两台电脑各写各的,Git 合并几乎不冲突。
legacy / native:前者是"沿用旧账本",后者是"服务自带账本"。行为一样,存的地方不一样。
在你的电脑上建一个空文件夹,取名 Tasks。什么都不用装,只是先给这本账一个家。后面第 7 章装的时候,你会知道它应该放在哪。
装起来:用 Codex 或 Claude Code 自助安装
这一章是一份可以照着做的安装单。它装的是"独立版":服务自带账本,不需要我的 AI_OS 目录。你可以自己在终端里敲,也可以把本章末尾那段提示词直接喂给 Codex 或 Claude Code,让它替你敲。但有三步它替不了你。
装之前:受支持的范围
| 项目 | 本版验证过的组合 | 说明 |
|---|---|---|
| 系统 | macOS | 路径、启停脚本、Hook 信任流程都在 macOS 上验证;Linux 未验证 |
| 运行时 | Python 3.12;Node.js 20.19 以上或 22 以上 | 系统自带的 Python 3.9 跑不了;Node 只用来构建管理页 |
| 接入的工具 | Claude Code、Codex;Cowork(仅"只在这台电脑上"模式);Hermes | 先接你用得最多的一两个。普通聊天窗口、云端 Cowork 不采集 |
| 模型 | 任意 OpenAI 兼容接口(本书用 DeepSeek) | 可先不配,走人工审核 |
| 运行方式 | 本机原生进程(本章);Docker 另有 compose 文件 | 同一本账同时只能有一个正式写入的服务 |
十步安装单
- 拿到固定版本的代码包,放到一个固定目录。比如
~/task-ledger。随书代码包是一个确定的版本,不要让 AI 凭文字自己"重新实现一遍"。 - 准备 Python 环境和管理页。在项目目录里执行:
python3.12 -m venv .venv312 .venv312/bin/python -m pip install -r requirements.txt cd web && npm ci && npm run build && cd ..
- 生成服务的私有配置。把
.env.standalone.example复制成~/.config/task-ledger-server/native.env,权限改成只有你能读(chmod 600)。要改的只有这几行:LEDGER_BACKEND=native ← 独立账本,不碰 AI_OS DEVICE_ID=my-macbook ← 这台电脑的稳定名字,另一台电脑要用不同的 DEVICE_TOKEN=(一串随机长字符) ← openssl rand -hex 32 生成 ADMIN_TOKEN=(另一串随机长字符) ← 和上面那串不能一样 MODE=shadow ← 先影子,只看不写 MODEL_ENABLED=false ← 先不配模型 # NATIVE_EXPORT_DIR="$HOME/Documents/task-cards" ← 可选:每张卡另存一份 Markdown
macOS 自带的 Python 缺证书时,再加一行SSL_CERT_FILE=/etc/ssl/cert.pem。两个令牌是密钥,不要发给任何人,也不要让 AI 替你填。 - 生成 Hook 的私有配置。Hook 只需要知道服务在哪、自己是谁:写到
~/.config/task-ledger-server/client.env(同样 chmod 600):TASK_LEDGER_API_URL=http://127.0.0.1:8765/v1/events:batch DEVICE_ID=my-macbook ← 和服务配置里一致 DEVICE_TOKEN=(和服务配置里同一串) HOOK_SPOOL_DIR=$HOME/.local/share/task-ledger-server/spool TASK_LEDGER_CAPTURE_EPOCH=1
管理令牌和模型密钥不进这个文件。 - 启动服务。执行
scripts/start_local.sh。它会立刻返回,在后台校验配置、重新构建管理页、清理端口、启动服务、做健康检查;结果写在数据目录下的local/8765.startup.log。然后跑一次scripts/check_health.sh,看到"healthy": true就是起来了。 - 打开管理页。浏览器打开
http://127.0.0.1:8765/,在右上角粘贴 ADMIN_TOKEN。令牌只留在页面内存,刷新就要重输。现在应该看到"当前没有记录",顶栏显示 shadow、运行中。 - 安装 Hook:先预览,再写入。
.venv312/bin/python -m clients.install claude status ← 看现状 .venv312/bin/python -m clients.install claude apply ← 只打印会改什么 .venv312/bin/python -m clients.install claude apply --write .venv312/bin/python -m clients.install codex apply --write
写入前安装器会把你原来的配置文件备份到~/.local/share/task-ledger-backups/并留一份哈希清单;它只动调用账本的那几条,你原有的别的 Hook、权限、模型设置一概不碰。恢复备份文件就是回滚。 - 在 Codex 里信任新 Hook。这一步 AI 替不了你:打开 Codex,用
/hooks查看并信任变更后的三个 Hook。没信任的 Hook 会被跳过,什么都不会记。Claude Code 不需要这一步。然后一律新开会话,旧会话不会热加载配置。 - 影子跑一天。在新会话里正常干活。没配模型时,每条消息会进管理页的"待审核"标签,这证明采集链路通了。看两件事:你的每条工作请求都在不在;来源、设备、项目字段对不对。
- 配模型,切正式。改 native.env:
MODEL_ENABLED=true,填MODEL_BASE_URL、MODEL_API_KEY、MODEL_NAME;先保持 shadow,执行scripts/stop_local.sh再scripts/start_local.sh,看管理页"审计"标签里模型的判断合不合理。合理了再把MODE改成apply,重启。从这一刻起它开始真的写账。
- 填令牌和模型密钥。让 AI 生成随机串可以,但它不该看到你最终写进文件的值。让它把占位符留给你填。
- 在 Codex 里点"信任"。这是 Codex 的安全设计,只能你在界面里做。
- 决定什么时候从影子切正式。看一天影子结果是最低要求,判断"它记得对不对"的人只能是你。
可以直接喂给 Codex 或 Claude Code 的安装提示词
把下面这段整个复制进一个新会话。它把上面十步交给 AI 执行,把三件替不了的事留给你。
我要在这台 Mac 上安装"任务账本"独立版。代码在 ~/task-ledger(固定版本,不要改源码)。 请严格按下面的顺序做,每一步先说明要执行的命令,执行后把关键输出贴给我: 1. 检查 python3.12、node、npm 版本,不满足就停下告诉我怎么装,不要自己换版本。 2. 在项目目录创建 .venv312,安装 requirements.txt;在 web/ 执行 npm ci 和 npm run build。 3. 读 .env.standalone.example,生成 ~/.config/task-ledger-server/native.env(chmod 600): LEDGER_BACKEND=native,MODE=shadow,MODEL_ENABLED=false,DEVICE_ID 用这台电脑的名字; DEVICE_TOKEN 和 ADMIN_TOKEN 两行写成 <我来填>,不要生成、不要猜、不要写进任何别的文件。 4. 生成 ~/.config/task-ledger-server/client.env(chmod 600),含 API 地址、DEVICE_ID、 DEVICE_TOKEN=<我来填>、HOOK_SPOOL_DIR、TASK_LEDGER_CAPTURE_EPOCH=1。 5. 停下来,等我填完两个文件里的令牌再继续。 6. 执行 scripts/start_local.sh,然后 scripts/check_health.sh,把 JSON 贴给我;healthy 不是 true 就读 数据目录下 local/8765.startup.log 找原因,不要反复重启。 7. 执行 python -m clients.install claude apply 和 codex apply 的预览,把会改什么贴给我;我确认后再加 --write。 8. 告诉我接下来要在 Codex 里用 /hooks 信任 Hook,并新开会话验证;然后停下。 全程不要执行任何 git 命令,不要运行全仓测试,不要修改 ~/.codex 和 ~/.claude 下除安装器写入之外的任何文件, 不要把令牌打印到终端或写进报告。
想装在 Docker 里
项目里有 compose.yaml 和 scripts/docker_service.sh,我自己在 9 月 17 到 20 日用 Docker 跑过正式写入,之后切回原生。但截至本版,这份 compose 文件仍然要求 AI_OS 的账本目录和锁目录,没有转发独立版需要的几个变量。独立版请先用原生方式;Docker 版的独立配置是下一版要补的东西,第 8 章的备份说明里还有一条同类的坦白。
venv(虚拟环境):给这个项目单独准备的一套 Python,不和系统里别的程序打架。
令牌:一串随机长字符,相当于密码。设备令牌给 Hook 用,管理令牌给你在管理页用,两串必须不同。
安装器:项目自带的一段脚本,负责往 Codex 和 Claude Code 的配置文件里加 Hook、备份、回滚。
信任:Codex 的一道安全门。配置里出现了新的 Hook,必须你在界面里点一次同意才会执行。
先别装。打开终端,敲三条命令:python3.12 --version、node --version、scutil --get ComputerName。前两条决定你能不能装,第三条就是你以后的 DEVICE_ID。三条都有输出,本章剩下的部分一个小时内能做完。
验收:怎么知道它真的在记
配置文件存在,只证明你写了配置。安装成功的定义是:你在工具里说了一句话,账本里出现了一张来源、设备、项目都对的卡,AI 回完之后这张卡有了明确的去处。这一章给你一套能逐条打勾的检查。
第一步:健康检查
这是我写这段话时,本机跑 scripts/check_health.sh 的真实输出:
{"backend": "legacy", "healthy": true, "mode": "apply",
"oldest_queue_age_seconds": 0,
"queue": {"done": 2479, "pending": 1, "review": 49},
"reasons": [], "service": "http://127.0.0.1:8765",
"state": "running", "unresolved_operations": 0}
退出码 0 表示:服务能连、后端就绪、工人没暂停、待对账为零、没有死信、最早的待处理不超过十分钟。review 那个数不算故障,它是留给人判断的审核项,我这里的 49 条是一个多月攒下的历史审核,不阻塞写入。这个脚本只读,不改任何东西,可以放进定时任务。
第二步:八项最小回归
- 打开
http://127.0.0.1:8765/health/ready:backend、mode、model_enabled 和你配置的一致;prompt_sha256 和仓库里提示词文件的哈希一致 - Codex 和 Claude Code 各开一个新会话,发一条真实任务:管理页"任务"标签出现新卡,来源、设备、项目正确
- 同会话换一件事:旧卡已完成、新卡进行中。同会话追加一句"那 X 呢":出现新卡,名字能看懂,目标以"延续自 TASK-…"开头
- 发"好的,谢谢":不建卡,审计里有一条 NOOP 二次验证记录;接着发"继续":有新卡
- 一轮结束后,这个会话里没有停在进行中的卡
- 审计里重复投递显示为 duplicate,不出现 conflict;服务里没有工具事件
- 停掉服务发一条消息:工具不受影响,暂存目录里多了文件;服务恢复后自动补交
- 管理页顶栏的新建复核、NOOP 复查、兜底次数、未记录率、审核率都有数
job=done 不算数,要看 operation=applied
这是新手最容易被骗的地方。服务处理一封信有两层状态:
这封信被工人处理完了。done 只说明"处理过了",结果可能是不记录、进审核、或者写入。
一次真正的账本写入。只有 applied 表示事件文件、任务卡、缓存三处都写了且核对一致。reconcile_required 表示写到一半对不上,工人会暂停等人。
所以验收一条任务,去管理页"操作"标签找它的 operation 是不是 applied,再打开任务卡文件本身看一眼。第 5 章那次人工改判,我列了命令号、事件号和 operation 三个编号,就是这个原因。
标准冒烟:一条消息走完全程
在一个隔离的目录里对 AI 说:"创建一个只包含当前日期的 smoke-test.txt,读取确认后汇报。"然后按顺序看:
- 你的消息之后,出现一张进行中的卡(native 后端登记即进行中)。
- AI 回完之后,这张卡进入已完成(文件真的建了)或待验证(它问了你一个必须由你决定的问题)。
- 卡的证据引用里有那个文件的路径,或者一条记账异常说明为什么没有。
- "操作"标签里这两步都是 applied。
这个冒烟是从项目里一份自动化的"真实进程场景"缩下来的。那个脚本实际启动服务、实际调用 Hook、实际让工人调用原命令行工具,走 11 步:服务没起来时先发消息(落暂存箱)、起服务(自动补交建卡)、重放同一封信(不重建)、业务脚本真的生成报告、AI 交付(进行中→待验证)、用户要求补充(→进行中)、一条迟到的旧交付消息(进审核、不覆盖)、重新交付、会话结束(保持待验证、不自动完成)、管理员验收(→已完成,重复请求返回原命令号)、暂停并重启(10 个正式文件哈希不变)。它验证的是链路,不是模型准确率:模型建议是脚本模拟的。
头一周每天看的三个数
| 看什么 | 在哪看 | 不对劲的样子 |
|---|---|---|
| 未记录复查里有没有本该建卡的消息 | 管理页"未记录复查" | 你明明在派活,它在这个列表里。点"这其实是任务",样本自动进评测 |
| 进行中的卡有没有过夜 | 任务大盘"需关注"或管理页"任务" | 会话早结束了卡还开着。先查那一轮的最终回复有没有被采到 |
| 待审核和待对账 | 健康检查的 queue 和 unresolved_operations | unresolved 不是 0 表示工人暂停了,去"操作"标签看原因,别直接重启 |
备份与恢复,以及一条坦白
备份要在管理页先点"暂停写入",等状态变成"已暂停"(在途工作已排空),再执行:
.venv312/bin/python -m server.maintenance backup --data-dir ~/.local/share/task-ledger-server --target /你的备份目录
坦白:截至本版,这条命令只备份服务数据库、暂存箱、验收回执和附件,不包含独立版的权威账本文件 ledger.sqlite3,也不包含模型判定凭据目录。独立版用户请在暂停之后直接复制整个数据目录。这是 9 月 22 日商品化评估里列出的第一条 P0 缺口,修好之前我不会把它写成"已支持"。恢复的验收标准是:在空目录里恢复后,任务、事件、凭据、附件都在,而且恢复后能继续记账。
applied(已应用):一次写入的三个地方都写了、都对得上。账本里真正算数的状态。
对账:写完之后逐文件核对"写进去的和打算写的是不是一样"。对不上就暂停,等人看。
审核队列:服务自己拿不定主意、又不能不记的东西堆在这里,只有两类:缺字段的输入和写入故障。
冒烟:装完之后用一件最小的事从头到尾走一遍,看有没有冒烟。
把"八项最小回归"打印出来。装好的当天做一遍,一周后再做一遍。第二遍还全绿,才算装成了;第一遍全绿只说明那一天没坏。
踩过的坑:二十天里的十个真实故障
服务从 9 月 16 日开始开发,17 日上线,到今天 24 日,账本里关于它自己的任务卡有 105 张。下面挑十个最有教学价值的故障,每一个都有复现、根因、修复和验证记录。你装的是修过之后的版本,但知道它们为什么会发生,出了新问题你才知道往哪看。
| # | 日期 | 现象 | 根因 | 定下的规则 |
|---|---|---|---|---|
| 1 | 09-17 | Codex 接入后"不记账":采集正常,卡一张没建 | 提示词 v2 把"候选为空"和问句式请求全判成不记录 | 先判是不是任务,再决定记到哪;候选为空绝不是不记录的理由 |
| 2 | 09-17 | 同会话第二件事没建卡,消息进了审核,理由"缺少可信字段 project" | 用户级 Cowork 插件和 settings 里的 Hook 同时触发,同一条消息投递两次;插件那一路把真实目录误标为不可信,恰好先到 | 只对 Cowork 工作区做目录映射;两份副本内容一致即为无害重复 |
| 3 | 09-17 | 同会话换了件事,被续接到旧卡 | 复核提示词写了"拿不准按延续",又把"同一项目的推进"算延续 | 误建和误续两个方向都要评测;"同一项目"不是延续理由 |
| 4 | 09-17 | 复核不一致时消息既没建卡也没续接,记录丢了 | 分类器判新建、复核判延续,当时的处理是转审核、不落账 | 两次判断都认定是工作就必须落账,分歧只是记到哪里;降级为续接并留审计 |
| 5 | 09-17 | "宁可多建不漏建"上线 15 分钟被否决 | "谢谢""好的"、一般问答也建卡,噪声不可接受 | 非任务话术不建卡;防漏靠二次验证,不靠取消 NOOP。涉及日常噪声的取舍,先拿几条真实消息对照再定 |
| 6 | 09-18 | 普通交付大量挂"待验证",每天要点几十次验收 | 把分类器的不确定转成了业务验收 | 完成优先:范围内做完就已完成;待验证只留两种情况 |
| 7 | 09-18 | 同一次运行里同一件事登记了两次 | 服务接管后旧 Agent 的命令行写入权限没有退役,两个写入方并存 | 写入归属持久化在账本外,命令行入口拒绝非服务写入;停机也不自动恢复 |
| 8 | 09-21 | 暂存箱重放时旧卡遗留、新旧卡串 | "先建后关"在乱序补投时会把旧输出关到新卡上 | 先关后建;补投按发生时间排序;每轮输出绑定该轮登记的卡 |
| 9 | 09-24 | 在看板上对一张阻塞的卡直接点"验收",整个 Claude 来源的写入被暂停 | 非法状态迁移在入队前没拦住,原命令行启动后才报错,触发对账保护暂停 | 入口和执行前都校验状态规则;无效命令不能触发全局暂停;跨设备恢复要区分 applied 和 superseded |
| 10 | 09-24 | Codex 单次执行的任务,AI 明明汇报了完成,账本里没有收口 | Codex 进程在最终回复后立即退出,取消了还在后台跑的 Stop 钩子 | Codex 的 Stop 改为同步完成短时投递(网络超时 0.3 秒,离线落暂存箱)再放行;不调用模型、不阻断 |
三个当时没想到的小坑
- 时间格式。Hook 发的是 UTC 带 Z 的时间,原命令行工具规范化成 +00:00,对账比较字符串就误判"时间不一致",整条队列暂停。修法是解析成时间再比,不是放宽成任意字符串。
- Docker 里的锁。宿主机上的文件锁拦不住容器,两边可以同时写。改成同一个持久目录里的原子目录锁,双向互斥测试才过。
- 提示词钉死了路径。私有配置里写死了提示词文件路径,之后每升一版都得手改并重启。现在留空用仓库默认,上线只核对健康接口里的提示词哈希。
- 服务恢复不等于历史任务自动完成。暂停期间积压的任务,恢复后要逐条核对产物、目标日事件和远端提交,再按状态机收口。业务质检没过的,继续阻塞。
- 异步采集不能假设宿主会等你。进程退出码是 0 也不证明工具调用成功,要读它自己的错误标记。
- 事件和数据库一致,不足以证明派生视图一致。任务卡、看板、日报要分别回读。项目里的开发记录和正式账本的任务卡也是两回事,不以一个的"已完成"推断另一个。
把上面十行里的"现象"一列单独抄下来,贴在你装好之后的第一周随手能看到的地方。装好之后遇到的问题,十有八九能在这一列里找到长得像的。
边界、隐私、费用与十问十答
这套系统能做的事,前面九章说完了。这一章说它不做什么、你的数据去了哪、要花多少钱,最后是被问得最多的十个问题。
它不做的事
| 不做 | 为什么 | 你该怎么办 |
|---|---|---|
| 自动 Git 拉取、提交、推送 | 网络操作和冲突处理需要人判断;Hook 和服务从不碰 Git | 离开一台电脑前手动提交推送,到另一台先拉取 |
| 替你判断交付质量 | 账本记录的是"依据什么判定完成",不是"做得好不好" | 把它当记录,不当验收 |
| 项目管理:排期、资源、权限、多人协同 | 它是跨项目的总账,补充而不替代项目管理 | 项目里的 STATUS、任务卡照旧维护;账本记全局 |
| 多人高并发、企业级权限与审计 | 一套设备令牌加一套管理令牌,没有租户和角色 | 一人一实例;团队版需要另做身份、权限和隔离 |
| 自动脱敏你写进任务里的敏感信息 | 只有规则式脱敏(邮箱、用户目录) | 别把密钥、密码、Cookie 写进对话里让它记 |
| 采集普通聊天、云端 Cowork、任意平台 | 只有装了 Hook 的本机入口才采集 | 接入清单以第 7 章为准,不承诺任意环境通用 |
| 保证一条不漏 | 磁盘满、进程被杀这类极端条件下做不到;采集缺口会被可观察地报告 | 看健康检查和"未记录复查",不看到就当没有 |
你的数据去了哪
- 留在本机的:全部事件、任务卡、日报、服务数据库、暂存箱、回执、日志。服务只监听本机回环地址,外面连不进来。
- 发给模型供应商的:被判断的那条消息正文(头尾截断、去掉邮箱和用户目录)、同会话最近八条上下文(每条最多四千字)、候选任务的编号和标题。工具调用的正文不采集、不发送。开了闸门的话,同样这份输入会再发给 TypeSafe 一次。
- 不发的:你的文件内容、命令输出、密钥。模型也没有权限来读。
所以"本地部署"不等于"内容不出电脑"。只要开了模型判断,你的对话正文就会离开本机。接受不了,可以不配模型:所有消息进审核队列,你手动判,一条内容都不出去。也可以把模型地址指向本机跑的兼容接口,质量要你自己验。
要花多少钱
软件本身不要钱,费用在模型调用。一条用户消息最少一次调用(分类),最多五次(分类、新建复核或 NOOP 二次验证、返工关联、闸门,加一次失败重试)。AI 的最终回复和会话结束,只在会话里有未完成任务时才调用。
月模型成本 = Σ(各阶段输入 token × 输入单价 + 输出 token × 输出单价)+ 闸门调用成本
服务的统计接口和管理页顶栏会实时显示:今日模型调用次数、新建复核、NOOP 复查、跳过、过滤、兜底次数、未记录率、审核率、token 用量。我不在这里给你一个"每月多少钱"的数,因为它取决于你的消息量、模型单价和你开了哪几道复核。装好跑一周,看统计接口,再对着供应商账单算,比听我说准。
问 1它会不会拖慢我的 Codex 和 Claude Code?
感觉不到。三个 Hook 里两个是异步的,投递完就退出,超时两到五秒;只有会话结束那个是同步的,限三秒。Codex 的 Stop 是同步的,但只等 0.3 秒的网络投递,不等模型。服务不在线时 Hook 写本地暂存箱,立刻返回。裁掉工具事件之前确实拖慢过,那些事件占九成、又没人用,所以裁了。
问 2服务挂了,消息会丢吗?
不会丢,会晚到。Hook 投递失败就把信写进本地暂存目录,服务恢复后每 5 秒补交一次,靠信封上的稳定编号保证不重记。会晚到的代价是:补投的事件按发生时间重新排序处理,第 9 章第 8 个坑就是这个场景。
问 3AI 明明说"已完成",账本里为什么还是进行中?
三种可能,按概率排:一是 Hook 没采到最终回复(比如第 9 章第 10 个坑);二是模型把它判成了"缺交付信息",记了一条记账异常、保留原状态;三是这条回复不是最终回复,中间输出不收口。去管理页看审计和"操作"标签,能看到这条消息走到了哪一步。
问 4为什么我说"谢谢"它也建了卡?或者说"继续"它没建?
前者去"未记录复查"看不到,因为它被判成了任务,去任务列表里忽略或改判;后者去"未记录复查"点"这其实是任务"。两种误判的样本都会自动进评测收件箱,下一版提示词就是用它们改的。第 4 章说过,闸门只往"记录"方向纠,所以误建比漏建常见一点,这是有意的取舍。
问 5两台电脑怎么用?
每台各装一套服务,各用自己的设备 ID 和令牌,各写各的事件文件。同步靠你手动 Git。同一张卡一次只在一台电脑上继续。不要把一台的私有配置复制到另一台,尤其是设备 ID。第 4 章的闸门阈值也要在新电脑上重测。
问 6需要会编程吗?
不需要写代码,但需要能在终端里跑几条命令、会复制路径、会改一个配置文件。第 7 章给了一段可以直接喂给 Codex 或 Claude Code 的安装提示词,它会替你跑命令、看输出。但它替不了你做三件事:填自己的令牌、在 Codex 里信任新 Hook、决定什么时候从影子切正式。
问 7可以不用 DeepSeek 吗?
可以。模型接口是任意 OpenAI 兼容的地址加密钥加模型名,本机跑的兼容接口也行,但非 https 地址只允许指向本机。换模型之后判断质量要在评测集上自己跑,接口兼容不等于分类准确。完全不配模型也能跑,走人工审核。
问 8它能替我做项目管理吗?
不能。它是账,不是计划。它不排期、不分配、不催办。第 1 章说的五个问题它能答,"接下来该做什么"它不答。我自己的做法是每周从账本里看"未闭环"和"待验证",再手动定下周的目标,任务大盘左上角那块"计划分布"就是这么来的。
问 9Hermes 也能接吗?Cowork 呢?普通聊天呢?
Hermes 能接,它是第一个接进服务的端,但目前还是 9 个 Hook 的老集合,没裁到 3 个。Cowork 能接,要开"只在这台电脑上"模式并装插件;云端 Cowork 不行。普通聊天窗口不采集,也不打算采。每多一条支持链就多一份维护,我的建议是先接你用得最多的一两个。
问 10装了之后我需要每天做什么?
头一周:每天看一眼管理页顶栏的数字和"未记录复查",跑一次健康检查。之后:只看任务大盘,处理"待验证"和"阻塞"。每周:拉一次"未闭环"清单定下周目标。每月:备份一次服务数据(先在管理页暂停排空再备份)。如果你发现自己每天在纠正它,比手记还费时间,那就是定位错了,停下来回第 4 章看评测集。
- 记账从 AI 身上卸下来。AI 只干活,钩子只送信,服务判断,规则落账。
- 用证据决定完成,不用语气。"已完成"必须能指回一个文件、一条命令、一次提交或一份你的回执。
- 模型只给建议,你有最后一票。它拿不准的,不许变成你的验收;你改过的,它不许覆盖。
术语对照表、自查清单、配图来源与版本记录
书里出现过的词,这里一句话一个。后面是三张可以打印的检查表、每张真实配图的来源,以及这本白皮书从 v1.0 到 v3.0 改了什么。
一、术语对照表:三十二个词的人话翻译
- 任务账本
- 加在"你跟 AI 说话"和"AI 交出东西"之间的一层自动记录,一件事一张卡,用证据决定完成。
- 任务卡
- 一张 Markdown 文件,编号是创建时间。给人看的投影,可重建。
- 事件 / 不可变事件
- 账本里真正的账。每发生一件事就多一个小文件,写了不改,纠错用新事件。
- 投影 / 重建
- 从事件算出任务卡、日报、看板。它们坏了可以重算。
- 分片
- 按天分目录、按事件分文件,两台电脑各写各的,几乎不冲突。
- 五态
- 待开始、进行中、待验证、已完成、阻塞。从 v1.0 起没变过。
- 收口
- 一轮对话结束时,给还开着的任务一个明确去处。
- 完成优先
- v9 规则:范围内做完就已完成;待验证只留"要你决定下一步"和"要你确认实质风险"两种。
- 先关后建
- 同会话换任务时,先把旧卡收口并核验,再登记新卡。
- 延续自 / 返工自
- 新卡目标开头的两种前缀,记录它从哪张旧卡来。旧卡不动。
- 证据引用
- 完成必须带的指针,六种:file、command、test、commit、url、acceptance。纯文字不算。
- 回执
- 你在看板上点"验收"后服务写在仓库外的小文件,就是 acceptance 类型的证据。
- 来源
- 记录从哪个客户端来:codex、claude、hermes、webui、user。说的是工具,不是触发者。
- 设备
- 哪台电脑。和来源是两个独立维度。
- 会话
- 一次打开到关闭之间的对话。一个会话可以有多件事。
- 项目
- 这件事属于哪个目录。跨电脑时用户目录会被归一,同一个项目在两台电脑上算一个。
- Hook(钩子)
- AI 工具在特定时刻自动执行的小命令。本书里每端三个:你发消息、AI 最终回复、会话结束。
- 薄 Hook
- 只做投递、一两秒必退出、失败放行的 Hook。不调用模型、不注入上下文、不阻断回合。
- 服务
- 常驻本机、只监听本机端口的小程序。收信、排队、判断、落账、提供管理页。
- Worker(工人)
- 服务里串行处理来信的循环。只有一个。
- spool(暂存箱)
- 服务不在线时 Hook 写信的本地目录,恢复后每 5 秒补交。
- 幂等
- 同一封信送两次只记一次。靠稳定的事件编号。
- 影子 / 正式(shadow / apply)
- 影子只判断不写账,正式才写。新装先影子。
- 分类器
- 给每条消息贴"是不是任务、记到哪"标签的模型调用。DeepSeek 加一份提示词。
- NOOP
- "不记录"。寒暄、致谢、一般问答、明确说别记、工具内部提示词。
- 候选任务
- 同会话还没完成的任务列表。模型只能从里面挑编号。
- 新建复核 / NOOP 二次验证 / 返工关联
- 三道独立复核,分别堵误建、漏建、串卡。
- 闸门
- 模型判"不记录"后再问一个校准概率,按阈值分三档;只能把不记录改成记录。
- 校准概率
- 0.9 真的意味着十次里大概九次是。模型自报的"置信度"不是这个。
- 评测集
- 人工标好答案的样本。改提示词后跑三遍一致才上线。
- applied / 对账
- 一次写入三处都写了且核对一致才叫 applied;对不上就暂停等人。
- legacy / native
- 沿用旧账本目录,或服务自带 SQLite 账本。行为一样,存的地方不一样。
二、三张自查清单
装之前
- macOS;python3.12 和 node 都能输出版本号
- 知道这台电脑的稳定名字,另一台电脑会用不同的名字
- 两串不同的随机令牌已经生成,只存在两个 chmod 600 的私有文件里
- 拿到的是固定版本的代码包,不是让 AI 自己写的
- 决定了先接哪一两个工具,先不配模型
接入之后
- 健康检查 healthy 为 true,退出码 0
- Codex 里已信任新 Hook;所有验收都在新开的会话里做
- 影子跑了至少一天,待审核里能看到你的每条工作请求,来源设备项目都对
- 配模型后先看审计里的判断,再切正式
- 八项最小回归全绿,一周后再做一遍还全绿
日常
- 每天看一眼未记录复查和需关注,处理待验证和阻塞
- 进行中的卡不过夜;过夜先查那一轮的最终回复有没有采到
- 健康检查的 unresolved 不是 0 时去"操作"看原因,不直接重启
- 每周从未闭环清单定下周目标;每月暂停排空后备份整个数据目录
- 离开一台电脑前手动提交推送;到另一台先拉取再重建视图
三、真实配图来源
所有真实截图取自 2026 年 9 月 24 日本机运行中的两个界面:工作空间的任务看板(本机 4001 端口)和账本服务的管理页(本机 8765 端口);任务卡、事件、健康检查输出取自同日的 AI_OS 账本目录与 task-ledger 项目。
| 章 | 图 | 来源 | 说明 |
|---|---|---|---|
| 1 | 首页任务看板卡片 | 工作空间首页 | 今日活跃 40 条、1 条未闭环 |
| 2 | 任务详情页 | 任务看板 /tasks/TASK-20260924-035110 | 一条延续任务,人工验收完成 |
| 2、3、5 | 任务卡与两条事件 | AI_OS/Tasks 与 Ledger/events/2026-09-24 | 字段按原文抄录,路径省略 |
| 6 | 大盘顶部、设备与来源、项目分布、全部任务、每日回顾 | 任务看板 /tasks/dashboard、/tasks/daily | 917 条任务、49 个项目、36 个活跃日 |
| 6 | 服务管理页 | http://127.0.0.1:8765/ | 未输入令牌的空状态 |
| 8 | 健康检查输出 | scripts/check_health.sh | 本机 legacy/apply 实例 |
示意插画 13 张由 AI 生成(gpt-image-2,经 Grsai 接口),统一暖陶风,仅用于辅助理解。
四、版本记录
| 日期 | 版本 | 说明 |
|---|---|---|
| 2026-08-21 | v1.0 | 方法论 SOP 教学白皮书。SQLite 加同步索引为主要数据,Agent 按协议自己记账 |
| 2026-08-28 | v2.0 | 商业落地版。不可变事件分片成为权威;显式写入模式(Codex agent_managed,Claude/Hermes hook_managed);来源与设备注册;完成证据门禁 |
| 2026-09-24 | v3.0(本版) | 服务化。记账从 Agent 卸到独立本机服务;三个薄 Hook;服务端模型判断加三道复核与闸门;延续也新建、先关后建、完成优先;看板五态改判;独立 native 后端;单文件 HTML 出版 |
v2.0 到 v3.0,具体改了什么
| 主题 | v2.0 | v3.0 |
|---|---|---|
| 谁写账 | Agent 按提示词协议调用命令行,或 Hook 直接写 | 独立服务。Hook 只投递;Agent 提示词里没有账本协议 |
| 每端 Hook | 四到五个,含每次工具调用 | 三个:用户消息、最终回复、会话结束。Hermes 仍是旧集合 |
| 怎么判断 | 轻量规则加 Agent 自判 | 服务端分类器 v9,加新建复核、NOOP 二次验证、返工关联,加 TypeSafe 闸门 |
| 同会话续接 | 续接原卡、追加目标 | 延续也新建,目标写"延续自";返工写"返工自";先关旧卡再建新卡 |
| 收口 | 证据充分直接完成,需用户验收到待验证 | 完成优先;待验证只留两种例外;判不了记账异常,不转嫁 |
| 人工入口 | 命令行 | 管理页审核、未记录复查;看板五态改判与备注 |
| 写入归属 | 按客户端选模式 | 服务接管后,命令行拒绝 Agent 直接写;停机不自动恢复 |
| 存储 | AI_OS 目录 | 同上(legacy),或服务自带 SQLite(native) |
| 部署 | 安装脚本加三端配置 | 原生启停脚本或 Docker;安装器预览、备份、回滚 |
| 验收 | 文件、代码、账本、客户端、真实链路、跨设备六层 | 加健康检查脚本、八项最小回归、job 与 operation 两层状态 |
v1.0、v2.0 的 Markdown 原文继续保留在项目仓库里,本版不覆盖它们。