Valhalla静态工程审阅|Planning with Files 深度评测:用持久化文件解决 AI 长任务的上下文与恢复问题【Agent Skill 特辑 #020】

0 阅读18分钟

Valhalla静态工程审阅|Planning with Files 深度评测:用持久化文件解决 AI 长任务的上下文与恢复问题【Agent Skill 特辑 #020】

评测对象planning-with-files
仓库https://github.com/OthmanAdi/planning-with-files
固定提交9b7d0a007946ae7694216642fd5be78c2f13b6db
评测类型:证据驱动的只读静态工程审阅
评测边界:本文仅依据固定源码快照进行分析,未执行项目代码、测试、依赖扫描或运行时安全验证。 作者:Valhalla Matrix治理实验室

摘要

AI 编码代理在处理短任务时通常表现良好,但面对跨文件修改、长时间调试、复杂重构和多阶段交付时,容易遇到几个共性问题:

  • 上下文窗口不足;
  • 中途压缩后丢失任务状态;
  • 长任务执行顺序不稳定;
  • 任务重启后无法恢复进度;
  • Agent 重复执行已经完成的步骤;
  • 用户难以了解当前任务处于什么阶段。

planning-with-files 采用一种相对直接、但具有工程实用性的思路:将任务计划、阶段状态、执行记录和相关元数据持久化到 Markdown 或其他文件中,让 AI Agent 通过文件系统维护长任务状态。

基于固定提交的静态证据,本项目包含:

  • 274 个受支持源文件;
  • 181 个 Shell 文件;
  • 85 个 Python 文件;
  • 8 个 TypeScript 文件;
  • 18 个 Skill 条目;
  • 17 个一级目录或模块入口;
  • 52 个测试文件线索;
  • 3 个 CI 工作流线索;
  • 47 条静态风险命中。

从工程结构看,它不是一个大型运行时平台,而是一个围绕“文件化规划、状态恢复和多 Agent 平台适配”构建的专项工具。项目的优点是目标聚焦、实现路径清晰、测试文件较多;主要挑战则集中在 Shell 脚本复杂度、路径边界、跨平台兼容性、Hook 行为一致性和状态文件的可靠性上。

核心结论:
planning-with-files 具备较明确的工程价值,适合用于验证 AI 长任务的计划持久化和断点恢复方法。但在实际使用前,应重点验证路径隔离、脚本参数处理、Hook 生命周期、并发访问和异常恢复行为。


一、项目解决了什么问题?

1. AI 长任务为什么容易失控?

一个典型的 AI 编码任务可能包含以下步骤:

理解需求
  ↓
扫描项目
  ↓
制定方案
  ↓
修改多个文件
  ↓
执行测试
  ↓
修复失败
  ↓
重新验证
  ↓
整理交付结果

如果这些状态只存在于模型上下文中,就会面临几个问题:

  1. 上下文被压缩后,早期计划可能丢失;
  2. Agent 重启后,不知道之前完成了哪些工作;
  3. 长任务中途失败时,无法准确恢复;
  4. 多轮执行后,计划、实际修改和测试结果可能不一致;
  5. 用户无法快速判断当前任务进展。

planning-with-files 的基本思路是将这些信息写入项目目录中的持久化文件:

任务计划文件
执行状态文件
阶段记录文件
检查结果
恢复信息

于是,Agent 的任务状态从:

仅存在于上下文

变成:

上下文 + 文件系统中的持久化状态

这是一种“外部化任务记忆”的工程实践。


二、静态资产概览

2.1 源码规模

本次扫描识别出 274 个受支持源文件:

语言文件数量可能承担的职责
Shell181Hook、安装、状态管理、文件操作和自动化流程
Python85测试、辅助逻辑和验证脚本
TypeScript8特定 Agent 平台或扩展入口
合计274

Shell 文件占比约为三分之二。这与项目的设计目标相符,因为文件化规划通常需要完成:

  • 创建任务目录;
  • 初始化计划文件;
  • 解析任务状态;
  • 检查阶段完成情况;
  • 写入或读取 Markdown;
  • 安装 Hook;
  • 适配不同 Agent 平台;
  • 计算文件摘要;
  • 调用外部命令。

