一个松散、还没成形的想法来了:它太大,一个代理会话装不下,而且裹在迷雾里——从这里到目的地的路还看不见。寻路要做的是找到那条路,而不是朝着目的地猛冲。本技能把这条路画成仓库议题跟踪器上的一张共享地图,然后一张一张地处理它的决策工单(那些解决结果是一个决定、而不是一段待执行的构建切片的疑问),直到路线清楚为止。
目的地因工作而异;而给它命名是绘制地图的第一个动作:它决定了每一张工单的形态。目的地可能是一份要交出去并反复迭代的规格,一个在规划开始前就要锁定的决定,或者一处就地完成的改动,比如数据结构迁移。地图不挑领域:工程工作、课程内容,凡是长成这个形状的都可以。
先规划,不要动手
Wayfinder 默认只做规划:每张工单解决一个决定;等路清楚了,地图就算做完——在有人真正去做那件事之前,没有什么再要定的了。那种想直接动手的冲动,通常正是你已经走到地图边缘、该交接出去的信号。一项工作可以在自己的 Notes 里覆盖这条默认规则,把执行也纳入地图本身;但没有这样的说明时,就产出决定,不要产出交付物。
按名字指代
每张地图、每张工单都是一个议题,因此它有一个名字:它的标题。在人类会读到的一切地方(讲述、地图的 Decisions so far),都用这个名字来指代它,绝不要只写一个光秃秃的 id、编号或 slug。一堵由 #42, #43, #44 砌成的墙没法读;名字一眼就能看懂。id 和 URL 并不会消失:名字会把链接包在里面,但它们是待在名字_里面_,绝不代替名字。
地图
地图是本仓库议题跟踪器上的单个议题,打上 wayfinder:map 标签,是这份工作的规范产物。它的工单是地图的子议题。
地图是一份索引,不是存储。它列出已经做出的决定,并指向承载细节的工单;一个决定只存在一个地方,也就是它的工单,所以地图从不复述决定,只给出要点和链接。
地图、它的子工单、阻塞关系与前沿查询在物理上放在哪里,取决于具体的跟踪器。 议题跟踪器应该已经提供给你了。如果没有,请告诉用户运行 /setup-matt-pocock-skills。查阅跟踪器文档里「寻路操作」(Wayfinding operations)一节,看_这个_仓库是怎么表达它们的。如果没有提供任何跟踪器,就默认使用本地 Markdown 跟踪器。
地图正文
整张地图的低分辨率视图,每个会话加载一次。未关闭的工单不列在这里:它们是未关闭的子议题,靠查询找到。
markdown## Destination <what reaching the end of this map looks like: the spec, decision, or change this effort is finding its way to. One or two lines; every session orients to it before choosing a ticket.> ## Notes <domain; skills every session should consult; standing preferences for this effort> ## Decisions so far <!-- the index: one line per closed ticket, enough to judge relevance, then zoom the link for the detail the ticket holds --> - [<closed ticket title>](link): <one-line gist of the answer> ## Not yet specified <!-- see "Fog of war": in-scope fog you can't ticket yet; graduates as the frontier advances --> ## Out of scope <!-- see "Out of scope": work ruled beyond the destination; closed, never graduates -->
工单
每张工单都是地图的子议题;跟踪器上的议题 id 就是它的身份。它的正文是一个问题,体量按一次 100K token 的代理会话设计:
markdown## Question <the decision or investigation this ticket resolves>
每张工单都带一个 wayfinder:<type> 标签,取值是 research、prototype、grilling、task 之一(见工单类型)。
一个会话要认领一张工单,就把它指派给驱动这张地图的开发者,而且在做任何工作之前就要先做,这样并发的会话就会跳过它。那个被指派者_就是_认领:一张未关闭、无人指派的工单就是没被认领的。
阻塞关系使用跟踪器原生的依赖关系:这一点很关键,因为它会在跟踪器自己的界面里把前沿_可视化_地画出来,让人不用打开地图就能看到哪些工单可以拿。只有不具备原生阻塞能力的跟踪器,才退回用正文约定。当所有阻塞某张工单的工单都已关闭时,这张工单就是已解除阻塞的;前沿就是那些未关闭、已解除阻塞、无人认领的子工单,也就是已知世界的边缘。
答案不属于正文;它在工单解决时被记录下来(见沿地图推进)。解决工单期间产出的素材,从议题里链接过去,不要粘贴进来。
工单类型
每张工单要么是 HITL(human in the loop,_和_一位能替自己发言的人一起做事),要么是 AFK,由代理独自驱动。HITL 工单只能通过那场实时交流来解决;代理绝不替人站在人的那一侧(一个自问自答的盘问代理已经破坏了这一点)。
- 调研(AFK):阅读文档、第三方 API,或者知识库这样的本地资源,把某个决定正等着的事实翻出来。由调用 Skill 工具、传入 "research" 的子代理来解决。当所需的知识在当前工作目录之外时使用。
- 原型(HITL):做一个廉价、粗糙、具体的产物供人反应(一份提纲、一个粗略的方案、一个桩,或者界面/逻辑代码),以此抬高讨论的保真度;调用 Skill 工具时传入 "prototype"。原型会作为素材链接到议题里。当「它该长什么样」或「它该怎么表现」是核心问题时使用。
- 盘问(HITL):对话。默认情况。永远要调用 Skill 工具两次,分别传入 "grilling" 和 "domain-modeling"。
- 任务(HITL 或 AFK):在做出一项_决定_之前必须先完成的人工操作:没有什么可决定、可原型化、可研究的,但在它做完之前讨论就被卡住。比如注册某个服务,好判断它的 API 行不行;开通访问权限;搬运数据,好看清它的形状。这是唯一一种_动手做_而不是做决定的类型,它靠解除某个决定的阻塞来挣得自己的位置,而不是靠把目的地直接交付出来。代理能独自驱动就独自驱动(AFK);否则就给人一份精确的清单(HITL)。工作做完即算解决;答案记录做了什么,以及后续工单依赖的任何事实(凭据放在哪里、新的 URL、行数)。
战争迷雾
地图是_故意_不完整的:还没看见的东西就不要画。在活工单之外,躺着的是战争迷雾:那些你能感觉到要来、但还钉不下来的决定与调研,只能模糊地看见,因为它们悬在仍然开放的问题上。解决一张工单会清除它前方的迷雾,把如今说得清的东西升格成新的工单,一次一张,直到通往目的地的路清清楚楚、一张工单也不剩。
地图的 Not yet specified 一节,就是写下那片模糊视图的地方:你怀疑存在的问题、以后要回头再看的地方。它是_朝着_目的地、尚未被发现的前沿:这里的一切都在范围内,只是还没有清晰到能立成工单。你可以写得很粗略,也可以写得很完整,取决于当前能看清多少;它同时是给协作者看的路标,让人知道这项工作正往哪里去。
是迷雾还是工单? 判据是你现在能不能精确地说出这个问题,_而不是_你现在能不能回答它。
- 问题已经足够清晰时,就立成工单,哪怕它被阻塞、你现在还动不了它。
- 还说不了那么清晰时,就留在 Not yet specified 里。不要预先就把迷雾切成工单大小的碎块:它比一张工单更粗,等前沿推进到那里时,一小片可能升格成好几张工单,也可能一张都不升格。
Not yet specified 不包括已经决定的事(Decisions so far)、已经是活工单的事,以及不在范围内的事(见下一节)。
Out of scope
迷雾只会朝着_目的地_的方向聚拢。目的地定住范围,所以超出它的工作就是不在范围内:它不是迷雾,也不属于 Not yet specified。它在地图上有自己的一节 Out of scope:你有意识地排除在_本次_工作之外的事情。决定它落在这里的,是范围,而不是清晰度。
不在范围内的工作永远不会升格(前沿到目的地为止),所以只有目的地被重画时它才会回来,而且那时它是一项全新的工作,不是接着上次做。
把某件事排除出范围是一次划定范围的动作,不是路线上的一步。当一张已经存在的工单被发现落在目的地之外(绘制时划错了范围,或者被某次解决暴露出来),就关闭它(关闭的工单毫无疑问不在前沿上),并在 Out of scope 一节留下一行:要点,加上它为什么不在范围内,并链接那张已关闭的工单。它不会进入 Decisions so far——那一节记录的是真正走过的路线;范围的边界不是路线上的一个步骤。
调用方式
两种模式。无论哪种,每个会话最多只解决一张工单,调研类工单除外。
绘制地图
用户带着一个还不成熟的想法发起。
- 给目的地命名。 调用 Skill 工具两次,分别传入 "grilling" 和 "domain-modeling",把这张地图正寻路前往的东西钉下来:那份规格、那个决定,或者那处改动。目的地定住范围,所以先把它定下来。
- 把前沿画出来。 再盘问一次,这次广度优先:在整个空间里铺开,而不是在某一根线上深挖,把开放的决定和现在就能迈的第一步翻出来。如果这样没有翻出任何迷雾(通往目的地的路已经清楚,整段旅程小到一个会话就能走完),你就不需要地图。停下来,问用户想怎么继续。
- 创建地图(标签
wayfinder:map):填好 Destination 和 Notes,Decisions so far 留空,把迷雾草草勾进 Not yet specified。 - 把现在就能说清的工单建出来,作为地图的子议题;然后在第二遍里连阻塞边(议题要先有 id 才能互相引用)。连边会把它们分到前沿和被阻塞两堆;你暂时还说不出的一切留在迷雾里:也就是 Not yet specified 一节。
- 放出调研子代理。 对你刚创建的每张
research工单,各起一个子代理,调用 Skill 工具、传入 "research" 并行解决它,把它的发现记在一个用完即弃的research/<name>分支上,并从工单里留一个上下文指针指过去。 - 到此为止:绘制地图是一个会话的活;它不顺手解决任何东西。
沿地图推进
用户带着一张地图(URL 或编号)发起。工单是可选的:不给工单,就由你来挑下一个要做的决定,而不是用户来挑。
- 加载地图:那个低分辨率视图,不是每张工单的正文。
- 选工单。如果用户点名了一张,就用它。否则按顺序取前沿上的第一张。认领它:在任何工作开始之前,把它指派给自己。
- 解决它。按需放大:随时取来任何相关或已关闭工单的完整正文;
## Notes一节里点名了哪些技能,就为哪些技能调用 Skill 工具。拿不准时,调用 Skill 工具两次,分别传入 "grilling" 和 "domain-modeling"。 - 记录解决结果:把答案作为解决评论发出去,关闭该议题,并往地图的 Decisions so far 里追加一个上下文指针。
- 把新冒出来的工单加进去(先建后连);答案让哪些迷雾变得说得清,就把那些升格掉,并从 Not yet specified 里清掉每一片已升格的迷雾,让它只作为新工单存在。如果答案揭示出某张工单(这张或另一张)落在目的地之外,就把它排除出范围,而不要在路线上解决它。如果这个决定让地图的其他部分失效,就更新或删掉那些工单。
用户可能会并行推进已解除阻塞的工单,所以要预料到别的会话会同时改动跟踪器。


