Skill Learning

wayfinder

1. Bilingual SKILL.md

左右滑动可直接切换英文版与中文版;两种语言按段落自动对齐。英文中的蓝色虚线词语可点击查看解释。共标记 17 处。

入口 skill:wayfinder左右滑动切换语言 · 段落位置自动对齐
A loose idea has arrived, too big for one agent session, and : the way from here to the **destination** isn't visible yet. Wayfinding is about . This skill charts the way as a **shared map** on the repo's issue tracker, then works its **decision tickets** (questions whose resolution is a decision, not slices of a build to execute) one at a time until the route is clear.
The destination varies per effort, and : it shapes every ticket. It might be a spec to hand off and iterate on, a decision to lock before planning starts, or a change made in place like a data-structure migration. The map is domain-agnostic: engineering work, course content, whatever fits the shape.
##
Wayfinder is **planning** by default: each ticket resolves a decision, and the map is done when the way is clear, with nothing left to decide before someone goes and does the thing. The pull to just do the work is usually the signal you've reached the edge of the map and it's time to hand off. An effort can override this in its **Notes**, carrying execution into the map itself, but absent that, produce decisions, not deliverables.
## Refer by name
Every map and ticket is an issue, so it has a **name**: its title. In everything the human reads (narration, the map's Decisions-so-far), refer to it by that name, never by a bare id, number, or slug. A wall of `#42, #43, #44` is illegible; names . The id and URL don't vanish; a name wraps its link, but they ride _inside_ the name, never stand in for it.
## The Map
The map is a single issue on this repo's issue tracker, labelled `wayfinder:map`, the canonical artifact. Its tickets are child issues of the map.
The map is . It lists the decisions made and points at the tickets that hold their detail; a decision lives in exactly one place, its ticket, so the map never restates it, only gists it and links.
**Where the map, its child tickets, blocking, and frontier queries physically live is tracker-specific.** The issue tracker should have been provided to you. If not, tell the user to run `/setup-matt-pocock-skills`. Consult the tracker doc's "Wayfinding operations" section for how _this_ repo expresses them. If no tracker has been provided, default to the local-markdown tracker.
### The map body
The whole map , loaded once per session. Open tickets are **not** listed: they are open child issues, found by query.
```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 "": 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 --> ```
### Tickets
Each ticket is a **child issue** of the map; the tracker's issue id is its identity. Its body is the question, sized to one 100K token agent session:
```markdown ## Question <the decision or investigation this ticket resolves> ```
Each ticket carries a `wayfinder:<type>` label, one of `research`, `prototype`, `grilling`, `task` (see [Ticket Types](#ticket-types)).
A session **claims** a ticket by assigning it to the dev driving the map, , so concurrent sessions skip it. That assignee _is_ the claim: an open, unassigned ticket is unclaimed.
Blocking uses the tracker's **: essential because it renders the frontier _visually_ in the tracker's own UI, so the human sees what's takeable without opening the map. Only a tracker that lacks native blocking falls back to a body convention. A ticket is **unblocked** when every ticket blocking it is closed; the **frontier** is the open, unblocked, unclaimed children, .
The answer isn't part of the body; it's recorded on resolution (see [Work through the map](#work-through-the-map)). Assets created while resolving a ticket are linked from the issue, not pasted in.
## Ticket Types
Every ticket is either **HITL** (human in the loop, worked _with_ a human who speaks for themselves) or **AFK**, driven by the agent alone. A HITL ticket only resolves through that live exchange; the agent never of it (a grilling agent that answers its own questions has broken this).
- **Research** (AFK): Reading documentation, third-party APIs, or local resources like knowledge bases to surface a fact a decision waits on. Resolved by a subagent that calls the Skill tool with "research". Use when knowledge outside the current working directory is required. - **Prototype** (HITL): by making a cheap, rough, concrete artifact to react to (an outline, a rough take, a stub, or UI/logic code) by calling the Skill tool with "prototype". Links the prototype as an asset. Use when "how should it look" or "how should it behave" is the key question. - **Grilling** (HITL): Conversation. The default case. Always call the Skill tool twice, for "grilling" and "domain-modeling". - **Task** (HITL or AFK): Manual work that must happen before a _decision_ can be made: nothing to decide, prototype, or research, but the discussion is blocked until it's done. Signing up for a service so its API can be judged, provisioning access, moving data so its shape can be seen. This is the one type that _does_ rather than decides, and it earns its place by unblocking a decision, not by delivering the destination. The agent drives it alone where it can (AFK); otherwise it hands the human a precise checklist (HITL). Resolved when the work is done; the answer records what was done and any resulting facts (credentials location, new URLs, row counts) later tickets depend on.
##
The map is _deliberately_ incomplete: don't chart what you can't yet see. Beyond the live tickets lies the ****: the dim view of decisions and investigations you can tell are coming but can't yet pin down, because they hang on questions still open. Resolving a ticket clears the fog ahead of it, graduating whatever's now specifiable into fresh tickets, one at a time, until the way to the destination is clear and no tickets remain.
The map's **Not yet specified** section is where that dim view is written down: the suspected question, the area to revisit later. It's the undiscovered frontier _toward_ the destination: everything here is in scope, just not sharp enough to ticket. Write as loosely or as fully as the view allows; it doubles as a signpost for collaborators reading where the effort is headed.
**Fog or ticket?** The test is whether you can state the question precisely now, _not_ whether you can answer it now.
- **Ticket when** the question is already sharp, even if it's blocked and you can't act on it yet. - **Not yet specified when** you can't yet phrase it that sharply. Don't pre-slice the fog into ticket-sized pieces: it's coarser than a ticket, and one patch may graduate into several tickets, or none, once the frontier reaches it.
**Not yet specified** excludes what's already decided (Decisions so far), what's already a live ticket, and what's out of scope (the next section).
## Out of scope
Fog only ever gathers _toward_ the destination. The destination fixes the scope, so work beyond it is **out of scope**: it isn't fog, and it doesn't belong in **Not yet specified**. It gets its own **Out of scope** section on the map: work you've consciously ruled out of _this_ effort. Scope, not sharpness, lands it here.
Out-of-scope work never graduates (the frontier stops at the destination), so it returns only if the destination is redrawn, and then as a fresh effort, not a resumption.
Ruling something out of scope is a scoping act, not a step on the route. When a ticket that already exists turns out to sit past the destination (mis-scoped in while charting, or exposed by a resolution), **close it** (a closed ticket is unambiguously off the frontier) and leave one line in the **Out of scope** section: the gist plus why it's out of scope, linking the closed ticket. It stays out of **Decisions so far**, which records the route actually walked; a scope boundary isn't a step on it.
## Invocation
Two modes. Either way, **never resolve more than one ticket per session**, with the exception of research tickets.
### Chart the map
User invokes with a loose idea.
1. **Name the destination.** Call the Skill tool twice, for "grilling" and "domain-modeling", to pin down what this map is finding its way to: the spec, decision, or change. The destination fixes the scope, so it's settled first. 2. **Map the frontier.** Grill again, **** this time: fan out across the whole space rather than deep on any one thread, surfacing the open decisions and the first steps takeable now. **If this surfaces no fog** (the way to the destination is already clear, the whole journey small enough for one session), you don't need a map. Stop and ask the user how they'd like to proceed. 3. **Create the map** (label `wayfinder:map`): Destination and Notes filled in, Decisions-so-far empty, the fog sketched into **Not yet specified**. 4. **Create the tickets you can specify now** as child issues of the map, then wire blocking edges in a **second pass** (issues need ids before they can reference each other). Wiring sorts them into the frontier and the blocked; everything you can't yet specify stays in the fog: the **Not yet specified** section. 5. **Fire the research subagents.** For each `research` ticket you just created, spin up a subagent that calls the Skill tool with "research" to resolve it in parallel, capturing its findings on a throwaway `research/<name>` branch with a context pointer from the ticket. 6. Stop: charting is one session's work; it hand-resolves nothing.
### Work through the map
User invokes with a map (URL or number). A ticket is **optional**: without one, you pick the next decision, not the user.
1. Load the **map**: the low-res view, not every ticket body. 2. Choose the ticket. If the user named one, use it. Otherwise take the first frontier ticket in order. **Claim it**: assign it to yourself before any work. 3. Resolve it. **Zoom as needed**: fetch the full body of any related or closed ticket on demand; call the Skill tool for whichever skills the `## Notes` block names. If in doubt, call the Skill tool twice, for "grilling" and "domain-modeling". 4. Record the resolution: post the answer as a **resolution comment**, **close** the issue, and **append a context pointer** to the map's Decisions-so-far. 5. Add newly-surfaced tickets (); graduate any fog the answer has made specifiable, clearing each graduated patch from **Not yet specified** so it lives only as its new ticket. If the answer reveals that a ticket (this one or another) sits beyond the destination, **rule it out of scope** rather than resolving it on the route. If the decision invalidates other parts of the map, update or delete those tickets.
The user may run unblocked tickets in parallel, so expect other sessions to be editing the tracker concurrently.
一个尚未成形的想法出现了,它大到单个 agent 会话容纳不下,又被迷雾包围:从这里通往**目的地(destination)**的道路还看不见。寻路(Wayfinding)关注的是找出这条路,而不是径直冲向目的地。这个技能把道路绘制成仓库 issue tracker 上的**共享地图(shared map)**,再逐一处理其中的**决策工单(decision tickets)**。这些工单要解决的是问题对应的决策,而不是待执行的构建切片,直到路线清晰。
每项工作的目的地都不相同,而为它命名是绘图的第一步:它会塑造每张工单。目的地可能是一份要交接并持续迭代的规格,也可能是规划开始前必须锁定的决策,或是像数据结构迁移那样就地完成的变更。地图与领域无关:工程工作、课程内容,任何符合这种形态的事情都可以。
## 只规划,不执行
Wayfinder 默认做的是**规划**:每张工单解决一个决策;当道路已经清晰,且在某个人真正动手之前已没有剩余决策,地图就完成了。想要直接做工作的冲动,通常意味着你已经抵达地图边缘,该交接了。某项工作可以在自己的 **Notes** 中覆盖这条默认规则,把执行也纳入地图;但若没有明确覆盖,就应产出决策,而不是交付物。
## 用名称引用
每张地图和工单都是 issue,因此都有一个**名称**,也就是它的标题。在人类会阅读的一切内容里(叙述、地图的 Decisions-so-far),都要用名称引用,绝不能只写裸 id、编号或 slug。满墙的 `#42, #43, #44` 无法阅读;名称则能一眼看懂。id 和 URL 并不会消失;名称包裹着链接,但它们位于名称_内部_,绝不能取代名称。
## 地图
地图是这个仓库 issue tracker 上的一条 issue,带有 `wayfinder:map` 标签,是规范产物。地图的工单都是它的子 issue。
地图是**索引**,不是存储库。它列出已经做出的决策,并指向保存细节的工单;一个决策只存在于一个位置,也就是它自己的工单。因此地图绝不复述决策,只给出摘要并链接过去。
**地图、子工单、阻塞关系和 frontier 查询实际位于何处,由 tracker 决定。** 你本应已获得 issue tracker 配置;若没有,让用户运行 `/setup-matt-pocock-skills`。查阅 tracker 文档的 “Wayfinding operations” 一节,了解_这个_仓库如何表达这些操作。如果没有提供 tracker,默认使用 local-markdown tracker。
### 地图正文
这是整张地图的低分辨率视图,每个会话只加载一次。地图**不会**列出开放工单:它们是开放的子 issue,通过查询找到。
```markdown ## 目的地 <抵达地图终点时应呈现什么:本项工作正在寻找通往哪份规格、哪项决策或哪次变更的道路。用一两行说明;每个会话在选择工单前都要先以此校准方向。> ## 备注 <领域;每个会话都应查阅的技能;本项工作的长期偏好> ## 到目前为止的决策 <!-- 索引:每张已关闭工单占一行,信息足够判断相关性;随后可放大链接,查看工单保存的细节 --> - [<已关闭工单标题>](link): <答案的一行摘要> ## 尚未具体化 <!-- 参见“战争迷雾”:范围内但暂时还无法建票的迷雾;随着 frontier 前进而逐步转化 --> ## 超出范围 <!-- 参见“超出范围”:被判定处在目的地之外的工作;已关闭,永不转化 --> ```
### 工单
每张工单都是地图的**子 issue**;tracker 的 issue id 就是它的身份。正文只有问题,其规模应适合一个 100K token 的 agent 会话:
```markdown ## 问题 <这张工单要解决的决策或调查> ```
每张工单带有一个 `wayfinder:<type>` 标签,类型是 `research`、`prototype`、`grilling`、`task` 之一(参见 [工单类型](#ticket-types))。
一个会话要认领工单,必须在开展任何工作**之前**,**首先**把它指派给驱动地图的开发者,这样并发会话就会跳过它。该 assignee _就是_认领标记:开放且未分配的工单就是无人认领。
阻塞使用 tracker 的**原生**依赖关系。这一点至关重要,因为原生关系会在 tracker 自己的 UI 中把 frontier _可视化_,人类无需打开地图就能看见哪些工单可以领取。只有缺乏原生阻塞能力的 tracker 才退回正文约定。当所有阻塞某张工单的工单都已关闭时,它就是**未阻塞(unblocked)**的;**frontier** 是开放、未阻塞且无人认领的子工单,也就是已知范围的边缘。
答案不属于正文;它会在解决工单时记录(参见 [沿地图推进](#work-through-the-map))。解决工单期间创建的资产应从 issue 链接出去,而不是直接粘贴进去。
## 工单类型
每张工单要么是 **HITL**(human in the loop,由一个能代表自己发言的人类_共同_完成),要么是由 agent 独立驱动的 **AFK**。HITL 工单只能通过实时交流解决;agent 永远不能代替人类回答属于人类的一侧(一个自己回答自己问题的 grilling agent 已经破坏了规则)。
- **Research**(AFK):阅读文档、第三方 API 或知识库等本地资源,以找出某个决策正在等待的事实。由一个调用 Skill 工具加载 “research” 的子 agent 解决。需要当前工作目录之外的知识时使用。 - **Prototype**(HITL):调用 Skill 工具加载 “prototype”,制作一个便宜、粗糙、具体、可供反馈的产物(提纲、粗略方案、stub 或 UI/逻辑代码),以提高讨论保真度。把原型作为资产链接。关键问题是“应该长什么样”或“应该如何表现”时使用。 - **Grilling**(HITL):对话,是默认类型。始终调用 Skill 工具两次,分别加载 “grilling” 和 “domain-modeling”。 - **Task**(HITL 或 AFK):在做出某个_决策_之前必须完成的手工工作:没有决策、原型或研究可做,但讨论在完成它之前被阻塞。例如注册服务以便评估其 API、开通访问权限、移动数据以便看清其形态。这是唯一一种以“做事”而非“决策”为主的类型;它之所以有资格进入地图,是因为它解除某个决策的阻塞,而不是因为它交付了目的地的一部分。agent 能独立完成时就独立驱动(AFK);否则给人类一份精确清单(HITL)。工作完成即解决;答案要记录做了什么,以及后续工单依赖的事实(凭据位置、新 URL、行数)。
## 战争迷雾
地图是_有意_不完整的:不要绘制你还看不见的东西。实时工单之外是**战争迷雾(fog of war)**:你能隐约看出即将到来的决策和调查,却还无法精确描述,因为它们依赖仍未解决的问题。解决一张工单会清除前方迷雾,把此刻已经可以具体化的内容逐一转化成新工单,直到通往目的地的道路清晰且不再剩余工单。
地图的 **Not yet specified** 一节用于写下这种模糊视图:可疑的问题、以后要重访的区域。它是朝向目的地、尚未发现的 frontier:这里的一切都在范围内,只是还不够清晰,无法建票。按当前视野允许的松散或完整程度来写;它也充当路标,让协作者知道这项工作正走向哪里。
**迷雾还是工单?** 判断标准是你现在能否精确说出问题,而_不是_你现在能否回答它。
- **建工单的时机:** 问题已经足够清晰,即便它仍被阻塞、现在无法行动。 - **放入 Not yet specified 的时机:** 你现在还无法把问题说得同样清晰。不要预先把迷雾切成工单大小的碎片:迷雾比工单更粗,一个区域抵达 frontier 后可能转化成多张工单,也可能一张都没有。
**Not yet specified** 不包含已经决定的内容(Decisions so far)、已经存在的实时工单,以及超出范围的内容(下一节)。
## 超出范围
迷雾只会朝_目的地_聚集。目的地固定了范围,因此目的地之外的工作就是**超出范围(out of scope)**:它不是迷雾,也不属于 **Not yet specified**。地图上有独立的 **Out of scope** 一节,用来记录你有意识地排除在_本次_工作之外的事项。决定它落在这里的是范围,而不是清晰度。
超出范围的工作永远不会转化(frontier 停在目的地);只有重新绘制目的地时它才会回来,而且那会是一次全新的工作,不是恢复旧工作。
把某件事排除在范围外是一项范围界定动作,不是路线中的一步。当已经存在的工单后来被发现位于目的地之外(绘图时错误纳入范围,或由某次解决结果暴露),要**关闭它**(关闭的工单明确不在 frontier 上),并在 **Out of scope** 留下一行:摘要、为何超出范围,以及指向已关闭工单的链接。不要把它放入 **Decisions so far**;后者记录真正走过的路线,而范围边界不是路线的一步。
## 调用方式
有两种模式。无论哪种,**每个会话都绝不能解决超过一张工单**,research 工单除外。
### 绘制地图
用户以一个尚未成形的想法调用。
1. **为目的地命名。** 调用 Skill 工具两次,分别加载 “grilling” 和 “domain-modeling”,明确这张地图要找到通往哪份规格、哪项决策或哪次变更的道路。目的地固定范围,因此必须先确定。 2. **绘制 frontier。** 再次 grilling,但这次采用**广度优先(breadth-first)**:横向展开整个空间,而不是深入任何单一线程,找出开放决策和现在可采取的第一步。**如果没有发现迷雾**(通往目的地的道路已清晰,整个旅程小到一个会话能完成),就不需要地图。停止,并询问用户希望如何继续。 3. **创建地图**(标签 `wayfinder:map`):填好 Destination 和 Notes,Decisions-so-far 为空,把迷雾勾勒进 **Not yet specified**。 4. 把**现在已经可以具体化的工单创建为子 issue**,然后在**第二遍**连接阻塞边(issue 必须先有 id,才能互相引用)。连边会把它们分为 frontier 与被阻塞项;仍无法具体化的一切继续留在迷雾,也就是 **Not yet specified**。 5. **启动 research 子 agent。** 对刚创建的每张 `research` 工单,启动一个调用 Skill 工具加载 “research” 的子 agent 并行解决,把发现记录在一次性的 `research/<name>` 分支上,并从工单留下 context pointer。 6. 停止:绘图就是一个会话的全部工作;它不会亲自解决任何工单。
### 沿地图推进
用户以一张地图(URL 或编号)调用。工单是**可选**的:若不指定,由你选择下一个决策,而不是让用户选择。
1. 加载**地图**:只加载低分辨率视图,不加载每张工单的正文。 2. 选择工单。若用户点名就使用它;否则按顺序领取第一张 frontier 工单。**认领它**:开展任何工作前先把它指派给自己。 3. 解决工单。**按需放大:** 需要时再获取任何相关或已关闭工单的完整正文;调用 `## Notes` 中点名的技能。若不确定,就调用 Skill 工具两次,分别加载 “grilling” 和 “domain-modeling”。 4. 记录解决结果:把答案发布为**解决评论(resolution comment)**,**关闭** issue,并把一条 **context pointer** 追加到地图的 Decisions-so-far。 5. 添加新浮现的工单(先创建,再连边);把答案已经变得可具体化的迷雾转化为工单,并从 **Not yet specified** 清除每个已转化区域,让它只存在于新工单中。如果答案暴露某张工单(当前或其他工单)位于目的地之外,就把它**排除在范围外**,而不是当作路线上的工单解决。若该决策使地图其他部分失效,则更新或删除那些工单。
用户可能并行运行未阻塞的工单,因此应预期其他会话会同时编辑 tracker。

Entry SHA-256: fee6e1d0c50f0e736b4ef8a599060c959afae904c9a97d82c97f049fcc3aa0f1

2. Why This Skill Is Clever

一句话核心机制

把一个大到单会话装不下、路线仍被迷雾遮住的工作,建模成 issue tracker 上由“目的地、frontier、迷雾和决策工单”组成的共享地图,再以一次一张工单的节奏逐步消除不确定性,直到可以交接给下游执行流程。

触发与调用边界

直接来源: frontmatter 的 disable-model-invocation: true 表明它必须由用户显式调用。技能有两种入口:用一个松散的大想法“绘制地图”,或用已有地图 URL/编号“沿地图推进”。

直接来源: 适用条件同时包含两点:工作大到单个 agent 会话容纳不下,而且“从这里到目的地”的路线仍不可见。如果广度优先访谈没有发现任何迷雾,技能必须停止并告诉用户不需要地图。

直接来源: 默认边界是 Plan, don't do。地图的工单解决决策,不是实现切片;道路清晰时要交接,而不是继续构建。只有地图 Notes 明确覆盖默认规则时,执行才可以进入地图。

支持性上下文: docs/engineering/wayfinder.md 和 ask-matt 把它定位为 situational on-ramp:单会话规划用 /grill-with-docs;多会话且路线模糊才用 /wayfinder;地图清空后通常回到 /to-spec,再进入 /to-tickets 与 /implement。这些说明帮助理解产品定位,但不属于所选 SKILL.md 原文。

信息架构 / 执行顺序

  1. 先命名目的地: 用 grilling 与 domain-modeling 明确整张地图要抵达的规格、决策或变更;目的地随即成为范围函数。
  2. 横向扫描问题空间: 采用 breadth-first 访谈,找出现在可描述的决策、可立即领取的第一步,以及仍无法具体化的迷雾。
  3. 建立低分辨率地图: 一条 wayfinder:map issue 只保存 Destination、Notes、Decisions so far、Not yet specified 和 Out of scope。
  4. 把清晰问题变成子工单: 先创建取得 id,再在第二遍连接阻塞边;平台据此计算开放、未阻塞、无人认领的 frontier。
  5. 按问题性质选择执行器: research 由 AFK 子 agent 读取外部事实;prototype 用廉价具体产物提高讨论保真度;grilling 通过人与 agent 的实时交流做决策;task 只做解除决策阻塞所必需的手工工作。
  6. 会话先认领、后工作: assignee 本身就是并发锁,其他会话必须跳过已认领工单。
  7. 一次解决一张: 按需放大相关工单,发布 resolution comment,关闭工单,再把一行 context pointer 追加到 Decisions so far。
  8. 让地图随知识变化: 把刚刚变清晰的迷雾转化为新工单;从 Not yet specified 删除已转化区域;更新或删除已失效工单;把越过目的地的事项关闭并移入 Out of scope。
  9. 在道路清晰时交接: 开放工单与迷雾都消失后,地图完成;默认产物仍是决策网络,不是实现。

最巧妙的设计点

1. 目的地不是愿景口号,而是范围函数

“naming it is the first act of charting”

直接来源: 目的地必须在任何工单之前确定,并且每个会话选票前都先以它校准方向。Fog 只能朝目的地聚集;目的地之外的事项属于 Out of scope。

解释: 许多规划系统先列任务再谈终点,结果只能用“是否清晰”判断该不该纳入。Wayfinder 先定义终点,使每个候选问题同时接受两次测试:它是否在范围内,以及它是否已经清晰到可以建票。范围和清晰度由此成为两个正交维度。

2. 地图只做索引,细节严格单一归属

“an index, not a store”

直接来源: 决策答案只存在于对应工单;地图的 Decisions so far 只保存一行 gist 与链接。会话先加载低分辨率地图,需要时再 zoom 到个别工单。

解释: 这是一种面向上下文窗口的信息架构。地图规模可以持续增长,而每个会话只支付“全局摘要 + 当前局部”的 token 成本。禁止复述还消除了两份答案漂移的可能,让工单成为明确的单一事实源。

3. 把未知拆成“可建票”与“尚不可建票”

“The test is whether you can state the question precisely now”

直接来源: 能准确说出问题就建工单,即使暂时被阻塞;无法准确措辞才留在 Not yet specified。判断标准不是“现在能否回答”。

解释: 普通 backlog 往往迫使团队过早把模糊区域切成看似精确的任务。Wayfinder 给“不确定但在范围内”的内容一个正式位置,使地图可以故意不完整。随着前置决策落地,一个迷雾区域可能转化为多张工单,也可能消失,从而避免把早期假设固化成计划债务。

4. 用 tracker 原生图结构把并发安全做成可见状态

“the frontier is the open, unblocked, unclaimed children”

直接来源: 阻塞必须优先使用 tracker 原生依赖关系;认领必须在任何工作之前完成,assignee 就是 claim。frontier 因而可由开放状态、依赖闭包和指派状态计算出来。

解释: 这里没有额外发明调度数据库。既有 issue tracker 同时承担持久化、依赖图、并发锁和人类 UI。规则不仅告诉 agent 下一张工单是什么,也让人类不打开地图就能看见哪些工作可领取。文本 fallback 被明确降级,说明可视化和可查询性是设计目标,而非偶然便利。

5. 四种工单按“消除哪类不确定性”分流

“Every ticket is either HITL ... or AFK”

直接来源: research 获取工作目录外的事实;prototype 把抽象讨论变成可反馈的具体产物;grilling 让人类亲自表达判断;task 只完成阻碍决策的前置动作。

解释: 这不是按部门或交付物分类,而是按不确定性的解决机制分类:事实缺口、体验缺口、偏好决策或访问/数据前置。尤其是“agent 不能替人回答 HITL 问题”和“task 不得交付目的地”两条边界,防止自动化为了尽快闭票而伪造用户判断或偷跑实现。

6. 创建与连边分成两遍,顺应实体身份约束

“wire blocking edges in a second pass”

直接来源: issue 必须先有 id 才能互相引用,所以先创建所有当前可描述工单,再连接阻塞关系。

解释: 这是图数据导入中可靠的 create-then-wire 模式。它避免为了边关系而猜 id、串行创建整张图,或在创建中途把暂时缺失引用误判为错误。同一原则适用于数据库对象、API 资源和基础设施依赖图。

防失败机制与显式不变量

直接来源:

取舍、可移植风险与宿主假设

解释: 这套流程用 issue tracker 换取跨会话持久性和多人可见性,但也带来较高启动成本。对于本可在一个会话完成的工作,地图、子 issue、标签和依赖边会成为流程税,因此“无迷雾就停止”非常关键。

支持性上下文: companion docs 记录了两项现实风险。第一,Notes 既承载“可覆盖 plan-only”的权限,又由 agent 编写,受约束者可能给自己授权执行;当前缺少更硬的外部保护。第二,过早绘制大量后续工单可能落入 waterfall trap,前面决策改变后,后半张地图会失效。这些是实际使用反馈,不是所选源文件已经完全解决的问题。

解释: 原生 child issues、blocking、assignee 查询和 resolution comments 是重要宿主假设。缺少原生依赖的平台可以退回正文约定,但 frontier 的可视化、自动查询和并发可靠性都会下降。技能还假设宿主提供 Skill tool、子 agent、分支操作、tracker 配置,以及 grilling、domain-modeling、research、prototype 等具名能力;迁移到其他 harness 时应映射这些语义,而不是机械复制名称。

解释: “每会话一张工单”保护上下文聚焦,却会牺牲吞吐;research 被允许并行,是因为事实读取不需要代表人类做决定。即使 frontier 表面上允许多个 HITL 工单并行,它们仍可能在隔离上下文中重复提问或形成冲突判断,因此图上的可并行不等于认知上的无风险。

可迁移原则

  1. 先定义终点,再建立工作图。 让终点成为范围判断函数,而不是一句装饰性愿景。
  2. 把摘要层与权威细节层分离。 导航页只保存 gist 和 link,每项事实只拥有一个规范位置。
  3. 为尚不可精确表达的未知提供正式容器。 不要用伪精确任务填满早期迷雾。
  4. 按不确定性的解决机制分流。 分清外部事实、体验反馈、人类判断和前置动作,避免用同一种 agent 行为处理所有问题。
  5. 复用现有系统的可查询状态。 用 assignee 充当认领、原生依赖表达阻塞,而不是再造一套隐藏调度器。
  6. 实体先创建、关系后连接。 对需要稳定身份才能互相引用的图结构使用两阶段事务。
  7. 把停止条件写成不变量。 无迷雾不建图、一次一票、已毕业迷雾立即删除、越界事项永不进入路线历史。

今日实践题

你正在规划一次跨多个团队的数据平台迁移,已经知道最终要“切换所有生产流量”,但暂时只能准确描述认证方案和回滚策略,成本模型与组织职责仍很模糊。哪些内容应立即建成工单,哪些应留在 Not yet specified,哪个问题需要先解决才能让下一片迷雾转化?

Evidence note

本文关于目的地、计划边界、名称引用、地图结构、单一决策存储、tracker 适配、工单身份、认领、原生阻塞、frontier、四种工单类型、HITL/AFK、战争迷雾、范围边界、两种调用模式、广度优先绘图、create-then-wire、研究并行、逐票解决和并发编辑的结论均来自所选 skills/engineering/wayfinder/SKILL.md。关于它在完整技能链中的位置、与 /grill-with-docs 的分界、地图清空后转入 /to-spec,以及 Notes 自我授权、过度建票和并行 HITL 风险的信息来自 docs/engineering/wayfinder.md 与 ask-matt,仅作支持性上下文。关于目的地作为范围函数、地图作为上下文压缩层、按不确定性分流、复用 tracker 状态机和两阶段图构建的判断属于设计解释。

Source & provenance
Repository path
skills/engineering/wayfinder/SKILL.md
Generated
2026-08-26 08:26 Asia/Shanghai
Upstream commit
6654f6b60cd9d5be8b54c6fafe44346dabeb3b76
Source
View on GitHub