不过,Shell 占比较高也意味着项目的稳定性高度依赖:

  • Shell 解释器差异;
  • 命令行工具可用性;
  • 环境变量;
  • 路径格式;
  • 文件编码;
  • 子进程退出码;
  • 错误处理方式。

2.2 Skill 表面

项目识别出 18 个 SKILL.md 或技能条目,并分布在多个 Agent 平台适配目录中,包括:

.agents
.codebuddy
.codex
.continue
.cursor
.factory
.gemini
.hermes
.kiro
.mastracode
.opencode
.pi

这说明项目并非只服务于一个固定客户端,而是尝试将同一套规划方法适配到多个 Agent 工具或开发环境。

多平台适配的价值在于:

  • 降低重复配置成本;
  • 保持规划方法的一致性;
  • 便于不同团队采用;
  • 能够根据平台提供相应 Hook 和扩展入口。

与此同时,也需要确认不同平台的行为是否一致:

  • 计划文件是否写入相同位置;
  • 当前任务状态是否使用同一格式;
  • Hook 是否全部安装成功;
  • 中断和恢复事件是否等价;
  • 路径解析是否存在平台差异;
  • 某些平台是否会绕过计划检查。

三、核心架构:文件化规划与状态恢复

根据源码目录和抽样文件,可以将项目的工作流程抽象为以下结构:

flowchart TD
    A[用户任务] --> B[初始化任务会话]
    B --> C[生成计划文件]
    C --> D[拆分阶段与步骤]
    D --> E[执行当前阶段]
    E --> F[写入执行记录]
    F --> G{阶段是否完成}
    G -- 否 --> E
    G -- 是 --> H[进入下一阶段]
    H --> I{任务是否完成}
    I -- 否 --> E
    I -- 是 --> J[生成完成报告]

    E --> K[任务中断或上下文压缩]
    K --> L[读取计划与状态]
    L --> E

3.1 初始化阶段

init-session.sh 是重要的静态阅读入口。报告提取到的函数包括:

slugify
short_uuid
gen_nonce
apply_v3_mode
write_default_task_plan

从命名可以推断,初始化阶段可能涉及:

  • 将任务名称转换为安全标识;
  • 生成短 ID;
  • 生成随机标记;
  • 应用不同版本的规划模式;
  • 写入默认任务计划。

需要重点验证:

  • 任务名称是否可能影响路径;
  • 生成的目录是否存在冲突;
  • 随机 ID 是否仅用于标识,还是承担安全认证作用;
  • 初始化失败时是否留下半成品文件;
  • 重复初始化是否会覆盖既有计划;
  • 计划文件是否使用安全的原子写入方式。

3.2 计划注入阶段

inject-plan.sh 是抽样文件中结构最复杂的入口之一,报告提取到的函数包括:

slug_is_valid
norm_slashes
canonicalize
is_within_root
smart_plan_extract

这些函数名显示出项目对路径规范化和工作区边界有所关注。

其中,is_within_root 这类逻辑尤其重要。文件化规划系统需要避免出现以下问题:

计划根目录
  ↓
用户输入路径
  ↓
路径穿越
  ↓
访问计划目录之外的文件

理想的路径处理过程应包括:

  1. 统一路径分隔符;
  2. 处理相对路径;
  3. 规范化 ...
  4. 解析符号链接;
  5. 获取真实路径;
  6. 检查是否仍位于允许根目录内;
  7. 再执行文件读写。

仅依赖字符串前缀判断并不足够。例如,以下判断可能存在边界问题:

[[ "$target" == "$root"* ]]

因为同名前缀目录、符号链接和未规范化路径都可能造成误判。

3.3 完成检查阶段

check-complete.sh 中出现了:

advisory_report
ledger_line_count
json_escape
first_in_progress_phase

这表明项目可能通过计划文件和日志记录判断:

  • 当前任务是否完成;
  • 是否还有进行中的阶段;
  • 记录条数是否符合预期;
  • 输出是否需要 JSON 转义;
  • 是否需要生成提醒或报告。

这里有一个重要的工程问题:

“计划上标记为完成”是否等于“实际工作已经完成”?

例如,Agent 可能在修改文件后直接更新状态,却没有成功执行测试。因此,完成检查最好同时验证:

计划状态
+ 实际文件变更
+ 测试结果
+ 必需产物
+ 未完成事项

否则,状态文件可能成为“看起来已完成”的来源,而不是实际执行结果的可信证明。

