Process Issues Skill
Execute the appropriate implementation recipe for each triaged GitHub issue, respecting the
batch order defined by the triage-issues manifest. This skill is the execution counterpart
to triage-issues — it consumes the manifest and orchestrates the full lifecycle: claim all
issues upfront, load recipe, execute session, collect result, report.
When to Use
- After
/autoskillit:triage-issueshas produced a manifest in{{AUTOSKILLIT_TEMP}}/triage-issues/ - User says "process issues", "run issues", "execute pipeline for issues"
- When a triage manifest exists and batched issues need implementation sessions launched
Critical Constraints
NEVER:
- Create files outside
{{AUTOSKILLIT_TEMP}}/process-issues/directory - Apply
batch:Nlabels to GitHub issues (batch assignments are internal — they live only in the manifest JSON, not on GitHub objects) - Modify any source code files
- Reimplement recipe steps inline — always use
load_recipeto load the recipe YAML and follow it as an orchestrator - Run subagents in the background (
run_in_background: trueis prohibited)
ALWAYS:
- Process batches in ascending order: batch 1 before batch 2 before batch 3
- Use
load_recipeto execute the recipe for each issue - After loading a recipe via
load_recipe, execute every step in the recipe's step graph in sequence. Never skip, replace, or improvise steps. optional: truemeans the step is skipped ONLY when itsskip_when_falseingredient evaluates to false. When the ingredient is true, the step is mandatory.- Follow
on_success,on_failure,on_result, andon_context_limitrouting exactly as declared in the recipe YAML. - NEVER replace recipe PR steps (
prepare_pr,run_arch_lenses,compose_pr,annotate_pr_diff,review_pr) with manualrun_cmdcalls such asgh pr create. - Between issues: immediately begin step 1 for the next issue after completing the previous issue. Do not output prose status between issues — inter-issue text creates end_turn windows that cause stochastic session termination.
- NEVER use AskUserQuestion to confirm proceeding to the next issue or the next batch. Once Step 2a's initial confirmation gate passes, all subsequent issue and batch transitions are fully automated.
- Emit
---process-issues-result---result block on completion (success or failure) - Write the summary report to
{{AUTOSKILLIT_TEMP}}/process-issues/(relative to the current working directory) - Use
model: "sonnet"when spawning subagents via the Task tool - Use
ghCLI for all GitHub operations (not raw API calls) - Include
--forcein allgh label createcalls
Arguments
- Positional (optional): path to triage manifest JSON
--batch N— only process batch N (default: process all batches in order)--dry-run— print the processing plan and exit without launching any recipe sessions--status-updates— append body sections to each issue at pickup and at completion--merge-batch— after each batch completes, runanalyze-prs+merge-prto merge the batch PRs into the integration branch before starting the next batch
Workflow
Step 0: Parse Arguments
Parse arguments:
- If a positional path is given, use it as the manifest path.
--batch N: record the target batch number; process only that batch.--dry-run: set dry_run flag; print plan then exit after Step 2.--status-updates: set status_updates flag.--merge-batch: set merge_batch flag.
Step 1: Locate and Read Manifest
Locate the manifest:
- If a positional path argument was given, use it directly.
- Otherwise, auto-discover the most recently modified manifest:
ls -t {{AUTOSKILLIT_TEMP}}/triage-issues/triage_manifest_*.json 2>/dev/null | head -1 - If no manifest is found, abort:
"No triage manifest found. Run
/autoskillit:triage-issuesfirst, or pass the manifest path as the first argument."
Parse the manifest JSON. Extract:
batches: ordered list; each entry hasbatch(number) andissues(array)- Per issue:
number,title,recipe("implementation"or"remediation")
Derive the repository reference for constructing issue URLs. Try in order:
- Read
github.default_repofrom.autoskillit/config.yamlif present. - Infer from git remote:
This yields{ git remote get-url upstream 2>/dev/null || git remote get-url origin; } | sed 's|.*github.com[:/]||; s|\.git$||'owner/repo.
Construct each issue's URL:
https://github.com/{owner}/{repo}/issues/{number}
Step 2: Dry Run Mode
If --dry-run is active, print a table:
Dry run — would process N issues in M batches:
BATCH ISSUE RECIPE TITLE
------ ------ ---------------- ----------------------------------------
1 #42 implementation Add user authentication
1 #43 remediation Fix login redirect bug
2 #44 implementation Refactor auth module
...
Total: N issues, M batches. No sessions launched.
Then emit the ---process-issues-result--- block with "dry_run": true and exit.
Step 2a: Batch Scope Confirmation
Before executing any batch, display the full processing plan and confirm scope with the user:
━━━ Process Issues — Batch Scope ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
About to process {N} issues in {M} batches:
BATCH ISSUE RECIPE TITLE
------ ------ ---------------- ----------------------------------------
{batch rows from manifest}
Processing mode: sequential within each batch (batches processed in order)
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Proceed? [Y/n]
- Y (or Enter): Proceed to Step 2b.
- n: Abort. Emit
process-issues-resultwith"aborted": trueand exit cleanly.
Skip this step when --dry-run is active (Step 2 already prints the plan and exits) or when
--batch N limits scope to a single batch (show only that batch's issues).
Step 2b: Upfront Claiming (Phase 0.5)
Before dispatching any recipe, claim all candidate issues atomically.
Initialize two tracking lists:
pre_claimed_urls = [] # issues we successfully claimed
completed_urls = [] # issues whose recipe fully returned
Collect all issues from all batches that will be processed (respecting --batch N filtering).
For each issue in the collected list:
- Call
claim_issue(issue_url=<url>, label="queued")— noallow_reentry(defaultFalse) - If
result.claimed == true:- append
issue_urltopre_claimed_urls
- append
- If
result.claimed == false:- log:
"Issue #{number} skipped — already claimed by another session" - the issue will be excluded from dispatch entirely
- log:
After this phase:
pre_claimed_urlscontains every issue for which this session holds the claim- Issues absent from
pre_claimed_urlsare excluded from dispatch
Step 3: Process Batches
For each batch in ascending order (batch 1, then batch 2, etc.):
- If
--batch Nwas given, skip all batches with a different number.
3a. Log batch header:
━━━ Batch N/M ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Processing X issues:
#42 — implementation: Add user authentication
#43 — remediation: Fix login redirect bug
3b. For each issue in the batch (process sequentially):
Check pre_claimed_urls: If
issue_urlis NOT inpre_claimed_urls→ skip (excluded by upfront claim phase — another session holds it).Pre-dispatch check: Before executing the recipe for this issue, check if any previously completed issue in the CURRENT batch has
status: failure. If so, skip this issue withstatus: skippedand continue to the next issue in the batch. This prevents wasted compute on issues within the same batch after a failure. Skipped issues are recorded asstatus: skipped(notstatus: failure), so the batch failure gate below counts only the original failure(s) that triggered the skip.Promote queued → in-progress for this issue: Call
claim_issue(issue_url=<url>, allow_reentry=true)(No label argument — defaults to in-progress; removes the "queued" label and adds "in-progress".)Optionally append pickup status to issue body (if
--status-updatesis active):PROCESS_BODY_FILE="{{AUTOSKILLIT_TEMP}}/process-issues/status_{number}_$(date +%s).md" mkdir -p "$(dirname "$PROCESS_BODY_FILE")" gh issue view {number} --json body --jq '.body' > "$PROCESS_BODY_FILE" printf '\n\n---\n\n## In Progress\n\nProcessing in batch %s — recipe: `%s`\n' \ "{N}" "{recipe}" >> "$PROCESS_BODY_FILE" gh issue edit {number} --body-file "$PROCESS_BODY_FILE" sleep 1Determine recipe name and
run_name:recipefieldRecipe to load run_namePR Title Prefix implementationimplementationfeature[FEATURE]remediationremediationfix[FIX]These values correspond to the GitHub labels applied by
triage-issues:recipe:implementation(new features/enhancements) andrecipe:remediation(bugs).The
run_nameencodes recipe origin for theopen-prskill, which derives the PR title prefix from it by convention (seeopen-prSKILL.md).Load the recipe:
load_recipe("{recipe_name}")This returns the recipe YAML. Read it and execute it as an orchestrator — follow each step in the recipe, calling the specified MCP tool with the specified
with:arguments.Execute the recipe with these ingredient values:
task: the issue title (the recipe'smake-planstep detectsissue_urland fetches full content internally)issue_url: the constructed issue URLrun_name:"feature"(implementation) or"fix"(remediation)base_branch:"develop"(or readgit rev-parse --abbrev-ref HEAD)open_pr:"true"audit:"true"review_approach:"false"upfront_claimed:"true"← always set for upfront-claimed issues
The recipe's
claim_issuestep will receiveallow_reentry=true(via theupfront_claimedingredient) and recognize the pre-existing label as a valid reentry, returningclaimed=trueto proceed normally.After recipe returns (any outcome), append to completed_urls:
completed_urls.append(issue_url)Then record the result:
- On success path (
donestep reached):{issue_number, recipe, status: success, pr_url} - On failure path (
escalate_stopreached):{issue_number, recipe, status: failure, error}
- On success path (
Optionally append completion status to issue body (if
--status-updatesis active):PROCESS_BODY_FILE="{{AUTOSKILLIT_TEMP}}/process-issues/status_{number}_$(date +%s).md" mkdir -p "$(dirname "$PROCESS_BODY_FILE")" gh issue view {number} --json body --jq '.body' > "$PROCESS_BODY_FILE" printf '\n\n---\n\n## Status\n\n%s\n' \ "{✅ Processing complete — PR: $pr_url | ❌ Processing failed — manual intervention required}" \ >> "$PROCESS_BODY_FILE" gh issue edit {number} --body-file "$PROCESS_BODY_FILE" sleep 1
Fatal failure cleanup — if any unrecoverable error occurs during recipe dispatch:
uncompleted = [url for url in pre_claimed_urls if url not in completed_urls]
For each url in uncompleted:
Call release_issue(issue_url=url)
Log: "Released N upfront-claimed issues due to fatal failure"
Propagate the error
Batch failure gate (mandatory): After all issues in the current batch have been
processed, count the number of issues with status: failure. If ANY issue in this
batch has status: failure:
- Log: "Batch {N} had {count} failure(s). Halting batch processing."
- Skip all remaining batches.
- Proceed directly to Step 4 (Summary Report), recording unprocessed issues
from remaining batches as
status: skipped. - Call
release_issue()for each pre-claimed but unprocessed issue URL.
3c. After all issues in batch complete (if --merge-batch is active):
Run the analyze-prs → merge-pr cycle for the batch's PRs:
run_skill("/autoskillit:analyze-prs {base_branch}")
Parse the pr_order_file from the skill output. For each PR in the recommended
merge order:
run_skill("/autoskillit:merge-pr {pr_number} {complexity}")
Log merge results and proceed to the next batch.
3d. Batch Clone Cleanup (always, after all batches complete):
After all batches finish (whether or not --merge-batch was used), call:
batch_cleanup_clones()
This reads the shared registry at {{AUTOSKILLIT_TEMP}}/clone-cleanup-registry.json,
deletes all clones registered with status=success by the current kitchen (their
pipelines completed cleanly), and leaves all status=error clones on disk for investigation.
The call is scoped to the current kitchen's entries by default — entries registered by other parallel orchestrator sessions are not touched.
Operator escape hatch (recovery only): batch_cleanup_clones(all_owners="true") ignores
owner scoping and deletes all success-status entries, including legacy orphan entries from
registries created before the owner field was introduced. Do not use this on the normal happy
path — it is intended for manual recovery of stale registry files only.
Step 4: Write Summary Report
Compute timestamp: YYYY-MM-DD_HHMMSS.
Create {{AUTOSKILLIT_TEMP}}/process-issues/ if it does not exist.
Write {{AUTOSKILLIT_TEMP}}/process-issues/process_report_{ts}.md:
# Process Issues Report — {ts}
## Summary
| Metric | Value |
|--------|-------|
| Total issues | N |
| Successes | X |
| Failures | Y |
| Skipped (foreign claim) | Z |
| Batches processed | M |
## Results by Batch
### Batch 1
| Issue | Title | Recipe | Status | PR |
|-------|-------|--------|--------|----|
| #42 | Add user auth | implementation | success | #101 |
| #43 | Fix redirect | remediation | failure | — |
### Batch 2
...
## Failures
For each failed issue: error message captured from recipe terminal step.
Step 5: Emit Result Block
Print the structured result for pipeline capture:
---process-issues-result---
{
"report_path": "{{AUTOSKILLIT_TEMP}}/process-issues/process_report_{ts}.md",
"total_issues": N,
"successes": X,
"failures": Y,
"skipped": Z,
"batch_count": M,
"dry_run": false,
"pr_urls": ["https://github.com/.../pull/101", ...],
"pre_claimed": <count of pre_claimed_urls>,
"skipped_foreign_claim": <count of issues skipped because another session owned them>
}
---end-process-issues-result---
Also emit the report path as a standalone structured token for recipe capture:
dispatch_results = {{AUTOSKILLIT_TEMP}}/process-issues/process_report_{ts}.md
Output Location
{{AUTOSKILLIT_TEMP}}/process-issues/
process_report_{ts}.md # Human-readable summary (created per run)
Related Skills
/autoskillit:triage-issues— Produces the manifest that this skill consumes/autoskillit:analyze-prs— Used in--merge-batchmode/autoskillit:merge-pr— Used in--merge-batchmode/autoskillit:open-pr— Called by each executed recipe; derives[FEATURE]/[FIX]PR title prefix from therun_nameingredient