Overview
PyAutoLabs has no door that reconciles the GitHub issue trackers. /repo_cleanup sweeps git debris and stops there, /community handles external issues awaiting a reply, and /create_issue / /update_issue are single-issue primitives — nothing owns "audit the open issues, find the dead ones, close them". The trackers had drifted to 82 open issues across 18 repos, of which 35 were closable.
An ad-hoc sweep on 2026-07-28 cleared those 35 (29 shipped-but-still-open, 6 obsolete 2018–2019 PyAutoCTI) leaving 47. This issue makes that reconciliation a reusable, human-gated skill so the tracker never silently drifts to 80+ again.
Plan
- Add
PyAutoBrain/skills/issue_cleanup/ as a standalone execution door modelled on /repo_cleanup: audit → bucketed dashboard → per-bucket human confirmation → execute → recap.
- Encode the four ways a naive "has a PyAutoMind record → close it" rule was proven wrong, above all the record header-key taxonomy.
- Require two independent evidence legs (record header + merged PR) before any issue is even proposed for closing.
- Wire it into
COMMANDS.md, bin/install.sh, and the /wake_up digest — audit auto-runs read-only, every close stays human-gated.
Detailed implementation plan
Affected Repositories
- PyAutoBrain (primary, only)
Branch Survey
| Repository |
Current Branch |
Dirty? |
| ./PyAutoBrain |
main |
M skills/WORKFLOW.md (concurrent, unrelated) |
Suggested branch: feature/issue-cleanup
Worktree: ~/Code/PyAutoLabs-wt/issue-cleanup/
What the ad-hoc sweep established
The classifier needed four corrections, each found by verification rather than inspection. These are the skill's core requirements:
-
Body mentions are not claims. Grepping record files for an issue URL over-matches — complete/2026/05/many-vis-prep-dft.md discusses PyAutoArray#326 in prose while its own - issue: header reads (CI-triage cluster G, no GitHub issue). Only the header line is evidence.
-
The header key carries the meaning — the load-bearing rule. Across 800 records: issue: (630 uses) means this record completes that issue. But followup-issue:, follow-up-issue:, library-followup-issue:, parent-issue:, upstream-issues-filed: and plan: (13 uses) mean the opposite — the record spawned that issue and it is legitimately open. A loose *issue*: match would close live follow-ups.
-
Annotations override. Records mark deliberate exceptions inline: (open — findings census stays as reference), (STAYS OPEN — real finding + resumable fit), (STAYS OPEN for the optional model-parity fit leg), (both stay OPEN for parked design work only). Any open token means hands off — and these appear on plan: lines, not just issue: lines.
-
A record in complete/ does not mean the work completed. ep-hierarchical-scale-collapse.md carries Status: issued — it filed PyAutoFit#1405 and reported two defects on it. The record is complete; the issue is a live bug. Read the status field, not the directory.
Corroborating: PyAutoReduce#8's record already said (CLOSED) while GitHub had it open — closes do silently fail to land.
Buckets
| Bucket |
Definition |
Action |
| A shipped |
completing header key + no open annotation + merged PR |
closable, on confirmation |
| B weak evidence |
record exists, an evidence leg fails |
report only |
| C deliberately open |
annotation says so |
never touch |
| D in flight |
present in active.md / parked.md |
never touch |
| E external |
author is not the maintainer |
route to /community |
| F unreconciled |
no record at all |
the real backlog; sub-split by age |
The PR leg needs both paths: the GitHub timeline cross-reference and a PR number named in the record body — 12 of the 29 closable issues had only the latter, so timeline alone under-reports.
Obsolescence needs a real check, not an age threshold
The 8 oldest issues split on evidence, not age. The 6 PyAutoCTI ones (2693–2785 days) named FrameGeometry, CIFrame, CIData, ci_data_analysis, ci_pattern, phase.py/pipeline — grep of autocti/ returns zero for every one (the CTI resurrection removed that surface), so they closed not_planned. PyAutoHands#16 (test against pre-release deps) and #17 (fail build if RTD docs fail) are the same vintage (~1337 days) but were left open — no --pre workflow and no RTD gating exist in PyAutoHands/.github/workflows/, so they remain valid unimplemented asks. The skill must probe whether the named API/infra still exists.
Implementation Steps
skills/issue_cleanup/issue_cleanup.md — canonical command body (the <verb>.md convention /hygiene and /wake_up follow): scope repos → fetch open issues (select(.pull_request == null)) → parse record headers → classify A–F → dashboard → per-bucket confirm → execute → recap.
skills/issue_cleanup/SKILL.md — thin discovery wrapper, frontmatter name: issue-cleanup (hyphenated for Codex).
skills/issue_cleanup/reference.md — header taxonomy table, bucket definitions, dashboard layout, per-bucket execution.
skills/COMMANDS.md — add /issue_cleanup as a maintenance/execution door (/repo_cleanup is currently absent from this file too; add alongside).
skills/wake_up/wake_up.md — add a read-only reconciliation count to the digest.
Mechanics
gh issue close is broken in this environment. Comment first, then gh api -X PATCH repos/<owner>/<repo>/issues/<n> -f state=closed -f state_reason=<completed|not_planned>.
completed for bucket A; not_planned for obsolete.
- Every close leaves a comment naming its evidence (record path + PR) so the decision is auditable and reversible.
- Recognise bot-authored self-refreshing issues (
[url-check], [heart-health]) and exclude them from staleness ranking.
Testing
Re-run the audit half against today's post-sweep state and assert it reproduces the known-good classification: 47 open, zero bucket-A candidates (all closed today), the 5 annotated C issues held back, and the 6 follow-up-key issues correctly not proposed. A real regression bar, not a smoke check.
Install caveat
bin/install.sh run from a worktree repoints ~/.claude at that worktree. Create the two symlinks by hand; leave install.sh to run from the main checkout post-merge.
Key Files
PyAutoBrain/skills/issue_cleanup/issue_cleanup.md — command body (new)
PyAutoBrain/skills/issue_cleanup/SKILL.md — discovery wrapper (new)
PyAutoBrain/skills/issue_cleanup/reference.md — taxonomy + execution detail (new)
PyAutoBrain/skills/COMMANDS.md — routing entry
PyAutoBrain/skills/wake_up/wake_up.md — digest line
Notes on classification
Brain's Feature Agent returned large (score 9) → split-into-phases; overridden to single phase — one skill in one repo, with the design reasoning already settled by the sweep rather than pending discovery. Brain's cited risk ("public-API change may ripple downstream") is a false positive: a skill body is not an API. Heart is YELLOW (65) but its tick is stale (2026-07-27 17:18, citing 07-21 validation data) and none of its reasons gate a Brain skill addition.
Original Prompt
Click to expand starting prompt
See PyAutoMind/active/issue_cleanup_skill.md. The originating request was:
do we have a skill to do a github issue clean up?
Answered: no — /repo_cleanup covers git debris only, /community covers external issues, /create_issue and /update_issue are single-issue primitives. The user asked for an ad-hoc sweep first, then this skill.
Overview
PyAutoLabs has no door that reconciles the GitHub issue trackers.
/repo_cleanupsweeps git debris and stops there,/communityhandles external issues awaiting a reply, and/create_issue//update_issueare single-issue primitives — nothing owns "audit the open issues, find the dead ones, close them". The trackers had drifted to 82 open issues across 18 repos, of which 35 were closable.An ad-hoc sweep on 2026-07-28 cleared those 35 (29 shipped-but-still-open, 6 obsolete 2018–2019 PyAutoCTI) leaving 47. This issue makes that reconciliation a reusable, human-gated skill so the tracker never silently drifts to 80+ again.
Plan
PyAutoBrain/skills/issue_cleanup/as a standalone execution door modelled on/repo_cleanup: audit → bucketed dashboard → per-bucket human confirmation → execute → recap.COMMANDS.md,bin/install.sh, and the/wake_updigest — audit auto-runs read-only, every close stays human-gated.Detailed implementation plan
Affected Repositories
Branch Survey
M skills/WORKFLOW.md(concurrent, unrelated)Suggested branch:
feature/issue-cleanupWorktree:
~/Code/PyAutoLabs-wt/issue-cleanup/What the ad-hoc sweep established
The classifier needed four corrections, each found by verification rather than inspection. These are the skill's core requirements:
Body mentions are not claims. Grepping record files for an issue URL over-matches —
complete/2026/05/many-vis-prep-dft.mddiscussesPyAutoArray#326in prose while its own- issue:header reads(CI-triage cluster G, no GitHub issue). Only the header line is evidence.The header key carries the meaning — the load-bearing rule. Across 800 records:
issue:(630 uses) means this record completes that issue. Butfollowup-issue:,follow-up-issue:,library-followup-issue:,parent-issue:,upstream-issues-filed:andplan:(13 uses) mean the opposite — the record spawned that issue and it is legitimately open. A loose*issue*:match would close live follow-ups.Annotations override. Records mark deliberate exceptions inline:
(open — findings census stays as reference),(STAYS OPEN — real finding + resumable fit),(STAYS OPEN for the optional model-parity fit leg),(both stay OPEN for parked design work only). Anyopentoken means hands off — and these appear onplan:lines, not justissue:lines.A record in
complete/does not mean the work completed.ep-hierarchical-scale-collapse.mdcarriesStatus: issued— it filedPyAutoFit#1405and reported two defects on it. The record is complete; the issue is a live bug. Read the status field, not the directory.Corroborating:
PyAutoReduce#8's record already said(CLOSED)while GitHub had it open — closes do silently fail to land.Buckets
openannotation + merged PRactive.md/parked.md/communityThe PR leg needs both paths: the GitHub timeline cross-reference and a PR number named in the record body — 12 of the 29 closable issues had only the latter, so timeline alone under-reports.
Obsolescence needs a real check, not an age threshold
The 8 oldest issues split on evidence, not age. The 6 PyAutoCTI ones (2693–2785 days) named
FrameGeometry,CIFrame,CIData,ci_data_analysis,ci_pattern,phase.py/pipeline— grep ofautocti/returns zero for every one (the CTI resurrection removed that surface), so they closednot_planned.PyAutoHands#16(test against pre-release deps) and#17(fail build if RTD docs fail) are the same vintage (~1337 days) but were left open — no--preworkflow and no RTD gating exist inPyAutoHands/.github/workflows/, so they remain valid unimplemented asks. The skill must probe whether the named API/infra still exists.Implementation Steps
skills/issue_cleanup/issue_cleanup.md— canonical command body (the<verb>.mdconvention/hygieneand/wake_upfollow): scope repos → fetch open issues (select(.pull_request == null)) → parse record headers → classify A–F → dashboard → per-bucket confirm → execute → recap.skills/issue_cleanup/SKILL.md— thin discovery wrapper, frontmattername: issue-cleanup(hyphenated for Codex).skills/issue_cleanup/reference.md— header taxonomy table, bucket definitions, dashboard layout, per-bucket execution.skills/COMMANDS.md— add/issue_cleanupas a maintenance/execution door (/repo_cleanupis currently absent from this file too; add alongside).skills/wake_up/wake_up.md— add a read-only reconciliation count to the digest.Mechanics
gh issue closeis broken in this environment. Comment first, thengh api -X PATCH repos/<owner>/<repo>/issues/<n> -f state=closed -f state_reason=<completed|not_planned>.completedfor bucket A;not_plannedfor obsolete.[url-check],[heart-health]) and exclude them from staleness ranking.Testing
Re-run the audit half against today's post-sweep state and assert it reproduces the known-good classification: 47 open, zero bucket-A candidates (all closed today), the 5 annotated
Cissues held back, and the 6 follow-up-key issues correctly not proposed. A real regression bar, not a smoke check.Install caveat
bin/install.shrun from a worktree repoints~/.claudeat that worktree. Create the two symlinks by hand; leaveinstall.shto run from the main checkout post-merge.Key Files
PyAutoBrain/skills/issue_cleanup/issue_cleanup.md— command body (new)PyAutoBrain/skills/issue_cleanup/SKILL.md— discovery wrapper (new)PyAutoBrain/skills/issue_cleanup/reference.md— taxonomy + execution detail (new)PyAutoBrain/skills/COMMANDS.md— routing entryPyAutoBrain/skills/wake_up/wake_up.md— digest lineNotes on classification
Brain's Feature Agent returned large (score 9) → split-into-phases; overridden to single phase — one skill in one repo, with the design reasoning already settled by the sweep rather than pending discovery. Brain's cited risk ("public-API change may ripple downstream") is a false positive: a skill body is not an API. Heart is YELLOW (65) but its tick is stale (2026-07-27 17:18, citing 07-21 validation data) and none of its reasons gate a Brain skill addition.
Original Prompt
Click to expand starting prompt
See
PyAutoMind/active/issue_cleanup_skill.md. The originating request was:Answered: no —
/repo_cleanupcovers git debris only,/communitycovers external issues,/create_issueand/update_issueare single-issue primitives. The user asked for an ad-hoc sweep first, then this skill.