| name | repo-maintenance |
| description | Audit and evolve repository structure safely across the full maintenance lifecycle: repository topology and scope, application and build-system profiles, module and folder boundaries, canonical source-of-truth and monorepo decisions, sibling consolidation, generated/build artifact retention, worktree and branch hygiene, local-versus-remote state, verified closeout into local main, and preparing a repository for open-source or external distribution (personal-content and secret scrub, internal-artifact de-tracking, .git bloat and history-leak review, distribution signing/notarization). Use when asked how any kind of repo should be structured or maintained, what application/build profile it has, why it has duplicate source or many build directories, whether repositories or modules should split or merge, to clean generated artifacts or a polluted data store (a log, telemetry, cache, or dataset corrupted by test/non-production writes), to review open commits/worktrees/branches/stashes, to merge and close completed local work, or to get a repo ready to open-source / ship to external users. Never push, delete unique source, remove recovery refs, or rewrite history unless explicitly authorized. |
| user-invocable | true |
Repository Maintenance
Optimize the repository for the product's real boundaries, then keep it recoverable as worktrees, builds, generated state, and branches evolve. Treat closeout as one phase of maintenance, not the whole workflow.
Resolve REPO_MAINTENANCE_ROOT to the directory containing this SKILL.md before running bundled scripts. Under Claude Code this is normally ${CLAUDE_PLUGIN_ROOT}/skills/repo-maintenance; under Codex or another host, derive it from the loaded skill path.
Establish the product and repository contract
- Read applicable
AGENTS.md, architecture, build, coordination, and document-lifecycle guidance.
- Check live coordination before editing shared files or refs. Treat notes as provenance, not code proof.
- Identify the product, shipped artifacts, consumers, release boundary, owners, and canonical build/test commands.
- Resolve the canonical Git root, local
main, upstream, linked worktrees, and nested or sibling repositories.
- Run the read-only baseline:
python3 "$REPO_MAINTENANCE_ROOT/scripts/audit_repo_maintenance.py" \
--repo "$PWD" --base main --json
Read references/safety-protocol.md before changing structure, refs, worktrees, stashes, or generated directories.
For repository-boundary, module, or folder-layout work, read references/repository-taxonomy.md. For application-specific, build-system, cache, or generated-layout work, read references/stack-profiles.md. When preparing a repository for open-source publication or external/paid distribution — personal-content and secret scrub, de-tracking internal artifacts, .git bloat and history-leak review, and distribution signing — read references/pre-public-hygiene.md. Classify signals before recommending a target structure.
Classify the repository without forcing one label
- Record observed application, language, build-system, workspace, runtime, ownership, and release signals.
- Classify portfolio strategy, repository scope, composition, release coupling, runtime deployment, internal organization, and physical layout independently.
- Label heuristic results as inferred with confidence. Directory names and manifests are not product-boundary proof.
- Separate current state from target state and name the smallest transition that addresses measured cost.
- Preserve framework conventions unless changing them has a concrete product, ownership, security, release, build, or navigation benefit.
Do not flatten workspace, product monorepo, service polyrepo, and orchestration repo into one topology enum. They describe different dimensions. Do not treat agent configuration such as .claude/ or .codex/ as product architecture.
Decide the source of truth from product boundaries
Prefer one repository when a component:
- ships only with the parent product;
- changes and verifies in the same release gate;
- has no independent consumers, version, or ownership boundary;
- must stay code-identical to a bundled or generated artifact.
Keep a separate repository when it has an independent public contract, release cadence, consumers, operational boundary, or ownership/security boundary. Do not preserve a repository split merely because history started that way.
Compare a sibling source repository to its proposed in-tree prefix:
python3 "$REPO_MAINTENANCE_ROOT/scripts/audit_repo_maintenance.py" \
--repo "$PWD" --base main \
--compare-repo /path/to/source-repo \
--compare-prefix path/inside/current/repo --json
If the sibling head is already an ancestor of main and the in-tree prefix has since diverged, the usual disposition is retire-sibling, not another merge. Treat comparison output as source-tree evidence only; it is never sufficient retirement authorization. Audit sibling branches, worktrees, stashes, operations, and dirty paths separately before retirement. Preserve unique state under recovery refs.
Keep structure navigable without ceremonial refactors
- Give each shipped capability one canonical source and a thin stable public boundary.
- Organize internal files by capability or bounded context; use small, well-named modules behind the stable boundary.
- Keep generated, vendored, cached, and source-owned paths distinguishable.
- Verify that every generated or bundled artifact has one reproducible writer and a parity gate.
- Use revisit/churn and agent cost as structure signals. Do not claim that generic cleanup alone improves correctness.
- Require a concrete product, ownership, dependency, or verification reason for deep-module or repository-boundary changes.
- Split modules only when a boundary enforces a public contract, dependency direction, ownership/security rule, independent test/release, real reuse, or measured build benefit. Merge them back when scaffolding and coordinated edits dominate.
Control build and cache accumulation
Per-worktree or per-agent build roots are valid isolation. Accumulation without retention is repository hygiene debt. Inventory before deleting:
python3 "$REPO_MAINTENANCE_ROOT/scripts/audit_repo_maintenance.py" \
--repo "$PWD" --base main --artifacts --stale-days 7 --json
The recursive inventory finds matching roots below test modules, worktrees, and agent lanes while pruning descendants of an already-counted artifact root and dependency environments such as node_modules and Python virtual environments. It protects canonical top-level build and build-rust roots by default; use --protect-artifact for additional repo-specific roots. Use --no-default-artifact-protection only when the repository explicitly defines different canonical roots.
Classify each artifact root as protected, active, release-artifact, recent-cache, cleanup-candidate, or review-tracked-or-unignored. Treat cleanup-candidate as a stale ignored review candidate; the script does not prove reproducibility. A release-artifact contains a high-confidence distributable such as a DMG, package, archive, installer, mobile build, or an app bundle inside a distribution root and requires an explicit retain/archive/remove decision. Ordinary build products such as an .app inside an isolated build cache remain governed by cache retention. active-missing-artifact means a live process still references an artifact path that no longer exists; stop or reconcile that process before further deletion. Remove only reproducible, ignored, inactive artifacts within the user's authorized scope. Protect the coordinator/final build, active worktree builds, canonical dependency caches, and anything required for current verification.
Add a repository retention policy when isolation creates named build roots: naming convention, protected roots, active-process test, age threshold, cleanup owner, and the command that refreshes build-server metadata after pruning.
Structurally clean a polluted data store
The same discipline governs a polluted append-only data store — a log, telemetry corpus, cache, or generated dataset — not just build artifacts. Removing bad records by matching known-bad content is whack-a-mole: it misses the next unknown pollutant and invites repeated "it's clean now" claims that are each wrong (observed: five marker-based passes on one telemetry log, each declared done, each missing more).
- Derive one structural signal before deleting anything. Separate polluted from legitimate by shape, not content: a provenance field, an impossible/out-of-registry value, or a context field legitimate data never carries (a
tmp* temp-dir path, a test-harness cwd, a missing "written by the real path" stamp). A content denylist is acceptable only for a one-time sweep of known-historical strings, never as the permanent detector.
- Classify every record, then prove completeness by re-scan. Cleanup is done when a full re-scan returns zero suspects — never when the known-bad rows are gone. Eyeballing the tail is how residue survives.
- Move, never delete. Quarantine suspects to a sibling archive (
*.quarantined.*) plus one full pre-clean snapshot, so every removed record is recoverable.
- Fix the writer, not just the data. Re-pollution recurs until the source is closed. Add a provenance invariant — only the production path may write here (e.g. a live-hook flag; test/ad-hoc writers are suppressed) — and an integrity gate that fails loudly at the earliest boundary (pre-commit/CI) so a regression is caught the next commit, not weeks later. Pair it with an analysis-time quarantine so a consumer never silently computes on corrupted data.
- Never report the store "clean" while any record is unclassified — the same rule as unclassified repo state below.
Evolve work safely
- Use an isolated worktree for material changes when shared-checkout collision is possible.
- Map the change to its capability boundary and enumerate cross-repo consumers before changing contracts or paths.
- Run the narrow verifier during implementation and the canonical verifier on the final integration tip.
- Regenerate bundled outputs only from canonical source; verify code or artifact parity afterward.
- Collapse completed work back to one protected local
main; remove temporary worktrees and branches only after ancestry or patch-equivalence proof.
Close completed local work
Give every worktree, branch, stash, dirty path set, sibling source, and artifact root exactly one disposition:
integrate — unique completed work with review and verification.
redundant — ancestor of main or proven patch-equivalent.
retire-sibling — imported source whose in-tree canonical copy has evolved.
cleanup-candidate — reproducible, ignored, inactive generated state past retention.
release-artifact — distributable output requiring an explicit retain, archive, or remove decision.
active-missing-artifact — a live process references a removed artifact root; reconcile the process before cleanup.
preserve-only — incomplete, unrelated, user-owned, or historical material.
blocked — active ownership, failed verification, conflicts, or unclear provenance.
Before mutation, create dated annotated recovery tags for pre-integration main, every branch head, and every stash commit under archive/pre-closeout-YYYY-MM-DD/. Preserve dirty state including untracked files. Prefer fast-forward integration; re-run the canonical verifier on exact final main after the last mutation.
Clean in dependency order: auxiliary worktrees, contained branches, patch-equivalent branches with recovery proof, archived stashes, stale worktree metadata, then authorized generated artifacts. Never use git reset --hard or force-delete unique state as cleanup.
Report distinct truths
Lead with the disposition, then state:
- canonical source and repository-boundary decision;
- final local
main commit and verifier evidence;
- worktrees, branches, stashes, sibling repos, and artifacts integrated, retained, or removed;
- recovery namespace and residual risks;
- local-versus-upstream divergence;
- committed, merged locally, pushed, deployed, and runtime-tested status separately.
Do not report “merged” for work that exists only on another branch. Do not report “clean” while unique sibling, stash, dirty, or generated state remains unclassified.