Agent SkillsLanternOps/breeze › issue-to-pr

issue-to-pr

GitHub

用于将选定的 GitHub Issue 转化为 PR 的端到端执行流程。涵盖领取任务、修复代码、验证测试、提交 PR 及自动审查,最终移交用户处理合并与关闭。

.claude/skills/issue-to-pr/SKILL.md LanternOps/breeze

Trigger Scenarios

修复指定的 GitHub Issue 从待办列表中选取并处理 Issue

Install

npx skills add LanternOps/breeze --skill issue-to-pr -g -y
More Options

Non-standard path

npx skills add https://github.com/LanternOps/breeze/tree/main/.claude/skills/issue-to-pr -g -y

Use without installing

npx skills use LanternOps/breeze@issue-to-pr

指定 Agent (Claude Code)

npx skills add LanternOps/breeze --skill issue-to-pr -a claude-code -g -y

安装 repo 全部 skill

npx skills add LanternOps/breeze --all -g -y

预览 repo 内 skill

npx skills add LanternOps/breeze --list

SKILL.md

Frontmatter
{
    "name": "issue-to-pr",
    "description": "Use when implementing a fix for a known GitHub issue end-to-end on the Breeze repo — \"work on issue"
}

Issue → PR

Overview

Execution runbook that carries one already-chosen GitHub issue from claim to a reviewed, open PR. Triage already happened (see gh-queue); this skill runs after the decision to work an issue is made.

Repo: LanternOps/breeze. Two hard boundaries: the worker never merges and the worker never closes the issue — those stay the user's call.

When to use vs. not

  • Use: "fix #1234", "take #1234 to a PR", an issue-fixer agent picking up a number.
  • Don't use for triage ("what's waiting on me", "any new issues") → that's gh-queue.
  • Don't redefine etiquette — comment style, never-self-close, and lifecycle live in the github-issues skill. Follow it; don't restate it.

The lifecycle

digraph issue_to_pr {
  "Read full issue + comments" [shape=box];
  "Eligible?" [shape=diamond];
  "ABORT — report back" [shape=box];
  "Assign to self" [shape=box];
  "Worktree off fresh main" [shape=box];
  "Fix (debug/brainstorm)" [shape=box];
  "Verify: tests + typecheck" [shape=box];
  "Commit / push / PR (Closes #N)" [shape=box];
  "/pr-review-toolkit:review-pr" [shape=box];
  "Findings?" [shape=diamond];
  "Comment: what the review ran" [shape=box];
  "STOP — hand off (no merge, no close)" [shape=doublecircle];

  "Read full issue + comments" -> "Eligible?";
  "Eligible?" -> "ABORT — report back" [label="no"];
  "Eligible?" -> "Assign to self" [label="yes"];
  "Assign to self" -> "Worktree off fresh main";
  "Worktree off fresh main" -> "Fix (debug/brainstorm)";
  "Fix (debug/brainstorm)" -> "Verify: tests + typecheck";
  "Verify: tests + typecheck" -> "Commit / push / PR (Closes #N)";
  "Commit / push / PR (Closes #N)" -> "/pr-review-toolkit:review-pr";
  "/pr-review-toolkit:review-pr" -> "Findings?";
  "Findings?" -> "Fix (debug/brainstorm)" [label="yes, address"];
  "Findings?" -> "Comment: what the review ran" [label="clean"];
  "Comment: what the review ran" -> "STOP — hand off (no merge, no close)";
}

