agentleFS
Tamircohen28Tamircohen28/tamirs-superpowers/skills/repo/cleanup/SKILL.md

cleanup

Skill2 starsChanged 3 months agoMITView on GitHub

Use when the user wants to clean up, tidy, or reset a GitHub repo — even if they name only one part. Triggers: repo cleanup, repo housekeeping, prune merged branches, delete stale remote branches, tidy my worktrees, drive all open PRs to merge-ready, wipe build and cache artifacts, reset local checkout to match remote.

  • Commits and pushes

71 other projects use a version of this.

Adopted by

Most recently taken up by

Used with

Projects with it also use chips, react-query-best-practices and 10 more.

Other files people use alongside this one.

Files found in the same public projects as a version of this one, more often than they turn up anywhere else. Each project counts once, large collections count for less, and this file's own repository is left out.
  • udecodeSkill

    chips

    Run the project's suggested-task ledger, the chips. /chips alone brings this session's open tasks up to date: it applies what the ledger helper says, settles stale and split tasks, cards what can start and reports the board, and /chips all also takes the ship-list tasks and the ones no live session owns, and merges duplicate tasks across the board. Use for /chips, /chips offer, start or drop, \"what chips are open\", \"suggest a task for X\", \"update the chips\", \"clean up the chips\", \"which chips are stale\", \"is this chip still worth doing\", \"merge duplicate chips\", at the last hand-back of a run that offered a task, and whenever pstack would file a tracked issue, a follow-up, a reflect Backlog item or an out-of-band PR.

    Also in 3 projects that use this

  • bibektimilsina00Skill

    react-query-best-practices

    Audit and fix React Query usage in apps/web — enforce query key factories, signal forwarding, staleTime, and proper mutation patterns. Use when reviewing or fixing server-state code.

    Also in 3 projects that use this

  • bibektimilsina00Skill

    you-might-not-need-a-callback

    Analyze and fix useCallback anti-patterns in your code

    Also in 3 projects that use this

  • Scylla23Skill

    redo

    Re-run the last routed task one model tier up (haiku → sonnet → opus → fable). User-invoked escalation when the previous result missed. Pass --dry-run to preview without running.

    Also in 3 projects that use this

  • Aetheria-Labs1Skill

    plan-page

    Plan one storefront page from strategy through final copy, section order, proof, offers, template direction, responsive layout, and production asset requirements. Stops at an approved execution-ready specification.

    Also in 3 projects that use this

  • SocialKit-APISkill

    video-transcripts

    Extract transcripts from social videos through SocialKit across YouTube, TikTok, Instagram, Facebook, X/Twitter, LinkedIn, and direct video file URLs. Use when the user asks to transcribe, get captions or subtitles, pull the spoken text, or read what a video says, including one video or many at once. Returns full text plus timestamped segments. Not for posting, private accounts, or unrelated website scraping.

    Also in 3 projects that use this

  • +3 more from bibektimilsina00

The file

We split this skill into the rules it gives an agent

9 rules. 0 are common, 5 are distinctive, and 4 are very specific to this project.

  • 0

    Common

    Most of the 61 edited versions we read keep these.

  • 5

    Distinctive

    This author's own choices. Worth a look.

  • 4

    Very specific

    Tied to their project's names, files or tools. Probably skip.

  • Common
  • Distinctive
  • Very specific
  1. Distinctive:

    No open PR exists for it and its last commit is older than 30 days

    line 116
  2. Very specific:

    Wait for yes. If the user says no, skip 1c and go directly to 1d.

    line 143
  3. Distinctive:

    If there are no open PRs, report "No open PRs — skipping." and move on.

    line 163
  4. Distinctive:

    If there are open PRs, spawn one sub-agent per PR using the Agent tool, all in the same call so they run in parallel.

    line 165
  5. Very specific:

    When a worktree was reclassified to dirty solely because of gitignored content (no uncommitted git changes), show that instead — a diff …

    line 244
  6. Very specific:

    Wait for the user's choice per worktree.

    line 262
  7. Distinctive:

    Verify with git worktree list that the list is now clean.

    line 275
  8. Very specific:

    If local $DEFAULT has commits not on remote, show them and ask:

    line 312
  9. Distinctive:

    Wait for the answer. After syncing, run git status and confirm the branch is clean.

    line 321

“Common” is measured: kept by at least 6 in 10 of the 61 edited versions of this file we could read. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.

Keep what fits and drop the rest. Your version, ready for your agents.
Files
SKILL.md

