git-repo-janitor
Made by JeffSafely triage committed-but-junky files in a git repo (ephemeral SQLite DBs, stray JSON artifacts, intermediate skill outputs, plan documents at the project root): move keepers to a sensible home, delete the rest with git rm plus .gitignore updates, never disturbing source. Use when "clean up my repo", "the repo junk cleaner", "tidy up the project root", "random .db / .md files committed", or when an agent swarm leaves ephemeral artifacts in the working tree.
Works With
Quality and Utility come from canonical skill metadata. Community ratings appear separately as stars when subscriber reviews exist.
Subscribe to download
Public previews are available, but downloads, CLI sync, and premium content require an active subscription.
Sign In to Subscribe- Full skill content with deterministic versioning
- CLI sync + local search index
- Access to Jeffrey’s premium library
Save to your account
Saved skills live in your cloud list. Run jsm sync on each machine to pull them locally.
What's New with this Skill
5Updates, enhancements, and release notes for this skill.
Updated: git-repo-janitor, apply-delete.sh removes only the files you approved
apply-delete.sh handed paths to git rm as patterns, so deleting notes[1].md also deleted notes1.md, and a directory or modified file in the batch aborted it partway. Paths are now literal and the whole batch is checked before anything is removed. The decision table also shows file paths again, and ignore patterns match the files being removed.
- Glob characters in file names no longer delete other files
- Directories, modified files and phantom deletions stop the batch before anything is removed
- The approval table shows the path of each file to be deleted
- Ignore patterns match the deleted files, so they stay out of the repo
Each script was run on throwaway repositories, fixed, and re-run.
- apply-delete.sh. Paths are matched literally (
:(literal)). The batch is checked first and refused, with nothing removed, if it contains a directory, a file with uncommitted changes, or a tracked file already missing from disk (a phantom deletion, which needsgit restoreorPHANTOM_DELETE_CONFIRMED=1). Names with spaces and non-ASCII characters work. - merge-triage.sh. The decision table shows each candidate's path and its ignore pattern; before, the columns were shifted and no path appeared.
Enhanced: git-repo-janitor, Phase 0.5 history mining works again
The skill's cass-mine.sh contained a Python syntax error, so it exited 1 on every run and left a findings file with only a heading. It now runs, and it reports UNKNOWN instead of an empty section when cass times out.
- cass-mine.sh failed on every run because of a Python syntax error. It now produces its findings file.
- A timed-out or unreadable cass answer prints an UNKNOWN line in its section instead of an empty list.
- Searches run under cass's own time budget and an outer timeout where one is available.
- Clean answers list each prior session as path, line and agent, and empty answers say no matches.
Phase 0.5 checks prior agent sessions for earlier cleanups of the same repository. The inline Python that formatted each hit used f"{hit[\"source_path\"]}", which is a syntax error on every Python version, so under set -e the script stopped with exit 1 after writing the heading.
The rewrite keeps the same output file and sections. Each search runs with cass's own --timeout, plus an outer timeout where a timeout binary exists. A response that is not a cass search result, or whose budget.timed_out is true, prints UNKNOWN: no complete answer from cass in its section with a warning on s
git-repo-janitor now knows when it is finished
Axioms 25 and 26 told the janitor to freeze its review surface and stop chaining addenda, but neither answered the question that actually ends a run. Axiom 27 makes done a four-condition checklist with measured values, and the contract they all depend on now has a template and a status check.
- Axiom 27: done means every inventory item dispositioned, broken references at zero, every contracted gate green on the final tree in one run, and a post-apply re-scan finding nothing new
- Second material miss now escalates the discovery method instead of triggering another re-baseline
- completeness_contract.md gets a real template, including a stopping-rule table and a miss ledger
- phase-status.sh flags a missing contract or blank disposition cells, and names writing the contract as the next step before the first mutation
- fresh-eyes is now explicitly verification, not discovery; a new material class hands back for re-baseline rather than being folded in
- Five new anti-patterns (A36-A40) and a seventh Top Mistake covering the stop-when-clean trap
The subscriber post-mortem behind version 6 diagnosed a cleanup run that reached ten phases without converging. Version 6 turned that into doctrine. This release adds the template, checks and checklist items that apply it.
The missing piece was a stopping rule. "The reviewers came back clean" is the weakest possible evidence: if the same query built an incomplete inventory, it will keep returning zero for exactly the class it never looked for. Axiom 27 replaces that with four objective conditions, each reported as a measured value rather than an impression.
git-repo-janitor gains a completeness contract and a rule for when it may call a pass final
A subscriber post-mortem showed cleanup runs where each 'final' pass kept widening to a surface nobody had declared. Two new kernel axioms make the review surface closed-world before mutation and reserve finality language for a global exit contract.
- Axiom 25: freeze every review surface with an explicit disposition, and union independent discovery methods, before any mutation
- Axiom 26: 'final', 'comprehensive' and 'merge-ready' are licensed only by the agreed exit contract, not by a locally-frozen patch
- A material post-approval miss now forces one replacement plan rather than an endless chain of small addenda
- Findings are bucketed so only correctness, broken-reference and agreed-requirement items gate merge; optional polish cannot silently become a release gate
- User time is treated as a first-class budget: approval count, wall-clock and repeated full-suite runs are costs, not free
The report described a cleanup that repeatedly failed to establish one complete definition of the review surface before editing began. Each pass inspected a narrower surface, corrected what it found, called itself final, and was then followed by another pass covering documentation links, then source comments, then diagnostics, then configuration prose. Every individual review was defensible in its own scope; the run as a whole became impossible to plan around.
New: git-repo-janitor, triage 100+ committed-but-junky files into move/delete/gitignore plans, never lose a byte
Agent swarms leave debris at the project root: SQLite-WAL siblings, nohup.out, progress_bd-*.md reports, multi-LLM PLAN_*.md clusters, ELF binaries, *.profraw / *.bak / findings.jsonl. The skill classifies each file into one of seven verdicts, copies every candidate byte-for-byte into a recovery bundle outside the repo before git rm runs, then applies focused commits with the project's full test suite running per commit.
- Seven verdicts, not just delete: every candidate gets reference-grepped against the entire repo before classification; one inbound hit flips a delete verdict to surface-to-user regardless of how junky the filename looks (the verify-script failure mode comes from this).
- Phase 3 recovery bundle is a hard gate: working-tree copies, index.tsv, and meta files at <repo>-repo-archive-<DATE>/, byte-equality verified for every entry against the live blob before any git rm runs.
- Per-commit gates run after every Phase 6/7/8 commit, not at the end. A broken import or markdown link from a move surfaces inside that one commit; compounding errors across a 50-file move never build up.
- Phase 2.5 secret-leak scan is non-negotiable. A real-secret hit halts the routine flow and switches to harden-secret-leak mode: mirror backup, user rotates the key, git filter-repo --invert-paths, force-with-lease push, .gitignore hardening, a smoke-tested .githooks/pre-commit.
- Axiom 16 catches the shallow-clone footgun: git filter-repo only rewrites commits the local repo can see. The skill verifies git rev-list --count <branch> == origin/<branch> and syncs via git update-ref if counts diverge before filter-repo runs.
- Never rm, never find -delete, never git ls-files | xargs rm: only git rm (history-recoverable) and git rm --cached (untrack without filesystem delete).
- Nine named modes: full, triage-only, move-only, delete-only, gitignore-only, harden-secret-leak, recover-from-bad-cleanup, add-archetype-profile, maintenance-review. Each declares its phases-run, stop condition, and forbidden actions.
- Phantom-deletion detection (Axiom 24): a tracked-but-deleted path with no matching intent in recent commits gets a restore-do-not-commit verdict and proposes restoring from HEAD instead of committing an accidental delete.
- Per-archetype protected_globs: Cargo.toml, package.json, LICENSE, .env.example, root-level README.md and CHANGELOG.md, and archetype-specific fixtures always get the protected verdict regardless of smell tags. The user can add globs but not remove them.
- Skip-list-first multi-repo orchestration (Axiom 23): on a fleet of N repos, decide which whole repos are excluded (submodules-only, third-party fork, mid-rebase) before per-file triage runs on the survivors.
The motivating cleanup took frankensqlite's root from 109 to 45 tracked files in 8 commits. Mistaking a tracked test fixture for junk would have broken the regression suite, so the skill makes that mistake recoverable by default: Phase 3 builds a byte-identical copy of every candidate at <repo>-repo-archive-<DATE>/ and verifies SHA-256 against the live blob before any destructive operation. Phase 2 builds a reference graph by grepping the entire repo for each candidate's basename + relative path; one inbound hit flips delete to surface-to-user. Phase 6 / 7 / 8 commits run the project's a