
快记快用
把 Spec(或当前对话)切成一组小 ticket,每个都是垂直切片(tracer bullet):一条可独立演示的完整路径,而不是按层拆分。每个 ticket 标明依赖(blocking edges),并按单次会话的 context window 体量切分。跨多会话时用;单会话可直接 /implement。输入 /to-tickets 即可。
to-tickets 能解决什么问题?
首先这里提到的“票”是 agent 执行任务的一个抽象概念。按照层级顺序切票是这件事最自然的错误做法:所有 schema 实现一张票、所有 API 实现一张票、所有 UI 实现一张票。这样切出来的票,每张的验收标准都要伸进别人拥有的工作里,没有任何一张能独立演示,集成全部堆到最后。
没有它会发生什么问题:
- 每个票任务的验收标准都必须要引用别人的实现逻辑,票与票之间无法独立验证。
- 按层级顺序拆分票任务,会把集成风险全部堆到最后,而且代价极高。
- 切分票任务太粗时,一张巨票装不进一个上下文窗口,接手它的陌生 session 干不完。
使用方法和运行机制
输入
输入:spec issue(可用 `/to-tickets #<spec_issue>` 引用)、或仅对话、或任意 plan; tracker 与 triage 标签词汇由 `/setup-matt-pocock-skills` 事先提供处理
收集上下文(对话或引用)→ (可选)探索代码库,找 prefactor 机会→ 按垂直切片规则起草(prefactor 排最前)→ 向用户确认:粒度 / blocking edges 真伪 / 合并拆分,iterate until approved→ 按 tracker 形态发布输出
输出:一组票。每张:窄而完整地穿透 schema / API / UI / tests、可独立演示、 单个上下文窗口大小、声明 Blocked by; 本地 = 每票一个文件 `.scratch/<feature-slug>/issues/<NN>-<slug>.md`; 真实 tracker = 每票一个 issue,带原生阻塞链接与 `ready-for-agent` 标签产物的去向按 tracker 分两种。
-
本地模式写到工作区的
.scratch/<feature-slug>/issues/下,从01起按依赖顺序编号; -
真实 tracker 上每票一个 issue,阻塞边是原生链接或子任务关系。发布完成之后技能就结束了,运行是人的工作:你需要查看哪几张票的阻塞者都已完成(frontier),就开几个 agent session,每张票一个新鲜上下文;本地模式则从顶端没有阻塞的票开始手工往下做。
实现解析
文件开头的说明区
name: to-tickets description: Break a plan, spec, or the current conversation into a set of tracer-bullet tickets, each declaring its blocking edges, published to the configured tracker (edges as text in one file per ticket locally, or native blocking links on a real tracker). disable-model-invocation: true
译文
名称是 to-tickets。介绍说的是把一个 plan、一份 spec 或当前对话拆成一组 tracer-bullet 票,每张票声明自己的 blocking edges,发布到配置好的 tracker(本地是每票一个文件、边写成文本,真实 tracker 是原生阻塞链接)。disable-model-invocation 为 true。
总纲
Break a plan, spec, or conversation into a set of tickets: tracer-bullet vertical slices, each declaring the tickets that block it.
译文
把一个 plan、一份 spec 或一段对话拆成一组票:tracer-bullet 垂直切片,每张票声明阻塞它的那些票。
第一步:收集上下文
Work from whatever is already in the conversation context. If the user passes a reference (a spec path, an issue number or URL) as an argument, fetch it and read its full body and comments.
译文
从对话上下文里已有的内容出发。如果用户传了一个引用(spec 路径、issue 编号或 URL)作为参数,取来并读完整正文和评论。
第二步:探索代码库与 prefactor 机会
If you have not already explored the codebase, do so to understand the current state of the code. Ticket titles and descriptions should use the project’s domain glossary vocabulary, and respect ADRs in the area you’re touching.
Look for opportunities to prefactor the code to make the implementation easier. “Make the change easy, then make the easy change.”
译文
如果还没探索过代码库,去了解代码的当前状态。票的标题和描述要用项目领域词汇表的词,并尊重所碰区域的 ADR。寻找让实现更容易的 prefactor 机会。“先让改动变容易,再做容易的改动。”
第三步:起草垂直切片
Break the work into tracer bullet tickets.
译文
把工作拆成 tracer bullet 票。
说明
tracer bullet 指一条窄而完整的纵向路径,具体约束写在下面的规则块里。
- Each slice cuts a narrow but COMPLETE path through every layer (schema, API, UI, tests): vertical, NOT a horizontal slice of one layer
- A completed slice is demoable or verifiable on its own
- Each slice is sized to fit in a single fresh context window
- Any prefactoring should be done first
译文
每张切片切一条窄但完整的路径,穿过每一层(schema、API、UI、tests):纵向,不是某一层的横向切片。完成的切片可以独立演示或验证。每张切片的大小要能放进一个全新的上下文窗口。任何 prefactoring 都先做。
阻塞边的声明
Give each ticket its blocking edges: the other tickets that must complete before it can start. A ticket with no blockers can start immediately.
译文
给每张票写上它的 blocking edges:在它开始之前必须完成的其他票。没有阻塞者的票可以立即开始。
wide refactor 是垂直切片的例外
Wide refactors are the exception to vertical slicing. A wide refactor is one mechanical change (rename a column, retype a shared symbol) whose blast radius fans across the whole codebase, so a single edit breaks thousands of call sites at once and no vertical slice can land green. Don’t force it into a tracer bullet; sequence it as expand–contract. First expand: add the new form beside the old so nothing breaks. Then migrate the call sites over in batches sized by blast radius (per package, per directory), each batch its own ticket blocked by the expand, keeping CI green batch to batch because the old form still exists. Finally contract: delete the old form once no caller remains, in a ticket blocked by every migrate batch. When even the batches can’t stay green alone, keep the sequence but let them share an integration branch that all block a final integrate-and-verify ticket; green is promised only there.
译文
wide refactor 是垂直切片的例外。一次机械性改动(改列名、改共享符号类型),它的 blast radius(爆炸半径)扇遍整个代码库,一次编辑同时打断几千处调用点,没有任何垂直切片能单独落地绿灯。不要硬把它塞进 tracer bullet,按 expand–contract 排序。先 expand:把新形式加在旧形式旁边,什么都不打破。然后按 blast radius 分批迁移调用点(按包、按目录),每批一张自己的票,被 expand 阻塞,因为旧形式还在,CI 在批与批之间保持绿。最后 contract:没有调用者了,删掉旧形式,这张票被每一张迁移批次的票阻塞。当连分批都无法单独保持绿时,保持顺序,但让它们共享一个集成分支,全部阻塞一张最终的集成并验证票;绿色只在那里承诺。
第四步:向用户确认拆分方案
Present the proposed breakdown as a numbered list. For each ticket, show:
- Title: short descriptive name
- Blocked by: which other tickets (if any) must complete first
- What it delivers: the end-to-end behaviour this ticket makes work
Ask the user:
- Does the granularity feel right? (too coarse / too fine)
- Are the blocking edges correct: does each ticket only depend on tickets that genuinely gate it?
- Should any tickets be merged or split further?
Iterate until the user approves the breakdown.
译文
把拟定的拆分以编号列表呈现,每张票显示标题(简短的描述性名称)、被谁阻塞(哪些票必须先完成,可以为空)、交付什么(这张票让什么端到端行为工作起来)。然后问用户:粒度是否合适(太粗或太细)、阻塞边是否正确(每张票是否只依赖真正卡住它的票)、是否有票需要合并或再拆分。反复迭代,直到用户批准拆分方案。
第五步:发布到配置好的 tracker
Publish the approved tickets. How depends on the tracker
/setup-matt-pocock-skillsconfigured; the tickets are the same either way, only the shape of the blocking edges changes:
- Local files → write one file per ticket under
.scratch/<feature-slug>/issues/<NN>-<slug>.md, numbered from01in dependency order (blockers first). Each file’s “Blocked by” lists the numbers/titles it depends on. Use the per-ticket file template below: one ticket per file, never a single combined file.- A real issue tracker (GitHub, Linear, …) → publish one issue per ticket in dependency order (blockers first) so each ticket’s blocking edges can reference real identifiers. Use the platform’s native blocking / sub-issue relationship where it has one; otherwise set each ticket’s “Blocked by” to the blocking issues. Apply the
ready-for-agenttriage label unless instructed otherwise; the tickets are agent-grabbable by construction.Work the frontier: any ticket whose blockers are all done. For a purely linear chain that means top to bottom.
Do NOT close or modify any parent issue.
译文
发布批准后的票。发布方式取决于 /setup-matt-pocock-skills 配置的 tracker;两种方式下票本身相同,只有阻塞边的形状不同。本地文件:在 .scratch/<feature-slug>/issues/<NN>-<slug>.md 下每票写一个文件,从 01 起按依赖顺序编号(阻塞者在先),每个文件的 “Blocked by” 列出它依赖的编号或标题,用下面的单票文件模板,一票一个文件,绝不写成一个合并文件。真实 issue tracker(GitHub、Linear 等):按依赖顺序(阻塞者在先)一票一个 issue 发布,这样每张票的阻塞边能引用真实标识;平台有原生阻塞或子任务关系就用原生的,否则把 “Blocked by” 写成指向阻塞 issue 的引用;除另有说明,打上 ready-for-agent triage 标签,这些票按构造就是 agent 可以捡的。走 frontier:所有阻塞者都已完成的票,纯线性链条就是从顶到底。不要关闭或修改任何父 issue。
本地票模板与 issue 模板
: What to build: the end-to-end behaviour this ticket makes work, from the user’s perspective, not a layer-by-layer implementation list.
Blocked by: the numbers/titles of the tickets that gate this one, or “None (can start immediately)”.
Status: ready-for-agent
- Acceptance criterion 1
- Acceptance criterion 2
译文
标题写成 <NN>: <票标题>。要建什么:这张票让什么端到端行为工作起来,从用户视角写,不是逐层实现清单。被谁阻塞:卡住这张票的票的编号或标题,或者 None (can start immediately)。状态:ready-for-agent。后面是两条验收标准勾选项。
Parent
A reference to the parent issue on the tracker (if the source was an existing issue, otherwise omit this section).
What to build
The end-to-end behaviour this ticket makes work, from the user’s perspective, not layer-by-layer implementation.
Acceptance criteria
- Criterion 1
- Criterion 2
Blocked by
- A reference to each blocking ticket, or “None (can start immediately)”.
译文
Parent 一节是指向 tracker 上父 issue 的引用(如果来源是已有 issue,否则省略这一节)。What to build 是从用户视角写的端到端行为,不是逐层实现。Acceptance criteria 是验收标准勾选项。Blocked by 指向每张阻塞票,或者写 None (can start immediately)。
说明
两套模板分别对应本地模式与真实 tracker,都以行为为中心,What to build 一律从用户视角写端到端行为。两套模板与 to-spec 七段模板的对应关系如下。
| to-spec 的 section | 流向 | to-tickets 的对应物 |
|---|---|---|
| Problem Statement / Solution(用户视角) | → | What to build:端到端行为,用户视角,明确禁止逐层实现 |
| User Stories(extremely extensive) | → | Acceptance criteria,但要能失败 |
| Implementation Decisions | → | 不流入票体;票只带行为,不带实现清单 |
| Testing Decisions | → | 不流入;由 implement 内部的 tdd 在预商定接缝上执行 |
| Out of Scope / Further Notes | → | 不流入,这正是 spec 留着自己承担的原因 |
票体禁用文件路径与 prototype 例外
In either form, avoid specific file paths or code snippets: they go stale fast. Exception: if a prototype produced a snippet that encodes a decision more precisely than prose can (state machine, reducer, schema, type shape), inline it and note briefly that it came from a prototype. Trim to the decision-rich parts, not a working demo, just the important bits.
译文
两种模板都避免写上具体文件路径或代码片段,它们过时得很快。例外情况是:如果原型产出的一段代码比散文更精确地编码了一个决策(状态机、reducer、schema、类型形状),把它内联进去,并简要注明它来自原型;只保留决策密集的部分,不是可运行的演示,只要重要的部分。
分享文章
生成精美分享图或复制链接,与更多人分享本文。
继续阅读
换条路线
从其他文章中稳定抽取
最后更新于 ,距今已过 43 天
部分内容可能已过时