| name | long-horizon |
| description | 用一次长程自主运行执行一个定稿的目标——数小时的 agent 工作推完整个验收台账,人只出现在两道闸:运行前的 spec、运行后的 review。适用于 /long-horizon、「长程执行这个任务」「跑一个长程目标」,或在已有 `.long-horizon/` 工作区的仓库中恢复工作时。入口交互式反复迭代;运行由 fan-out 驱动、副作用被授权信封约束;进展只认证据;实时 report.html 以 DAG 呈现台账。 |
| metadata | {"short-description":"spec 定稿后的自主长程执行"} |
long-horizon
一个目标,两道人的闸,一次长跑。人和 agent 反复迭代 spec 直到签字;然后运行在授权信封内自主推进数小时、推完整个台账;然后人读 report 给出调整。编排上下文只派发和验证——不亲自执行。持久状态在 .long-horizon/<goal-slug>/,三道价值闸全程有效:入口(说不出验证方式的不得进入)、证据(进展只在验证后成立)、出口(停下来是设计出来的,不是失败)。
语言:聊天跟随用户;工作区文件跟随项目的文档语言。
Load-on-use:本文档里每个 /name 都是调用指令——做那类工作之前,先加载该 skill 的完整文档(Skill 工具,或读它的 SKILL.md);绝不凭一行 description 复刻行为。
工作区 —— .long-horizon/<goal-slug>/
- 一个 goal 一个目录,slug 命名;同时只有一个活跃 goal。任何恢复都先做身份核对:读
goal.md——如果它描述的不是你的 goal,停下来问人。
goal.md —— 冻结的 spec:goal、non-goals、invariants、每条 Done-when 附可运行检查,以及授权信封。改它必须经人重新定稿,绝不能是顺手为之。
ledger.json —— 验收台账:{id, desc, verify, passes, evidence, deps, discovered-from}。每一项生来 passes: false。
log.md —— append-only:决策、死胡同、派发记录。失败的尝试留在里面——它们是证据。
next.md —— 恢复指针:什么在飞行中、接下来什么就绪。
report.html —— 实时监督视图;契约见下。
- 工作区不进 git:入口阶段就把它加进 .gitignore(以及格式化工具的忽略清单)——被 track 的工作区会污染每个工作分支的 diff。耐久性靠代码 commit、毕业蒸馏和 report。毕业时经
/to-ctx 蒸馏,然后归档或删除该目录。
第一道闸 —— Spec(交互式;要迭代多久就迭代多久)
- 把目标交给
/ctx-grill。与用户反复迭代,直到 spec 立得住:
- 每条 Done-when 都说得出可运行的检查——没有检查就不得进入;
- non-goals 和 invariants 写明;
- 授权信封——运行期无人值守时允许做什么。默认:在工作分支 commit、开 PR、push 自己的分支——允许;merge、删除工作区之外的东西、对外发送任何内容、花钱——禁止。收紧或放宽只在此处、显式进行。
- 验证配置——问一次:哪些检查由编排者自己重跑、哪些验收项配黑盒验证 agent、验证者用什么档位的模型(默认中档模型);
- 初始台账,带依赖关系。
- 一坐就能干完的目标拒绝进入——正常做掉即可。
- 签字后:写工作区,开始运行。
运行 —— 自主,数小时
- **只编排,不执行。**加载
/fan-out,把台账项写成任务契约派给 subagent;自己的上下文只保留 spec、台账、证据摘要和决策——探索噪声由 worker 吸收。这是结构性要求而非可选项:整个台账的执行量装不进一个上下文窗口。
- 按 DAG 调度:派发就绪集(依赖全部通过的项);独立项并行——会同时改同一仓库时用 worktree 隔离;高耦合的项簇交给同一个 worker。
- 先验证再翻位:worker 的说法永远不是证据。机械检查(测试、lint、构建)自己重跑;行为性验收交给黑盒验证 subagent(用 spec 定的档位),它只看产出物和验收标准。
- 一次失败只换来一次重写,换不来原样重来:派出去的项失败时——worker 报错,或验证否掉了它的说法——只重派一次,且契约必须围绕失败证据重写:试过什么、哪项检查没过、怎么没过。换角度或换 worker;绝不把同一份契约原样再发一遍。每项每轮派发只有这一次战术重试;重试再失败,该项按「没动」计入停滞账,失败写进
log.md——本轮不再有第三次。
- 每翻一位就刷新 report 的数据块——运行期间 report 就是人的实时仪表盘。
- 发现新问题是预期内的:新问题记为新台账项(
discovered-from)加入调度。会改变 spec 方向的问题记为 blocked 项并写下待答问题——不依赖它的所有分支继续推进。
- 若 harness 有原生 goal 机制,喂给它:「台账全部 passes 或 blocked,或 N 小时后停」。
- 停止条件:全部通过;剩余项全部悬在 blocked 上;连续两轮派发(含战术重试)台账不动(停滞——绝不做第三次一模一样的尝试);或预算耗尽。收尾必产出最终 report 和一份
/handoff。
第二道闸 —— Review
人读 report、给出评论。调整落为 spec 修正或台账修改——这是验收行可以被改写或删除的唯一通道。下一次运行从工作区恢复,先做身份核对。
中断是可幸存的,但不是节奏
假设任何时刻都可能是最后一刻:上下文死亡、崩溃、预算截断。新的编排者读工作区、核对 goal.md 身份、从 ledger.json + next.md 恢复。这些文件为此而存在——不是为了每做几项就把目标交还给人。
Report —— 契约,而非模板
report.html 由模型自作:怎么表达清楚就怎么设计,随模型进步随时整体重画——它可丢弃、可从状态再生。不可协商:
- 视图,绝非事实源:生成是单向的;展示的一切必须先存在于状态文件。必须展示:目标及其 Done-when;每个台账项及其状态;依赖结构必须画成图——关键路径和阻塞割点一眼可见,不能只列文字;blocked 项与待答问题(醒目位置);关键决策;最后更新时间与 session 计数。
- 自包含:单文件、
file:// 直接打开、无外部请求。
- 数据与渲染分离:只嵌一个数据块;日常刷新只碰数据块,不动标记。
规则
- 信封在所有阶段都是硬边界:不做不可逆的事,不越界。
- 台账行对 agent 写保护:只能翻
passes、追加 evidence、新增条目;改写或删除只发生在 review 阶段、由人执行。
passes 翻在验证通过时,不翻在代码写完时。
- 聊天中与工作区文件矛盾的纠正必须同回合写回文件——否则过期文件会赢。
- 依赖方向:可以使用
/ctx-grill、/fan-out、/handoff、/to-ctx;long-horizon 位于图的最顶端,没有 skill 会调用它。