issue-flow
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseIssue Flow
Issue 流程
Manages the full GitHub issue lifecycle: select → issue → branch → commits → PR → merge → close. Supports entering at any step and advancing forward. Reads the target repo's CLAUDE.md for project-specific conventions.
This skill owns every git and write in the issue pipeline — branch creation, snapshots, commits, squashing, pushes, PRs, merges — plus issue selection. Skills that orchestrate the pipeline () delegate those actions here rather than reimplementing them, so the commit subject format and the squash rules exist in exactly one place.
ghsolve-issue管理完整的GitHub issue生命周期:选择→创建issue→创建分支→提交代码→创建PR→合并PR→关闭issue。支持从任意步骤切入并推进流程。会读取目标仓库的CLAUDE.md文件以遵循项目特定规范。
该技能管控issue流程中所有git和的写入操作——包括分支创建、快照、提交、合并提交、推送、创建PR、合并PR——以及issue选择。编排流程的技能(如)会将这些操作委托给本技能,而非重新实现,因此提交主题格式和合并规则仅在一处定义。
ghsolve-issueBundled Scripts
内置脚本
Located in relative to this skill:
scripts/| Script | Purpose |
|---|---|
| Validate git repo, gh CLI, authentication |
| Detect base branch name (main/master/next/epic-*) |
| Fetch labels, collaborators, projects |
| Classify repo as personal / org / external |
| Rank top PR reviewers by recent review activity |
| Rank top issue assignees by recent assignments |
| Add issue to GitHub Projects V2 |
| List projects an issue is already a member of |
| Rank up to 4 likely projects (USED + RELATED) |
| Update project board status |
detect-base.shgit log <base>..HEADunknown revisiongit checkoutgit pull origingh pr create --basebash
baseref=$(git rev-parse --verify --quiet "origin/$base" || git rev-parse --verify --quiet "$base")It exits when the repo has no remote, in which case there is no base to detect —
stop and tell the user to add a remote rather than guessing .
2mainThe name can also be missing in the other direction: it scans local branches
too, so the base may be a branch the remote has never seen. Anything that talks to the
remote with it — , ,
— fails on such a base. Check before those steps and stop
with Detection is still right
to find it: falling back to the default branch would make Consolidate treat the whole
epic as commits ahead and squash it.
epic-*git pull origin <base>git rebase origin/<base>gh pr create --base <base>Base branch <base> is not on the remote — push it first.Run scripts from the skill directory:
bash
bash "<skill-dir>/scripts/check-env.sh"
bash "<skill-dir>/scripts/detect-base.sh"
bash "<skill-dir>/scripts/repo-context.sh"
bash "<skill-dir>/scripts/repo-ownership.sh" [<owner>/<repo>]
bash "<skill-dir>/scripts/pr-reviewers.sh" [<owner>/<repo>] [<limit>]
bash "<skill-dir>/scripts/issue-assignees.sh" [<owner>/<repo>] [<limit>]
bash "<skill-dir>/scripts/add-to-project.sh" <issue-number> <project-title> [status]
bash "<skill-dir>/scripts/get-issue-projects.sh" <issue-number>
bash "<skill-dir>/scripts/suggest-projects.sh" [<owner>/<repo>]
bash "<skill-dir>/scripts/project-status.sh" <issue-number> <status>位于本技能相对路径的目录下:
scripts/| 脚本名称 | 用途 |
|---|---|
| 验证git仓库、gh CLI及身份认证状态 |
| 检测基础分支名称(main/master/next/epic-*) |
| 获取标签、协作者、项目信息 |
| 将仓库分类为个人仓库/组织仓库/外部仓库 |
| 根据近期评审活跃度排序顶级PR评审人 |
| 根据近期分配情况排序顶级issue经办人 |
| 将issue添加至GitHub Projects V2 |
| 列出issue已加入的项目 |
| 排序最多4个潜在项目(已使用+相关项目) |
| 更新项目看板状态 |
detect-base.shgit log <base>..HEADunknown revisiongit checkoutgit pull origingh pr create --basebash
baseref=$(git rev-parse --verify --quiet "origin/$base" || git rev-parse --verify --quiet "$base")当仓库没有远程仓库时,该脚本会以状态码2退出,此时无法检测基础分支——需提示用户添加远程仓库,而非默认使用分支。
main另一种情况是分支名称仅存在于本地:脚本也会扫描本地的分支,因此检测到的基础分支可能并未推送到远程仓库。若使用该分支执行与远程交互的操作——如、、——会执行失败。在执行这些步骤前需检查并提示用户: 检测逻辑是正确的,若回退到默认分支,会导致Consolidate将整个epic分支的提交视为超前并合并。
epic-*git pull origin <base>git rebase origin/<base>gh pr create --base <base>Base branch <base> is not on the remote — push it first.从技能目录运行脚本:
bash
bash "<skill-dir>/scripts/check-env.sh"
bash "<skill-dir>/scripts/detect-base.sh"
bash "<skill-dir>/scripts/repo-context.sh"
bash "<skill-dir>/scripts/repo-ownership.sh" [<owner>/<repo>]
bash "<skill-dir>/scripts/pr-reviewers.sh" [<owner>/<repo>] [<limit>]
bash "<skill-dir>/scripts/issue-assignees.sh" [<owner>/<repo>] [<limit>]
bash "<skill-dir>/scripts/add-to-project.sh" <issue-number> <project-title> [status]
bash "<skill-dir>/scripts/get-issue-projects.sh" <issue-number>
bash "<skill-dir>/scripts/suggest-projects.sh" [<owner>/<repo>]
bash "<skill-dir>/scripts/project-status.sh" <issue-number> <status>Step Router
步骤路由
Before routing, detect current state in parallel:
bash
undefined路由前,并行检测当前状态:
bash
undefinedRun all three in parallel (independent calls)
并行执行三个独立命令
git branch --show-current # → current branch name
git status --short # → working tree state (staged, unstaged, untracked)
git log --oneline -1 # → latest commit context
Use the current branch name to determine which steps are already done:
- On `issue-<N>` branch → Steps 1-2 are done, detect entry from there
- On base branch (main/master/etc.) with no changes → nothing to do
- On base branch with changes → full flow from Step 1
Determine entry step from user intent, check prerequisites, then proceed forward. Do NOT re-run earlier completed steps.
| User intent | Entry step | Prerequisite |
| ------------------------------------ | ---------- | ------------------------ |
| "what's next", "pick an issue", "which issue" | Step 0 | gh authenticated |
| Work intent with no issue number given | Step 0 | gh authenticated |
| No arguments / empty invocation | Step 1 | Staged or changed files |
| "create issue", "new issue" | Step 1 | gh authenticated |
| "create issue linked to #N", "create sub-issue of #N" | Step 1 + Project Inheritance | Parent #N exists |
| "add sub-issues to #N", "link issues to #N" | Sub-issues | Parent issue exists |
| "X blocks #N", "block #N with #M", "unblock #N" | Blocked-by | Both issues exist |
| "start work on #N", "branch for #N" | Step 2 | Issue exists |
| "commit", "commit changes" | Step 3 | On issue-* branch |
| "snapshot", "wip snapshot" | Step 3 snapshot | Dirty tree |
| "push", "push changes" | Step 4 | Commits ahead of remote |
| "create PR", "open PR" | Step 5 | Branch pushed |
| "merge", "merge PR" | Step 6 | PR exists |git branch --show-current # → 当前分支名称
git status --short # → 工作区状态(已暂存、未暂存、未跟踪)
git log --oneline -1 # → 最新提交上下文
根据当前分支名称判断已完成的步骤:
- 处于`issue-<N>`分支 → 已完成步骤1-2,从该节点切入
- 处于基础分支(main/master等)且无变更 → 无需操作
- 处于基础分支且有变更 → 从步骤1开始完整流程
根据用户意图确定切入步骤,检查前置条件后推进流程。**不要重新执行已完成的步骤**。
| 用户意图 | 切入步骤 | 前置条件 |
| ----------------------------------------- | -------- | ------------------------ |
| "下一步做什么"、"选择一个issue"、"选哪个issue" | 步骤0 | gh已完成身份认证 |
| 未指定issue编号的工作意图 | 步骤0 | gh已完成身份认证 |
| 无参数调用/空调用 | 步骤1 | 存在已暂存或变更的文件 |
| "创建issue"、"新建issue" | 步骤1 | gh已完成身份认证 |
| "创建关联#N的issue"、"创建#N的子issue" | 步骤1 + 项目继承 | 父issue #N存在 |
| "给#N添加子issue"、"将issue关联到#N" | 子issue流程 | 父issue存在 |
| "X阻塞#N"、"用#M阻塞#N"、"取消阻塞#N" | 依赖关系设置 | 两个issue均存在 |
| "开始处理#N"、"为#N创建分支" | 步骤2 | issue已存在 |
| "提交"、"提交变更" | 步骤3 | 处于issue-*分支 |
| "快照"、"WIP快照" | 步骤3(快照模式) | 工作区有未提交变更 |
| "推送"、"推送变更" | 步骤4 | 本地提交超前于远程仓库 |
| "创建PR"、"打开PR" | 步骤5 | 分支已推送到远程仓库 |
| "合并"、"合并PR" | 步骤6 | PR已存在 |No Arguments (Full Flow from Changes)
无参数调用(从变更开始完整流程)
When invoked without arguments, use the state detected above:
- If shows no output, stop — nothing to commit
git status --short - If there are changes, analyze the diff content to infer issue type and description
- Run the full flow (Steps 1–6) — stage only the identified files in Step 3
When the user says "full flow" or asks to go from issue to merge, run all steps sequentially. Otherwise, start at the detected step and ask whether to continue to the next step after each one completes.
无参数调用时,根据上述检测到的状态执行:
- 若无输出,停止操作——无内容可提交
git status --short - 若存在变更,分析diff内容推断issue类型和描述
- 执行完整流程(步骤1–6)——步骤3中仅暂存已识别的文件
当用户要求"完整流程"或从issue到合并的全流程时,按顺序执行所有步骤。否则从检测到的步骤开始,每完成一步询问用户是否继续下一步。
Conventions
规范
Read the target repo's CLAUDE.md for project-specific formatting. Use these defaults when no override is found:
- Issue titles: (conventional commit format)
<type>: <description> - Commit subjects:
<Issue Title> #<number> - PR titles:
<Issue Title> #<number> - PR body: concise change list + , one per line. GitHub links only the first reference after a keyword, so
Closes #<number>closes #1 and leaves #2 and #3 openCloses #1 #2 #3
Common types: , , , , , , ,
featfixdocschorerefactorteststyleci读取目标仓库的CLAUDE.md文件以遵循项目特定格式。若未找到自定义规范,使用以下默认规则:
- Issue标题:(规范提交格式)
<type>: <description> - 提交主题:
<Issue Title> #<number> - PR标题:
<Issue Title> #<number> - PR正文:简洁的变更列表 + ,每行一条。GitHub仅会关联关键字后的第一个引用,因此
Closes #<number>只会关闭#1,#2和#3仍会保持打开状态Closes #1 #2 #3
常见类型:、、、、、、、
featfixdocschorerefactorteststyleciAsking the User
询问用户
Every question in this skill is written as options. Use that tool where
the host offers it, or the host's nearest structured-choice equivalent. Where the host has
neither, ask the same question in normal chat as a numbered list of 2–5 options —
recommended first, one short line of description each — and wait for the user to reply
with a number.
AskUserQuestionNever silently pick for the user at a gate that changes git or GitHub state.
本技能中的所有问题均以选项形式呈现。若宿主支持该工具则直接使用,或使用宿主提供的最接近的结构化选择工具。若宿主均不支持,则在聊天中以编号列表形式呈现2-5个选项——推荐选项排在首位,每个选项配简短描述——等待用户回复编号。
AskUserQuestion在会修改git或GitHub状态的节点,切勿擅自替用户做选择。
Skip Interactive Prompts
跳过交互式提示
When the user explicitly provides values for labels, assignee, project, or other options in their request, use those values directly — do NOT ask to confirm what was already stated. Only ask about fields the user left unspecified.
当用户在请求中明确指定标签、经办人、项目或其他选项的值时,直接使用这些值——不要询问确认已明确提供的内容。仅询问用户未指定的字段。
Assignment Defaults
默认分配规则
Nothing this skill creates is ever left unassigned by default. Every issue and PR gets an assignee unless the user explicitly asked for none.
"The current user" always means the authenticated account — resolve it, never assume a hardcoded login:
ghbash
gh api user --jq .loginPrefer the literal in flags; use the resolved login only when a report or comparison needs the actual name.
@meghClassify the repo once per flow — at whichever step the flow is entered, if not already done:
bash
bash "<skill-dir>/scripts/repo-ownership.sh"KIND | Meaning | Default behaviour |
|---|---|---|
| Owned by the current user | Assign the current user ( |
| Owned by an organization | Ask via |
| Another user's personal repo | Same as |
In every case the fallback is the current user: if the user skips the question, the prompt cannot be shown, or fails, assign rather than nothing.
repo-ownership.sh@meAn explicit instruction always wins — "assign to @octocat", "leave it unassigned", or a reviewer/assignee rule in the target repo's CLAUDE.md overrides everything above, in personal repos too.
本技能创建的所有内容默认不会无人分配。除非用户明确要求,否则每个issue和PR都会分配经办人。
"当前用户"始终指已认证的账户——需解析该账户,切勿假设硬编码的登录名:
ghbash
gh api user --jq .login在参数中优先使用字面量;仅在报告或比较需要实际名称时使用解析后的登录名。
gh@me每个流程仅分类一次仓库——无论从哪个步骤切入,若尚未分类则执行:
bash
bash "<skill-dir>/scripts/repo-ownership.sh"KIND | 含义 | 默认行为 |
|---|---|---|
| 当前用户拥有的仓库 | 静默分配给当前用户( |
| 组织拥有的仓库 | 通过 |
| 其他用户的个人仓库 | 与 |
在任何情况下,回退选项都是当前用户:若用户跳过问题、无法显示提示或执行失败,分配而非留空。
repo-ownership.sh@me明确指令优先级最高——"分配给@octocat"、"不分配经办人"或目标仓库CLAUDE.md中的评审人/经办人规则会覆盖上述所有规则,包括个人仓库的默认规则。
Step 0: Select Issue
步骤0:选择Issue
Use when no issue number was given and the intent is to work on something — "what's
next", "pick an issue", or a bare work intent with nothing to work on named.
Validate the environment and resolve the repo first:
bash
bash "<skill-dir>/scripts/check-env.sh"
gh repo view --json nameWithOwner --jq '.nameWithOwner'
gh api user --jq .loginIf fails, stop:
gh repo viewNot inside a GitHub repository.Then run the ranking pipeline in . It reads local git
state, plan files, open PRs, and the backlog, ranks candidates into five tiers, and
presents up to four picks via . Every command it runs is a read — Step
0 never writes.
references/issue-selection.mdAskUserQuestionOn selection it hands off to the skill for the full implementation
analysis. Continue to Step 2 with the selected number when the flow is meant to keep
going; stop after the analysis when the user only asked what to work on next.
issue-analyzeIf the user picks , stop — do not fall through to Step 1 and create an issue
nobody asked for.
None当未指定issue编号且用户意图是开始工作时使用——如"下一步做什么"、"选择一个issue"或未指定工作内容的工作意图。
首先验证环境并解析仓库:
bash
bash "<skill-dir>/scripts/check-env.sh"
gh repo view --json nameWithOwner --jq '.nameWithOwner'
gh api user --jq .login若执行失败,停止操作:
gh repo viewNot inside a GitHub repository.然后运行中的排序流程。该流程读取本地git状态、计划文件、打开的PR和待办事项,将候选issue分为五个层级,并通过呈现最多4个选项。该步骤仅执行读取操作——步骤0不会写入任何内容。
references/issue-selection.mdAskUserQuestion用户选择后,将任务交给技能进行完整的实现分析。若流程需要继续推进,则携带选中的issue编号进入步骤2;若用户仅询问下一步工作内容,则分析完成后停止。
issue-analyze若用户选择,停止操作——不要自动进入步骤1创建无人需要的issue。
NoneStep 1: Create Issue
步骤1:创建Issue
Run these in parallel (they are independent):
bash
undefined并行执行以下操作(相互独立):
bash
undefinedParallel batch
并行执行
bash "<skill-dir>/scripts/check-env.sh"
mktemp -d # → save output as <TMPDIR>
bash "<skill-dir>/scripts/repo-context.sh"
bash "<skill-dir>/scripts/repo-ownership.sh"
Wait for all four before proceeding. `detect-base.sh` is not needed until Step 2.bash "<skill-dir>/scripts/check-env.sh"
mktemp -d # → 保存输出为<TMPDIR>
bash "<skill-dir>/scripts/repo-context.sh"
bash "<skill-dir>/scripts/repo-ownership.sh"
等待四个命令执行完成后再继续。`detect-base.sh`需到步骤2才会用到。Title
标题
Use conventional commit format: . Defer to CLAUDE.md conventions if they differ.
<type>: <description>使用规范提交格式:。若CLAUDE.md中有不同规范,优先遵循该规范。
<type>: <description>Epic Detection
Epic检测
Before writing the body or picking a label, determine if this is an epic issue — one that coordinates work without containing implementation itself. Signals:
- User mentions "epic", "umbrella", "tracking issue", or "aggregated issue"
- Issue groups multiple child issues or feature areas
- No concrete implementation details — only scope or coordination
If it is an epic, and the repo has an label (check output), apply as the label without asking. Skip the normal type-based label inference. If label does not exist in the repo, fall through to normal label selection.
epicrepo-context.shepicepic在编写正文或选择标签前,判断该issue是否为epic issue——即用于协调工作但不包含具体实现的issue。判断信号:
- 用户提及"epic"、"总览"、"跟踪issue"或"汇总issue"
- issue包含多个子issue或功能模块
- 无具体实现细节——仅包含范围或协调内容
若为epic issue,且仓库存在标签(检查输出),则自动添加标签,无需询问用户。跳过常规的基于类型的标签推断。若仓库不存在标签,执行常规标签选择流程。
epicrepo-context.shepicepicBody
正文
Write a brief 2-4 sentence description. No markdown headers.
For epic issues: do NOT list child issue numbers in the body. Sub-issue relationships are managed via the GitHub sub-issues API (see ## Sub-Issues), not via body text.
编写2-4句话的简短描述,不使用markdown标题。
对于epic issue:不要在正文中列出子issue编号。子issue关系通过GitHub子issue API管理(见**## 子Issue**),而非正文文本。
Labels
标签
Auto-detect label from the issue type (e.g., → or ). Match against labels fetched by . Use to confirm with the user — show top 3 matching labels + "No label".
featfeatureenhancementrepo-context.shAskUserQuestion根据issue类型自动检测标签(如→或)。匹配获取的标签列表。通过确认用户选择——展示排名前3的匹配标签 + "无标签"选项。
featfeatureenhancementrepo-context.shAskUserQuestionAssignee
经办人
Follow ### Assignment Defaults. The issue always gets an assignee unless the user explicitly asked for none.
KIND=personal@me--assignee "@me"issue-assignees.shKIND=orgKIND=externalissue-assignees.shbash
bash "<skill-dir>/scripts/issue-assignees.sh"Output: per row, up to 3 rows (excludes self and bots). Compose :
<user>\t<count>AskUserQuestion- (Recommended)
@me - First result, description:
"Assigned to <count> of last 100 issues" - Second result, description:
"Assigned to <count> of last 100 issues" - "No assignee"
If returns nothing, show only and "No assignee". Do not fall back to the generic collaborator list — those are repo members ranked by nothing meaningful, and inventing labels like "Frequent collaborator" misleads the user.
issue-assignees.sh@merepo-context.shIf the question is skipped or unanswered, default to — never create the issue with no assignee.
@me遵循**### 默认分配规则**。除非用户明确要求,否则issue必须分配经办人。
KIND=personal--assignee "@me"issue-assignees.shKIND=orgKIND=externalissue-assignees.shbash
bash "<skill-dir>/scripts/issue-assignees.sh"输出格式:每行,最多3行(排除自己和机器人)。构造选项:
<user>\t<count>AskUserQuestion- (推荐)
@me - 第一个结果,描述:
"最近100个issue中被分配<count>次" - 第二个结果,描述:
"最近100个issue中被分配<count>次" - "无经办人"
若无输出,仅展示和"无经办人"选项。不要回退到获取的通用协作者列表——这些仓库成员没有有意义的排序,使用"频繁协作者"等标签会误导用户。
issue-assignees.sh@merepo-context.sh若用户跳过或未回答问题,默认分配——切勿创建无经办人的issue。
@meType
类型
Issue types are an organization-level feature. Probe for them:
bash
gh api "repos/<owner>/<repo>/issue-types" --jq '.[].name' 2>/dev/null || true- Names returned → map the conventional commit type onto the closest one and pass
to
--type "<name>".gh issue create - → the repo has no issue types. This is the normal answer for a personal repo, since only orgs define them. Skip silently.
404 Not Found
Do not probe with . There is no
flag on ; it fails with regardless of whether the repo
supports types, so the probe always reports "unsupported".
gh issue create --type bug --dry-run--dry-rungh issue createunknown flagIssue类型是组织级功能。检测仓库是否支持:
bash
gh api "repos/<owner>/<repo>/issue-types" --jq '.[].name' 2>/dev/null || true- 返回名称列表 → 将规范提交类型映射到最接近的类型,并在中传递
gh issue create参数。--type "<name>" - 返回→ 仓库不支持issue类型。个人仓库通常不支持该功能,因为只有组织可以定义。静默跳过该步骤。
404 Not Found
不要使用检测。没有参数,无论仓库是否支持类型,该命令都会因失败,导致检测结果始终为"不支持"。
gh issue create --type bug --dry-rungh issue create--dry-rununknown flagProject
项目
If creating a child of an existing parent (linked, attached, or sub-issue of #N), follow ## Project Inheritance From Parent instead.
Otherwise, rank candidates via (output: per row; = projects from your recent issues, = other active projects):
suggest-projects.sh<bucket>\t<id>\t<title>\t<note>USEDRELATEDbash
bash "<skill-dir>/scripts/suggest-projects.sh"Compose : slot 1 (Recommended) = first row, slots 2–4 = next rows, with as each option's description. Backfill the last slot with "No project" when fewer than 4 rows exist; skip silently when zero rows. On selection, run .
AskUserQuestion<note>add-to-project.sh <issue-number> "<project-title>"若创建现有父issue的子issue(关联、附加或属于#N的子issue),则遵循**## 从父Issue继承项目**规则。
否则,通过排序候选项目(输出格式:每行;=你近期issue所在的项目,=其他活跃项目):
suggest-projects.sh<bucket>\t<id>\t<title>\t<note>USEDRELATEDbash
bash "<skill-dir>/scripts/suggest-projects.sh"构造选项:第1位(推荐)=第一行,第2-4位=后续行,每行的作为选项描述。若不足4行,最后一个选项填充"无项目";若无输出则静默跳过。用户选择后,运行。
AskUserQuestion<note>add-to-project.sh <issue-number> "<project-title>"Milestone
里程碑
Trigger: Check milestones when either:
- The user explicitly asks to assign a milestone
- The target repo's CLAUDE.md mentions milestones (any mention — section headers, instructions, config)
If neither trigger matches, skip silently.
When triggered, fetch open milestones:
bash
gh api "repos/<owner>/<repo>/milestones?state=open" --jq '.[] | {number, title, state, open_issues, closed_issues, due_on}'Then apply:
- 0 milestones: skip silently
- 1 milestone: assign automatically — inform the user which milestone was used
- 2+ milestones: use to pick one:
AskUserQuestion
Which milestone for this issue?
1. "<title1>" (Recommended) — X open / Y closed, due YYYY-MM-DD
2. "<title2>" — X open / Y closed, due YYYY-MM-DD
3. No milestoneOrder by due date (soonest first). The first non-closed milestone is recommended.
Assign via in the command.
--milestone "<title>"gh issue create触发条件:满足以下任一条件时检查里程碑:
- 用户明确要求分配里程碑
- 目标仓库的CLAUDE.md提及里程碑(任何提及——章节标题、说明、配置)
若两个触发条件均不满足,静默跳过该步骤。
触发后,获取开放的里程碑:
bash
gh api "repos/<owner>/<repo>/milestones?state=open" --jq '.[] | {number, title, state, open_issues, closed_issues, due_on}'然后执行:
- 0个里程碑:静默跳过
- 1个里程碑:自动分配——告知用户使用的里程碑
- 2个及以上里程碑:通过选择:
AskUserQuestion
该issue分配哪个里程碑?
1. "<title1>"(推荐)—— X个开放 / Y个已关闭,截止日期YYYY-MM-DD
2. "<title2>"—— X个开放 / Y个已关闭,截止日期YYYY-MM-DD
3. 无里程碑按截止日期排序(最近的优先)。第一个非关闭状态的里程碑为推荐选项。
在命令中通过参数分配里程碑。
gh issue create--milestone "<title>"Create
创建
Use the from the parallel setup batch. Write the issue body to with the host's file-write tool, then create the issue with :
<TMPDIR><TMPDIR>/body.md--body-filebash
gh issue create --title "<title>" --body-file <TMPDIR>/body.md --label "<label>" --assignee "<assignee>" [--milestone "<name>"]When creating multiple issues, use unique filenames per issue: (e.g. , ). Resolve once and reuse it for all issues.
<TMPDIR>/<slug>-body.mdauth-body.mdsettings-body.md<TMPDIR>Important: Replace with the literal absolute path in all commands (e.g. ). Do NOT set as an env var prefix on commands — that changes the command pattern and triggers permission prompts.
<TMPDIR>--body-file /var/folders/.../issue-flow-AbCdEf/body.mdTMPDIR=Do NOT use — the command substitution makes the command unmatchable against any pre-approval rule, so hosts that gate shell commands re-prompt every time.
--body "$(cat <<'EOF'...)"$()Print the Step 1 report (see ).
references/report-format.md使用并行设置步骤中获取的。通过宿主的文件写入工具将issue正文写入,然后使用参数创建issue:
<TMPDIR><TMPDIR>/body.md--body-filebash
gh issue create --title "<title>" --body-file <TMPDIR>/body.md --label "<label>" --assignee "<assignee>" [--milestone "<name>"]创建多个issue时,每个issue使用唯一的文件名:(如、)。仅解析一次并复用。
<TMPDIR>/<slug>-body.mdauth-body.mdsettings-body.md<TMPDIR>重要提示:将所有命令中的替换为实际的绝对路径(如)。不要将作为环境变量前缀添加到命令中——这会改变命令格式并触发权限提示。
<TMPDIR>--body-file /var/folders/.../issue-flow-AbCdEf/body.mdTMPDIR=不要使用格式——命令替换会导致命令无法匹配任何预审批规则,因此管控shell命令的宿主会每次重新提示。
--body "$(cat <<'EOF'...)"$()打印步骤1报告(见)。
references/report-format.mdSub-Issues (Optional)
子Issue(可选)
If the user mentioned other issue numbers to include in this aggregated issue, add them as sub-issues immediately after the parent is created — before printing the Step 1 report. See ## Sub-Issues for the procedure.
若用户提及要包含在汇总issue中的其他issue编号,在父issue创建完成后立即添加为子issue——在打印步骤1报告前执行。操作步骤见**## 子Issue**。
Sub-Issues
子Issue
Use when an aggregated (parent) issue should group related child issues. Needs the integer , not the issue number — they are different things. See for ID type details.
.idreferences/github-relationships.md用于汇总(父)issue分组相关子issue的场景。需要整数,而非issue编号——两者不同。ID类型详情见。使用输出中的值——即标题后的行,而非输出第一行。
.idreferences/github-relationships.mdrepo-context.sh<owner>/<repo>=== Repository ===Procedure
操作步骤
Fetch each child's integer ID, then POST it. Use the value from — it is the line after the header, not the first line of output.
<owner>/<repo>repo-context.sh=== Repository ===bash
PARENT=<parent_number>
for num in <child1> <child2> <child3>; do
id=$(gh api repos/<owner>/<repo>/issues/$num --jq '.id')
gh api repos/<owner>/<repo>/issues/$PARENT/sub_issues \
--method POST \
-F sub_issue_id="$id"
done-F-f422bash
gh api repos/<owner>/<repo>/issues/<parent_number>/sub_issues --jq '.[].number'When a newly created issue is being linked as a child of an existing parent, also follow ## Project Inheritance From Parent so the child lands on the same project board(s) as the parent.
获取每个子issue的整数ID,然后执行POST请求。
bash
PARENT=<parent_number>
for num in <child1> <child2> <child3>; do
id=$(gh api repos/<owner>/<repo>/issues/$num --jq '.id')
gh api repos/<owner>/<repo>/issues/$PARENT/sub_issues \
--method POST \
-F sub_issue_id="$id"
done必须使用(表单字段)——会发送字符串,导致错误。POST请求返回父issue对象——响应中包含父标题表示成功。验证:
-F-f422bash
gh api repos/<owner>/<repo>/issues/<parent_number>/sub_issues --jq '.[].number'当新创建的issue被链接为现有父issue的子issue时,还需遵循**## 从父Issue继承项目**规则,使子issue与父issue处于相同的项目看板。
Project Inheritance From Parent
从父Issue继承项目
When a new issue is being created as a child of an existing parent (sub-issue link, "attach to #N", "linked to #N"), inherit the parent's project membership instead of using the generic Project picker.
Fetch the parent's projects (output: ):
<id>\t<title>bash
bash "<skill-dir>/scripts/get-issue-projects.sh" <parent_number>Apply based on count:
- 0 — fall through to the generic Project subsection.
- 1 — add automatically and tell the user which project was inherited.
- 2+ — :
AskUserQuestion- "Add to all <N> parent projects" (Recommended)
- "Pick individually" — follow-up yes/no per project
- "Skip projects"
Run sequentially per selected project (parallel calls hit Projects V2 rate limits).
add-to-project.sh <child_number> "<title>"When linking many children to the same parent (see ## Batch Issue Creation), fetch the parent's projects once and reuse the decision for every child — do not prompt per child.
当新创建的issue作为现有父issue的子issue(子issue链接、"附加到#N"、"关联到#N")时,继承父issue的项目成员身份,而非使用通用的项目选择器。
获取父issue的项目(输出格式:):
<id>\t<title>bash
bash "<skill-dir>/scripts/get-issue-projects.sh" <parent_number>根据数量执行:
- 0个——执行通用项目选择流程。
- 1个——自动添加并告知用户继承的项目。
- 2个及以上——选项:
AskUserQuestion- "添加到所有<N>个父项目"(推荐)
- "单独选择"——逐个确认是否添加到对应项目
- "跳过项目"
按顺序为每个选中的项目运行(并行调用会触发Projects V2速率限制)。
add-to-project.sh <child_number> "<title>"当多个子issue链接到同一个父issue时(见**## 批量创建Issue**),仅获取一次父issue的项目,并将决策复用给所有子issue——不要逐个提示。
Blocked-By
依赖关系(Blocked-By)
Use when child issues have dependencies between them — e.g., issue B cannot start until issue A is done. Requires GraphQL node IDs (not issue numbers or integer IDs) — see . Use the value from — it is the line after the header, not the first line of output.
references/github-relationships.md<owner>/<repo>repo-context.sh=== Repository ===用于子issue之间存在依赖关系的场景——例如,issue B需在issue A完成后才能开始。需要GraphQL node ID(而非issue编号或整数ID)——详情见。使用输出中的值——即标题后的行,而非输出第一行。
references/github-relationships.mdrepo-context.sh<owner>/<repo>=== Repository ===Procedure
操作步骤
Step 1 — Fetch node IDs in one batch query:
bash
gh api graphql -f query='{
repository(owner: "<owner>", name: "<repo>") {
a: issue(number: <blocking-num>) { id }
b: issue(number: <blocked-num>) { id }
}
}'Step 2 — Add relationship ("b is blocked by a"):
bash
gh api graphql -f query='mutation {
addBlockedBy(input: {
issueId: "<node-id-of-b>",
blockingIssueId: "<node-id-of-a>"
}) { issue { number } blockingIssue { number } }
}'Use with the same signature to undo. See for full details and ID type reference.
removeBlockedByreferences/github-relationships.md步骤1——批量查询获取node ID:
bash
gh api graphql -f query='{
repository(owner: "<owner>", name: "<repo>") {
a: issue(number: <blocking-num>) { id }
b: issue(number: <blocked-num>) { id }
}
}'步骤2——添加关系("b被a阻塞"):
bash
gh api graphql -f query='mutation {
addBlockedBy(input: {
issueId: "<node-id-of-b>",
blockingIssueId: "<node-id-of-a>"
}) { issue { number } blockingIssue { number } }
}'使用并传递相同参数取消依赖关系。完整详情和ID类型参考见。
removeBlockedByreferences/github-relationships.mdBatch Issue Creation
批量创建Issue
When the user asks to create multiple issues at once (e.g., an epic with child issues, or a set of related issues):
当用户要求一次性创建多个issue时(如包含子issue的epic或一组相关issue):
Workflow
工作流程
- Resolve once via
<TMPDIR>mktemp -d - Create the parent/epic issue first (if applicable)
- Write all child issue body files with unique slugs:
<TMPDIR>/<slug>-body.md - Create all child issues in parallel (calls) — apply ### Assignment Defaults once and reuse the same assignee for every issue in the batch, including the parent. Do not prompt per issue.
gh issue create - Batch-link sub-issues to parent (if applicable) — use the for loop from ## Sub-Issues
- Add all issues to project sequentially — run in a for loop, one at a time (parallel calls cause API rate-limit failures and require retries). When children are linked to an existing parent, resolve the project set via ## Project Inheritance From Parent instead of asking generically.
add-to-project.sh - Ask about initial project status (e.g., "Backlog", "Current Sprint") via — then batch-update via
AskUserQuestionproject-status.sh - Print a summary table at the end instead of per-issue Step 1 reports
- 通过解析一次
mktemp -d<TMPDIR> - 先创建父/epic issue(若有)
- 使用唯一的slug为所有子issue写入正文文件:
<TMPDIR>/<slug>-body.md - 并行创建所有子issue(调用)——应用**### 默认分配规则**一次,并将相同的经办人复用给批量中的所有issue,包括父issue。不要逐个提示。
gh issue create - 批量将子issue链接到父issue(若有)——使用**## 子Issue**中的for循环
- 按顺序将所有issue添加到项目——在for循环中运行,逐个执行(并行调用会导致API速率限制失败并需要重试)。若子issue链接到现有父issue,通过**## 从父Issue继承项目**解析项目集,而非通用询问。
add-to-project.sh - 通过询问初始项目状态(如"待办"、"当前迭代")——然后通过
AskUserQuestion批量更新project-status.sh - 最后打印汇总表格,而非逐个issue的步骤1报告
Summary Table Format
汇总表格格式
| Issue | Title | Milestone |
| ----- | ----------------------- | ----------- |
| [#10023](https://github.com/owner/repo/issues/10023) | AnchorDialog for Editor | Alpha (MVP) |
| [#10024](https://github.com/owner/repo/issues/10024) | Toolbar refactor | Alpha (MVP) |Omit the Milestone column if no milestone was assigned to any issue.
| Issue | 标题 | 里程碑 |
| ----- | ----------------------- | ----------- |
| [#10023](https://github.com/owner/repo/issues/10023) | 编辑器的AnchorDialog | Alpha (MVP) |
| [#10024](https://github.com/owner/repo/issues/10024) | 工具栏重构 | Alpha (MVP) |若没有issue分配里程碑,则省略里程碑列。
Step 2: Create Branch
步骤2:创建分支
Run to find the correct base branch.
detect-base.shIf the working tree is dirty (full flow from uncommitted changes):
bash
git checkout -b issue-<number>Changes carry over to the new branch automatically. Skip checkout and pull — pulling on a dirty tree fails, and you're already on the base.
If the working tree is clean (entered at Step 2 directly, e.g. "start work on #N"):
bash
git checkout <base> && git pull origin <base>
git checkout -b issue-<number>If already exists, use :
issue-<number>AskUserQuestion- "Switch to existing branch" (Recommended)
- "Delete and create fresh"
Update project status to "In Progress" (if project integration is available):
bash
bash "<skill-dir>/scripts/project-status.sh" <number> "In Progress"Resolve the fork point for the report, so callers never have to turn the base name back
into a rev:
bash
baseref=$(git rev-parse --verify --quiet "origin/$base" || git rev-parse --verify --quiet "$base")
git merge-base "$baseref" HEADPrint the Step 2 report, including both and .
Base:Fork:运行查找正确的基础分支。
detect-base.sh若工作区有未提交变更(从未提交变更开始完整流程):
bash
git checkout -b issue-<number>变更会自动携带到新分支。跳过checkout和pull操作——在脏工作区执行pull会失败,且当前已处于基础分支。
若工作区干净(直接切入步骤2,如"开始处理#N"):
bash
git checkout <base> && git pull origin <base>
git checkout -b issue-<number>若分支已存在,通过询问用户:
issue-<number>AskUserQuestion- "切换到现有分支"(推荐)
- "删除现有分支并重新创建"
更新项目状态为"进行中"(若支持项目集成):
bash
bash "<skill-dir>/scripts/project-status.sh" <number> "In Progress"解析报告的分叉点,调用方无需将基础名称转换为版本号:
bash
baseref=$(git rev-parse --verify --quiet "origin/$base" || git rev-parse --verify --quiet "$base")
git merge-base "$baseref" HEAD打印步骤2报告,包含和字段。
Base:Fork:Step 3: Commit
步骤3:提交
This step owns the commit subject format, the commit body, and the squash rules for
the whole pipeline. Nothing else defines them — callers delegate here.
本步骤管控整个流程中的提交主题格式、提交正文和合并规则。其他部分均不定义这些规则——调用方需委托给本步骤。
Subject
主题
Use as the commit subject. The issue title is already in conventional commit format from Step 1 or from the skill.
<Issue Title> #<number>issue-analyzeIf there is no linked issue (e.g., entered at Step 3 directly), use the repo's CLAUDE.md commit format or fall back to .
<type>: <description>No subject may survive into the final history.
wip:使用作为提交主题。issue标题已在步骤1或技能中使用规范提交格式。
<Issue Title> #<number>issue-analyze若未关联issue(如直接切入步骤3),使用仓库CLAUDE.md中的提交格式或回退到。
<type>: <description>最终提交历史中不得包含主题。
wip:Body
正文
Invoke the skill to generate the commit body. It weighs the change and
either derives a body from the code — what the running code does that forced the change,
which call paths reach it, what breaks on update, when it broke, what was deliberately left
alone — or returns two to three lines for a mechanical or generated change.
commit-summaryIf the host cannot invoke another skill, or is not installed, do the same
inline. Derive when the change alters behaviour, a contract, a public type, or a default, or
fixes a defect; otherwise write two or three past-tense lines and stop. To derive, answer in
blank-line-separated paragraphs wrapped at 80, skipping any question with no real answer:
what the running code does that forces the change (read the implementation, not the diff
again), which call paths reach it and which are ruled out, how it failed observably, what
breaks for someone who updates and why it is still correct, when it broke
(, ), what the tests pin, and what
was noticed and deliberately not fixed. A hash appears only if a command returned it in this
session; no result means the paragraph is dropped, not softened.
commit-summarygit log -S '<removed expression>' -- <path>git blameWhen the caller supplies design rationale pulled out of source comments (the
skill produces this), it answers the first question — fold it into that paragraph. It is not
a block to append at the end of the body.
code-cleanup调用技能生成提交正文。该技能会评估变更内容,要么从代码中推导正文——运行代码的哪些行为导致了变更、哪些调用路径会影响该变更、更新时会破坏什么、何时出现问题、哪些内容被故意保留——要么为机械或生成的变更返回2-3行内容。
commit-summary若宿主无法调用其他技能,或未安装,则自行推导。当变更改变行为、契约、公共类型或默认值,或修复缺陷时,进行推导;否则编写2-3行过去式描述后停止。推导时,用空行分隔段落,每行不超过80字符,跳过无实际答案的问题:运行代码的哪些行为导致了变更(阅读实现,而非再次查看diff)、哪些调用路径会影响该变更并排除哪些路径、变更如何导致可观察的失败、更新时会破坏什么以及为何仍正确、何时出现问题(、)、测试固定了哪些内容、哪些问题被发现并故意未修复。仅当会话中命令返回哈希值时才包含哈希值;若命令无结果,则删除对应段落,而非弱化描述。
commit-summarygit log -S '<removed expression>' -- <path>git blame当调用方提供从源代码注释中提取的设计原理(技能会生成此类内容),该原理可回答第一个问题——将其合并到对应段落中。不要将其作为块附加到正文末尾。
code-cleanupNo attribution
无署名
This step runs the , so it is the last place an attribution footer can be caught.
Read the assembled message before committing and remove any of these, wherever they came
from — a body another skill returned, text a caller passed in, a message being amended:
git commit- "Drafted with AI", "Generated with", or any line naming a model, an assistant, or a tool
- a session, chat, or transcript link
- a attribution line, a trailing
<sub>rule, a badge, or a promotional line--- - a trailer crediting an assistant
Co-Authored-By
Do not add one either, and do not copy one forward from the previous commit. A trailer
already in the log is not licence to repeat it; mirroring the last commit's footer is how one
reproduces itself indefinitely.
A trailer crediting a human is fine where the repo's convention asks for one. The only
exception is an explicit request — the repo's instruction file, the user's configuration, or
the user's prompt asking for attribution outright. Finding one in is not that.
git log本步骤执行,因此是最后可以捕获署名页脚的环节。提交前读取组装好的消息并移除以下内容,无论来源——其他技能返回的正文、调用方传递的文本、正在修改的消息:
git commit- "Drafted with AI"、"Generated with"或任何提及模型、助手或工具的行
- 会话、聊天或转录链接
- 署名行、末尾的
<sub>规则、徽章或推广行--- - 署名助手的trailer
Co-Authored-By
也不要添加这些内容,且不要从之前的提交中复制。日志中已存在的trailer并不允许重复使用;镜像上一次提交的页脚会导致该内容无限重复。
若仓库规范要求,署名人类的trailer是可以的。唯一例外是明确要求——仓库的说明文件、用户配置或用户提示明确要求署名。在中找到署名并不属于这种情况。
git logConsolidate
合并提交
The branch must end this step at exactly one commit, and this section owns the only gate that can decide otherwise.
分支在本步骤结束时必须恰好有一个提交,本部分是唯一可以决定是否例外的环节。
Resolve the fork point
解析分叉点
Count and reset must use the same ref, and it must be an ancestor of . Resolve it once:
HEADbash
base=$(bash "<skill-dir>/scripts/detect-base.sh" 2>/dev/null | tail -n1) || base=""
[ -n "$base" ] || { echo "No base branch — add a remote first."; exit 1; }
baseref=$(git rev-parse --verify --quiet "origin/$base" || git rev-parse --verify --quiet "$base")
fork=$(git merge-base "$baseref" HEAD)
git log "$fork"..HEAD --onelineStop if is empty. exits 2 with no output when the repo has no
remote, and just errors — there is no base to consolidate against.
basedetect-base.shgit merge-base "" HEADNever reset to , and never to a branch name. moves whenever anything fetches, and fetches on its own. Reset to it and the new commit's parent is newer than the point the branch was cut from, so the commit silently reverts every upstream change made since — and Step 5 force-pushes that, and Step 6 merges it. is an ancestor of by construction, so it cannot have that effect.
origin/<base>origin/<base>detect-base.sh$forkHEAD计数和重置必须使用相同的引用,且该引用必须是的祖先。仅解析一次:
HEADbash
base=$(bash "<skill-dir>/scripts/detect-base.sh" 2>/dev/null | tail -n1) || base=""
[ -n "$base" ] || { echo "No base branch — add a remote first."; exit 1; }
baseref=$(git rev-parse --verify --quiet "origin/$base" || git rev-parse --verify --quiet "$base")
fork=$(git merge-base "$baseref" HEAD)
git log "$fork"..HEAD --oneline若为空,停止操作。当仓库没有远程仓库时,会以状态码2退出且无输出,会直接报错——没有可合并的基础分支。
basedetect-base.shgit merge-base "" HEAD切勿重置到或分支名称。会在每次fetch时更新,且会自行执行fetch操作。重置到该引用会导致新提交的父节点比分支创建时的节点更新,因此提交会静默回滚自分支创建以来的所有上游变更——步骤5会强制推送该提交,步骤6会合并该提交。是的祖先,因此不会出现这种情况。
origin/<base>origin/<base>detect-base.sh$forkHEADChoose the action
选择操作
Commits ahead of | Action |
|---|---|
| 0 | Nothing to unwind — go to Execute. |
| 1, subject already canonical | Keep the commit. If the tree is dirty (a caller's comment trim or cruft deletion usually leaves it that way), stage the remaining edits and rewrite the message from Subject and Body: |
1, a | |
2+, one shared subject, or any | |
| 2+, genuinely different subjects | Ask before rewriting deliberate history: option 1 |
A caller that asked for a single commit ( from an orchestrating skill) has already answered that question — squash without prompting.
"commit #<N>"超前于 | 操作 |
|---|---|
| 0 | 无需回退——进入执行环节。 |
| 1,主题已符合规范 | 保留该提交。若工作区有未提交变更(通常是调用方的注释修剪或清理遗留的),暂存剩余编辑内容并根据主题和正文重写消息: |
1, | |
2+,主题相同,或包含 | |
| 2+,主题确实不同 | 在重写有意保留的历史前询问用户:选项1 |
若调用方要求单个提交(编排技能的指令),则已确认合并——无需提示直接合并。
"commit #<N>"Check the index before committing
提交前检查索引
git reset --soft$forkwip:bash
git diff --cached --name-only
git restore --staged <path> # per file that does not belong in the commitDeleting the file from disk is not enough once it is staged — unstage it. Untracked files are the one thing the reset does not capture; they stay untracked unless something adds them.
git reset --soft$forkwip:bash
git diff --cached --name-only
git restore --staged <path> # 逐个移除不应提交的文件文件已暂存后,仅删除磁盘上的文件是不够的——需取消暂存。未跟踪文件是重置不会捕获的内容;除非主动添加,否则会保持未跟踪状态。
Execute
执行
Stage what belongs in the commit, then commit:
bash
git add <files>
git commit -m "<subject>" -m "<body>"Two different states reach this point, and the staging rule differs:
- No reset happened (the row). The index starts empty, so
0fully determines the commit. Prefer naming files overgit add <files>— here it genuinely is the check that keeps scratch files out.git add -A - A reset happened. The index already holds everything Consolidate unwound. Naming files cannot narrow it, so Consolidate's index check is what keeps scratch out; here is only for files that were never committed.
git add
Finish with showing nothing you meant to commit. Untracked files you deliberately left out may still be listed — that is expected, and Step 3 has no authority to delete them.
git status --shortPrint the Step 3 report.
暂存应提交的内容,然后提交:
bash
git add <files>
git commit -m "<subject>" -m "<body>"有两种状态会进入该环节,暂存规则不同:
- 未执行重置(行)。索引初始为空,因此
0完全决定提交内容。优先指定文件而非git add <files>——这是防止临时文件被提交的检查手段。git add -A - 已执行重置。索引已包含合并提交回滚的所有内容。指定文件无法缩小范围,因此合并提交的索引检查是防止临时文件被提交的手段;仅用于添加从未提交过的文件。
git add
结束时应显示无待提交内容。故意排除的未跟踪文件仍可能被列出——这是预期情况,步骤3无权删除这些文件。
git status --short打印步骤3报告。
Snapshot Mode
快照模式
Entered on intent "snapshot" — a caller needs the working tree frozen into a commit
without finishing the work. Used to give reviewers a stable diff, or to checkpoint
during a long implementation.
bash
git status --short # confirm nothing scratch is about to be staged
git add -A && git commit -m "wip: snapshot"Snapshot mode skips the Subject, Body, and Consolidate sections entirely:
- The subject is content-free. A snapshot message describing the work leaks the implementer's reasoning into a place reviewers can read.
- No call — there is no body.
commit-summary - No report. Print one line: .
Snapshot: <short-sha>
Snapshots are not final commits. A later Step 3 run squashes them away via
Consolidate.
当用户意图为"snapshot"时进入该模式——调用方需要将工作区冻结为提交,但未完成工作。用于为评审者提供稳定的diff,或在长时间实现过程中创建检查点。
bash
git status --short # 确认没有临时文件会被暂存
git add -A && git commit -m "wip: snapshot"快照模式完全跳过主题、正文和合并提交环节:
- 主题无实际内容。描述工作的快照消息会将实现者的推理泄露给评审者。
- 不调用——无正文。
commit-summary - 不生成报告。仅打印一行:。
Snapshot: <short-sha>
快照不是最终提交。后续步骤3运行时会通过合并提交环节将其合并。
Step 4: Push
步骤4:推送
Push the branch to remote:
bash
git push -u origin issue-<number>将分支推送到远程仓库:
bash
git push -u origin issue-<number>Rebase if needed
必要时变基
If push fails because the remote has diverged, or if the user asks to rebase — capture the
remote tip first, per Leasing a force-push:
bash
before=$(git rev-parse "origin/issue-<number>" 2>/dev/null || true)
git fetch origin <base>
git rebase origin/<base>
if [ -n "$before" ]; then
git push --force-with-lease="issue-<number>:$before"
else
git push -u origin issue-<number>
fi若推送因远程仓库分支已偏离而失败,或用户要求变基——先捕获远程分支的最新提交,遵循强制推送租赁:
bash
before=$(git rev-parse "origin/issue-<number>" 2>/dev/null || true)
git fetch origin <base>
git rebase origin/<base>
if [ -n "$before" ]; then
git push --force-with-lease="issue-<number>:$before"
else
git push -u origin issue-<number>
fiAmend
修改提交
If the user asks to amend the last commit:
bash
before=$(git rev-parse "origin/issue-<number>" 2>/dev/null || true)
git commit --amend -m "<subject>" -m "<body>"
if [ -n "$before" ]; then
git push --force-with-lease="issue-<number>:$before"
else
git push -u origin issue-<number>
fiAlways pass the message. A bare opens , which hangs a
non-interactive shell. Use only when the existing message is being kept
verbatim and nothing new needs to land in it.
git commit --amend$EDITOR--no-edit若用户要求修改最后一次提交:
bash
before=$(git rev-parse "origin/issue-<number>" 2>/dev/null || true)
git commit --amend -m "<subject>" -m "<body>"
if [ -n "$before" ]; then
git push --force-with-lease="issue-<number>:$before"
else
git push -u origin issue-<number>
fi始终传递消息。仅会打开,导致非交互式shell挂起。仅当完全保留现有消息且无需添加新内容时,使用。
git commit --amend$EDITOR--no-editLeasing a force-push
强制推送租赁
Every force-push in this pipeline pins the SHA it expects the remote to be at, captured
before anything fetches:
bash
before=$(git rev-parse "origin/issue-<number>" 2>/dev/null || true)本流程中的每次强制推送都会固定预期远程仓库的SHA,在任何fetch操作前捕获:
bash
before=$(git rev-parse "origin/issue-<number>" 2>/dev/null || true)... rebase, amend, or consolidate ...
... 变基、修改或合并提交 ...
git push --force-with-lease="issue-<number>:$before"
`rev-parse` is guarded because the branch may not be on the remote yet, and a bare
`git rev-parse origin/issue-<number>` exits 128 with `unknown revision` — which under
`set -e` aborts the step instead of pushing. An empty `$before` means there is nothing to
lease against, so that case is a plain `git push -u origin issue-<number>`.
A bare `git push --force-with-lease` leases against `refs/remotes/origin/issue-<number>`.
Any fetch that refreshes that ref makes the lease describe where the remote is *now*
rather than where it was when you started — at which point it permits exactly the
overwrite it exists to prevent. `detect-base.sh` runs a bare `git fetch origin`, which
refreshes every branch, inside Step 3 → Consolidate; and nothing stops an unrelated fetch
landing between the rewrite and the push. Reading the SHA before any of that is what makes
the lease mean anything.
`--force-if-includes` (git 2.30+) is not a substitute here. `git help push` is explicit
that when it is combined with `--force-with-lease=<refname>:<expect>` it is a **no-op** —
so alongside the pinned form above it does literally nothing. It is the right tool for the
*valueless* `--force-with-lease`, since it consults the local reflog rather than the
remote-tracking ref; but it needs git 2.30+, it fails oddly after a `gc` or in a fresh
clone where the reflog is thin, and it would diverge from the pinned idiom used
everywhere else in this file. Pin the SHA instead.
If the push is rejected, the remote moved: fetch, rebase onto the new tip, and re-run
rather than escalating to `--force`.
Print the Step 4 report.git push --force-with-lease="issue-<number>:$before"
`rev-parse`添加了错误处理,因为分支可能尚未推送到远程仓库,且`git rev-parse origin/issue-<number>`会因`unknown revision`以状态码128退出——若启用`set -e`会中止步骤而非推送。空`$before`表示无租赁对象,因此执行普通的`git push -u origin issue-<number>`。
仅`git push --force-with-lease`会租赁`refs/remotes/origin/issue-<number>`。任何刷新该引用的fetch操作都会使租赁描述远程仓库**当前**状态,而非开始操作时的状态——此时租赁会允许其本应阻止的覆盖操作。`detect-base.sh`在步骤3→合并提交环节中会执行`git fetch origin`,刷新所有分支;且在重写和推送之间可能会有无关的fetch操作。在这些操作前读取SHA才能使租赁有效。
`--force-if-includes`(git 2.30+)不能替代该方式。`git help push`明确说明,当与`--force-with-lease=<refname>:<expect>`结合使用时,该参数是**无效操作**——因此与上述固定格式结合使用时毫无作用。它是无值`--force-with-lease`的合适工具,因为它会查询本地reflog而非远程跟踪引用;但它需要git 2.30+,在`gc`后或reflog稀疏的新克隆中会异常失败,且与本文档中使用的固定方式不一致。因此固定SHA更可靠。
若推送被拒绝,说明远程仓库已更新:fetch远程仓库,变基到新的最新提交,然后重新运行,而非升级为`--force`。
打印步骤4报告。Step 5: Create PR
步骤5:创建PR
Run to determine the PR base.
detect-base.sh运行确定PR的基础分支。
detect-base.shPre-PR: Squash Commits
创建PR前:合并提交
Apply Step 3 → Consolidate as-is. It owns the fork point, the count, the squash rules, and the one gate that may leave several commits — including the case where the single commit on the branch is a snapshot, which must not reach a PR title. Do not restate any of those rules here; a second copy is how the two drift.
wip:The only thing this step adds is that the branch is already on the remote, so the rewrite has to be force-pushed. Capture the remote tip before consolidating and lease against it explicitly, per Leasing a force-push:
bash
before=$(git rev-parse "origin/issue-<number>")直接应用步骤3→合并提交规则。该环节管控分叉点、提交计数、合并规则以及允许保留多个提交的唯一条件——包括分支上的单个提交是快照的情况,该快照不能作为PR标题。不要在此处重述任何规则——重复定义会导致两者不一致。
wip:本步骤仅添加分支已推送到远程仓库的处理,因此重写后需强制推送。合并提交前先捕获远程分支的最新提交并明确租赁,遵循强制推送租赁:
bash
before=$(git rev-parse "origin/issue-<number>")... apply Step 3 -> Consolidate ...
... 应用步骤3→合并提交 ...
git push --force-with-lease="issue-<number>:$before"
This must happen before PR body generation, since consolidating changes the commit log.git push --force-with-lease="issue-<number>:$before"
这必须在生成PR正文前执行,因为合并提交会改变提交日志。Title and Body
标题和正文
- Title:
<Issue Title> #<number> - Body: Generate from — reuse the
git log "$fork"..HEAD --onelinethat Step 3 → Consolidate just resolved. Do not write$fork:git log <base>..HEADis a branch name, and an epic branch that exists only on the remote fails there with<base>. Addunknown revision.Closes #<number>
markdown
undefined- 标题:
<Issue Title> #<number> - 正文:从生成——复用步骤3→合并提交刚解析的
git log "$fork"..HEAD --oneline。不要使用$fork:git log <base>..HEAD是分支名称,仅存在于远程仓库的epic分支会因<base>失败。添加unknown revision。Closes #<number>
markdown
undefinedChanges
变更
- <change 1>
- <change 2>
Closes #<number>
undefined- <变更1>
- <变更2>
Closes #<number>
undefinedAssignee and Reviewer
经办人和评审人
Follow ### Assignment Defaults. Reviewer selection is separate from assignment: the current user is an assignee on every PR this skill creates, whatever the reviewer outcome.
In a repo, skip the reviewer prompt entirely unless the repo's CLAUDE.md sets a reviewer rule or the user asked for one — a solo repo has no one else to review, and the reviewer question is the step where assignment silently gets dropped.
KIND=personalCheck the target repo's CLAUDE.md for reviewer rules (e.g., "PRs to main should be reviewed by @username", default reviewer for specific branches). If a matching rule exists, use that reviewer directly.
Otherwise, run to find users with actual recent PR review activity:
pr-reviewers.shbash
bash "<skill-dir>/scripts/pr-reviewers.sh"Output: per row, up to 3 rows (excludes self and bots; counts both reviews submitted and review-requests received across the last 100 PRs in any state).
<user>\t<count>- 0 results: skip the prompt entirely and create the PR without . Do not fall back to the generic
--reviewercollaborator list — repo members with zero review history are not real reviewer candidates, and inventing labels like "Frequent collaborator" misleads the user.repo-context.sh - 1+ results: compose :
AskUserQuestion- First result (Recommended), description:
"<count> review events across the last 100 PRs" - Second result (if any), description:
"<count> review events across the last 100 PRs" - "No reviewer"
- First result (Recommended), description:
Check if the selected reviewer is the same as the PR creator:
bash
gh api user --jq .loginIf same, skip flag (GitHub doesn't allow self-review).
--reviewer遵循**### 默认分配规则**。评审人选择与经办人选择分开:本技能创建的每个PR中,当前用户都是经办人,无论评审人选择结果如何。
在仓库中,除非仓库CLAUDE.md设置了评审人规则或用户要求,否则完全跳过评审人提示——单人仓库没有其他评审人,且评审人环节会导致经办人被静默丢弃。
KIND=personal检查目标仓库CLAUDE.md中的评审人规则(如"main分支的PR需由@username评审"、特定分支的默认评审人)。若存在匹配规则,直接使用该评审人。
否则,运行查找近期有实际PR评审活动的用户:
pr-reviewers.shbash
bash "<skill-dir>/scripts/pr-reviewers.sh"输出格式:每行,最多3行(排除自己和机器人;统计最近100个PR中提交的评审和收到的评审请求)。
<user>\t<count>- 0个结果:完全跳过提示,创建PR时不使用参数。不要回退到
--reviewer获取的通用协作者列表——无评审历史的仓库成员不是真正的评审候选人,使用"频繁协作者"等标签会误导用户。repo-context.sh - 1个及以上结果:构造选项:
AskUserQuestion- 第一个结果(推荐),描述:
"最近100个PR中有<count>次评审活动" - 第二个结果(若有),描述:
"最近100个PR中有<count>次评审活动" - "无评审人"
- 第一个结果(推荐),描述:
检查选中的评审人是否与PR创建者相同:
bash
gh api user --jq .login若相同,跳过参数(GitHub不允许自我评审)。
--reviewerAssignees
经办人
The PR creator (, i.e. the current user) is always an assignee — in personal and org repos alike, with or without a reviewer. Setting a reviewer never replaces the creator on Assignees; it adds to it.
@me- Reviewer set (and not the creator): assign and the reviewer.
@me- e.g. creator sets
aliceas reviewer → Reviewers:octocat, Assignees:octocat,octocat.alice
- e.g. creator
- No reviewer (or reviewer is the creator / self-review): assign only .
@me
There is no branch of this step that produces zero assignees. If a reviewer prompt is skipped or returns nothing, still goes on .
pr-reviewers.sh@me--assigneePR创建者(,即当前用户)始终是经办人——无论个人仓库还是组织仓库,无论是否有评审人。设置评审人不会替换创建者的经办人身份;只会添加到经办人列表。
@me- 已设置评审人(且评审人不是创建者):分配和评审人。
@me- 例如,创建者设置
alice为评审人 → 评审人:octocat,经办人:octocat、octocat。alice
- 例如,创建者
- 无评审人(或评审人是创建者/自我评审):仅分配。
@me
本步骤不会出现无经办人的情况。若跳过评审人提示或无输出,仍会被添加到参数。
pr-reviewers.sh@me--assigneeCreate
创建
Write the PR body to with the host's file-write tool, then create the PR with . Replace with the literal absolute path — do NOT use as an env var prefix.
<TMPDIR>/pr-body.md--body-file<TMPDIR>TMPDIR=With a reviewer (pass once per assignee):
--assigneebash
gh pr create --title "<title>" --body-file <TMPDIR>/pr-body.md --base <base> --assignee @me --assignee <reviewer> --reviewer <reviewer>Without a reviewer (or self-review):
bash
gh pr create --title "<title>" --body-file <TMPDIR>/pr-body.md --base <base> --assignee @meDo NOT use — the command substitution makes the command unmatchable against any pre-approval rule, so hosts that gate shell commands re-prompt every time.
--body "$(cat <<'EOF'...)"$()Update project status to "Review":
bash
bash "<skill-dir>/scripts/project-status.sh" <number> "Review"通过宿主的文件写入工具将PR正文写入,然后使用参数创建PR。将替换为实际的绝对路径——不要使用作为环境变量前缀。
<TMPDIR>/pr-body.md--body-file<TMPDIR>TMPDIR=指定评审人时(每个经办人传递一次):
--assigneebash
gh pr create --title "<title>" --body-file <TMPDIR>/pr-body.md --base <base> --assignee @me --assignee <reviewer> --reviewer <reviewer>无评审人时(或自我评审):
bash
gh pr create --title "<title>" --body-file <TMPDIR>/pr-body.md --base <base> --assignee @me不要使用格式——命令替换会导致命令无法匹配任何预审批规则,因此管控shell命令的宿主会每次重新提示。
--body "$(cat <<'EOF'...)"$()更新项目状态为"评审中":
bash
bash "<skill-dir>/scripts/project-status.sh" <number> "Review"Verify mergeability
可合并性验证
Always run this after creating a PR, whether or not Step 6 will follow. A PR that cannot merge is not a finished step, and reporting "PR created" without checking hides that.
GitHub computes asynchronously, so it returns for the first second or two — poll until it settles:
mergeableUNKNOWNbash
for i in 1 2 3; do
state=$(gh pr view <pr-number> --json mergeable,mergeStateStatus --jq '.mergeable + " " + .mergeStateStatus')
case "$state" in UNKNOWN*) sleep 3 ;; *) break ;; esac
done
echo "$state"| Result | Action |
|---|---|
| Report |
| Rebase onto base ( |
| Report |
mergeStateStatusCLEAN- — base moved ahead; rebase and force-push.
BEHIND - — branch protection or a required review is pending. Not a conflict; report it as-is.
BLOCKED - — checks are failing or still running.
UNSTABLE
Do not run here. Check monitoring belongs to Step 6; a PR-only flow reports the mergeability state and ends.
gh pr checks --watchPrint the Step 5 report, including the line.
Mergeable:创建PR后始终执行该步骤,无论是否会进入步骤6。无法合并的PR不是已完成的步骤,仅报告"PR已创建"而不检查会隐藏该问题。
GitHub会异步计算状态,因此最初几秒钟会返回——轮询直到状态稳定:
mergeableUNKNOWNbash
for i in 1 2 3; do
state=$(gh pr view <pr-number> --json mergeable,mergeStateStatus --jq '.mergeable + " " + .mergeStateStatus')
case "$state" in UNKNOWN*) sleep 3 ;; *) break ;; esac
done
echo "$state"| 结果 | 操作 |
|---|---|
| 在步骤5报告中添加 |
| 变基到基础分支( |
3次轮询后仍为 | 报告 |
当不是时,需添加上下文报告:
mergeStateStatusCLEAN- ——基础分支已更新;变基并强制推送。
BEHIND - ——分支保护或必需的评审待处理。不是冲突;按实际状态报告。
BLOCKED - ——检查失败或仍在运行。
UNSTABLE
不要在此处运行。检查监控属于步骤6;仅创建PR的流程会报告可合并性状态并结束。
gh pr checks --watch打印步骤5报告,包含行。
Mergeable:Step 6: Merge PR
步骤6:合并PR
Skip Condition
跳过条件
Determine the current user: . If the PR reviewer OR assignee is someone other than the current user, skip Step 6:
gh api user --jq .loginPR #<number> is ready for review by @<reviewer> (mergeable: <state from Step 5>). Merge skipped — awaiting external review.If reviewer AND assignee are the current user (self-review), or user explicitly asked to merge, proceed below.
确定当前用户:。若PR评审人或经办人不是当前用户,跳过步骤6:
gh api user --jq .loginPR #<number>已准备好由@<reviewer>评审(可合并性:<步骤5中的状态>)。已跳过合并——等待外部评审。若评审人和经办人均为当前用户(自我评审),或用户明确要求合并,继续执行以下步骤。
Entering Step 6 at all
进入步骤6的条件
Step 6 runs only when merging was asked for. Reaching Step 5 is not an invitation to
merge — a caller whose intent was wants the flow to end at
Step 5, and suggesting a merge there overrides a choice the user already made.
"push and open PR for #<N>"Step 6 is entered on exactly three things: an intent naming the merge
(, ), the user answering the suggestion below,
or the user asking to merge in conversation. Otherwise stop after Step 5.
"merge #<N>""push, PR, and merge #<N>"仅当用户要求合并时才运行步骤6。进入步骤5并不意味着可以合并——若用户意图是,则流程应在步骤5结束,此时建议合并会覆盖用户已做出的选择。
"推送并为#<N>打开PR"仅在三种情况下进入步骤6:用户意图明确提及合并(如、)、用户同意以下建议、或用户在对话中要求合并。否则在步骤5结束。
"merge #<N>""push, PR, and merge #<N>"Confirm exactly once
仅确认一次
The merge is confirmed once per flow, and this section decides where that happens.
Classify the entry, then take one branch and skip the other.
| Entry | Confirmation |
|---|---|
The intent already names the merge — | Already confirmed. Print the pre-merge summary for the record and go straight to Pre-checks. Asking again is the duplicate prompt callers are told not to create. |
| A full flow that entered at Step 1 and was never told what to do about merging | Not yet confirmed. Print the pre-merge summary and suggest merging (below). |
| Direct entry at Step 6 by the user, no earlier step in this flow | Not yet confirmed. Print the pre-merge summary and MUST stop and confirm before merging. |
When confirmation is still needed, ask via :
AskUserQuestion- "Merge now" (Recommended) — wait for checks and merge
- "Skip" — leave PR open, end flow
"Skip" → print the skip message and stop. "Merge now" → continue to Pre-checks.
Either way the pre-merge summary is printed (see ) — it is
the record of what is about to be merged, not the prompt itself.
references/report-format.mdThe suggestion branch additionally requires all of:
- Issue assignee is the current user
- PR assignee is the current user
- No external reviewer was set on the PR
If any of those is false, the Skip Condition above already applies and Step 6 ends.
每个流程仅确认一次合并,本部分决定确认时机。分类进入方式,然后执行对应分支并跳过其他分支。
| 进入方式 | 确认方式 |
|---|---|
意图明确提及合并—— | 已确认。打印合并前汇总记录并直接进入预检查环节。再次询问会重复提示,调用方应避免这种情况。 |
| 从步骤1开始的完整流程,未告知合并相关操作 | 未确认。打印合并前汇总并建议合并(如下)。 |
| 用户直接进入步骤6,流程中无更早步骤 | 未确认。打印合并前汇总并必须停止并确认后再合并。 |
当仍需确认时,通过询问:
AskUserQuestion- "立即合并"(推荐)——等待检查通过后合并
- "跳过"——保持PR打开,结束流程
选择"跳过"→打印跳过消息并停止。选择"立即合并"→继续进入预检查环节。
无论哪种情况,都会打印合并前汇总(见)——这是即将合并内容的记录,而非提示本身。
references/report-format.md建议合并分支还需满足以下所有条件:
- issue经办人是当前用户
- PR经办人是当前用户
- PR未设置外部评审人
若任一条件不满足,上述跳过条件已适用,步骤6结束。
Pre-checks
预检查
- Check PR state:
bash
gh pr view <pr-number> --json state,mergeable- If PR is not open: report current state and stop.
- If there are conflicts: rebase onto base, force-push, then continue to step 2.
- Wait for CI checks using (use a 5-minute Bash timeout):
gh pr checks --watch
bash
gh pr checks <pr-number> --watch --fail-fast- Exit 0 (all passed/skipped) → proceed to step 3
- Exit 1 (failure) → report failed checks, stop. Do not merge.
- Bash timeout → report timeout, ask user via :
AskUserQuestion- "Merge anyway" — proceed to step 3
- "Wait longer" — re-run with another 5-minute timeout
gh pr checks --watch --fail-fast - "Abort" — stop
- After checks pass, verify mergeability one more time:
bash
gh pr view <pr-number> --json mergeable --jq '.mergeable'If conflicts appeared, rebase and re-run checks.
- 检查PR状态:
bash
gh pr view <pr-number> --json state,mergeable- 若PR未打开:报告当前状态并停止。
- 若存在冲突:变基到基础分支,强制推送,然后进入步骤2。
- 使用等待CI检查完成(设置5分钟Bash超时):
gh pr checks --watch
bash
gh pr checks <pr-number> --watch --fail-fast- 状态码0(所有检查通过/跳过)→进入步骤3
- 状态码1(检查失败)→报告失败的检查,停止。不要合并。
- Bash超时→报告超时,通过询问用户:
AskUserQuestion- "仍合并"→进入步骤3
- "继续等待"→使用另一个5分钟超时重新运行
gh pr checks --watch --fail-fast - "中止"→停止
- 检查通过后,再次验证可合并性:
bash
gh pr view <pr-number> --json mergeable --jq '.mergeable'若出现冲突,变基并重新运行检查。
Merge
合并
bash
gh pr merge --rebase --delete-branchCloses #<number>bash
undefinedbash
gh pr merge --rebase --delete-branchPR正文中的会在合并到默认分支时自动关闭issue。仅当合并目标为非默认分支(如epic-*或next)时,才需手动验证并关闭issue:
Closes #<number>bash
undefinedOnly run this if base branch is NOT the default branch
仅当基础分支不是默认分支时运行
gh issue close <number>
Update project status to "Done":
```bash
bash "<skill-dir>/scripts/project-status.sh" <number> "Done"Print the Step 6 merged report.
gh issue close <number>
更新项目状态为"已完成":
```bash
bash "<skill-dir>/scripts/project-status.sh" <number> "Done"打印步骤6合并报告。
Error Handling
错误处理
- Projects V2 fails: Warn once, then skip all project operations for the rest of the flow. The core lifecycle works without project integration.
- fails: Treat as
repo-ownership.sh— assign the current user and continue. Do not prompt, and do not leave the issue or PR unassigned.personal - Assignment rejected (reports the assignee is not a valid collaborator): report which assignee was dropped, then continue. Do not abort the flow or retry with a different user.
gh - gh not authenticated: Stop immediately, tell user to run .
gh auth login - Branch already exists: Ask user via (switch vs. recreate).
AskUserQuestion - CI checks failing: Report failed checks, do not attempt merge.
- No CLAUDE.md: Use the default conventions listed above.
- No remote: exits 2 and there is no base branch. Steps 2, 3, 5, and 6 all depend on it, so stop at whichever of them was entered and tell the user to add a remote. Do not fall back to
detect-base.sh.main - Host cannot show structured choices: Fall back to a numbered list in chat per ### Asking the User. Do not skip the question.
- Projects V2失败:警告一次,然后流程中剩余的项目操作全部跳过。核心生命周期无需项目集成即可运行。
- 失败:视为
repo-ownership.sh仓库——分配给当前用户并继续。不要提示,也不要让issue或PR无人分配。personal - 分配被拒绝(报告经办人不是有效协作者):报告被移除的经办人,然后继续。不要中止流程或重试其他用户。
gh - gh未认证:立即停止,告知用户运行。
gh auth login - 分支已存在:通过询问用户(切换到现有分支还是重新创建)。
AskUserQuestion - CI检查失败:报告失败的检查,不要尝试合并。
- 无CLAUDE.md:使用上述默认规范。
- 无远程仓库:以状态码2退出且无基础分支。步骤2、3、5、6均依赖基础分支,因此在进入的步骤停止并告知用户添加远程仓库。不要回退到
detect-base.sh分支。main - 宿主无法显示结构化选择:回退到**### 询问用户**中的聊天编号列表形式。不要跳过问题。
Integration
集成
- For commit message body → invoke the skill; fall back to the inline derivation in Step 3 → Body if the host cannot chain skills
commit-summary - For project token setup → see
references/project-integration.md - For report templates → see
references/report-format.md - For sub-issues and blocked-by relationships → see
references/github-relationships.md
- 提交消息正文→调用技能;若宿主无法链式调用技能,回退到步骤3→正文中的内联推导
commit-summary - 项目令牌设置→见
references/project-integration.md - 报告模板→见
references/report-format.md - 子issue和依赖关系→见
references/github-relationships.md