Issue Analyze
Fetches a GitHub issue, analyzes its full scope, cross-references local project docs, checks blocking relationships, and outputs a structured analysis with an implementation task list. Standalone — no forced next step.
Reports only; the tree stays byte-identical. Every call it makes is a read: gh issue view, gh api GETs, git rev-parse, and local file reads. allowed-tools cannot
express a method restriction, so its gh and git grants are wider than that — this
sentence is the limit, not the declaration.
Phase 1: Resolve & Fetch
Guard: no argument
If $ARGUMENTS is empty, stop:
Provide an issue number or URL. Usage: /issue-analyze 42
Detect repo
gh repo view --json nameWithOwner --jq '.nameWithOwner'
Outputs owner/repo. Split on / to get owner and repo name separately.
Parse argument
$ARGUMENTS is either:
- A bare number:
42 - A full URL:
https://github.com/owner/repo/issues/42
For a URL, extract the number from the last path segment. If the URL contains a different owner/repo than the current repo, use the URL's owner/repo for all API calls.
Fetch the issue
gh issue view <N> --repo <owner>/<repo> --json number,title,body,state,labels,assignees,url
Detect current user
gh api user --jq .login
Guard: closed issue
If state is "closed":
Issue #<N> is closed — no implementation plan needed.
<url>
Stop. Do not output anything else.
Guard: not assigned to you
If assignees is non-empty and none match the current user login, print this line before
all other output:
> Note: #<N> is assigned to @<other-user> — you may be looking at someone else's work.
Then continue normally.
Fetch sub-issues
gh api repos/<owner>/<repo>/issues/<N>/sub_issues 2>/dev/null
- Empty array
[]→ no sub-issues, skip - HTTP 404 → sub-issues feature not enabled on this repo, skip silently
- Non-empty array → for each sub-issue number, fetch:
gh issue view <sub-N> --repo <owner>/<repo> --json number,title,body,state
Collect all sub-issue data. A closed sub-issue is noted in the analysis as already implemented and generates no implementation task.
End Phase 1 with one line: Fetched #<N> "<title>" — <state>, <N> sub-issues, assigned to <user|nobody>.
Phase 2: Local Context Search
Find the git root:
git rev-parse --show-toplevel
Check whether any of these local context sources exist. If none do, skip this phase entirely — do not mention it in output.
<git-root>/AGENTS.md<git-root>/CLAUDE.md<git-root>/.claude/<git-root>/.agents/
Find doc files
Glob for:
<git-root>/AGENTS.md<git-root>/CLAUDE.md<git-root>/.claude/*.md<git-root>/.claude/docs/*.md<git-root>/.agents/*.md<git-root>/.agents/docs/*.md<git-root>/docs/superpowers/**/*.md
If no files found, skip phase.
Search for issue number
Search every file the globs returned — not a sample of them — for:
#<N>(e.g.#42)- Word-boundary match for bare number (to avoid matching
142when looking for42)
Extract and search key terms
From the issue title and body, extract:
- Capitalized component/module names (e.g.
TreeView,AuthService) - camelCase or PascalCase identifiers
- File paths mentioned (e.g.
src/components/Button.tsx) - Technical terms: API endpoint names, config keys, function names in backticks
Search every found file for each extracted term. Collect unique (file path, matching line) pairs. Deduplicate across term searches.
Result
If nothing found across all searches → omit the Local Context section from output.
If matches found → collect as: { file: string, reason: string }[] for use in Phase 4.
End Phase 2 with one line: Local context: <N> files searched, <N> matched. A skipped
phase says Local context: none present. — say which, never nothing.
Phase 3: Dependency Analysis
Query issue relationships via GraphQL. Fetch the issue's tracking relationships:
gh api graphql -f query='{
repository(owner: "<owner>", name: "<repo>") {
issue(number: <N>) {
trackedInIssues(first: 5) {
nodes { number title state url }
}
}
}
}'
trackedInIssues — parent issues or epics that track this issue. If this issue is part
of a larger epic, these are the parents.
Also try blocked-by relationships. GitHub stores these via node-ID-based relationships
(same mechanism as addBlockedBy / removeBlockedBy mutations). Query them directly as
a separate call so a failure here does not affect the trackedInIssues result:
gh api graphql -f query='{
repository(owner: "<owner>", name: "<repo>") {
issue(number: <N>) {
blockedByIssues(first: 10) {
nodes { number title state url }
}
blockingIssues(first: 10) {
nodes { number title state url }
}
}
}
}' 2>&1 || true
blockedByIssues — what is blocking this issue (must be resolved first).
blockingIssues — what this issue blocks (expects deliverables from this one).
These fields are part of GitHub's issue dependencies preview and are not available on
most repos or plans. When unavailable, gh api exits with code 1 and prints an
undefinedField GraphQL error on stdout (not stderr). Handle this silently:
- The
|| trueabove prevents the non-zero exit from surfacing as a tool error. - If the response contains an
errorsfield, or anyundefinedField/Field '...' doesn't existmessage, treat it as "not available" and skip this section. - Only parse
data.repository.issue.blockedByIssues/blockingIssueswhen the response has noerrorsfield.
If all queries fail or return no data, skip silently.
Relevance filter
For each dependency found:
- Open blocker (blocks this issue and is still open): always include — it constrains what can be built. Fetch its title and state. Note what it's expected to deliver.
- Closed blocker: skip — already resolved, doesn't affect planning.
- Parent epic: include only if it adds implementation context not in the issue itself.
- No dependencies: omit the Dependencies section from output entirely.
End Phase 3 with one line naming the queries that did not run and why: Dependencies: <N> open blockers, <N> parents or Dependencies: blockedBy unavailable on this repo; <N> parents.
Phase 4: Synthesize & Output
Scope Analysis — quality bar
This is the highest-value section. Write it to be directly useful for implementation planning — not a summary of the issue text, but an interpretation of it.
A high-quality Scope Analysis:
- Explains what the issue is truly asking for (beyond restating the title)
- Identifies technical scope: what needs to be built or changed, and roughly where
- For epics: weaves sub-issues into a coherent narrative, per the Phase 1 rule on closed ones. Example: "This epic covers three areas: authentication (#43, done), session management (#44), and token refresh (#45)."
- Surfaces implicit requirements not stated in the issue (e.g., "adding X implies Y also needs to handle the new input format")
- Calls out ambiguities or decisions the implementer will face
- States what is explicitly out of scope
- When a blocker is open: explains what cannot be built until it's resolved, and what can be built in parallel
Length: 2–5 paragraphs for a normal issue; more for a large epic (one paragraph per sub-issue area).
Implementation Tasks — quality bar
- Each task is a concrete, actionable step (not "investigate X" — investigation is part of Scope Analysis)
- Ordered logically: setup before implementation, implementation before tests, tests before integration
- 3–12 tasks (3–4 is fine for small/trivial issues; 5–12 for normal scope)
- For epics: group tasks under sub-issue headings
- If a blocker is open: mark affected tasks as "blocked by #N" and list them last
Output format
Print output in this exact structure:
> Note: #<N> is assigned to @<user> — you may be looking at someone else's work.
(omit line if current user is among assignees, or if issue has no assignees)
# #<N>: <title>
## Scope Analysis
<analysis paragraphs>
## Local Context
(omit entire section if Phase 2 found nothing)
- `.claude/docs/foo.md` — <one sentence on why it's relevant to this issue>
## Dependencies
(omit entire section if no implementation-relevant open dependencies)
Depends on #<M> (open) — <what that issue provides that this one needs>.
This issue's output expected by #<K> — must deliver <Y>.
## Implementation Tasks
1. <task>
2. <task>
3. <task>
---
<issue URL>
A filled-in analysis
# #412: Tooltip clips at the viewport edge
## Scope Analysis
The report is about clipping, but the cause is placement: `Tooltip` picks a side once, on
mount, from an anchor rect that `useAnchorRect` has already clamped to the viewport. A
tooltip anchored near the bottom edge therefore measures as if it fits, renders below, and
is cut off. Fixing the clamp alone is not enough — placement has to be re-resolved after
measuring, which means the flip decision moves out of the mount path.
Implicitly in scope: `Popover` consumes the same hook, so returning an unclamped rect
changes its input too. Explicitly out of scope: `Popover`'s own placement logic, which has
a separate clamp of its own and is not what this issue reports.
One decision the implementer faces: re-measure on scroll and resize, or resolve once after
first paint. The issue does not say, and the second is materially cheaper.
## Local Context
- `.claude/docs/overlays.md` — states the overlay layer owns positioning, not the anchor
## Implementation Tasks
1. Return the raw measured rect from `useAnchorRect`; drop the viewport clamp
2. Resolve placement in `Tooltip` after measurement, flipping when the rect overflows
3. Re-check `Popover`'s use of the hook for a regression from the unclamped rect
4. Add a `Tooltip` test asserting resolved placement near the bottom edge
---
https://github.com/owner/repo/issues/412
Then stop. This skill analyzes and reports — it does not create a branch, edit a file, or
start implementing, and it does not offer to. A caller that wants the work done invokes
issue-flow or solve-issue next; that is the caller's decision, not this skill's.
Error Handling
| Situation | Action |
|---|---|
gh not authenticated |
Stop: "Run gh auth login first." |
| Not in a git repo + no URL given | Stop: "Provide a full GitHub URL or run from inside a git repository." |
Issue number not found (gh 404) |
Stop: "Issue # not found in /." |
| Issue body is empty | Analyze from title only; note in Scope Analysis that the issue has no description |