3.4 停止门控阶段

gate-stop.sh 可能承担停止前检查或任务结束门控职责。

这类机制通常用于防止 Agent 在以下情况下过早结束:

  • 仍有未完成阶段;
  • 存在未处理错误;
  • 测试尚未执行;
  • 计划文件未更新;
  • 还有未提交的任务结果;
  • 需要用户确认的操作没有完成。

但停止门控不能仅依赖自然语言状态。建议将其设计为结构化条件,例如:

completion:
  plan_status: complete
  pending_phases: 0
  required_checks:
    tests: passed
    lint: passed
  user_approval: not_required
  side_effects: recorded

四、项目的主要工程优势

4.1 目标聚焦,边界相对清晰

与同时包含模型服务、前端、数据库和多个运行时的大型 Agent 平台相比,planning-with-files 的目标比较集中:

长任务规划
+ 文件化状态
+ Hook 触发
+ 多平台适配

这种聚焦带来的好处是:

  • 容易理解;
  • 便于部署;
  • 适合个人和小团队试用;
  • 更容易围绕核心流程编写测试;
  • 能够快速验证“持久化计划是否改善 Agent 执行”。

4.2 测试覆盖方向具有针对性

报告列出的测试文件包括:

tests/test_planning_disabled_optout.py
tests/test_check_complete_resolver.py
tests/test_nested_plan_isolation.py
tests/test_v238_command_files.py
tests/test_hook_resolver_integration.py
tests/test_precompact_hook.py
tests/test_resolver_plan_root_pin.py
tests/test_hook_body_v240.py
tests/test_path_fix.py
tests/test_injection_determinism.py
tests/test_session_catchup.py
tests/test_ledger_utf8.py
tests/test_ps1_windows_encoding.py
tests/test_cursor_nested_root_isolation.py
tests/test_resolver_parity.py
tests/test_plan_attestation.py
tests/test_codex_nested_root_isolation.py
tests/test_stop_hook_dispatch.py
tests/test_gate.py
tests/test_line_endings.py
tests/test_containment.py
tests/test_canonical_script_sync.py

从测试名称来看,项目已经关注了一些实际问题:

  • 规划功能关闭或退出;
  • 嵌套目录隔离;
  • Hook 集成;
  • 计划根目录固定;
  • 注入稳定性;
  • 会话恢复;
  • UTF-8 和 Windows 编码;
  • 不同平台行为一致;
  • 停止门控;
  • 路径包含关系;
  • 脚本同步。

这比只测试“能否创建一个计划文件”更加接近真实工程场景。

4.3 存在计划完整性校验思路

attest-plan.sh 中出现:

resolve_plan_file
attestation_path_for
compute_hash

从静态命名看,项目可能尝试为计划文件建立摘要或证明文件。

如果该机制确实用于运行时校验,它可以帮助发现:

  • 计划文件被外部修改;
  • Agent 在执行过程中覆盖计划;
  • 多个任务误用了同一计划;
  • 恢复时读取了错误版本;
  • 计划与执行记录不一致。

不过,文件哈希只能证明内容变化,不能证明内容本身可信。它还需要配合:

  • 哈希生成者身份;
  • 版本信息;
  • 任务 ID;
  • 时间戳;
  • 文件位置;
  • 写入权限;
  • 失败处理;
  • 回滚机制。

五、需要重点关注的风险

5.1 Shell 脚本规模较大

181 个 Shell 文件构成了本项目最重要的工程风险面。

Shell 适合处理文件、Hook 和命令行环境,但其复杂度容易被低估。常见风险包括:

  • 未加引号的变量展开;
  • 空格和换行导致参数拆分;
  • eval 或间接命令执行;
  • 管道中间步骤失败未被发现;
  • set -e 行为与预期不一致;
  • 子 Shell 环境变量丢失;
  • 命令不存在时错误被吞掉;
  • Windows PowerShell 与 Unix Shell 行为不一致;
  • 临时文件权限过宽;
  • 并发执行造成状态覆盖。

建议对生产可达脚本统一检查:

set -Eeuo pipefail

并根据实际环境补充:

  • 参数白名单;
  • -- 参数终止符;
  • 明确的临时目录;
  • trap 清理逻辑;
  • 命令存在性检查;
  • 退出码传递;
  • 日志脱敏;
  • 文件锁;
  • 超时控制。

