repo-fleet-hygiene is the machine-wide coordination layer for repository hygiene. Its job is to
discover canonical repositories across the machine, collect fleet-scale Git/GitHub evidence, roll
that evidence up, and hand an action plan to the per-repository owners. It does not replace those
owners or reimplement their cleanup decisions.
The currently shipped audit reports:
- local branches whose matching GitHub pull request is merged;
- remote-tracking heads that still exist on origin after a GitHub merge, because
delete_branch_on_mergeis not enabled or was blocked. Enabling that setting is complementary to this visibility rather than a substitute for it, and this plugin never changes repository settings; - merged-PR, missing, prunable, or administratively mismatched worktree registrations;
- linked worktrees that do not conform to the configured worktree root (or placement when unset); and
- GitHub repositories whose configured remote resolves to a different owner or name.
The plugin is deliberately read-only by default. /repo-fleet-hygiene:audit never fetches,
prunes, repairs, deletes, checks out, or rewrites anything. Every finding names its evidence,
confidence, disposition, and exact target. Fleet-wide mutation is a separate explicit act:
/repo-fleet-hygiene:apply --plan-file <path> [--apply] [--yes] consumes the audit's action-plan
JSON behind one confirmation gate (see Fleet cleanup plan). Per-repository
owners remain available for interactive work:
/repo-hygiene:clean gitfor a local-branch audit and its own confirmation gate;/source-control:worktree cleanup --dry-runfor worktree cleanup planning; andgit worktree repaironly as a manually reviewed option for an administrative mismatch.
The epic's fleet architecture is intentionally split from the current implementation status:
| Capability | Owner | Availability in this release |
|---|---|---|
Bounded repository discovery (bare path, drive root, --root, --repo, config rungs) and canonical-checkout resolution |
repo-fleet-hygiene |
Shipped |
| Machine-wide discovery with no argument (ghq / configured roots / agent state / bounded sweep ladder) | repo-fleet-hygiene |
Not shipped. Remaining contract work, not an open issue; a no-scope run fails with remedies rather than guessing a root |
| Cross-repository GitHub merge and repository-identity evidence | repo-fleet-hygiene |
Shipped |
| Per-repository worktree status, stranded-work classification, and cleanup | /source-control:worktree |
Delegated; fleet-local reclaimability was retired in #2605 |
| Per-repository branch, cache, build, and deletion triage | /repo-hygiene:clean |
Delegated |
| Per-repository verdicts, target deduplication, and a machine-readable rollup artifact | repo-fleet-hygiene |
Shipped |
| One fleet cleanup-plan handoff consuming that artifact | repo-fleet-hygiene:apply (owns batched merged-local-branch deletion; worktree cleanup in plan order) |
Shipped |
| Conformance against the configured worktree root | repo-fleet-hygiene, reading the convention owned by source-control |
Shipped |
| Complete exact branch merge evidence via GraphQL | repo-fleet-hygiene |
Shipped |
| Merged remote-branch reporting and its separate safety gate | repo-fleet-hygiene |
Tracked by #2607; follow-up PR #2645 |
Rows marked "not yet shipped" are contracts, not commands this version accepts. Their linked child issues become the shipping record when merged; until then, the audit preserves the current detailed report and exact per-repository handoffs.
| Skill | Purpose |
|---|---|
/repo-fleet-hygiene:audit |
Scan one repository, explicit repositories, or repository-tree roots and render a fleet report (read-only; writes an action-plan JSON) |
/repo-fleet-hygiene:apply |
Dry-run or apply a prior action-plan JSON behind one fleet confirmation (--apply + confirm / --yes) |
/repo-fleet-hygiene:setup |
check inspects the optional tracked fleet configuration read-only; apply creates or updates it without touching user settings |
Audit the current project repository explicitly (no fleet config required):
/repo-fleet-hygiene:audit --repo <checkout>
A bare /repo-fleet-hygiene:audit with neither CLI scope nor fleet.root / fleet.repo in a
resolved config hard-fails and names remedies. It does not audit the session project directory.
Audit one or more repository-tree roots:
/repo-fleet-hygiene:audit --root <repo-root>/github.com --root <other-root>/internal
Audit exact repositories without recursive discovery:
/repo-fleet-hygiene:audit --repo <repo-root>/github.com/acme/api --repo <repo-root>/github.com/acme/web
Config resolution is a whole-file precedence ladder: explicit --config <path>, else
.claude/repo-fleet-hygiene.conf in the consumer project, else the user-global
~/.claude/repo-fleet-hygiene.conf (a machine-scoped fleet config that applies from every
project). The audit report header names which config was consumed. Explicit CLI roots/repos are
additive.
/repo-fleet-hygiene:apply consumes the machine-readable action-plan JSON from
#2608 /
#2609; it never scrapes the
human report.
/repo-fleet-hygiene:apply --plan-file <path-from-audit>
/repo-fleet-hygiene:apply --plan-file <path-from-audit> --apply
/repo-fleet-hygiene:apply --plan-file <path-from-audit> --apply --yes
The apply verb:
- validates
schema_version: 1and preserves repository-qualified targets; - owns batched
merged-local-branchdeletion (repo-hygiene branch deletion stays interactive) and cleans merged/prunable/missing worktrees in the plan's declared order; - shows one fleet plan and requires one explicit confirmation (or
--yes) before any mutation; and - re-derives mutable branch/worktree OIDs at execution time. Tip drift skips fail-closed.
Audit remains read-only. A HIGH finding is never itself permission to delete; only :apply --apply after confirmation (or --yes) mutates. Do not add an execute flag to audit-fleet.sh.
Configuration uses Git's own config-file grammar, so no JSON parser or third-party runtime is required.
Relative paths resolve from the configuration file's directory. Repeat root and repo as needed:
[fleet]
root = ../../repos/github.com
repo = ../../special/exact-checkout
maxDepth = 5
# Key by the remote identity observed before GitHub redirect resolution.
# This is the supported escape hatch for manager-owned/non-obvious canonical checkouts.
[canonical "github.com/acme/dotfiles"]
path = ../../../.local/share/chezmoiResolution order is explicit --canonical REMOTE=PATH, config [canonical "REMOTE"], then
git rev-parse --show-toplevel on the discovered checkout. REMOTE is the normalized
github.com/owner/repository identity from the selected fetch remote. A canonical override changes
where local branches and worktrees are read; it does not suppress remote-migration detection.
The selected remote is origin when present, otherwise the sole configured remote. Ambiguous or
non-GitHub remotes are reported as unknown rather than guessed. This is GitHub-only v1; GitHub
Enterprise and other forges are not contacted.
| Confidence | Meaning | Cleanup disposition |
|---|---|---|
HIGH |
Direct authoritative evidence agrees (for example, a GitHub merged PR head OID equals the local branch tip) | Candidate for the named per-repo tool's own dry run/gate |
MEDIUM |
Direct evidence identifies a condition, but another fact prevents safe cleanup (for example, commits after the merged PR head) | Manual review |
LOW |
Local or indirect evidence only | Informational; never a cleanup candidate |
UNKNOWN |
A prerequisite, permission, identity, or API result is unavailable/ambiguous | Investigate; never infer absence or safety |
Absolute local paths appear only in local report output. The only network calls are authenticated,
read-only gh queries to github.com; no report content, file content, or git object is uploaded.
When gh is absent or unauthenticated, the Git/worktree portion still runs and all GitHub-backed
claims become UNKNOWN. Each gh invocation has a 30-second deadline followed by a five-second
TERM-to-KILL grace; a timeout degrades only the affected GitHub evidence instead of stalling the
fleet. GNU timeout/gtimeout is used when its kill-after capability is available, with a Bash
watchdog fallback on other supported platforms.
Every Git probe disables lazy fetching and optional locks, so a read cannot contact a promisor remote
or refresh repository metadata as a side effect. Git and gh execution is fail-closed: the collector
accepts only its documented command, option, operand, and environment shapes. A failed worktree or
branch inventory becomes UNKNOWN; partial output is discarded and the repository is not counted as
successfully audited.
"Can I delete this repository safely?" is deletion triage, an inventory of dirty files, stashes,
and unpushed branches, and belongs to /repo-hygiene:clean (its scan/stash/git tiers), which owns
per-repository disposability analysis. This audit is a read-only cross-repository evidence REPORT;
it names candidates and hands off. Linked unlocked worktrees are named in worktree-status-handoff
for /source-control:worktree status stranded-work classification. This audit does not emit a
git status-based reclaimability substitute.
- Git with
git worktree list --porcelain -zandgit rev-parse --path-format=absolutesupport. - Bash (Claude Code's Bash tool; Git Bash is the supported Windows path).
- Optional: authenticated GitHub CLI (
gh) for bounded merged-PR and moved/renamed-repository evidence. GNUtimeout(GNU/Linux and Git Bash) orgtimeout(GNU coreutils on macOS) is preferred; the collector provides its own finite Bash watchdog when neither compatible command is available.
The plugin-acceptance review is recorded in
reference/security-review.md. The audit script uses no
eval, never sources consumer configuration, never follows filesystem links during discovery, sends
no local content to GitHub, and exposes only an explicit allowlist of read-only Git/GitHub command
shapes.
The current official documentation and the decisions each source supports are recorded in
reference/official-sources.md.
MIT (SPDX-License-Identifier: MIT). See the repository root LICENSE.