Wayfinder
一个事项太大,单次 Agent 会话装不下,且从当前状态到目的地的路线仍笼罩在迷雾中。Wayfinder 在仓库内建立一张共享地图,把当前能够说清的问题记录为决策票,然后持续推进地图前沿,直到全部票解决、迷雾清空,通往目的地的路线清晰。
目的地可以是一份可进入 to-prd 的完整决策、实施前必须锁定的关键选择,或一次需要跨多轮确定路径的迁移。第一步始终是命名目的地,因为它决定每张票是否属于当前地图。
只规划,不实施
Wayfinder 默认只解决决策。每张票产出答案,不交付最终功能;当问题已经变成明确的构建工作时,说明它越过了地图边缘,应交给 to-prd、to-api、to-task 或 impl。只有地图的 Notes 明确要求边规划边执行时,才把实施纳入地图。
地图与决策票
使用当前仓库既有的本地 Markdown 布局:
docs/scratch/<NN>-<中文需求名称>/
├── WAYFINDER.md
└── wayfinder/
├── 01-<中文问题名称>.md
└── 02-<中文问题名称>.md
沿用已有需求目录;没有对应目录时,按 docs/scratch/ 当前最大编号加一创建。地图和票的名称使用项目 CONTEXT 中的统一术语。
地图
WAYFINDER.md 是唯一权威地图:它是索引,不是答案仓库。每个决策的完整答案只存在于对应决策票;地图只保留一句摘要和相对链接。
# <地图名称>
## Destination
<到达地图终点时得到什么;一至两行>
## Notes
<领域、每轮必须加载的项目知识、是否允许执行、长期偏好>
## Decisions so far
- [<已关闭决策票名称>](./wayfinder/01-xxx.md):<答案的一句话摘要>
## Not yet specified
<确定仍在范围内、但目前还无法精确表述为问题的迷雾>
## Out of scope
<已明确越过目的地的事项及原因>
决策票
每张票只解决一个能够在一次会话内闭环的问题:
# <问题名称>
- Type: research | prototype | ask-me | task
- Status: open | claimed | resolved
- Blocked by: <相对链接列表;无依赖时写 none>
## Question
<本票要回答的精确问题>
## Resolution
<解决时追加答案;未解决时留空>
文件编号是稳定排序,不代替名称。面向用户或地图引用决策票时始终使用带链接的完整名称,不用裸编号。
Blocked by 中所有票均为 resolved 时,本票才解除阻塞。地图前沿是所有 open、已解除阻塞的票,按文件编号排序。开始工作前先把所选票改为 claimed;结束时写入 Resolution 并改为 resolved。
地图前沿只计算决策票。一张 ask-me 票内部的设计树另有设计树前沿,由 ask-me 维护。设计树前沿为空只表示本票的 HITL 决策树走完,不表示地图前沿为空,也不表示地图完成。
票类型
每张票要么需要人参与(HITL),要么可由 Agent 独立完成(AFK)。先尽可能按 AFK 自行解决;只有仍存在必须由用户参与的分支时,才进入 HITL:
- research(AFK):读取代码、项目知识、官方文档或外部资料,补齐某个决策依赖的事实。结论必须附可复核的文件位置或来源。
- prototype(HITL 或 AFK):制作便宜、粗糙、可反应的原型,用于回答“应该长什么样”或“行为是否合适”。能从需求、事实和既有约束判断时由 Agent 自行解决;必须取得用户反馈时,通过
ask-me完成相关决策后再解决本票,并把原型路径链接到 Resolution。 - ask-me(HITL):通过
ask-me围绕本票的问题完成决策树。Agent 不替用户回答需要用户作出的决定。 - task(HITL 或 AFK):在决策前必须先完成、但本身没有要决定内容的手工事项,例如取得访问权限或迁移一份样本数据。Agent 能执行时直接执行;确需用户操作或授权时,通过
ask-me收口解除阻塞的路径。它只为解除决策阻塞,不交付目的地。
事实查找、代码读取、资料调研、可执行操作和能从既有约束唯一推出的答案都由 Agent 完成。不得把“向用户提问更省事”当作 ask-me 的理由。只有答案取决于用户偏好、业务取舍、风险接受度或授权时,才需要用户决策。
迷雾与范围
地图故意不完整。当前能够精确表述的问题建立为决策票;只能看见方向、还无法精确提问的内容留在 Not yet specified。判断标准是“现在能否把问题说准确”,而不是“现在能否回答”。
解决一张票后,重新检查迷雾:已经能够精确表述的部分毕业为新票,并从 Not yet specified 删除,使其只保留一个权威位置。
目的地之外的事项写入 Out of scope,不会随着地图前沿推进而重新出现。若已有票被证明超出范围,关闭该票,在 Resolution 说明原因,并只在 Out of scope 留一句带链接的摘要;不要把它记入 Decisions so far。
持续推进
一次调用启动一个持续循环,而不是只处理一张票。每解决一张票都重新读取最新地图、更新迷雾和依赖,然后从已解除阻塞的 open 票中选择文件编号最小者。除非用户明确指定另一张已解除阻塞的票,否则始终按此顺序推进。
执行只在以下位置完成或暂停:
- 所有票均为
resolved,且 Not yet specified 已清空,地图完成; - 当前需要用户决策:立即进入本票的
ask-me决策树,等待用户回答;决策树完成后把结果写回本票,并在同一轮 Wayfinder 流程中恢复循环,无需用户再次调用 Wayfinder; - 所有未解决票都被无法由 Agent 解除的外部事实、操作或授权阻塞:把已尝试事项、确切阻塞和恢复条件写入对应票,再向用户收口解除阻塞所需的决策或动作。用户处理后自动恢复循环。
等待用户回答只是循环的暂停点,不是 Wayfinder 的完成点。只要地图尚未满足完成条件,就保持当前地图为待继续事项;不得在一张票解决后、一次 ask-me 结束后或新票生成后宣告流程结束。
调用方式
建图
用户带着一个仍有迷雾的大事项调用:
- 命名目的地:收口地图最终要得到的结果,用它划定范围。
- 广度优先扫描:横向发现当前已经能够精确提问的决策、依赖关系和仍无法提问的迷雾,不深入解决任何一张票。若路线已经完全清晰且单次会话足以容纳,停止建图并说明可以直接进入相应工作流。
- 创建地图:写入 Destination、Notes、Not yet specified 和 Out of scope,保持 Decisions so far 为空。
- 创建当前可描述的票:先创建全部文件,再写入
Blocked by,得到可工作的地图前沿。 - 开始推进:创建完成后立即进入“推进地图”的持续循环,不在建图处停止。
推进地图
用户带着 WAYFINDER.md 路径调用,或建图完成后自动进入;用户可以指定起始票,也可以让 Agent 选择:
- 只加载地图的低分辨率视图,不一次性读取全部票。
- 用户指定票时先确认其已解除阻塞;未指定时选择地图前沿中编号最小的票。先将其改为
claimed。 - 读取本票、相关项目知识及真正影响答案的已关闭票,按票类型解决问题。
- 把完整答案写入 Resolution,改为
resolved;在地图 Decisions so far 追加一句摘要和相对链接。 - 根据答案新增或调整决策票、依赖和迷雾;被证明越界的内容移入 Out of scope。
- 回到第 1 步并处理下一张票。若地图前沿为空但仍有迷雾,先利用已得答案重新扫描迷雾;确实无法精确提问时记录缺失事实和恢复条件。若地图前沿和迷雾都为空,地图完成,按实际需要交给
to-prd、to-api、to-task或impl。
处理 ask-me 票时,把它当作循环中的子流程:完成该票的设计树后,将完整决策树或其链接写入 Resolution,更新地图,然后直接选择下一张地图前沿票。不要把 ask-me 的最终输出当作 Wayfinder 的最终输出;不要把设计树前沿为空当成地图完成条件。
并发推进不同决策票时,每个执行上下文必须先认领不同的地图前沿票,并只修改自己的票;地图索引更新需要基于最新文件合并,不能覆盖其他会话新写入的决策。