repo-cleanup

Full repository housekeeping: prune remote branches, drive open PRs in parallel via sub-agents, clean local worktrees, discard or rescue uncommitted work, and reset the local environment to a clean state matching remote.

Why this skill exists

Repos accumulate cruft quickly — merged branches that weren't deleted, PRs that stalled, worktrees from old tasks, temp build files, and local checkouts that drifted from main. Doing this manually is error-prone and tedious. This skill sweeps all of it in one pass, asks for confirmation before any destructive action, and parallelizes PR work across sub-agents so the whole process finishes faster.

Why this skill is model-invocable (disable-model-invocation: false): cleanup is meant to be orchestrated — an operator points sub-agents (or a Workflow) at many repos and fans out one cleanup per repo. Gating a skill with disable-model-invocation: true also blocks that path, because a sub-agent invoking a skill is itself model invocation. So safety lives inside the skill — every destructive step shows a plan and waits for confirmation, and dry-run mode changes nothing — not in the invocation flag. The flag is reserved for skills that must never be invoked autonomously (internal companions), which cleanup is not.

Scope flags

FlagEffect
--remote-onlyRun only Phase 1 (remote branches + PRs)
--local-onlyRun only Phases 2–3 (worktrees + local reset)
--dry-runPrint every planned action without executing it
(none)Full sweep — all phases

Parse flags from args at startup. Default = full sweep.

Headless / non-interactive use

For fan-out across many repos — one sub-agent (or Workflow stage) per repo — use the companion script instead of the interactive flow:

bash scripts/cleanup.sh [--dry-run] [--remote-only | --local-only] [--yes] [REPO_PATH]

scripts/cleanup.sh is the provably-safe deterministic core of this skill: it performs only the deletions that need no human judgment — remote branches fully merged into the default branch, auxiliary worktrees that are clean and merged/gone, git-ignored build/cache directories, and a fast-forward-only sync of the default branch. Anything requiring judgment — dirty worktrees, unpushed commits, unmerged branches, non-ignored files, a diverged default branch — is reported and left untouched.

  • It is dry-run by default; it changes nothing unless --yes is passed.
  • It keeps every branch GitHub reports protected (the protected flag or a ruleset deletion rule), every branch at the default tip, and every worktree with unpushed commits, a live agent claim or an unfinished objective task.
  • It never drives PRs, never rescues uncommitted work, and never drops anything a human would want to review.

The full interactive skill below remains the default for a single repo — it adds per-item confirmation, rescuing uncommitted work, and driving open PRs in parallel via pr-dev. Reach for the script when you need cleanup to run unattended at scale; reach for the skill when a human is in the loop.

Startup checks

Before doing anything:

  1. Confirm the GitHub CLI is signed in to this repository's host (gh repo view succeeds in the checkout; it resolves the host from the remote, so GitHub Enterprise works) — if not, stop and ask the user to sign in to the GitHub CLI for that host.
  2. Confirm cwd is a git repo with a remote. If not, stop.
  3. Resolve REPO and DEFAULT once; reuse throughout:
    REPO=$(gh repo view --json nameWithOwner -q .nameWithOwner)
    DEFAULT=$(gh repo view --json defaultBranchRef -q .defaultBranchRef.name)

Phase 1 — Remote branch cleanup

1a. Discover branches

git fetch --prune origin

# Branches fully merged into the default branch
git branch -r --merged "origin/$DEFAULT" \
  | grep -vE "HEAD|^ *origin/($DEFAULT|develop)$|^ *origin/(release|hotfix)/" \
  | sed 's|  origin/||' | sort > /tmp/rc_merged.txt

# Branches with no open PR and last commit older than 30 days
gh api "repos/$REPO/branches" --paginate \
  --jq '.[] | select(.protected == false) | .name' | sort > /tmp/rc_all.txt

A branch is a delete candidate when ANY of the following is true:

  • Fully merged into the default branch (appears in git branch -r --merged)
  • Its associated PR is merged/closed and the branch was not auto-deleted
  • No open PR exists for it and its last commit is older than 30 days

