repo-state-authority
Skill2 starsChanged 12 days agoMITView on GitHub
Decide what a repository's state really is before cleaning, merging, deleting, or reporting it. Use when asked "are these branches stale?", "is anything unmerged?", "clean up and push all", "where did that file go?", "is prod on the right commit?", or when a status file, handoff, or branch name claims a state. Separates Git, runtime, and notes as different authorities, classifies branches by ancestry and patch identity instead of diff size, preserves human-owned work, and deletes only with a ref backup.
- Commits and pushes
In this repository5 other files it gives its agents.
- AGENTS.mdAGENTS.md
- claim-checkSkill
- nvim-plugin-makerSkill
- pre-build-discoverySkill
- production-ops-disciplineSkill
The file
We split this skill into the rules it gives an agent
6 rules. About 0 are common, 4 are distinctive, and 2 are very specific to this project.
≈0
Common · estimate
Many files like this have a rule of this kind.
≈4
Distinctive · estimate
This author's own choices. Worth a look.
2
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Distinctive: line 21
Not for writing new features, or for one obvious command the user named exactly.
- Distinctive: line 39
Inventory before judging: Run in parallel: git status -sb, git branch -vv, git worktree list, git log --oneline --graph -20 --all, git …
- Distinctive: line 58
Run the focused tests for what changed.
- Distinctive: line 60
Only after that readback, delete branches whose history is contained in the pushed branch.
- Very specific: line 66
Delete the remote ref first, in its own call, then the local one with git branch -d.
- Very specific: line 86
One blocked command is not a blocked task: If an authorized exact ref deletion is refused by a shell guard on one porcelain command, an …
≈ “Common” is an estimate: at least 1 in 5 of the 350,495 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
Repo State Authority
Agents read repository state from the easiest signal instead of the right one. They call a branch stale because its name is old, call it lost work because git diff main <branch> is huge, trust a STATUS.md over git log, and conclude a file is gone because git diff is empty. Then they delete, merge, or report on that belief.
This skill fixes the order: decide which source is authoritative for each question, read that source, and only then clean up.
When to Use
- "Are these branches stale?", "do any branches hold unmerged work?", "delete merged branches".
- "Clean and push all repos", "consolidate to one branch per repo".
- "Where did file X go?", "why isn't X committed?".
- "Is production on the right commit?", "did the merge deploy?".
- A status file, handoff note, or session summary claims what the repository contains.
Not for writing new features, or for one obvious command the user named exactly.
Authority Model
Each question has one owning source. Using a different one produces confident wrong answers.
| Question | Authority |
| Stable rules and constraints | Project instructions (AGENTS.md, CONTRIBUTING.md) |
| What source exists, branches, history | Git |
| What is deployed | Runtime readback: container image label, version endpoint, installed package version |
| What outsiders see | The public or logged-out path |
| What the owner intends | The owner's latest explicit words; human-written notes are owner content |
A status file, handoff, or summary is a claim about one of these. Read the owning source before acting on it. Do not add a new status file to fix stale state: it becomes the next stale claim.
Procedure
- Inventory before judging. Run in parallel:
git status -sb,git branch -vv,git worktree list,git log --oneline --graph -20 --all,git remote -v, andgit fetch --dry-run --verbose origin(shows new remote branches without writing refs). Note every dirty, untracked, and stashed item before touching anything. - Classify every branch by ancestry and patch identity, not by size or name.
git rev-list --left-right --count main...<branch>: the right number is commits on the branch thatmainlacks.git cherry main <branch>:+lines are patches not onmain;-lines are already applied under another SHA (squash or cherry-pick).- Right count 0, or every cherry line
-, means merged. This holds even whengit diff main <branch>shows thousands of lines; that diff only measures how farmainmoved on. git cherryreports a revert chain as unique even whenmainalready has the final behavior. For each branch with+lines, decide which it is: equivalent patch already onmain, squash-merged PR, deliberately reverted experiment, or genuinely missing behavior. Only the last is lost work.- A worktree under a temporary or auto-pruned directory will vanish with its uncommitted files. Flag it.
- scripts/classify_branches.sh runs both checks for every local branch except the base itself (local
mainis included when the base isorigin/main, so unpushed commits show up) and prints same as base, merged, equivalent, or unique per branch, plus whether it is checked out in a worktree. It is read-only; pass a backup file path as the second argument to also write the step 7 rollback list. Rungit fetchfirst when remote refs matter. It does not judge revert chains; that stays your call.
- Keep three identities apart. The deployed revision, the source branch it was built from, and the canonical commit after a merge can all differ correctly. A merge commit can be canonical while production rightly stays on its tested parent. Report all three instead of calling the difference drift.
- Know what a push to the main branch triggers. Before pushing, read the
on:triggers in.github/workflows/*.yml(or the CI config) and say whether a push builds, releases, or deploys. Tag-only triggers mean a branch push deploys nothing; a push-to-main deploy means the push is a deployment and needs its own go. - Preserve human-owned work exactly. Dirty files you did not create, notes, and stashes stay as they are. Commit them only when the user asks for consolidation, with their exact content. Never rewrite owner text for a tidier history, and never stash or reset it away to make a merge easier.
- Clean up in this order, one repository at a time.
- Classify each path as needed, stale or generated, or ambiguous before staging. Ambiguous items go back to the user as an exact list.
- Stage explicit paths. Use separate commits when code, config, and docs have different intent.
- Run the focused tests for what changed.
- Push without force,
git fetch, and confirmHEADequalsorigin/<branch>. - Only after that readback, delete branches whose history is contained in the pushed branch.
- Delete branches with a rollback file. Deletion needs the user's go that names it.
- First write every target's full SHA to a backup file outside temp directories:
git for-each-ref --format='%(objectname) %(refname)' <refs>plusgit ls-remote --heads origin <names>. That file is the whole rollback (git branch <b> <sha>,git push origin <sha>:refs/heads/<b>). - Split targets into remote plus local, local-only, and stale tracking refs (present under
refs/remotes/origin/but absent fromls-remote). Only the first group gets a remote delete. - Per branch, confirm: local tip equals remote tip,
git merge-base --is-ancestor <sha> main, not checked out in any worktree, not the default branch, and no open pull request uses it as head. - Delete the remote ref first, in its own call, then the local one with
git branch -d.-drefuses unmerged work; never reach for-Dto get past it. -dchecks against the branch's upstream, orHEADwhen none is set. A branch with no upstream on a checkout whose localmainis stale (a build machine, a second clone) is refused even whenorigin/maincontains it: fetch, confirm withgit branch --merged refs/remotes/origin/main, setgit branch -u origin/main <b>, then-d. A branch whose upstream already contains its tip deletes normally. Do not fast-forward that checkout'smainunasked.- Finish with
git fetch --prune originand read backgit for-each-ref refs/heads refs/remotesandgit ls-remote --heads origin. Release tags keep merged commits reachable; say so.
- First write every target's full SHA to a backup file outside temp directories:
- Answer "where did the file go" from the filesystem and Git separately.
git diffnever shows untracked or ignored files, so an empty diff proves nothing about a missing file. Check:- the filesystem, including ignored files (
rg --files -uu, orls -a); git ls-files --error-unmatch <path>(exit 1 means not in the index: untracked, ignored, or absent alike, so use the other checks to tell them apart);git check-ignore -v -- <path>, which names the exact rule and file;git log --all --full-history -- <path>for historical copies. Report the absolute path and one status: tracked, untracked, ignored, historical-only, or absent.
- the filesystem, including ignored files (
- Treat a deliberate exclusion as a decision. When asked to commit a file that is ignored,
check-ignore -vtells you who decided:.gitignoreis a shared team decision,.git/info/excludeis one clone's private decision (common for local agent notes), and a global excludes file is user-wide noise. An exclusion rule means stop and ask. A file that documents its own exclusion means recommend doing nothing. A file holding credentials is never committed, whatever the request. "No secrets in it" is not enough to commit: local notes, per-person assignment lists, and internal strategy are still visible to everyone on a shared branch. Offer doing nothing, or versioning it privately (a dotfiles or private repository). Editing the exclude rule so the commit works is a second, unrequested policy change.
Pitfalls
- Counting branches is not evidence. Twenty old branches can all be merged; one recent one can hold the only copy of a fix.
- A session summary is not the owner's intent. For behavior-sensitive state, compare against the owner's last explicit instruction before calling a branch a regression or proposing a restore.
- Stale snapshot commits. A branch holding a prepared change for an event that never ran (a maintenance window, a resize, a migration) describes the state at that time. Re-check the live state before re-arming it, and do not merge it blindly.
- State documents: check before you claim, and clean both halves. Before saying a status or handoff file exists, check its exact path in the filesystem and in Git; memory and earlier reports are hints, not evidence. If it is already gone, do not recreate it or stage a deletion. When you remove one, also remove the instructions that point to it, or the next agent recreates it; when both the deletion and the reference cleanup were asked for, do both in one pass instead of asking again. Keep durable history, labeled as historical.
- Do not populate an empty owner file just because a request mentioned it.
- One blocked command is not a blocked task. If an authorized exact ref deletion is refused by a shell guard on one porcelain command, an equally narrow plumbing command (
git update-ref -d refs/heads/<name>) does the same thing; verify the ref afterward. Never use the workaround to widen scope. - Corrupt tracking ref.
fatal: bad object refs/remotes/origin/mainon fetch usually means the tracking ref file holds a null or truncated SHA. Delete only that tracking ref (git update-ref -d refs/remotes/origin/main) and fetch again; local branches are untouched. - "No commits between main and branch" on a pull request. The commit was made on
mainbefore the branch was cut, so both point at the same SHA. Checkgit rev-list --count origin/main..<branch>is at least 1 before opening the request. Prevent it by creating the branch first, then committing. If it already happened: onmain,git reset --soft origin/main, drop the staged change (git restore --staged . && git checkout -- .), switch to the branch, andgit cherry-pick <stray-sha>onto it. If the wrong SHA was already pushed, fixing the branch needs a force push, which needs its own go. In fork or multi-remote setups the request can also fail on repository detection alone: name the repository explicitly in the request command before touching history. - Cleanup commits break consumers. After a sweep that deletes files, search the remaining tree for every deleted path. A retained script that loads a deleted data file, or a report that cites it, leaves a broken path. Either restore the file or retire every consumer in the same change.
Done When
The report states, per repository:
- Canonical branch and its remote-verified SHA.
- Each branch classified (merged, equivalent, reverted, or unique), with the command output that decided it.
- Deployed, source, and canonical identities when deployment matters.
- What changed: exact refs and files; what was deleted, and the rollback file path.
- Dirty or human-owned work left untouched.
- Whether anything was pushed, released, or deployed.
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
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.