0. Select an issue (when you weren't handed a number)

If invoked with a specific issue number, skip to step 1. If asked to "find something to work on" / "grab an issue off the backlog", select one yourself:

# Open issues with the signals needed to rank them.
gh issue list --repo LanternOps/breeze --state open --limit 60 \
  --json number,title,assignees,labels,createdAt,comments

Rank candidates, best first. Prefer an issue that is:

  • Unassigned (or assigned to you — see the note on "you" in step 1).
  • Actionable without design — a clear repro, root cause, or file pointers in the body/comments. A precise root-cause comment from a maintainer is gold.
  • Bounded — one component, a contained fix.

Skip (don't even open a worktree):

  • Anything labeled tracking/epic/meta, needs-design/question/discussion/RFC.
  • Infra firefighting (ci-red, broad "X is broken on main") unless explicitly asked.
  • Anything that needs a product/pricing/policy decision.

Then run the step 1 guard on your top candidate — that's the real gate (it catches already-shipped fixes and in-flight PRs that ranking can't see). If the top candidate aborts on the guard, move to the next candidate; repeat until one passes or the list is exhausted. Report which issues you considered and why you skipped each — don't silently pick one and hide the rest.

When selecting several to fan out, cap the count and state the cap.

1. Read & guard (do this before touching anything)

gh issue view N --repo LanternOps/breeze --comments \
  --json number,title,body,state,assignees,labels,comments
# PRs that reference it — ANY state, not just open (a merged/closed PR may have
# already shipped the fix; --state open would never show it).
gh pr list --repo LanternOps/breeze --state all --search "N in:body" \
  --json number,title,state,headRefName,mergedAt

Read the whole issue and every comment. ABORT and report back (do not start work) if any of these is true:

  • Issue is closed.
  • Already assigned to someone else (not you, not unassigned). "You" is the operator's GitHub account — the @me login, resolved with gh api user --jq .loginnot a separate agent identity. An issue assigned to that account is "assigned to you" and is eligible (work it); only an issue assigned to a different login is "someone else" → abort. If you're a subagent, you have no GitHub identity of your own, so never read the operator's own assigned issues as belonging to a third party.
  • A PR already references it. An open PR → work is in flight, don't duplicate. A merged/closed PR (or a member comment / commit on main saying "fixed in #NNN" / "merged to main") → the fix likely already shipped and the issue is open only awaiting reporter confirmation. Verify against origin/main before concluding either way — a gh pr list --state open miss does NOT mean no fix exists. Don't open a duplicate no-op PR.
  • It's too ambiguous or too large to fix without design — needs a spec or a product decision first. Say so; don't guess a fix.

Aborting is a success, not a failure. Report why so the orchestrator/user can decide. Guessing past a guard wastes a worktree and a review cycle.

2. Claim

gh issue edit N --repo LanternOps/breeze --add-assignee @me

3. Isolated worktree

REQUIRED SUB-SKILL: Use superpowers:using-git-worktrees. The main working copy at /Users/toddhebebrand/breeze is shared across sessions and drifts — verify your base is fresh main before branching (a stale base has nearly shipped dozens of unrelated commits in a PR).

Spawn-location trap (read this): When an orchestrator fans you out, your CWD is very likely already inside an existing worktree under .claude/worktrees/ that belongs to a different task. That is NOT your workspace. Do not edit there, and do not reach back into the shared /Users/toddhebebrand/breeze checkout (it may be on a stale branch). Always git fetch origin main, then create your own new worktree off origin/main, cd into it, and confirm git rev-parse HEAD equals origin/main before you branch. Editing the spawn worktree or the shared checkout has silently reverted other in-flight PRs' files.

Branch naming (AGENTS.md — no codex/ / claude/ prefixes): fix/N-short-slug, feat/N-short-slug, docs/short-slug, chore/short-slug.

Fresh worktrees need pnpm install and the gitignored .env.test symlink — without it RLS forge tests pass vacuously on a BYPASSRLS connection. Prefix node-pinned commands: PATH=$HOME/.nvm/versions/node/v22.20.0/bin:$PATH.

4. Fix

  • Bug → REQUIRED: superpowers:systematic-debugging (find root cause before patching).
  • Feature/behavior change → superpowers:brainstorming first if the issue left design open.
  • Touching tenant tables / migrations → follow the RLS shapes + migration rules in CLAUDE.md (policies in the same migration, idempotent, never edit a shipped migration). Touching the Go agent → write to agent/, not apps/agent/.

5. Verify (evidence before "done")

REQUIRED SUB-SKILL: breeze-testing for what to cover.

  • Run the affected test files single-fork (the full API suite is flaky in parallel — don't trust or trigger a full red run): pnpm exec vitest run <path>.
  • Type-check touched areas: npx tsc --noEmit (and astro check if .astro changed — plain tsc skips Astro files).
  • Go changes: cd agent && go test -race ./internal/<pkg>/....

Do not proceed to the ready comment on red tests. REQUIRED SUB-SKILL: superpowers:verification-before-completion.

6. Commit / push / PR

Use commit-commands:commit-push-pr (or do it by hand). The PR body must include Closes #N. PR title follows fix(scope): summary (#N) / feat(scope): summary (#N). Required trailers:

  • Commit messages end with: Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
  • PR body ends with the 🤖 Generated with [Claude Code]… line.

7. Review

Run /pr-review-toolkit:review-pr on the PR. Address every real finding (loop back to step 4 → re-verify). Re-run review if you made non-trivial changes.

8. Ready signal — comment reports what the last review ran

Assignee stays you. Post a comment on the PR (not the issue) in the bold-section style (github-issues / comment-style conventions). The comment's job is to record what the last review run was and its outcome — NOT a generic "ready for review" banner.

**Review run:** /pr-review-toolkit:review-pr (code-reviewer, silent-failure-hunter, pr-test-analyzer)
**Findings:** 2 raised → both addressed in <sha>; 0 outstanding.
**Tests:** apps/api affected suite green (`vitest run routes/foo.test.ts`, 14 passed); `tsc --noEmit` clean.
**Status:** review-clean, awaiting maintainer merge.

If review surfaced nothing, say that explicitly ("0 findings") rather than omitting the line — a missing line reads as "didn't run it."

9. Hand off — STOP

Report the PR number + a one-line summary to the orchestrator/user. Then stop.

The worker does NOT merge and does NOT close the issue. Merge (--admin, gated on green required checks) and closure (after the reporter/user verifies) are the user's judgment calls — see the merge/hold rules. The issue stays open and assigned to you until then.

Red flags — STOP if you catch yourself

  • "It's obviously fixed, I'll just close the issue." → Never. Hand off open.
  • "Checks are green, I'll merge it." → Never. Merge is the user's call.
  • "The issue's a bit vague but I'll guess what they meant." → Abort & ask (step 1).
  • "Someone's assigned but they seem stalled, I'll take it." → Abort & report — don't poach. (But an issue assigned to the operator's own @me account is not poaching — work it; see step 1.)
  • "No open PR, so nobody's fixed it." → Check merged/closed PRs + commits on main too. Open-only is a blind spot.
  • "I'll skip the worktree, the main copy is fine." → No. Stale base + shared copy = wrong-commit PR.
  • "I'm already inside a worktree, I'll just use this one." → No — it's another task's worktree. Make your own off fresh origin/main.
  • "Affected tests pass, skip the rest / skip typecheck." → Run typecheck (and astro check) too.
  • "Posting 'ready for review' is enough." → No. Record which review ran and what it found.
Rationalization Reality
"A commit means it's done, close it." A commit isn't verification. Reporter/user closes.
"Green CI means I can merge." Merge is gated on the user's hold/judgment rules, not just CI.
"Aborting wastes the dispatch." Aborting on a guard is the correct, cheap outcome. Guessing is expensive.
"Full suite is red so my change is broken." The full API suite is flaky in parallel — verify via affected files single-fork.

Orchestrating multiple issues

To work several issues at once, the in-session agent acts as orchestrator:

  1. Decide the issue numbers BEFORE dispatch — never let multiple workers self-select in parallel. Each worker's step-0 selection ranks the backlog the same way and claims aren't visible at selection time, so parallel self-selecting agents converge on the same top issue and open duplicate PRs (observed: 3 agents → PRs #1917/#1918/#1919, all on #1896). Get a distinct set one of two ways:

    • The user named explicit numbers / a label filter → use that list.
    • The user asked you to "find a few" with no numbersyou (the orchestrator) do the selection: scan the backlog once, rank with the step-0 criteria, pick N distinct eligible candidates, run the step-1 guard on each, and claim each up front (gh issue edit <N> --add-assignee @me) so the set is reserved. Only then dispatch.

    Any orchestrator-level eligibility pre-check has the same blind spot as the worker's: gh pr list --state open won't reveal an already-merged fix, so don't pre-declare an issue "eligible" on that basis — the worker's full guard (comments + --state all + origin/main) is the real gate.

  2. REQUIRED SUB-SKILL: superpowers:dispatching-parallel-agents — spawn one issue-fixer agent per already-chosen number, each in its own worktree (isolation prevents branch/DB collisions; see the worktree skill). Every agent gets a concrete number — none self-selects.

  3. Each agent runs this runbook independently and returns its PR number (or its abort reason). A worker that finds its handed number already assigned to @me (because the orchestrator pre-claimed it) treats that as eligible — that's the reservation working, not a poach.

  4. Collect the results into one summary table for the user. The orchestrator does not merge or close either — same boundary applies.

Do not auto-expand the list beyond what the user named. If you self-selected from a label, log/state the cap and which issues were dropped.

Anti-pattern (do not do this): dispatching 2+ issue-fixer agents that each run step-0 selection, trusting a "skip already-claimed issues" instruction to keep them apart. Selection precedes any visible claim, so the guard can't see a sibling's pick — they collide. Distinctness is the orchestrator's job, settled before dispatch.

Version History

  • 10bb1af Current 2026-08-20 08:50

Same Skill Collection

.claude/skills/agent-info/SKILL.md
.claude/skills/agent-log-debugging/SKILL.md
.claude/skills/ai-agent/SKILL.md
.claude/skills/breeze-helper/SKILL.md
.claude/skills/breeze-testing/SKILL.md
.claude/skills/e2e-coverage/SKILL.md
.claude/skills/feature-testing/SKILL.md
.claude/skills/security-review/SKILL.md
.claude/skills/worktree-stack/SKILL.md
.claude/skills/gh-queue/SKILL.md
.claude/skills/ui-qa-sweep/SKILL.md

Metadata

Files
0
Version
0ee1815
Hash
3836d634
Indexed
2026-08-20 08:50

inicio - Wiki
Copyright © 2011-2026 iteam. Current version is 2.155.2. UTC+08:00, 2026-09-16 17:54
浙ICP备14020137号-1