take-issue · diff
git:20260916.7ee21bb to git:20261014.0f16275
76 added, 18 removed. Audit B to B.
---
description: Take a GitHub issue onto the branch — export the thread and its attachments, commit them, and hand the number back to whoever called. Invoke as `/take-issue <number|url>`; its callers are `/task`, `/plan` and `/go`, each running it first when the prompt carries a `#<N>`.
---
- End state of this skill: `docs/issue/<n>/` holds the thread and its attachments, that export is committed on the branch, you have read it, and control is back with the caller — which is where every decision about the work is made.
+ End state of this skill: `docs/issue/<n>/` holds the thread and its attachments,
+ that export is committed on the branch, you have read it, and control is back
+ with the caller — which is where every decision about the work is made.
- This skill decides nothing. It is the one place an issue gets pulled onto a branch, so its contract to its callers is that the issue has been **taken**: exported, committed, and there for a later session to re-read.
+ This skill decides nothing. It is the one place an issue gets pulled onto a
+ branch, so its contract to its callers is that the issue has been **taken**:
+ exported, committed, and there for a later session to re-read.
## Argument shape
- The argument is an issue number or a full issue URL, optionally with prose around it — `fix the sidebar scroll #847` is the same invocation as `847`. The prose is the operator's own summary of the issue and is worth reading as a hint at what they care about, but **the export outranks it**: where the two disagree, the thread is what the work is against.
+ The argument is an issue number or a full issue URL, optionally with prose
+ around it — `fix the sidebar scroll #847` is the same invocation as `847`. The
+ prose is the operator's own summary of the issue and is worth reading as a hint
+ at what they care about, but **the export outranks it**: where the two disagree,
+ the thread is what the work is against.
## Step 0 — Mode gate: native plan mode is not supported
- If the session is in **native plan mode** — the launch banner or system prompt says so, `ExitPlanMode` is the offered exit, or an edit is refused for that reason — **stop before running anything below.** Tell the operator:
+ If the session is in **native plan mode** — the launch banner or system prompt
+ says so, `ExitPlanMode` is the offered exit, or an edit is refused for that
+ reason — **stop before running anything below.** Tell the operator:
- - this flow is plan-**file**-based (`@.claude/skills/plan/SKILL.md`), and native plan mode cannot write the two artifacts it depends on: the export under `docs/issue/<n>/` and the plan under `docs/plans/`. Both must be committed and pushed, because the operator reviews from a different machine than the one you run on;
- - the plan-mode approval UI is unreliable in web sessions regardless (anthropics/claude-code#72704);
- - so switch to **accept-edits** or **auto** and send any reply — the run picks up from there; no re-invocation needed.
+ - this flow is plan-**file**-based (`@.claude/skills/plan/SKILL.md`), and native
+ plan mode cannot write the two artifacts it depends on: the export under
+ `docs/issue/<n>/` and the plan under `docs/plans/`. Both must be committed and
+ pushed, because the operator reviews from a different machine than the one you
+ run on;
+ - the plan-mode approval UI is unreliable in web sessions regardless
+ (anthropics/claude-code#72704);
+ - so switch to **accept-edits** or **auto** and send any reply — the run picks
+ up from there; no re-invocation needed.
Do not work around it, and do not fall back to a chat-only plan.
## Step 1 — Export the issue locally (then read the export)
- **Look under `docs/issue/<n>/` before running anything: the export is normally already there.** `.claude/hooks/prompt-issue-export.sh` runs this step's command ahead of a session's first turn when that prompt *ends* in `#<N>`, and names what it wrote in that turn's context — so where the export exists, this step is the reading below and nothing else. Run the command when it is absent: a number that reached you any other way, a hook that reported a failure, or a tree that adopted `/take-issue` without the hook.
+ **Look under `docs/issue/<n>/` before running anything: the export is normally
+ already there.** `.claude/hooks/prompt-issue-export.sh` runs this step's command
+ ahead of a session's first turn when that prompt _ends_ in `#<N>`, and names
+ what it wrote in that turn's context — so where the export exists, this step is
+ the reading below and nothing else. Run the command when it is absent: a number
+ that reached you any other way, a hook that reported a failure, or a tree that
+ adopted `/take-issue` without the hook.
**First command:** run the bundled exporter:
```bash
python3 scripts/export-github-item.py <issue-number|https://github.com/OWNER/REPO/issues/N> [--repo OWNER/REPO]
```
- The script writes `docs/issue/<n>/issue.md` (body + comments + timeline) and downloads any image / file attachments referenced in the thread to `docs/issue/<n>/attachments/`.
+ The script writes `docs/issue/<n>/issue.md` (body + comments + timeline) and
+ downloads any image / file attachments referenced in the thread to
+ `docs/issue/<n>/attachments/`.
- Consult the issue only through the export — never `gh issue view`, the GitHub MCP tools, or `WebFetch` in its place. `gh issue view` alone does **not** fetch attachments: GitHub's `private-user-images.githubusercontent.com` URLs require an authenticated request even when the issue is public, which is why the export script exists. `WebFetch` on a github.com issue page often fails outright in isolated environments. For a quick metadata check unrelated to the task at hand — labels, assignees, linked PRs — `gh issue view <n> --json title,body,labels,assignees,state,url` is still fine.
+ Consult the issue only through the export — never `gh issue view`, the GitHub
+ MCP tools, or `WebFetch` in its place. `gh issue view` alone does **not** fetch
+ attachments: GitHub's `private-user-images.githubusercontent.com` URLs require
+ an authenticated request even when the issue is public, which is why the export
+ script exists. `WebFetch` on a github.com issue page often fails outright in
+ isolated environments. For a quick metadata check unrelated to the task at hand
+ — labels, assignees, linked PRs —
+ `gh issue view <n> --json title,body,labels,assignees,state,url` is still fine.
- **Then read** `docs/issue/<n>/issue.md` end to end, and **open the files under** `docs/issue/<n>/attachments/` when you need pixels (screenshots, mockups, design references).
+ **Then read** `docs/issue/<n>/issue.md` end to end, and **open the files under**
+ `docs/issue/<n>/attachments/` when you need pixels (screenshots, mockups, design
+ references).
- **Auth:** the script reads `$GH_TOKEN` (or `$GITHUB_TOKEN`) first, then falls back to `gh auth token`. One of those must be available. **Deps:** stdlib Python 3.9+ only — no `pip install` needed.
+ **Auth:** the script reads `$GH_TOKEN` (or `$GITHUB_TOKEN`) first, then falls
+ back to `gh auth token`. One of those must be available. **Deps:** stdlib Python
+ 3.9+ only — no `pip install` needed.
- **Repo:** if `--repo OWNER/REPO` is omitted and the argument isn't a full issue URL, the script reads `origin` from the current git checkout. Pass `--repo` explicitly when exporting an issue from a different repo than the one you're working in.
+ **Repo:** if `--repo OWNER/REPO` is omitted and the argument isn't a full issue
+ URL, the script reads `origin` from the current git checkout. Pass `--repo`
+ explicitly when exporting an issue from a different repo than the one you're
+ working in.
- If the export fails, **stop and report** — do not start solving the task from the title alone. Tell the user what failed and how to proceed. The script exits non-zero on every failure — auth, network, repo not found, or an attachment that wouldn't download — so check the status, not just the last line. A partial attachment failure still writes the Markdown and prints `Downloaded 2/3 attachment(s)` plus each URL it missed: the thread is there, but you'd be reading it with pixels missing.
+ If the export fails, **stop and report** — do not start solving the task from
+ the title alone. Tell the user what failed and how to proceed. The script exits
+ non-zero on every failure — auth, network, repo not found, or an attachment that
+ wouldn't download — so check the status, not just the last line. A partial
+ attachment failure still writes the Markdown and prints
+ `Downloaded 2/3 attachment(s)` plus each URL it missed: the thread is there, but
+ you'd be reading it with pixels missing.
### Attachments with no extension
- The filename stem is the asset id, so an attachment's type is not readable off its name — `file docs/issue/<n>/attachments/*` before deciding what to open. An image you read directly. **A video** (e.g. `ISO Media, Apple QuickTime movie`) you cannot play: load `@.claude/skills/take-issue/video-frames.md`, which extracts frames you can read as images.
+ The filename stem is the asset id, so an attachment's type is not readable off
+ its name — `file docs/issue/<n>/attachments/*` before deciding what to open. An
+ image you read directly. **A video** (e.g. `ISO Media, Apple QuickTime movie`)
+ you cannot play: load `@.claude/skills/take-issue/video-frames.md`, which
+ extracts frames you can read as images.
## Step 2 — Commit the export
```bash
git add docs/issue/<n> && git commit -m "docs: #<n> export the issue"
```
- Commit it **now**, before any planning. The export is the source of truth for what the issue says, so an agent resuming this branch — after a context wipe, a handoff, or in a parallel session — re-reads the thread instead of re-exporting it, and committing it up front means that holds even if the session dies mid-plan. Never commit it on the trunk or a promotion branch.
+ Commit it **now**, before any planning. The export is the source of truth for
+ what the issue says, so an agent resuming this branch — after a context wipe, a
+ handoff, or in a parallel session — re-reads the thread instead of re-exporting
+ it, and committing it up front means that holds even if the session dies
+ mid-plan. Never commit it on the trunk or a promotion branch.
- `@.claude/skills/finalize/SKILL.md` deletes the whole `docs/issue/` tree in the last commit before `gh pr ready`, so this add and that delete cancel out in the squash. **You** must not delete it.
+ `@.claude/skills/finalize/SKILL.md` deletes the whole `docs/issue/` tree in the
+ last commit before `gh pr ready`, so this add and that delete cancel out in the
+ squash. **You** must not delete it.
## Step 3 — Return to the caller
- Hand back the export path (`docs/issue/<n>/issue.md`) and the number. **Whether it is the number a PR closes is the caller's to decide**, and often it isn't one: an issue taken for context — a related report, the thread a decision was argued in, the parent of a carve — is read and closes nothing. Where the caller carves, `@.claude/skills/plan/carving.md` settles which number the PR closes.
+ Hand back the export path (`docs/issue/<n>/issue.md`) and the number. **Whether
+ it is the number a PR closes is the caller's to decide**, and often it isn't
+ one: an issue taken for context — a related report, the thread a decision was
+ argued in, the parent of a carve — is read and closes nothing. Where the caller
+ carves, `@.claude/skills/plan/carving.md` settles which number the PR closes.
Then stop. Everything downstream belongs to the caller.