agentleFS
JeanKadangJeanKadang/DOC-GitHub-Practice-Skills/skills/github-hygiene/SKILL.md

github-hygiene

Skill1 starsChanged 45 days agoMITView on GitHub

Use when opening or updating a pull request in a repository you maintain, merging PRs, closing issues, reconciling acceptance criteria, decomposing large work into sub-issues, auditing an issue after a merge, or cleaning up branches at the end of a session — before running gh pr create, gh pr merge, gh issue close, or any merge step.

  • Deletes or force-pushes
  • Commits and pushes

The file

Show its rules and text

We split this skill into the rules it gives an agent

21 rules. About 0 are common, 12 are distinctive, and 9 are very specific to this project.

  • ≈0

    Common · estimate

    Many files like this have a rule of this kind.

  • ≈12

    Distinctive · estimate

    This author's own choices. Worth a look.

  • 9

    Very specific

    Tied to their project's names, files or tools. Probably skip.

  • Common
  • Distinctive
  • Very specific
  • could be automatic: a setting could enforce it
  1. Distinctive:

    Every change follows one path, and each link is enforced by the tool rather than by memory:

    line 17
  2. Distinctive:

    Before approving a merge that would close an issue:

    line 38
  3. Distinctive:

    Read every closing issue body and identify its acceptance criteria.

    line 40
  4. Very specific:

    Update satisfied checkboxes with a newline-preserving body file: gh issue edit <N> --body-file <file>.

    line 44
  5. Very specific:

    If any in-scope criterion is unmet or unevaluated, keep it unchecked and use Refs #N in the PR.

    line 47
  6. Very specific:

    Only when every in-scope criterion passes, change Refs #N to Closes #N and proceed with the ordinary merge gate.

    line 49
  7. Distinctive:

    Do steps 2 to 5 when you open the PR, not after the merge.

    line 52
  8. Distinctive:

    If a criterion is no longer required, record the scope decision and rationale on the issue before merge.

    line 61
  9. Very specific:

    Prefer gh issue develop <N> --name <branch> --base main --checkout to start work: it creates the branch and links it to the issue.

    line 97
  10. Very specific:

    Commit style: conventional (fix:, feat:, ci:, test:, release:), subject ≤ 50 chars, body says why.

    line 98
  11. Very specific:

    Wait for CI green on every matrix leg (e.g.

    line 99
  12. Very specific:

    A closing keyword needs acceptance approval too: Do not merge a PR carrying Closes #N until the closure-gate procedure above passes for …

    line 101
  13. Distinctive:

    Never re-run a red job hoping it turns green.

    line 113
  14. Distinctive:

    Solo repo (default): no Projects boards — milestones + labels are the whole tracking system.

    line 126
  15. Distinctive:

    Use native GitHub sub-issues whenever a single issue's work will span multiple PRs or sessions — not only when contributors need to pick up …

    line 135
  16. Very specific:

    Keep a checklist in the parent issue's body alongside the native links — - [x] #84 -- batch name (16 files) -- done, PR #90 — since the …

    line 167
  17. Distinctive:

    Sequence it: Do line-ending and ignore-rule fixes first so renames are not noisy.

    line 204
  18. Distinctive:

    Make the restructure behaviour-preserving: Use git mv so history follows, keep the public surface identical, and keep tests green before …

    line 207
  19. Distinctive:

    Update README and CI paths in the same pull request.

    line 209
  20. Very specific:

    Delete merged local branches: git branch --merged main | grep -v main | xargs -r git branch -d.

    line 219
  21. Distinctive:

    Run the closed-with-unchecked-boxes audit query (above, under "Acceptance criteria are closure gates") against any issue closed this …

    line 221

≈ “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.

Keep what fits and drop the rest. Your version, ready for your agents.
Files
SKILL.md

GitHub Hygiene

Conventions for PR flow, closure, and cleanup. Follow this instead of re-deriving from git history. Issue filing/triage is covered by the separate github-issue-first skill — file the issue first, then start work here. Cutting a release, tagging, branch protection, and milestones are github-releases — merge here, then ship there. Reviewing a PR before it reaches the merge decision is github-pr-review; multi-maintainer board setup is github-projects; a release that contains a security fix goes through github-security-response first.

This skill's PR/merge ceremony assumes a repo that warrants it. For a clearly low-stakes repo (no CI, no branch protection, no code that gets built/deployed/tested), see github-issue-first's "Scaling ceremony to repo risk" section before applying the full flow below by default.

The traceability chain

Every change follows one path, and each link is enforced by the tool rather than by memory:

issue (#N, priority + category labels, milestone)
  → gh issue develop <N>         # branch created AND linked to the issue
  → PR with "Refs #N"            # links work without promising completion
  → acceptance criteria verified # each criterion has concrete evidence
  → change "Refs" to "Closes"    # only now may merge close the issue
  → milestone                    # groups the release
  → auto-generated release notes # built from the merged PRs

Skipping a link doesn't fail loudly — it just quietly returns traceability to human memory. gh issue develop is the one most often skipped and the one that buys the most.

Acceptance criteria are closure gates

Acceptance criteria belong to the issue's implementation work. A completed issue means every in-scope criterion was evaluated, supported by concrete evidence, and checked before closure. A green PR, merged code, elapsed time, sunk effort, or a release deadline does not substitute for that evaluation.

Before approving a merge that would close an issue:

  1. Read every closing issue body and identify its acceptance criteria.
  2. Map each criterion to evidence in the diff, tests, CI, documentation, or a reproducible verification result.
  3. Record a concise completion comment linking that evidence.
  4. Update satisfied checkboxes with a newline-preserving body file: gh issue edit <N> --body-file <file>. Do not round-trip multiline Markdown through a PowerShell string array; it can flatten the issue body.
  5. If any in-scope criterion is unmet or unevaluated, keep it unchecked and use Refs #N in the PR. The PR may merge, but do not assume the issue stays open.
  6. Only when every in-scope criterion passes, change Refs #N to Closes #N and proceed with the ordinary merge gate.

Do steps 2 to 5 when you open the PR, not after the merge. Tick a criterion at that point when you have seen its evidence hold: a diff plus a test you ran, or a passing CI run on the PR's head. Do not tick on the strength of the code alone, and do not wait for the merge for a criterion that already has evidence. For each criterion left unchecked, say so in the PR and offer the maintainer a linked follow-up issue or a recorded scope decision; file the issue or record the decision only when the maintainer agrees. The criterion stays unchecked until one of those happens.

If a criterion is no longer required, record the scope decision and rationale on the issue before merge. Mark it explicitly as removed or superseded; never check it as though it was delivered. Deferred work gets a linked follow-up issue and the original issue remains open unless its recorded scope is formally changed.

Refs #N avoids a PR-body closing keyword; it does not guarantee the issue stays open when GitHub has a connected development branch. After every merge, immediately audit the linked issue state and body. If it is closed while any in-scope acceptance criterion is unchecked, unmet, or unevaluated, reopen it immediately and record the reason. For work that spans the PR merge, either use this audit-and-reopen flow or track the PR-scoped work in a child issue and leave the release-spanning parent unconnected. Every PR-scoped criterion still needs evidence before merge.

Closing as duplicate, invalid, or not planned is different from completed: use the appropriate state reason and a human-readable explanation; do not check criteria that were not delivered.

Audit for completed closures with unchecked task boxes:

gh issue list --state closed --limit 1000 --json number,title,body,stateReason \
  --jq '.[] | select(.stateReason=="COMPLETED") | select(.body | test("(?m)^\\s*- \\[ \\]")) | "#\(.number)\t\(.title)"'

PowerShell:

gh issue list --state closed --limit 1000 --json number,title,body,stateReason `
  --jq '.[] | select(.stateReason=="COMPLETED") | select(.body | test("(?m)^\\s*- \\[ \\]")) | "#\(.number)\t\(.title)"'

PR flow

  • One branch per issue: fix/…, feat/…, ci/…, test/…, docs/…, release/x.y.z. Branch from a fresh git pulled main — never commit on main.
  • main throughout this skill means the repo's default branch. Look it up with gh repo view --json defaultBranchRef -q .defaultBranchRef.name and substitute it where it differs.
  • Prefer gh issue develop <N> --name <branch> --base main --checkout to start work: it creates the branch and links it to the issue. Start the PR body with Refs #N; replace it with Closes #N only after the acceptance gate passes. When falling back to git checkout -b, add the same Refs #N link manually.
  • Commit style: conventional (fix:, feat:, ci:, test:, release:), subject ≤ 50 chars, body says why. PR body states what changed and how it was verified.
  • Wait for CI green on every matrix leg (e.g. windows + ubuntu) before merge — gh pr checks <N> --watch. Never merge on a red or pending check, and never bypass required checks with an admin merge.
  • Merging needs the maintainer's explicit approval — ask once per batch ("merge these N when green?"). The maintainer sometimes merges from the GitHub UI mid-session: before acting on a PR, git pull and re-check gh pr view <N> state rather than assuming.
  • A closing keyword needs acceptance approval too. Do not merge a PR carrying Closes #N until the closure-gate procedure above passes for issue #N. If it has not passed, stop before merging, say which criterion has no evidence, and offer the two ways forward: record the evidence, or change the PR to Refs #N and merge. "Merge it" or "merge when green" authorizes the merge, not an edit to the PR text, so do not rewrite Closes to Refs yourself and merge; let the maintainer choose.
  • Auto-merge is the maintainer's switch, not the agent's. GitHub's auto-merge merges a pull request the moment its required checks pass, so enabling it is the merge approval. Turn it on only when the maintainer has said to, only on a pull request whose acceptance criteria already have recorded evidence, and never on one carrying Closes #N unless every in-scope criterion is met: an auto-merged Closes closes the issue with no chance to run the closure gate first. Otherwise leave it off, merge by hand after approval, and audit the issue afterwards. Check whether the repo allows it with gh api repos/{owner}/{repo} --jq .allow_auto_merge; enabling it on a pull request is gh pr merge <N> --auto with the repo's merge flag.
  • Merge with the repo's configured method. Check gh repo view --json mergeCommitAllowed,squashMergeAllowed,rebaseMergeAllowed, use the matching flag (gh pr merge <N> --merge, --squash, or --rebase), and when several are allowed follow the repo's existing history. If gh repo view --json deleteBranchOnMerge reports false, delete the merged remote branch yourself.

When CI goes red

Never re-run a red job hoping it turns green. Read the failure first:

gh run list --branch <branch> --limit 5
gh run view <run-id> --log-failed          # only the failing steps
  • Genuine failure (test, lint, build): fix it on the same branch with its own commit; the fix rides the existing PR, no new issue needed — it is the same unit of work.
  • Flake (network blip, runner timeout, race): gh run rerun <run-id> --failed. If the same job flakes twice, that is a real defect in the test suite — file it (github-issue-first) rather than re-running a third time.
  • Infrastructure/config break (missing secret, expired token, action removed): file it as its own issue; it will hit every future PR, not just this one.

Solo vs multi-contributor tracking

  • Solo repo (default): no Projects boards — milestones + labels are the whole tracking system; a board is unmaintained overhead.
  • When the repo gains (or expects) additional contributors, upgrade the scaffolding — board setup, fields, automation and the rest of the multi-maintainer checklist live in the github-projects skill; use it rather than improvising a board here. The parts that belong to this skill either way:
    • A ruleset on main: require the CI status checks and at least one PR review; contributors never push to main. See github-releases.
    • Native blocked-by/blocks relations plus Depends on: #N body lines, so pick-up order is visible.
    • CODEOWNERS for review routing; CONTRIBUTING.md pointing at the conventions in this skill.
    • Assign every issue at triage — unassigned means unowned.

Sub-issues for any large-scope issue, solo repo included

Use native GitHub sub-issues whenever a single issue's work will span multiple PRs or sessions — not only when contributors need to pick up children independently. In a solo repo, the reason isn't parallelization, it's resumability and blast-radius control: if a session ends mid-work, the next one reads the parent issue's sub-issue list and knows exactly which units are done, in-flight, or untouched, instead of re-deriving state from chat history or a half-finished diff. If a bad batch ships, it's isolated to one sub-issue and one PR, not tangled into a giant one-shot change.

Trigger: a mechanical or repetitive task decomposes naturally into batches (one per chapter, module, service, file group, etc.) and doing it all in one PR would be unreviewable or too risky to revert as a unit.

Mechanics:

# 1. File one issue per batch (same title/label/assignee conventions as
#    github-issue-first), then link each as a native sub-issue of the parent:
id=$(gh api repos/{owner}/{repo}/issues/<child-number> --jq .id)
gh api -X POST repos/{owner}/{repo}/issues/<parent-number>/sub_issues -F sub_issue_id="$id"

# 2. Verify the link:
gh api repos/{owner}/{repo}/issues/<parent-number>/sub_issues --jq '.[].number'

Gotcha: the endpoint wants the child's internal id (a large opaque number), not its number (the small one everyone reads/types) — fetch it first. And it must be sent as a typed field with -F (capital), not -f (lowercase, which sends it as a string and gets rejected with Invalid property /sub_issue_id: "..." is not of type integer).

Keep a checklist in the parent issue's body alongside the native links — - [x] #84 -- batch name (16 files) -- done, PR #90 — since the native sub-issue UI shows open/closed state but not which PR closed it; the checklist is what a human skimming the issue actually reads. Update it each time a batch merges. Edit it through a newline-preserving body file, not an inline --body "..." string (same hazard as the closure-evidence step above):

gh issue view <parent> --json body --jq .body > parent-body.md
# edit parent-body.md: tick the finished child, add the PR number
gh issue edit <parent> --body-file parent-body.md

PowerShell:

gh issue view <parent> --json body --jq .body | Set-Content -Encoding utf8 parent-body.md
# edit parent-body.md: tick the finished child, add the PR number
gh issue edit <parent> --body-file parent-body.md

Close each child issue individually as its PR merges (Closes #<child> in the PR body does this automatically); leave the parent open until every child is closed.

Structure drift: suggest a restructure early

While doing ordinary work, notice when the layout is about to stop fitting the repository: one source file holding many unrelated units, a root cluttered with runner scripts, tests mixed with the distributable, or planned features that will each add more to the same place. Surface it before the next feature lands, not after — a restructure is cheapest while the repository is small and has few open pull requests and consumers' paths to keep working.

  • File it first (github-issue-first) as a decision-needed issue that records the proposed layout and states what must stay unchanged (exports, public paths, behaviour). Do not fold it into a feature pull request.
  • Sequence it. Do line-ending and ignore-rule fixes first so renames are not noisy; then the restructure; then the feature work that touches the same paths. Note the order on the affected issues.
  • Make the restructure behaviour-preserving. Use git mv so history follows, keep the public surface identical, and keep tests green before and after. Update README and CI paths in the same pull request.
  • Check ignore rules with git check-ignore -v <path> for every new path; blanket rules such as *.yml or *.json can silently hide new files.
  • The recommended starting layouts and the checks live in github-repo-bootstrap ("Starting layout") and github-repo-review ("The structure baseline"). Do not recommend folders a small repository does not need.

Cleanup checklist (end of session / after release)

  • git checkout main && git pull && git fetch --prune — local branch listings lie until pruned; verify remote state with gh api repos/{owner}/{repo}/branches before reporting leftover branches.
  • Delete merged local branches: git branch --merged main | grep -v main | xargs -r git branch -d.
  • Working tree clean, everything pushed, no open PRs left unmentioned.
  • Run the closed-with-unchecked-boxes audit query (above, under "Acceptance criteria are closure gates") against any issue closed this session — the PR template's checkbox catches it at merge time for one PR, but this catches anything closed a different way (bulk triage, manual gh issue close) that skipped the reminder.

Common mistakes

MistakeFix
Trusting git branch -r for remote stategit fetch --prune first, or query the API
Merging own PR without askingAsk once per batch; check whether the maintainer already merged it
Treating merged PR or green CI as proof every criterion passedEvaluate each criterion, record evidence, and keep the issue open until all in-scope criteria pass
Checking a removed or deferred criterion as deliveredRecord the scope decision; link follow-up work; never falsify completion
Letting Closes #N auto-close an unevaluated issueUse Refs #N until the acceptance gate passes; reopen immediately if it closes early
Committing on main before branchingBranch first; if it happens: branch from the commit, then git reset --hard origin/main on main
gh api -f sub_issue_id=<id> rejected with "not of type integer"Use -F (capital), not -f — sub_issue_id must be sent as a typed integer, not a string
Linking a sub-issue by its number instead of its idThe sub-issues endpoint wants the internal id — gh api repos/{owner}/{repo}/issues/<number> --jq .id first
Adding another feature to an overgrown single file or flat rootRaise a restructure issue first and sequence it before the feature work; see "Structure drift"
Re-running a red CI job without reading the loggh run view <id> --log-failed first; rerun only a diagnosed flake

Download now (ZIP)

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
What did you use it for? e.g. Reviewing pull requests in a Rails app

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.