A ruleset is a named list of rules with a target (branches, tags, or pushes), conditions selecting which refs it covers, an enforcement status, and a list of who may bypass it. Sam's first ruleset protects the default branch from deletion and force-pushes and requires a pull request, with every review thread resolved:
{
"name": "Protect main", "target": "branch", "enforcement": "active",
"conditions": { "ref_name": { "include": ["~DEFAULT_BRANCH"], "exclude": [] } },
"rules": [
{ "type": "deletion" }, { "type": "non_fast_forward" },
{ "type": "pull_request", "parameters": {
"required_approving_review_count": 0, "dismiss_stale_reviews_on_push": true,
"require_code_owner_review": false, "require_last_push_approval": false,
"required_review_thread_resolution": true } }
]
}gh api repos/{owner}/{repo}/rulesets --input protect-main.json \
--jq '"ruleset \(.id) \(.name): \(.enforcement), \([.rules[].type] | join(", "))"'
git push origin mainruleset 23992928 Protect main: active, deletion, non_fast_forward, pull_request remote: error: GH013: Repository rule violations found for refs/heads/main. remote: Review all repository rules at https://github.com/binarybehemoth/booknest/rules?ref=ref s%2Fheads%2Fmain remote: remote: - Changes must be made through a pull request. ... ! [remote rejected] main -> main (push declined due to repository rule violations) ...
The push fails with GH013 instead of GH006, and the message links to the rules page, which anyone with read access can open. Sam moves the commit to a branch for a pull request (git switch -c add-codeowners, then git branch -f main origin/main). Rulesets improve on classic rules in four ways: several can apply to one branch, with the strictest version of each rule winning; one can be switched to Disabled without deleting it; its bypass list names roles, teams or apps instead of a blanket admin exemption; and the same model covers tags, pushes and whole organizations. A repository holds up to 75 rulesets; the API needs a token with Administration write permission.