collapse-issues Skill
Identify clusters of related triaged GitHub issues sharing the same recipe:* label
and collapse qualifying clusters into single combined issues. Originals are closed with
cross-reference comments. This is the inverse of issue-splitter — where splitter
decomposes mixed-concern issues, this consolidates related small issues into fewer,
better-scoped units.
Grouping analysis is performed as in-context LLM reasoning. No parallel sessions are spawned.
When to Use
- After
issue-splitterhas decomposed issues into focused sub-issues, to re-consolidate overly granular results - Invoked by
triage-issuesvia the--collapseflag (Step 2c) - Directly by a user who wants to reduce issue count before an implementation sprint
- With
--dry-runto preview what would be collapsed without mutating GitHub
Arguments
/autoskillit:collapse-issues [--dry-run] [--min-group 2] [--max-group 5] [--repo owner/repo] [--no-label]
--dry-run— show proposed groupings, skip all GitHub mutations--min-group N— minimum issues per group to justify collapsing (default: 2)--max-group N— maximum issues per combined issue (default: 5)--repo owner/repo— explicit repo; if absent, resolve viagh repo view--no-label— skip all label creation and--labelcalls
Critical Constraints
NEVER:
- Close original issues before the combined issue is successfully created
- Apply
batch:Nlabels to combined or original issues - Collapse issues with different
recipe:*labels into one combined issue - Delegate grouping to parallel sessions — grouping analysis is in-context LLM reasoning only
- Use parallel session spawning (Agent/Task) for grouping analysis — it is in-context LLM reasoning
- Create files outside
temp/collapse-issues/ - Skip emitting the
---collapse-issues-result---block (emit even on error or no-collapse) - Summarize, paraphrase, truncate, or abbreviate the body of a source issue
- Substitute a hyperlink, URL reference, or cross-reference for inlined body content
- Use angle-bracket placeholder syntax (
<...>) in the combined issue body — always paste actual retrieved content from fetch_github_issue - Use the body field from
gh issue listfor body assembly — only fetched_content[N] from per-issue fetch is authoritative
ALWAYS:
- Include
--forceon all label creation calls (gh label create --force) for idempotency - Respect
--dry-run(skip all GitHub mutations when set) - Respect
--no-label(skip all label creation and--labelflags when set) - Cap groups at
--max-group(default 5) - Require at least
--min-group(default 2) issues to form a group - Emit
---collapse-issues-result---block even on dry-run or no-collapse decisions
Workflow
Step 0: Parse Arguments
Extract from ARGUMENTS:
--dry-run→dry_run = true--min-group N→min_group = N(default: 2)--max-group N→max_group = N(default: 5)--repo owner/repo→repo = "owner/repo"(omit--repoflag from gh commands if not provided)--no-label→no_label = true
Step 1: Authenticate
gh auth status
If auth fails, emit result block with {"error": "gh auth failed", "groups_formed": 0, "issues_collapsed": 0} and exit.
Step 2: Resolve Repo
gh repo view --json nameWithOwner -q .nameWithOwner
If repo cannot be resolved, emit result block with {"error": "repo resolution failed", "groups_formed": 0, "issues_collapsed": 0} and exit.
Step 3: Fetch Triaged Issues
gh issue list --state open --json number,title,labels --limit 200 [--repo {repo}]
- Filter to issues that carry at least one
recipe:*label (e.g.,recipe:implementation,recipe:remediation) - If the filtered list is empty: emit
no-collapseresult block and exit:---collapse-issues-result--- {"groups_formed": 0, "issues_collapsed": 0, "combined_issues": [], "standalone_issues": [], "dry_run": false, "reason": "no triaged issues"} ---/collapse-issues-result---
Step 4: LLM Grouping Analysis (in-context)
This step is pure in-context LLM reasoning — no parallel session spawning.
4a. Partition by recipe route (hard constraint):
Separate issues into per-recipe buckets. Issues with recipe:implementation form one group;
issues with recipe:remediation form another. Issues with different recipe:* labels are
never collapsed together into a single combined issue.
4b. Score pairwise relatedness within each bucket:
For each pair of issues in the same recipe bucket, evaluate:
- Overlapping component mentions (e.g., both mention
recipe/,execution/,server/) - Shared keywords in title/body (similar subsystem vocabulary)
- Complementary scope (e.g., two small enhancements to the same module)
- Size preference: prefer collapsing small/simple issues; large issues (long body, many sub-requirements) should remain standalone
4c. Form candidate groups:
- Greedily assign issues to groups, starting with most-related pairs
- Enforce
--max-groupcap per group (default: 5) - Issues that don't fit any qualifying group remain standalone
4d. Apply minimum-group threshold:
Groups with fewer than --min-group issues (default: 2) are dissolved — their members
remain standalone.
If no groups meet the threshold: emit no-collapse result block and exit:
---collapse-issues-result---
{"groups_formed": 0, "issues_collapsed": 0, "combined_issues": [], "standalone_issues": [<all issue numbers>], "dry_run": false, "reason": "no qualifying groups"}
---/collapse-issues-result---
Step 5: Fetch Full Issue Content
For each issue in each qualifying group (not standalone issues), call:
fetch_github_issue(issue_url, include_comments=true)
where issue_url is constructed as:
https://github.com/{repo}/issues/{number}
Do not output any prose between fetch calls — immediately proceed to the next issue.
Store the returned content field from the response. If fetch_github_issue returns
success: false for an issue, log the failure and proceed using the issue title
and a note that full body content was unavailable (do not fabricate body content).
This step produces the fetched_content[N] mapping used in Step 7b.
Step 6: Dry-run Gate
If --dry-run is set: print the proposed groups in human-readable form:
Group 1 (recipe:implementation): issues #12, #15, #18
Proposed title: "Combined: <descriptive scope phrase>"
Group 2 (recipe:remediation): issues #7, #9
Proposed title: "Combined: <descriptive scope phrase>"
Standalone: #3, #22, #25
Emit result block with "dry_run": true and exit without any GitHub mutations:
---collapse-issues-result---
{"groups_formed": 2, "issues_collapsed": 5, "combined_issues": [], "standalone_issues": [3, 22, 25], "dry_run": true}
---/collapse-issues-result---
Step 7: Create Combined Issues
For each qualifying group (in-context LLM reasoning for title synthesis):
Do not emit any prose or status text between groups — immediately proceed to create each combined issue.
7a. Synthesize title:
Write a title that describes the combined scope of all issues in the group.
Format: "Combined: <descriptive scope phrase>"
7b. Build combined issue body:
<!-- Collapses: #N, #M, #P -->
This issue combines related work originally tracked in #N, #M, and #P.
## From #N: {original title of issue N}
{Paste the complete, unmodified text of fetched_content[N].body here exactly
as returned by fetch_github_issue. Do not summarize, paraphrase, truncate, or
abbreviate any part of the body. Do not substitute a hyperlink, cross-reference,
or descriptive sentence. Every heading, list item, code block, and paragraph
from the original issue body must appear here without alteration.
SWITCH TO COPY MODE: The preceding title-synthesis step required generative
reasoning. This step requires strict verbatim reproduction — do not compose or
generate new prose. Copy only.}
---
## From #M: {original title of issue M}
{Paste the complete, unmodified text of fetched_content[M].body here exactly
as returned by fetch_github_issue. Do not summarize, paraphrase, truncate, or
abbreviate any part of the body. Do not substitute a hyperlink, cross-reference,
or descriptive sentence. Every heading, list item, code block, and paragraph
from the original issue body must appear here without alteration.
SWITCH TO COPY MODE: The preceding title-synthesis step required generative
reasoning. This step requires strict verbatim reproduction — do not compose or
generate new prose. Copy only.}
---
## From #P: {original title of issue P}
{Paste the complete, unmodified text of fetched_content[P].body here exactly
as returned by fetch_github_issue. Do not summarize, paraphrase, truncate, or
abbreviate any part of the body. Do not substitute a hyperlink, cross-reference,
or descriptive sentence. Every heading, list item, code block, and paragraph
from the original issue body must appear here without alteration.
SWITCH TO COPY MODE: The preceding title-synthesis step required generative
reasoning. This step requires strict verbatim reproduction — do not compose or
generate new prose. Copy only.}
7c. Collect labels:
Union of all non-batch:* labels from the original issues in the group. Typically this
is the shared recipe:* label plus any enhancement/bug labels.
7d. Ensure labels exist (skip if --no-label):
gh label create "recipe:implementation" --force [--repo {repo}]
gh label create "enhancement" --force [--repo {repo}]
Repeat for each unique label in the collected set (e.g., recipe:remediation, bug), always with --force.
7e. Create combined issue:
gh issue create \
--title "Combined: <synthesized title>" \
--body "<combined body>" \
--label "recipe:implementation" \
--label "enhancement" \
[--repo {repo}]
Capture the new issue number from the URL in stdout output.
Step 8: Close Original Issues
For each original issue that was collapsed (one by one, in order):
8a. Post closing comment:
gh issue comment {orig_number} \
--body "Collapsed into #{combined_number}: {combined_url}" \
[--repo {repo}]
8b. Close the issue:
gh issue close {orig_number} [--repo {repo}]
Step 9: Emit Result Block
---collapse-issues-result---
{
"groups_formed": <count>,
"issues_collapsed": <total originals closed>,
"combined_issues": [
{"number": X, "url": "...", "from": [N, M, P]},
...
],
"standalone_issues": [<list of issue numbers NOT collapsed>],
"dry_run": false
}
---/collapse-issues-result---
On error, emit:
---collapse-issues-result---
{"error": "<description>", "groups_formed": 0, "issues_collapsed": 0}
---/collapse-issues-result---
Output Location
Dry-run reports (if any): temp/collapse-issues/
Error Handling
- Auth failure → emit error result block, exit
- Repo resolution failure → emit error result block, exit
- No triaged issues → emit no-collapse result block, exit
- No qualifying groups → emit no-collapse result block, exit
gh issue createfails → log the failure, emit partial result with"error"in rationale, do not abort silently; do not close any originals for this groupgh issue closefails → log the failure and continue with remaining originals
Related Skills
/autoskillit:issue-splitter— Inverse: decomposes mixed-concern issues into focused sub-issues/autoskillit:triage-issues— Invokes this skill via--collapseflag (Step 2c)