5.2 静态风险命中大多出现在测试文件

报告列出的前 30 条风险样例中,大量路径属于:

tests/

例如:

tests/test_hook_resolver_integration.py
tests/test_injection_determinism.py
tests/test_plan_attestation.py
tests/test_gate.py
tests/test_containment.py

这会显著影响风险解读。

测试文件中出现 Shell 调用通常是合理的,因为测试需要:

  • 调用被测脚本;
  • 创建临时目录;
  • 模拟 Hook;
  • 检查退出码;
  • 验证跨平台行为;
  • 构造路径边界场景。

因此,47 条静态命中不能直接作为生产风险数量。应将命中按以下维度分类:

分类处理方式
测试代码检查测试隔离和夹具安全
示例代码确认不会进入生产包
安装脚本高优先级复核
Hook 实现高优先级复核
核心运行脚本最高优先级复核
文档片段检查是否会被自动执行
第三方或生成文件单独确认来源

5.3 计划文件可能遭遇污染

文件化规划的优势是持久化,风险也在于持久化。

如果 Agent 读取项目中的计划文件、日志或历史记录,需要防范:

  • 计划文件被恶意修改;
  • 外部输入通过计划文件注入指令;
  • 一个项目的计划被另一个任务读取;
  • 嵌套项目共享错误的计划根目录;
  • 计划状态被提前改为完成;
  • 旧任务状态影响新任务;
  • 多个 Agent 并发修改同一文件。

建议为计划文件增加:

任务 ID
工作区根目录
创建时间
最后修改时间
当前版本
文件摘要
写入者
状态变更记录

并确保恢复时同时检查:

计划文件
+ 工作区路径
+ 当前任务 ID
+ 执行日志
+ 文件摘要

5.4 多平台 Hook 适配容易产生行为差异

项目同时支持多个 Agent 或开发平台。不同平台的 Hook 机制可能存在差异:

  • 触发事件名称不同;
  • 输入格式不同;
  • 环境变量不同;
  • 当前工作目录不同;
  • 退出码语义不同;
  • 是否允许修改上下文不同;
  • 是否支持阻止后续执行不同。

因此,需要建立跨平台一致性测试矩阵:

能力平台 A平台 B平台 C平台 D
初始化计划通过/失败通过/失败通过/失败通过/失败
写入状态通过/失败通过/失败通过/失败通过/失败
中断恢复通过/失败通过/失败通过/失败通过/失败
停止门控通过/失败通过/失败通过/失败通过/失败
嵌套目录隔离通过/失败通过/失败通过/失败通过/失败

六、如何评价这份原始评测报告的数据质量?

这份原始报告的证据组织总体较好,但还存在几个需要改进的地方。

6.1 做得较好的地方

固定提交明确

报告提供了完整 Commit SHA:

9b7d0a007946ae7694216642fd5be78c2f13b6db

这使读者能够复核同一版本,避免因为仓库持续变化导致结论漂移。

对静态证据边界有明确说明

报告多次强调:

  • 未执行代码;
  • 未执行测试;
  • 未进行依赖扫描;
  • 静态命中需要人工复核;
  • 测试文件存在不等于测试通过。

这是比较重要的研究规范,能够减少过度解读。

风险样例可定位

报告给出了具体文件路径,而不是只提供抽象风险数量。例如:

.agents/skills/planning-with-files/scripts/inject-plan.sh
.agents/skills/planning-with-files/scripts/init-session.sh
tests/test_containment.py
tests/test_plan_attestation.py

文件级证据便于后续安排人工审阅和验证。

测试命名能够反映实际问题

从测试名称可以看出,项目关注了嵌套根目录、路径修复、Hook、编码、状态恢复和计划完整性等问题。这些方向与项目定位较匹配。

6.2 数据解释需要更加克制

文件数量不是质量评分

274 个源文件和 181 个 Shell 文件只能说明工程规模和语言构成,不能单独说明:

  • 代码质量;
  • 维护性;
  • 安全性;
  • 性能;
  • 架构先进程度。

AST 结构计数不能等同于复杂度

报告中的:

声明 89
分支 408
循环 141
异常路径 32

适合作为源码导航指标,不应被直接解释为:

  • 圈复杂度;
  • 缺陷概率;
  • 维护成本;
  • 性能瓶颈。

