Imported from MattCordell/agent-skills (
plan-issue/SKILL.md). Install upstream withnpx skills add MattCordell/agent-skills --skill plan-issue. Copyright stays with the author.
Plan a GitHub Issue
Research once, decide once, hand off clean. The output is a plan someone else -- human or agent -- can execute without this conversation.
Hard rules
- Plan mode only. No branch, no commit, no PR, no code. The only write actions this skill ever takes, all after approval: creating prerequisite issues, linking them as blockers, posting the approved plan as one issue comment, and updating the issue's project status.
- At most 2 subagents at a time, and only for genuinely independent work. Do research directly by default. Delegate to a subagent only when a piece of research is truly independent of the rest (e.g. two unrelated areas of the codebase) -- not merely because a step feels broad.
- The plan is the interface. Write it for a cold reader: zero access to this conversation, possibly a different agent entirely. If a step only makes sense because "we discussed this earlier," it is not in the plan yet.
- Nothing gets posted before approval. The plan is drafted and refined inside plan mode; it reaches GitHub only after the user approves it through
ExitPlanMode.
Step 0 — Enter plan mode
If you are not already in Claude Code's plan mode, enter it now (EnterPlanMode) before touching anything else. Everything through Step 3 is research and drafting -- read-only tools only.
Step 1 — Fetch issue context
gh issue view <num> --json number,title,body,labels,assignees,milestone,comments,url
Read the body AND every comment. The latest decisions are often in comments, not the description. Extract:
- Acceptance criteria (explicit or implicit)
- Linked issues, PRs, or discussions
- Constraints the reporter called out
- Labels (bug vs feature determines the PR closing keyword)
Step 2 — Research the codebase
Before forming a plan, ground yourself:
- Grep for symbols, files, or terms the issue names
- Read surrounding code, not just the named file
- Check
git logon relevant files for recent context - Read
CLAUDE.md(root and any nested) -- these carry architectural patterns, conventions, and test runner commands - Check whether the project has an ADR (Architecture Decision Record) directory. Common locations:
docs/adr/,docs/decisions/,adr/, or files namedNNNN-*.md. Note the location so the plan can point the executor at it.
Stop if the issue is ambiguous, acceptance criteria are unclear, or research reveals the issue's premise is wrong. Ask the user directly in this conversation rather than guessing -- do not post questions to the issue; nothing goes to GitHub until Step 4.
Step 3 — Clarifying questions
Ask the user clarifying questions in a single batch until you are at least 90% confident you understand:
- The problem being solved
- Expected behaviour: inputs, outputs, edge cases
- Acceptance criteria (explicit or implied)
- Constraints: performance, backwards compatibility, style conventions
Ask in one batch where possible. Do not fire questions one at a time. Do not draft the plan until you have reached the 90% threshold.
If the work spans multiple subsystems, has deeply interdependent phases, or looks like genuine multi-day effort, raise it now regardless of plan length: "This looks like it could be split into child issues -- do you want to break it down first, or plan it as one workstream?"
This is different from a prerequisite issue (see Step 4): splitting is about slicing this issue's own scope into smaller pieces, while a prerequisite is separate work -- often outside this issue's scope entirely -- that must land first (a migration, an upstream dependency bump, infra config).
Step 4 — Draft the plan
Write the plan content (you'll hand it to ExitPlanMode next, then post it verbatim). Keep it strategic, not prescriptive: aim for under ~200 lines. If you find yourself describing how to implement something rather than what to implement and why, you are writing a spec, not a plan -- pull back to strategy.
<!-- plan-issue:v1 -->
# Issue #<num>: <title>
**Link:** <issue url>
**Suggested branch:** <num>-short-description
**Closing keyword:** Fixes | Closes
**Size:** Small | Medium | Large — <one-sentence why>
**Complexity:** Low | Medium | High — <one-sentence why>
## Goal
<1-2 sentences: what done looks like>
## Acceptance criteria
- <explicit or implied criterion, one per line -- this is the executor's checklist>
## Approach
<3-6 bullets: strategy, not step-by-step>
## Phases
1. <name> — <one-line scope>
2. <name> — <one-line scope>
## Files likely to change
- `path/to/file` — <what changes and why>
## Prerequisite issues
- <title> — <one-line reason this must land before #<num> can proceed>
## Out of scope
- <things that look related but are not part of this issue>
## Open questions
- <anything still unresolved -- flag clearly if it would block an executor>
The <!-- plan-issue:v1 --> marker is load-bearing: /pick-up-issue looks for it to confirm a plan exists. Always include it as the first line, verbatim.
The closing keyword: default to Fixes for bug-labelled issues, Closes for everything else.
Size and complexity are for triage -- they tell whoever assigns the issue what to expect, at a glance. Rate them independently; a large refactor of a well-worn pattern is high size, low complexity, and a one-line fix to a subtle race condition is the reverse.
Size is volume of work. Judge it from the Phases and Files above:
- Small -- one phase, contained to a single component
- Medium -- multiple phases, or touches more than one component
- Large -- the multi-subsystem or multi-day case flagged in Step 3
Complexity is difficulty, independent of volume. Judge it from unknowns and risk:
- Low -- an established pattern in the codebase, no open design decisions
- Medium -- some judgment calls or unfamiliar territory, but no deep unknowns
- High -- genuine design decisions, ambiguity that survived Step 3, or a costly blast radius if the approach is wrong
Pick one word per axis and back each with a single sentence -- do not hedge with a range.
Prerequisite issues are separate work items research surfaced that must complete before this issue can, but are not part of this issue's own scope -- a migration, an upstream library bump, infra config, another team's change. Do not fold them into Phases; list them here instead so they can be tracked and blocked on separately. Leave the section out of the rendered plan if none apply.
Step 5 — Exit plan mode for approval
Call ExitPlanMode with the full plan content from Step 4, including any Prerequisite issues. This is the approval gate -- the user reviews and can request changes before anything touches GitHub. Do not create issues, link dependencies, or post anything until this returns approved.
Step 6 — Create prerequisites, post the plan, and update status
6a. Create prerequisite issues
For each entry under Prerequisite issues in the approved plan, create it and mark it as blocking the current issue in one step:
gh issue create --title "<title>" --body "<reason, and a link back to #<num>>" --blocking <num>
Note each new issue's number -- reference them in the plan comment below.
6b. Post the plan as an issue comment
gh issue comment <num> --body-file /tmp/issue-<num>-plan.md
rm /tmp/issue-<num>-plan.md
If prerequisite issues were created in 6a, make sure the posted plan's Prerequisite issues section references their real issue numbers (e.g. Blocked by #43), not just titles.
This is the single home for the plan -- discoverable from the issue itself, not buried in this conversation.
If the issue has active participants, mention to the user that it may be worth waiting for their feedback before anyone runs /pick-up-issue on it.
6c. Update project status to "Ready"
Check whether the issue is tracked on a GitHub Project (v2):
gh issue view <num> --json projectItems --jq '.projectItems'
If it belongs to one or more projects, move each to "Ready" now that a plan is posted:
PROJECT_ID=<id from projectItems above>
ITEM_ID=<id from projectItems above>
FIELD_ID=$(gh project field-list <project-number> --owner <owner> --format json --jq '.fields[] | select(.name=="Status") | .id')
OPTION_ID=$(gh project field-list <project-number> --owner <owner> --format json --jq '.fields[] | select(.name=="Status") | .options[] | select(.name=="Ready") | .id')
gh project item-edit --id "$ITEM_ID" --field-id "$FIELD_ID" --project-id "$PROJECT_ID" --single-select-option-id "$OPTION_ID"
Do this even if prerequisite issues were just added as blockers -- "Ready" means the plan is ready to execute once any blockers clear, not that it is unblocked today. If the issue is not on any project, skip this step.
Stop here. No branch, no PR, no code. Tell the user the plan is posted and ready for /pick-up-issue #<num> (by them, or by a different agent) whenever they want execution to start -- once any prerequisite issues are resolved, if there were any.
Red flags
| If you think this... | The reality is... |
|---|---|
| "I'll just post the plan now, approval is a formality" | Plan mode exists so the user can redirect before a comment goes public. Wait for ExitPlanMode to actually return approved. |
| "I'll sketch the how, not just the what" | That's a spec, not a plan. Pull back to strategy -- phases and files, not line-by-line instructions. |
| "This open question is minor, I'll just note it and move on" | If it would block whoever executes this cold, it's not minor. Flag it plainly under Open questions. |
| "I'll fix this while I'm in the code researching" | This skill never writes code. Note it in the plan (Files likely to change, or Out of scope) instead. |
| "This dependency is small, I'll just add it as a phase" | If it's separate work that must land first and isn't really part of this issue's scope, it's a prerequisite, not a phase. Carve it out so it can be tracked and blocked on its own. |