把 Obsidian、任务清单和 AI Agent 接成一个项目状态闭环
项目一多,最先混乱的通常不是文件,而是项目状态。
代码在 Git 里,实验结果散在几篇 Markdown 中,会议决定藏在聊天记录里,任务清单还挂着一个两周前写下的截止日期。每一处看起来都有信息,但没人能直接回答:
这个项目现在究竟在哪里,下一步是否仍然有效?
我不想再造一套全能项目管理软件,也不想把所有东西塞进同一张表。最后,我把它拆成几层:
flowchart LR O[Obsidian<br/>项目事实与证据] T[任务清单<br/>动作、时间与提醒] E[代码仓库 / 设备 / 实验环境<br/>实际结果] A[AI 助手<br/>定时核对] W[微信<br/>向用户确认] U[用户回复] O --> A T --> A E --> A A -->|发现冲突或未知项| W W --> U U -->|确认项目状态| O U -->|确认时间性行动| T
这套系统的重点不是“让 AI 自动管理项目”,而是让它负责对账、暴露未知项,并把真正需要人决定的部分送到我面前。
先定义三种真相
我给不同系统划定了边界。
| 层 | 工具 | 保存什么 |
|---|---|---|
| 项目事实层 | Obsidian | 目标、范围、阶段、证据、风险、已确认节点 |
| 行动层 | 任务清单 | 下一步动作、截止时间、会议、课程、提醒 |
| 实现层 | Git、设备、实验环境 | 当前代码、运行状态、现场结果、真实产物 |
它们不能互相冒充。
Obsidian 写着“验证完成”,不代表服务真的在线;Git 里有一个提交,也不代表项目状态页已经更新;任务清单上存在截止日期,更不代表这个动作现在仍值得做。
我把这条规则压缩成一句话:
Obsidian 解释状态,任务清单推动行动,真实环境证明实现。
每个项目只强制一个入口
每个活跃项目至少有一个 00-项目总览.md:
00-项目/<项目名>/
└── 00-项目总览.md不先创建十几个空目录。只有材料真实出现后,项目才逐渐长成:
00-项目/<项目名>/
├── 00-项目总览.md
├── 当前/
├── 参考资料/
├── 附件/
└── 归档/总览页是项目入口,不是过程材料的堆放处。它至少要回答:
- 这个项目解决什么问题,哪些内容不在范围内;
- 当前处于调研、实现、验证、等待、暂停还是完成;
- 最近得到过哪些有证据的结果;
- 用户确认过的下一节点是什么;
- 还有哪些事情不能确定;
- 当前材料、实验和决策记录从哪里进入。
一个够用的 Frontmatter 可以很简单:
---
title: <项目名>:项目总览
status: 进行中
updated: 2026-08-14
---详细实验、会议和复盘拆成独立笔记。总览只保留当前结论和链接。
当前/ 里只放还在工作的材料。被新证据替代的方案进入 归档/,不删除,也不继续混在活跃视图里。项目管理中很危险的一类错误,就是早期计划在几个月后重新被读到,然后被误认为当前决策。
“没有下一步”不是低优先级
有了单项目入口后,我在 00-项目/ 根目录增加了一张组合视图:
| 项目 | 当前阶段 | 最近进展 | 已确认的下一节点 | 仍需确认 |
|---|---|---|---|---|
| 项目 A | 准备第二次验证 | 第一轮结果已复盘 | 周六 15:30 继续 | 是否需要提前准备材料 |
| 项目 B | 需求调研 | 已形成初稿 | 周三完成确认稿 | 何时与对方核对真实流程 |
| 项目 C | 原型准备 | 硬件已到手 | 待确认 | 何时恢复 |
我最初给它们排过 P0、P1、P2。很快就发现这个模型会吞掉信息。
项目 C 没有下一步,可能不是因为不重要,而是我还没决定。AI 如果看到“没有任务、没有日期、依赖硬件”,然后自动把它降级,实际上是在替我做价值判断。
所以现在只允许两类状态:
- 用户确认过的节点,写入时间线;
- 未确认的节点,明确写成“待确认”。
候选技术路线可以保留,但不能伪装成计划。
用定时任务核对两边的状态
项目状态页和任务清单需要定期对账。我用 Hermes Agent 的 Cron 来做这件事。
调度时间可以直接写成标准 Cron 表达式:
0 8,12,17,22 * * *也就是每天 08:00、12:00、17:00 和 22:00 扫描。
每轮读取:
- 跨项目状态总览;
- 各项目的
00-项目总览.md; - 必要的“当前导航”;
- 上一轮待确认问题;
- 任务清单未来 14 天的未完成任务;
- 当前时间和时区。
检查逻辑是双向的:
flowchart LR O[Obsidian 项目事实] --> R[Reconciliation] T[任务清单近期动作] --> R R --> C{冲突 / 缺失 / 未知} C -->|无变化| S[SILENT] C -->|需要确认| Q[生成编号问题] Q --> M[微信] M --> U[用户回复] U --> W[确认后写回] W --> O W --> T
它寻找的主要异常包括:
- 两边的日期、时间和完成状态不一致;
- Obsidian 有明确近期节点,任务清单却没有行动或提醒;
- 任务清单出现了项目动作,项目总览却毫无记录;
- 项目没有确认过的下一步,也没有暂停或等待原因;
- 已经过期的节点仍被写成未来;
- AI 建议或技术候选被误写成了确定计划。
扫描阶段只有读权限和“写待确认清单”的权限。它不能根据推断修改项目事实,也不能自行创建正式任务。
发现问题后,完整依据进入 Obsidian 的 项目状态待确认.md,手机只收到一条短消息:
项目状态核对:发现 3 项待确认
- 项目 A:周六课程是否照常,是否需要提醒?
- 项目 B:任务截止是周二还是周三?
- 项目 C:近期恢复,还是继续暂停?
没有变化时,Agent 最终只返回:
[SILENT]Cron 会抑制投递。一天运行四次,不等于一天打扰四次。
微信接入的第一层:/sethome
Hermes 的定时任务可以配置:
deliver: weixin但 weixin 只是一个平台级别的路由名。系统仍然需要知道这个平台的默认目标会话是谁。
因此,在实际接收通知的微信 DM 中需要执行:
/sethome它会把当前聊天登记为 Weixin Home Channel。之后 deliver: weixin 才能在运行时解析到正确的微信会话。
这一步在重新绑定账号后尤其重要。重新登录 iLink Bot 解决的是“Gateway 使用哪个微信机器人”,/sethome 解决的是“定时通知发给机器人下的哪个会话”。它们不是同一个配置。
可以把路由过程理解为:
flowchart LR C[Cron deliver: weixin] --> H[WEIXIN_HOME_CHANNEL] H --> D[执行过 /sethome 的微信 DM]
如果换绑微信后忘记重新 /sethome,可能出现几种状态:
- Cron 没有可解析的 Home;
- 通知仍指向旧会话;
- 手动直发使用了新 context token,但平台级 Home 仍不稳定;
- 扫描成功,最终投递失败。
所以我的验收顺序是:重新绑定、重启 Gateway、在目标 DM 执行 /sethome,然后再做短消息直发和 Cron 投递测试。
微信接入的第二层:让回复拥有上下文
/sethome 解决投递目标,但还没有解决会话连续性。
Cron 默认在一个隔离会话中运行。它生成问题后可以把结果投递到微信,但微信里的日常 Agent 会话未必拥有这条 Cron 消息的上下文。
问题会在用户用编号简短作答时暴露:对用户而言,问题就在上一条消息里;对系统而言,Cron 投递和日常对话可能属于两个不同的会话状态。于是消息虽然出现在同一个聊天窗口,Agent 却未必知道编号对应什么。
要让 Cron 可继续回复,需要同时满足两个条件:
- 任务从用户真正用于回复的微信 DM 中创建,因此保存正确的
origin; - 创建或更新任务时设置
attach_to_session=true。
任务记录应包含类似结构:
origin:
platform: weixin
chat_id: <当前微信 DM>
attach_to_session: true
deliver: weixin三项各有职责:
| 配置 | 作用 |
|---|---|
/sethome | 把当前 DM 设为 Weixin 默认投递目标 |
origin | 记录这项自动化从哪个真实对话创建 |
attach_to_session | 把 Cron 投递镜像进 origin 会话上下文 |
deliver 回答“消息发往哪里”;attach_to_session 回答“用户回复时,Agent 是否记得自己刚才问过什么”。
我第一次是在 Desktop 中创建任务,再让它把结果发送到微信。消息确实到了,但任务并不是从这段微信对话创建的,因此没有记录当前微信会话是它的来源。
问题在真正回复时暴露了。Cron 发来五个编号问题,我直接回答:
- 是。2. 是。3. 明天可能汇报不了,提醒我重新约时间。
微信里的 Astra 能处理第三项,因为我把事情重新说了一遍;但它不知道前两个“是”对应哪两个问题。对我来说,问题就在上一条消息里。对 Agent 来说,那条消息只是一次外部投递,没有进入它正在使用的对话上下文。
最后我保留原来的时间、检查规则和工具配置,只调整任务的创建位置与会话设置:
- 暂停 Desktop 创建的旧任务;
- 在实际接收和回复的微信 DM 中重新创建;
- 确认新任务记录了当前微信
origin; - 开启
attach_to_session: true; - 再用“1. 是;2. 否”测试 Agent 能否还原原问题。
所以,消息出现在同一个聊天窗口里,并不自动意味着 Agent 拥有同一段上下文。投递目标和回复上下文需要分别配置。
任务成功和通知成功也不是一回事
Cron 的 last_status: ok 只说明 Agent 完成了扫描和输出,不说明微信收到了消息。
至少还要检查:
last_run_at
last_status
last_delivery_error以及:
- 对应运行的本地输出文件是否存在;
- Gateway 日志里平台发送是否成功;
- 当前消息是否投递到了最新 Home Channel。
我遇到过 iLink 返回频率限制:扫描结果已经生成,本地文件也存在,但最后一步发送失败。
如果防重复只看“问题是否生成过”,就会出现一个漏洞:首次投递失败,下一轮却认为“已经问过”,之后一直保持静默。
因此我的规则是:
- 上次成功送达,问题不变:静默;
- 上次投递失败:下一轮允许补发;
- 已经送达但没有回复:只在事实变化、截止进入 24 小时内,或超过约定时间后再提醒。
运行状态和投递状态必须分别建模。
不要把 Cron 运行档案发到手机
Hermes 会保存 Cron 运行产物。这类文件可能包含:
- 加载的 Skill;
- 完整 Prompt;
- 运行上下文;
- 调试信息;
- 最终 Response。
它是审计文件,不是用户消息。
我曾经为了补发结果,直接执行了类似操作:
hermes send --to weixin --file <cron-output.md>于是四万多字的运行档案被微信拆成多条消息,真正有用的五个问题埋在中间。
现在的输出规则是:
- 手机只收到最终 Response;
- 总长度尽量控制在 1000 个中文字符内;
- 最多五个编号问题;
- 完整证据只写进 Obsidian;
- 补发时提取最终结果,绝不发送整个运行产物;
- Agent 不在 Prompt 内调用发送工具,由 Cron 统一投递一次。
手机适合接收简短问题,不适合承载完整运行日志。
用户回复之后才允许写回
用户可以回复:
项目核对:1. 照常;2. 改到周三;3. 暂停到设备到手。
因为本轮 Cron 已挂载到微信会话,Agent 能将编号映射回问题,然后执行:
- 读取本轮 Cron 提问;
- 读取 Obsidian 中的完整依据;
- 更新对应项目的
00-项目总览.md; - 更新跨项目状态总览;
- 对有明确时间的动作创建或更新任务;
- 纯状态变化不强行创建待办;
- 清除已解决的待确认项;
- 下一轮不再重复询问。
如果用户顺便提到“明晚聚餐”,Agent 应识别它是新的时间性事项,但不能未经确认直接猜成 18:30。自动化的目标是减少交互成本,不是把猜测落成日历事实。
Obsidian Sync 负责传输,不负责信息架构
为了让服务器 Agent 和本地 Obsidian 读写同一个 Vault,我使用官方 Obsidian Sync:
flowchart LR L[电脑 / 手机 Obsidian] <-->|Obsidian Sync| R[远端 Vault] R <-->|Headless continuous sync| S[服务器 Vault 副本] S <--> A[AI Agent]
服务器使用 Headless 客户端持续双向同步 Markdown 和附件,但不启用 .obsidian 配置同步。
这样做是为了避免:
- 桌面主题和社区插件污染服务器;
- 工作区状态在设备之间互相覆盖;
- 服务器生成无意义的 UI 配置;
- 插件缓存进入协作数据层。
同步服务也需要验证。文件在服务器上出现,只能证明本地已经写入。要确认它进入 Obsidian Sync,应查看 Headless 客户端输出或 systemd Journal 中写入后的:
Upload complete
Fully syncedSync、Git、发布和备份分成四套机制
这四件事经常被说成同一件事,实际上恢复保证完全不同:
| 机制 | 解决的问题 | 不能保证什么 |
|---|---|---|
| Obsidian Sync | 多设备与服务器保持同一 Vault | 误删后的独立恢复点 |
| Git | 已提交内容的版本历史 | 未提交文件、账号与运行配置 |
| Quartz / 静态站 | 将选定 Markdown 发布为网站 | 私有 Vault 的完整保存 |
| 独立备份 | 在同步系统之外恢复数据 | 实时多设备协作 |
我只允许 60-发布/ 进入公开链路,每篇文章还要显式设置:
publish: true这里有两道限制:文件必须位于公开目录,并且明确选择发布。项目总览、私密附件和协作记录不会因为存在于同一 Vault 就自动进入网站。
最后留下四条规则
这套系统最后可以归结为四条规则:
- 状态分工:Obsidian、任务清单和真实环境分别保存什么;
- 证据边界:结论来自哪里,哪些信息仍未知;
- 会话连续:Cron 的问题怎样进入用户实际回复的会话;
- 确认后写回:只有用户确认后,Agent 才修改项目状态和任务。
端到端验收也很明确:
- Cron 能读到最新项目和任务;
- 没有变化时保持静默;
- 有问题时微信只收到一条摘要;
/sethome指向当前接收会话;- 任务保存正确的
origin; attach_to_session=true已实际写入任务配置;- 用户只回复编号,Agent 仍能准确还原问题;
- 确认结果被写回正确的项目与任务;
- 下一轮不再重复询问。
我不需要 AI 替我决定项目优先级。它更适合做一件朴素但高频的事:持续扫描状态漂移,把冲突和未知项压缩成几个可以回答的问题。
答案仍然由人给出。系统负责让答案不再丢失。