Read the plan's structure (phases, milestones, tasks) and decide the shape:
- a parent epic + N child issues when the plan has distinct sub-tasks worth tracking separately, or
- a flat list (or single issue) when it doesn't.
Four principles govern the breakdown, applied before you present anything:
- Fewest issues by default. Actively look for scopes where several related tasks can collapse into one issue with a checklist instead of separate issues. Merge aggressively; only split into its own issue/sub-issue when a task is genuinely independent, meaning a different lifecycle, owner, or PR. Default to the smallest number of issues and sub-issues that still tracks the work honestly. The user can always ask to split one further; starting consolidated and splitting on request beats starting fragmented.
- Vertical slices. Size each issue/sub-issue so it completes one testable feature end to end whenever possible, meaning a slice a person could verify on its own, rather than a horizontal layer (e.g. "all the DB models", "all the endpoints") that isn't demonstrable until other issues land. Prefer "user can log in with SSO" over separate "add OIDC table" / "add OIDC route" / "add OIDC UI" issues; fold those layers into the one vertical slice as checklist items. Size it, too, so one slice fits in a single fresh agent context / worktree session: if a slice couldn't plausibly be finished in one sitting, it's a sign to split it.
- Independent by default. Size and sequence issues so each can be picked up in its own git worktree and worked in parallel, with no issue waiting on another. When two candidate slices share state (a migration one creates and another consumes, an API contract one produces), first try to design the dependency away: fold them into one issue, or resequence so the shared piece ships inside the prerequisite. Only when a real ordering constraint survives do you record it: the dependent gets and a line, everything else gets . This is what makes the tracker safe to fan out across worktrees.
- Prefactor first. Before slicing the feature, look for a simplifying refactor that makes the real change trivial: "make the change easy, then make the easy change." File that refactor as its own issue (behavior-preserving → ) that the feature slices then build on. A clean prefactor often removes a dependency that would otherwise force a chain, so it earns its keep even as an extra issue.
Wide mechanical refactors. When a change has broad blast radius and genuinely can't be one vertical slice, such as renaming a shared column or retyping a symbol used everywhere, don't file it as one giant issue. Sequence it expand → migrate → contract:
- expand. Add the new form alongside the old; nothing breaks yet. .
- migrate. Update call sites in batches by area, each batch its own issue by the expand issue (). The batches are independent of each other, so fan them out in parallel.
- contract. Delete the old form once nothing uses it, by all the migrate batches.
This turns one un-sliceable change into a fan of mostly-parallel issues with honest
edges, and reuses the existing
/
machinery, with no new labels. If the batches can't each stay green on their own, add one final integrate-and-verify issue blocked by them all.
Milestones are opt-in. Do
not create GitHub milestones by default; map a plan's phases onto issues and checklists instead. Only when the user
explicitly asks for milestones (or points at a repo that already uses them) should you create one (
gh api --method POST repos/{owner}/{repo}/milestones -f title="<title>"
, then
gh issue create --milestone <title>
) and attach issues to it. Absent that ask, never introduce a milestone the user would then have to maintain.
Present the proposal as a preview table and stop for approval. Do not create anything yet:
| # | Type | Title | Parent | Priority | Depends on | Checklist |
|---|
| 1 | epic | epic(auth): add sso login
| none | high | none | none |
| 2 | child | feat(auth): oidc login end to end
| #1 | high | none | provider · session · token refresh · UI |
| 3 | child | feat(auth): sso account linking
| #1 | medium | #2 | link existing · unlink · conflict handling |
Titles follow the
title convention:
, lowercase, the epic and its children sharing the
scope. Each child is a vertical slice with its layers folded into a checklist, not one issue per layer. The
Depends on column is where independence is decided out loud: an empty cell means the issue is
, so pick it up in its own worktree now, while a
means it's
by that issue (row 3 waits on row 2). Keep the column as empty as honesty allows; a mostly-empty column is a tracker the user can fan out in parallel. Let the user add, drop, retitle, reparent,
reprioritize,
resequence to break a dependency, or
split any row before you proceed, and offer splitting explicitly when a slice is large. This guard is the point, so never spray a repo with auto-generated issues.
Propose a priority per row, and expect to be overruled. You can read relative importance off a plan, meaning what it calls out as the core of the feature versus the polish, what it defers, and what it flags as a risk, and that's a real signal worth putting in the column. What you cannot read is why the work is being done at all, which is the thing priority actually encodes. So propose from the plan, mark anything the plan doesn't rank as
, and treat the column as the one most likely to be corrected. This is exactly the right moment for that correction: setting priority here costs the user one glance at a table they're already reviewing, where doing it later means a pass back over issues that have scattered across the tracker.
Don't hand out from a plan. It means
preempt work already in progress, which is a claim about right now and not about the plan, and a document written last week cannot know what's in flight today. Propose
for the most important row and let the user escalate it if they mean it.
For an ad-hoc description, skip the table: draft one issue (title + body) and confirm it before creating.
读取规划的结构(阶段、里程碑、任务)并确定issue形态:
- 当规划包含多个可独立追踪的子任务时,分解为父epic + N个子issue;
- 否则分解为扁平列表(或单个issue)。
分解需遵循以下四个原则,且需在呈现给用户前应用:
- 默认最少issue数量:主动寻找可将多个相关任务合并为一个包含checklist的issue的场景,而非拆分为多个独立issue。尽可能合并;仅当任务确实独立(具有不同的生命周期、负责人或PR)时才拆分为独立issue/子issue。默认使用能如实追踪任务的最少issue和子issue数量。用户可随时要求进一步拆分;从合并状态开始,按需拆分,比一开始就碎片化处理更优。
- 垂直切片:调整每个issue/子issue的大小,使其尽可能完成一个可独立测试的端到端功能,即用户可单独验证的切片,而非水平层(例如“所有数据库模型”“所有接口”),这类水平层需等待其他issue完成后才能展示效果。优先选择“用户可通过SSO登录”而非拆分为“添加OIDC表”/“添加OIDC路由”/“添加OIDC UI”等独立issue;将这些层级合并为一个垂直切片的checklist项。同时调整大小,确保一个切片可在单个Agent上下文/工作树会话中完成:如果一个切片无法在一次会话中完成,则说明需要拆分。
- 默认独立可并行:调整issue的大小和顺序,确保每个issue都能在独立的git工作树中处理,且可并行进行,无需等待其他issue。当两个候选切片共享状态(例如一个切片创建的迁移被另一个切片使用,一个切片生成的API契约被另一个切片调用)时,首先尝试消除依赖:将它们合并为一个issue,或调整顺序使共享部分包含在前置依赖中。仅当确实存在顺序约束时才记录依赖:依赖的issue标记为并添加行,其余issue标记为。这是确保追踪器可安全并行处理的关键。
- 先重构再开发:在拆分功能前,寻找可简化后续修改的重构操作:“让修改变得简单,再进行简单的修改。” 将该重构操作创建为独立的issue(不改变功能 → ),功能切片基于该重构后的代码开发。合理的重构通常会消除原本会导致阻塞链的依赖,因此即使多创建一个issue也是值得的。
大范围机械重构:当修改影响范围广且无法拆分为单个垂直切片时,例如重命名共享列或修改全局使用的符号,不要创建一个巨型issue。应按照扩展 → 迁移 → 收缩的顺序拆分:
- 扩展:在保留旧版本的同时添加新版本;此时不会破坏现有功能。标记为。
- 迁移:按区域分批更新调用方,每批作为独立issue,标记为并依赖扩展issue()。各批次之间相互独立,可并行处理。
- 收缩:当所有调用方都已迁移后,删除旧版本;标记为并依赖所有迁移批次。
这样可将一个无法拆分的修改转换为一组大部分可并行处理的issue,并通过
/
机制管理依赖,无需新增标签。如果各批次无法单独保持正常运行,则添加一个最终的集成验证issue,依赖所有迁移批次。
里程碑为可选功能。默认
不创建GitHub里程碑;将规划的阶段映射为issue和checklist即可。仅当用户
明确要求使用里程碑(或仓库已在使用里程碑)时,才创建里程碑(
gh api --method POST repos/{owner}/{repo}/milestones -f title="<title>"
,然后使用
gh issue create --milestone <title>
关联issue)。若无明确要求,绝不创建用户后续需要维护的里程碑。
将拆分建议以预览表格形式呈现给用户,并等待批准。此时不要创建任何内容:
| # | 类型 | 标题 | 父issue | 优先级 | 依赖项 | Checklist |
|---|
| 1 | epic | epic(auth): add sso login
| 无 | high | 无 | 无 |
| 2 | child | feat(auth): oidc login end to end
| #1 | high | 无 | provider · session · token refresh · UI |
| 3 | child | feat(auth): sso account linking
| #1 | medium | #2 | link existing · unlink · conflict handling |
标题遵循
标题规范:
,全小写,epic及其子issue共享
scope。每个子issue都是一个垂直切片,其层级被折叠为checklist项,而非每个层级对应一个issue。
依赖项列用于明确独立性:空单元格表示issue为
,可立即转入工作树处理;
表示该issue被对应issue阻塞(第3行等待第2行完成)。尽可能保持该列为空;大部分为空的列表示追踪器支持并行处理。允许用户添加、删除、重命名、重新设置父issue、
重新排序优先级、
调整顺序以打破依赖或
拆分任意行,当切片较大时主动提供拆分选项。该校验是关键环节,绝不要自动在仓库中创建大量issue。
为每一行建议一个优先级,并预期会被用户修改。可从规划中读取相对重要性,例如规划中强调的功能核心与次要功能、延迟处理的内容、标记的风险点,这些都是有价值的信号,可填入该列。但无法读取任务的根本目的,而这正是优先级的核心依据。因此根据规划建议优先级,将规划未提及的项标记为
,并将该列视为最可能被修改的部分。这是修改优先级的最佳时机:用户在查看表格时只需 glance 一眼即可调整,而后续修改则需要重新遍历已分散在追踪器中的issue。
不要从规划中直接设置优先级。该优先级表示
优先于正在进行的工作,这是针对当前状态的判断,而非规划中的内容,上周编写的文档无法知晓当前正在进行的工作。将最重要的行建议为
优先级,由用户决定是否升级为
。
对于临时输入的描述,跳过表格环节:起草一个issue(标题 + 正文)并在创建前确认。