cleanup-local-branches — independently scanned and version-tracked by SaferSkills.
SaferSkills independently audited cleanup-local-branches (Agent Skill) and scored it 91/100 (green). The audit ran 55 deterministic rules across Security, Supply Chain, Maintenance, Transparency, and Community; it found 1 high-severity and 0 lower-severity findings. The full rule-by-rule trace and per-finding evidence are below. Free, methodology-open.
Findings & checks · 1 flagged
The text {match} is the classic direct prompt-injection phrasing. Placed in a skill body that the agent reads as trusted instructions, it tries to make the agent abandon its prior rules and follow whatever comes next — a full system-prompt override.
ignore/disregard/forget … previous instructions sentence.Every scanned point with the score it earned and what moved between them.
First recorded scan — no prior version to compare against.
The primary manifest — the file an agent reads to learn what this artifact does.
Prune dead local branches so the working copy only keeps branches that are still alive on origin or still recently active.
Two deletion categories:
@rules/git/general.mdcmain, master, develop, development, production, staging, or any branch matching release/* or hotfix/*git gc / git reflog expiregit cherry), so squash- and rebase-merged branches are recognized as integratedstale branch that is not integrated into the default branch automatically — keep it and report it unless the user explicitly authorizes force deletion (its commits never reached origin and are unrecoverable)Update remote-tracking refs and prune deleted ones so the gone markers and origin counterparts are accurate:
git fetch --prune originIf the repository has no origin remote, stop and report that the skill needs an origin remote to decide which branches are alive.
git rev-parse --abbrev-ref HEADmain, master, develop, development, production, staging, plus any branch matching release/* or hotfix/*git symbolic-ref --quiet --short refs/remotes/origin/HEAD 2>/dev/null | sed 's@^origin/@@' \
|| git remote show origin | sed -n 's/.*HEAD branch: //p'Exclude the current branch and every protected branch from both candidate groups below.
List local branches whose upstream was deleted on origin:
git for-each-ref --format='%(refname:short) %(upstream:track)' refs/headsA branch is a gone candidate when its %(upstream:track) value is exactly [gone].
List local branches with their last commit time and upstream:
git for-each-ref --format='%(refname:short)|%(committerdate:unix)|%(upstream)' refs/headsCompute the six-month cutoff timestamp:
date -v-6m +%s 2>/dev/null || date -d '6 months ago' +%s # BSD/macOS first, GNU fallbackA branch is a stale candidate when all of the following hold:
%(upstream) field is empty (or does not start with refs/remotes/origin/), and git ls-remote --heads origin <branch> returns no rows (it genuinely does not exist on origin), and%(committerdate:unix) is older than the cutoff timestamp from above.A branch already captured in group A is not re-listed in group B.
Classify each candidate by whether its work is already integrated into the default branch. Use content-based detection, not ref ancestry — git branch --merged / git branch -d only recognize fast-forward / merge-commit history and would report a squash-merged or rebase-merged branch as unmerged even though its changes already landed (the common case for a gone branch whose PR was squashed or rebased).
Detect integration by patch identity. Plain git cherry compares individual commits, which catches rebase / cherry-pick but not squash merges (a squash collapses many commits into one with a different patch id). To cover squash as well, synthesize a single commit holding the branch's net diff on top of the merge base and ask whether that patch already exists on the default branch:
default="origin/<default-branch>" # the freshly-fetched remote ref, never the possibly-stale local branch
base=$(git merge-base "$default" "<branch>")
probe=$(git commit-tree "$(git rev-parse '<branch>^{tree}')" -p "$base" -m probe)
git cherry "$default" "$probe" # one line: '- <sha>' ⇒ integrated, '+ <sha>' ⇒ not integrated-: the branch's net change is already present on the default branch (via fast-forward, merge, squash, or rebase) → safe to remove.+: the branch carries changes absent from the default branch → it may hold unpushed local-only work.git branch -d still refuses squash/rebase-integrated branches (it uses ref ancestry), so deletion of an integrated branch uses git branch -D. This is safe precisely because step 5 already proved the work is on the default branch.
Print one row per candidate with: branch name, category (gone / stale), last commit date, integration status (integrated / not integrated), and the planned action. Group rows by category. Do not delete anything before this preview is shown.
git branch -D <branch> command the user can run manually.git branch -D <branch> for every branch cleared for deletion in step 6 — -D is required because git branch -d rejects squash/rebase-integrated branches even after step 5 proved their work is on the default branch.gone branch; a stale branch only on explicit interactive authorization).Confirm the deletions with git branch -vv and produce the report described below.
integrated / not integrated), and planned action.gone, stale), each with its integration statusprotected, current, stale + not integrated — needs force, still on origin, active within six months)Keep the report concise and in English.
git fetch --prune origingit cherry) against the default branchgone branch; stale branches only when integrated, or not-integrated on explicit authorization)~30 seconds. Free. No account. Every finding cites a rule and a line of evidence.