A branch is safe to keep when:

  • It has an open (not merged, not closed) PR
  • It is protected on GitHub, or a ruleset with a deletion rule applies to it (gh api "repos/$REPO/rules/branches/<branch>"). This is the protection check. A name pattern is not.
  • It matches a long-lived name: main, master, develop, release/*, hotfix/* (an extra keep list, never the protection check)
  • It points at the default branch's tip (no commits of its own yet)

1b. Show the plan and confirm

Print the full classification before touching anything:

Remote branch cleanup plan for <REPO>:
  DELETE (merged into main):
    - fix/old-thing  (merged 2026-06-01)
    - chore/cleanup  (merged 2026-05-15)
  DELETE (stale, no open PR, 87 days idle):
    - wip/experiment (last commit 2026-04-01)
  KEEP (open PR #42):
    - feat/new-thing
  KEEP (protected / long-lived):
    - develop

Proceed with deletion? (yes/no)

Wait for yes. If the user says no, skip 1c and go directly to 1d.

1c. Delete confirmed branches

For each confirmed delete candidate:

git push origin --delete "<branch>" 2>&1 \
  || gh api -X DELETE "repos/$REPO/git/refs/heads/<branch>"

Log each result: Deleted: <branch> or Skipped (already gone): <branch>.

1d. Drive open PRs in parallel

gh pr list --repo "$REPO" --state open --json number,title,headRefName \
  --jq '.[] | "PR #\(.number): \(.title)"'

If there are no open PRs, report "No open PRs — skipping." and move on.

If there are open PRs, spawn one sub-agent per PR using the Agent tool, all in the same call so they run in parallel. Each agent's prompt:

You are driving PR #<N> in repo <REPO> to merge-ready.
Invoke the pr-dev skill (tamirs-superpowers:pr-dev) with PR number <N>.
Stop at the readiness gate — do NOT merge without explicit user approval.
Report back in one line: "PR #<N>: ready" or "PR #<N>: blocked — <reason>".

Important: spawn all PR sub-agents first, then immediately continue with Phases 2 and 3 yourself — don't wait for the PR agents to finish before proceeding locally. They run in the background while you do the local cleanup.

Collect results when all agents complete and include them in the final summary.

Phase 2 — Local worktree cleanup

2a. List all worktrees

git worktree list --porcelain

The first entry is the main worktree (the current checkout). Never remove it. All other entries are auxiliary worktrees — these are what you clean up.

For each auxiliary worktree, gather its state:

# uncommitted changes
git -C "<path>" status --porcelain 2>/dev/null

# unpushed commits
BRANCH=$(git -C "<path>" branch --show-current 2>/dev/null)
git -C "<path>" log --oneline "origin/$BRANCH..HEAD" 2>/dev/null

# last commit date
git -C "<path>" log -1 --format="%ar" 2>/dev/null

# gitignored-but-present content — invisible to `git status`, not necessarily unwanted.
# A repo can deliberately route session/scratch output into a gitignored directory; that
# makes it clean by git's definition while still holding real, irreplaceable work.
git -C "<path>" ls-files --others --ignored --exclude-standard 2>/dev/null

2b. Classify each auxiliary worktree

A nonzero ignored-file count overrides every row below to dirty, regardless of what git status says. git status --porcelain is empty for gitignored content by design — that is not the same as "nothing here." Check this before applying any other classification, not after: a worktree can be simultaneously stale-clean by branch age and holding real, irreplaceable content that nothing in git ever saw.

StateLabelIntended action
Clean + branch merged into defaultstale-cleanAuto-remove — safe, no data loss
Clean + open PR existspr-worktreeSkip — pr-dev sub-agent is already handling it
Clean + no PR + last commit >30 daysstale-cleanAuto-remove
Clean + no PR + last commit ≤30 daysrecent-cleanAsk before removing
Has uncommitted changesdirtyAlways ask — show diff summary before acting
Has only unpushed commitsready-to-pushPush branch, open/update PR, then remove

2c. Handle worktrees that need a decision

For any dirty or recent-clean worktree, show the user what's there before asking:

Worktree: ~/.session-worktrees/myrepo/feat-login
Branch: feat/login (last commit 3 days ago)
Uncommitted: 4 files changed

Modified:
  src/auth/login.ts (+42 -5)
  src/auth/session.ts (+12)
  ...

Options:
  push  — commit as "wip: save work from worktree cleanup", push, open draft PR
  skip  — leave this worktree untouched
  drop  — discard all changes and remove (IRREVERSIBLE)

When a worktree was reclassified to dirty solely because of gitignored content (no uncommitted git changes), show that instead — a diff summary doesn't apply to files git never tracked:

Worktree: ~/.session-worktrees/myrepo/old-audit
Branch: wip/old-audit (last commit 34 days ago, no open PR — would otherwise be stale-clean)
Gitignored content: 18 files, 332K (git status reports clean — this is invisible to it)

  session-files/report-01.md
  session-files/report-02.md
  ...

Options:
  keep  — leave this worktree untouched (default if unsure — this content is not in git anywhere else)
  drop  — discard everything, including the gitignored content, and remove (IRREVERSIBLE)

Wait for the user's choice per worktree. Never drop without an explicit drop response.

For ready-to-push worktrees, push the branch and open/update a PR, then remove.

2d. Remove clean/resolved worktrees

Skip a worktree when an agent holds a live claim on its branch (~/.agent-work-claims/), or when an objective task that is not finished owns it. Its worker is still running.

git worktree remove --force "<path>"
git worktree prune

Verify with git worktree list that the list is now clean.

Phase 3 — Local environment reset

3a. Delete build and temp files

Scan for known patterns (respecting .gitignore — prefer deleting only ignored dirs):

git ls-files --others --ignored --exclude-standard -z \
  | xargs -0 -I{} find "{}" -maxdepth 0 \( \
      -name "node_modules" -o -name ".next" -o -name "dist" -o \
      -name "build" -o -name ".cache" -o -name "__pycache__" -o \
      -name ".tox" -o -name "target" -o -name ".gradle" \
    \) -print 2>/dev/null

Or if git ls-files doesn't cover it, fall back to:

find . -maxdepth 3 \( \
  -name "node_modules" -o -name ".next" -o -name "dist" -o \
  -name "build" -o -name ".cache" -o -name "__pycache__" -o \
  -name ".tox" -o -name "target" -o -name ".gradle" \
\) -not -path "./.git*" -print

Show the list and ask: Delete these? (yes/no/[list items to skip]). Never delete without confirmation. Be conservative — skip anything that doesn't look like a generated artifact (e.g., a build/ directory that contains hand-written source files).

3b. Sync local to remote

git checkout "$DEFAULT"
git fetch --prune origin
git pull --rebase "origin/$DEFAULT"

If local $DEFAULT has commits not on remote, show them and ask:

Warning: local <DEFAULT> has 2 commits not on remote:
  abc1234 "some message"
  def5678 "another commit"
Push them or reset to remote? (push/reset)

Wait for the answer. After syncing, run git status and confirm the branch is clean.

Output format

Brief, state-change-only updates — not one line per command:

[Phase 1/3] Remote cleanup
  Scanning branches... found 5 total, 3 delete candidates
  Plan shown → user confirmed → deleted: fix/old-thing, chore/cleanup, wip/experiment
  Open PRs: 2 → PR agents spawned (#41, #43)

[Phase 2/3] Local worktrees
  Main worktree: skipped
  ~/.session-worktrees/myrepo/feat-login  → stale-clean → removed
  ~/.session-worktrees/myrepo/fix-bug     → dirty (4 files) → user chose push → PR #51 opened → removed
  ~/.session-worktrees/myrepo/old-spike   → stale-clean → removed

[Phase 3/3] Local reset
  Build artifacts: .next/, dist/ → user confirmed → deleted
  Synced to origin/<default-branch> (rebased 3 new commits)

PR agents completed:
  PR #41: ready — all checks green, 0 threads
  PR #43: blocked — CI failing (test coverage)

Summary:
  Remote branches deleted: 3
  Worktrees removed: 3 (1 rescued → PR #51)
  PRs driven: 2 (ready: 1, blocked: 1)
  Build artifacts removed: .next/, dist/
  Local state: clean ✓

Hard rules

  • Never delete the default branch, main, master, develop, release/*, or any protected branch. Check GitHub's protected flag and the rulesets that apply before deleting anything. A branch whose protection cannot be read is kept.
  • Never discard uncommitted work without an explicit drop from the user — always show the diff first.
  • Never remove the main worktree (first entry in git worktree list).
  • Always ask before deleting build artifacts — the generated-artifact list may contain intentional local directories.
  • Never force-push or hard-reset the default branch without explicit instruction.
  • In dry-run mode, print every planned action with a [dry-run] prefix and execute nothing. Before each destructive shell command, check if dry-run is active and skip it. Print Dry-run complete — no changes made. at the end.
  • If gh is unavailable, stop immediately and tell the user — do not attempt partial cleanup with git alone.

Download now (ZIP)

Does it work?

Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.

No reviews yet

People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.

  • It worked
  • Partly
  • It didn't
What did you use it for? e.g. Reviewing pull requests in a Rails app

Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.

Your trail

Files you open will collect here, so you can find them again.

Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.

Now do this for your own.

Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.