上个月,我做了一个很小的命令行工具,叫 PatchTrail。
它一开始解决的问题很简单:
text
AI 改代码前先记录项目状态。
AI 改完后,再检查这轮到底动了哪些文件,有没有明显风险。
对我来说,这已经很有用了。
因为在真实 iOS / Flutter 项目里,AI 改代码最麻烦的地方,往往不是它完全写不出来,而是它顺手多改了一些东西。
比如:
- 改一个页面文案,结果顺手动了
Info.plist。 - 调一个 Flutter 页面,结果
pubspec.yaml也变了。 - 改一个普通功能,结果碰到了登录、订阅、扫脸、历史记录这类核心流程。
- 临时跑通时留下了
bypass、mockUser、forceUnlock之类的代码。
这些问题不一定会马上让项目编译失败。
但等你过几天再回头看,就会很难判断:
text
这到底是本轮需求里应该出现的改动,
还是 AI 为了跑通功能顺手带出来的改动?
所以第一版 PatchTrail 只做了三件事:
bash
zmg init
zmg start
zmg check
zmg start 记录 AI 改代码前的项目状态。
zmg check 检查 AI 改完以后真实发生了什么。
它能告诉我:
text
这轮改了哪些文件?
新增和删除了多少行?
有没有动到高风险配置?
有没有碰到核心功能目录?
有没有留下疑似临时代码?
下一步应该人工验证什么?
这解决的是一个很具体的问题:
text
不要只听 AI 说它改了什么,要看项目里真实发生了什么。
但这几天我发现,这还只解决了一半。
一、只知道改了什么,还不够接手
今天有一个朋友看完这个开源库以后,给我发了一封邮件。
他问的不是怎么安装,也不是怎么运行命令。
他真正关心的是另一个问题:
text
Agent 应该记录什么,才能让另一个 Agent,或者未来的自己,理解一次代码改动为什么发生?
这个问题让我思考了一下,因为它问的不是"检查结果够不够详细",而是:
text
下一轮接手的人,能不能理解上一轮为什么这么改。
这和我一开始做 zmg check 时想解决的问题不完全一样。
zmg check 更像是在回答:
text
这轮真实发生了什么?
比如它会列出:
- 改了哪些文件
- 哪些文件风险高
- 哪些地方需要人工验证
- 完整报告在哪里
但它回答不了:
text
这轮任务为什么开始?
这轮目标是什么?
这些风险是不是本来就属于本轮目标?
下一轮 Agent 应该先看哪里?
这轮工作到底结束了没有?
这些问题,光靠 diff 和风险报告很难回答。
在真实项目里,这个差别很明显。
比如我让 AI 改一个扫脸结果页,它改到了历史记录模块。
zmg check 可以告诉我:
text
历史记录相关文件被改了。
这是核心功能目录,建议人工验证。
但它不知道:
text
这次任务本来就要求结果页和历史记录一起改,
还是 AI 自己把历史记录也带进来了。
这个判断需要任务目标。
如果没有任务目标,下一轮 Agent 看到报告,也只能知道"这里有风险",但不知道这个风险该不该出现。
所以我意识到了,PatchTrail 不能只留下"改动事实 ",还要留下"任务背景"。
二、我把记录拆成两层
这次迭代里,我把 PatchTrail 要记录的东西拆成了两层。
第一层是事实记录。
它回答:
text
这轮真实发生了什么?
这就是原来的 zmg start 和 zmg check 做的事情。
它记录的是:
- 修改之前的项目状态
- 当前 git 分支和 commit
- 文件 hash 和行数
- 改动文件列表
- 新增和删除行数
- 风险等级
- 高风险文件
- 核心功能目录
- 疑似临时代码
- 人工验证建议
这层记录很重要,因为它不靠 AI 自己描述,而是直接看项目里的真实变化。
第二层是任务记录。
它回答:
text
这轮为什么开始?
下一轮应该怎么接?
这层记录不是为了替代风险检查,而是给风险检查补充了上下文。
比如:
- 本轮任务目标是什么
- 这轮检查结果属于哪个任务
- 下一轮 Agent 应该先看哪份报告
- 这轮工作有没有生成交接文档
- 当前任务是否已经关闭
这层东西第一版本是没有的,没有它的时候,工具只能告诉我"哪里有风险"。
有了它以后,工具才开始接近一个完整的 AI coding session 记录。
我现在更愿意把 PatchTrail 理解成:
text
不是替 AI 写代码,而是让每一轮 AI 改代码都留下一条能继续跟下去的轨迹。
这也是我决定把项目名改成 PatchTrail 的原因,Patch 是代码改动,Trail 是留下来的轨迹,这比原来那个偏工具名的 zzh-mobile-ai-guard 更贴近现在的方向。
三、这次不是多加几个命令
这轮迭代以后,PatchTrail 的最小使用方式变成了这样:
bash
npm install -g patchtrail
zmg init
zmg task start --goal "Describe the change"
zmg check
zmg handoff
zmg task close
表面上看,只是多了几个命令:
bash
zmg task start --goal "..."
zmg handoff
zmg task close
但这几个命令背后,其实是在补一轮 AI 改代码的开始和结束。
原来的流程是:
text
记录改前状态
-> AI 修改
-> 检查改后风险
现在变成:
text
记录任务目标
-> 记录改前状态
-> AI 修改
-> 检查改后风险
-> 生成交接文档
-> 关闭任务
这个变化对我来说很关键。
因为真实项目里的 AI 协作编程,很少是一轮就结束的:
- 有时候我晚上让 AI 改一段逻辑,第二天早上再接着看;
- 有时候一个 Agent 做完第一轮,另一个 Agent 接着做验证和修补;
- 有时候我自己隔了几天再回来看,已经不记得当时为什么允许它改这个文件。
如果工具只留下 diff,我还是要重新判断一遍;如果工具留下任务目标、检查报告和交接文档,下一轮就不需要从零开始。
四、task start 先把这轮为什么开始写下来
以前我会先运行:
bash
zmg start
它会记录改代码前的状态。
现在如果我希望这一轮工作能被接手,我会先运行:
bash
zmg task start --goal "Fix Scan Home empty state copy"
这里最重要的不是多了一个命令,而是多了一个目标。
工具会把这轮任务目标写进当前任务里,同时自动记录 baseline。
也就是说,它把两件事放在了一起:
text
这轮为什么开始,这轮开始前项目是什么状态。
这两个信息如果分开放,下一轮再接手时,就很容易只看到代码变化,看不到这轮任务为什么开始,尤其是 AI coding 里,很多问题不是"没有记录",而是记录太散:
- 任务目标在聊天里;
- 代码改动在 git diff 里;
- 风险报告在另一个文件里。
等下一轮再接的时候,Agent 很容易只看到 diff,却看不到任务目标。
task start 要解决的就是这个问题。
它会在 .patchtrail/tasks/ 下留下当前任务记录,这让后面的 check 和 handoff 都知道:
text
这次检查不是孤立的一次检查,它属于某个具体任务。
五、handoff 不是总结,而是给下一轮看的入口
这次我还加了:
bash
zmg handoff
这个命令的作用,是基于最近一次 zmg check 生成一份更短的 Markdown 交接文档。
它不会重新判断业务是否正确。
它只是把下一轮最需要先看的信息放在一起:
- 本轮结论
- 任务目标
- 改动范围
- 风险项
- 人工验证项
- 完整检查报告路径
- 下一轮应该先确认的问题
为什么还要单独有一份交接文档?
因为完整报告适合追细节,但下一轮接手时,第一眼需要的是入口。
我不希望下一轮 Agent 一上来就重新扫所有文件,也不希望它只读 git diff。
我希望它先看到:
text
上一轮任务是什么。
上一轮检查结果是什么。
哪些风险还没验证。
完整报告在哪里。
这才是能接手的状态。
我以前做项目交接文档时,其实也是这个思路。
不是把所有细节都堆进去,而是让下一个人知道先从哪里看,哪些事情还不能默认通过。
现在只是把这个习惯放进了一个命令里。
六、task close 让一轮工作真正结束
还有一个小命令:
bash
zmg task close
这个命令看起来很普通,但我觉得它很重要。
因为很多 AI coding 的混乱,不是发生在开始时,而是发生在结束时。
一轮任务没有被明确关闭,下一轮就容易接着旧状态继续跑。
最后你分不清:
text
这个报告属于哪一次任务?
这个 handoff 是上一次的,还是这一次的?
当前 active task 还算不算有效?
所以 task close 做了几件很简单的事:
- 确认当前有 active task。
- 确认已经有最近一次检查结果。
- 生成或同步当前 handoff。
- 把交接文档保存到这次任务目录下。
- 写入关闭状态。
- 清掉当前 active task。
这样下一轮再开始时,就不会和上一轮混在一起。
它不是一个复杂的项目管理功能,它只是给 AI coding session 补了一个结束动作。
这件事在单轮演示里看不出价值,但只要你连续几天用 AI 改同一个项目,就会发现这个动作很重要。
七、现在 .patchtrail/ 里留下的是一条任务轨迹
最新版安装方式是:
bash
npm install -g patchtrail
第一次接入项目:
bash
zmg init
现在它会生成:
text
.patchtrail/
rules.yml
baselines/
reports/
handoffs/
tasks/
这里面每一层的作用都不一样。
baselines/ 记录 AI 改代码前的项目状态。
reports/ 保存 zmg check 的完整检查报告。
handoffs/ 保存可以给下一轮看的交接文档。
tasks/ 保存每一轮任务的目标、记录和关闭结果。
如果只看目录结构,它很普通,但它背后其实是一条工作顺序:
text
这轮为什么开始
-> 开始前是什么状态
-> 改完后发生了什么
-> 哪些地方需要验证
-> 下一轮从哪里接
-> 这轮是否已经结束
这就是我说的闭环,它不是说工具能自动完成所有工作,它只是把 AI 改代码中最容易散掉的几个信息,放进同一条轨迹里。
八、它仍然不能替代编译和测试
这部分我想说得更清楚。
PatchTrail 现在有了任务目标,有了检查报告,有了交接文档,但它仍然不能证明业务功能正确。
它不能证明:
- 项目能编译
- 页面一定能打开
- 支付、订阅、登录这些流程一定没问题
- AI 已经完整实现了需求
- 真机上没有问题
这些仍然要靠编译、测试和人工验证 ,所以我不会把 zmg check 或 zmg handoff 写成"通过验收"。
它们只是告诉我:
text
这轮改动留下了可检查的记录。
下一轮接手时,不需要只靠聊天记录和 git diff 猜。
这个边界必须守住,不然工具很容易从"帮你看风险 "变成"让你误以为已经安全",那就适得其反了。
九、如果你想试一下
现在可以直接安装:
bash
npm install -g patchtrail
在你的 iOS / Flutter 项目根目录运行:
bash
zmg init
zmg task start --goal "Describe the change"
然后让 AI 改代码。
改完后运行:
bash
zmg check
zmg handoff
zmg task close
如果你只是想用最基础的风险检查,也可以继续用:
bash
zmg start
zmg check
项目地址:
text
https://github.com/lmmzzh/patchtrail
它现在仍然更适合 iOS / Flutter 项目,尤其是那种你不希望 AI 随手改配置文件、权限文件、平台目录和核心业务目录的项目。
十、最后
我现在越来越觉得,AI coding 的问题不只是"AI 快速写出代码、实现功能"。
真实项目里更重要的是:
text
每一轮 AI 修改之后,
后面的人还能不能看懂这轮为什么发生。
第一版 PatchTrail 只是在回答:
text
这轮到底改了什么?
现在这版开始回答另一个问题:
text
下一轮应该怎么接?
这不是多几个命令的问题,它更像是把 AI 改代码从一次性动作,变成一段能被继续理解的工作记录。
对真实项目来说,我现在更需要的不是让 AI 每次都自称"已经完成",而是让它每次改完以后,都留下一条别人能继续跟下去的轨迹。