尤其是 Shell 语法经过词法或结构提取后,分支计数可能受到命令替换、条件表达式和脚本风格影响。

风险命中应区分测试与生产

当前风险样例大部分位于 tests/ 目录。报告虽然写明需要人工复核,但最好进一步增加:

生产可达命中
测试专用命中
构建和安装命中
示例命中
文档命中

这样更有利于技术负责人判断风险优先级。

“模块表面 broad”不等于模块耦合复杂

17 个一级模块根表示项目有多个顶层目录,但不能直接证明:

  • 模块职责清晰;
  • 内部依赖合理;
  • 组件可以独立部署;
  • 跨平台实现一致。

报告中已经写了“由一级模块根数量推导,不评价内部耦合”,这一点是正确的,建议在文章正文中继续保持。


七、建议的验证清单

1. 构建验证

记录以下信息:

  • 操作系统和版本;
  • Shell 类型和版本;
  • Python 版本;
  • Node.js 版本;
  • 包管理器版本;
  • 官方安装命令;
  • 官方测试命令;
  • 构建结果;
  • 失败日志;
  • 生成文件和临时文件。

2. 功能验证

至少覆盖:

  • 初始化任务;
  • 创建计划文件;
  • 读取当前计划;
  • 更新阶段状态;
  • 任务中断;
  • 任务恢复;
  • 嵌套项目隔离;
  • 计划完成检查;
  • 计划文件摘要;
  • 停止门控;
  • 关闭规划功能;
  • 多平台 Hook 行为。

3. 安全验证

建议测试:

测试场景预期结果
使用 ../ 访问计划根目录之外的文件被拒绝
使用符号链接绕过目录限制被拒绝
任务名包含空格和特殊字符正确处理
两个任务同时初始化不互相覆盖
两个 Agent 同时写入状态有锁或明确冲突处理
计划文件被外部修改能够发现或记录
Shell 参数包含特殊字符不产生额外命令
中断任务子进程和临时文件被清理
Windows 换行和编码结果一致
空计划、损坏计划返回可解释错误

4. 质量验证

补充确认:

  • 测试实际通过率;
  • 测试覆盖率;
  • 跳过测试的原因;
  • CI 是否执行所有关键路径;
  • 发布包是否包含测试和示例脚本;
  • 不同平台的脚本是否保持同步;
  • 依赖是否锁定;
  • 许可证文件是否完整;
  • 文档描述是否与当前实现一致。

八、最终评价

planning-with-files 是一个目标清晰、工程边界明确的 Agent 辅助项目。它没有试图解决所有模型能力问题,而是聚焦于一个非常具体的痛点:

如何让 AI Agent 在长任务中记住计划、保持进度,并在中断后继续工作。

从静态证据看,项目的优势主要包括:

  • 文件化规划思路简单易理解;
  • 具备多平台 Skill 适配;
  • 设计了计划初始化、注入、检查和停止门控流程;
  • 测试文件覆盖了多个真实边界场景;
  • 关注嵌套目录隔离、路径处理、编码和状态恢复;
  • 存在计划摘要或完整性校验相关逻辑;
  • 具备基础 CI 自动化。

主要风险和挑战包括:

  • Shell 文件数量较多;
  • 复杂控制流集中在关键脚本中;
  • 路径处理属于高敏感边界;
  • 多平台 Hook 可能出现行为差异;
  • 计划文件存在被污染或状态失真的可能;
  • 静态风险命中需要区分测试代码和实际执行路径;
  • 当前报告未提供测试通过率、覆盖率和运行时结果。

综合来看,可以将该项目评价为:

一个面向 AI 长任务的轻量级持久化规划工具,具有较强的实践价值和较清晰的技术方向;适合在隔离环境中开展功能、兼容性和安全验证,但当前静态证据不足以支持对生产稳定性和安全性的确定性判断。

最值得继续验证的不是“计划文件能否生成”,而是以下完整闭环:

任务初始化
  → 计划生成
  → 阶段执行
  → 状态写入
  → 测试记录
  → 中断恢复
  → 完成校验
  → 清理和审计

如果这条链路能够在不同平台、不同目录结构和异常场景下保持一致,planning-with-files 才真正具备作为 AI 编码代理长任务辅助组件的工程基础。