Control who can push to your default branch and what has to happen before a pull request can merge.
Every repository's default branch has one of three protection levels, set from the repository's Settings → Branch protection section:
For organization repositories left at None, the settings page recommends enabling protection — it's the one level where UnityFreak surfaces an explicit nudge.
Required approving reviews sets how many approvals a pull request needs before it can merge — 0 disables review requirements entirely. Reviewers can't approve their own pull requests, so this number always has to be satisfied by someone else.
Dismiss stale approvals, when enabled, means an approval only counts if it was given for the pull request's current head commit — pushing a new commit after someone approves clears that approval, so reviewers are always signing off on what's actually about to merge, not an earlier version of the diff.
Both of these are independent toggles from the protection level above — you can require approvals whether or not you also require pull requests for direct pushes (though requiring approvals only has an effect once pull requests are actually the way changes land).
With Require code owner approval enabled, every CODEOWNERS rule matching a changed file needs an approval from one of its eligible owners before the pull request can merge — on top of any general required-approvals count. The pull request page shows a Code owners panel with one row per rule: the pattern, its line in the file, the changed files it covers, its owners, and whether it is approved, waiting for an approval, or blocked.
UnityFreak reads the CODEOWNERS file from the pull request's target branch — never from the source branch, so a pull request can't rewrite its own owners. The first location that has a file wins, and only that one file is read:
.github/CODEOWNERS, then CODEOWNERS in the repository root, then docs/CODEOWNERS.CODEOWNERS, then .unityfreak/CODEOWNERS, then .github/CODEOWNERS. Repositories that existed before the standard order was introduced keep this order, so their owners never change without anyone choosing it, until a repository admin switches them.Admins see which locations exist, which file each order would pick, and whether switching would change the effective file in Settings → CODEOWNERS location, and can switch after a confirmation.
/docs/* owns files directly in docs, not docs/guides/a.md; use /docs/ or /docs/** for everything beneath). In the legacy order patterns keep the original .gitignore matching, so existing owners never change until an admin switches the order. Negation (!), [ ] ranges and \# escapes are not supported and are reported as errors, as on GitHub. In both orders a pattern longer than 1024 characters or with more than 64 path segments is reported and skipped.@username, @org/team — a department of the organization that owns the repository, including its sub-teams — or an email address that belongs to a UnityFreak account with a verified primary email.Only someone with write access to the repository counts, and the pull request's author can't approve their own pull request. For a team, any member with write access counts. With stale-approval dismissal on, only approvals for the current head commit count.
Required approval never quietly turns into zero approvals. Merging is blocked, with a message that says why, when:
CODEOWNERS file over 1 MB, a binary file, a Git LFS pointer, or a symbolic link means ownership is unknown, so the gate fails closed rather than falling back to a lower-priority location./src/api/, are the cheapest), or when a changed file sits more than 256 directories deep. Split the pull request or simplify the file; a temporary git error just needs a re-check. The error names the specific limit that was hit. If the server was too busy to finish the evaluation in time, that is not a problem with the pull request: try again in a few minutes (a pull request in the merge queue is retried automatically for up to 15 minutes before it is removed).The error lists each blocked rule with its problems, followed by a numbered How to fix list. Typically a repository admin edits the CODEOWNERS file on the target branch to name someone with write access, gives an owner write access, adds members to an empty team, or turns off Require code owner approval if code owner review shouldn't be enforced. After the owners change, use Re-check owners on the pull request to refresh its review requests. If the repository has no CODEOWNERS file at all, there is nothing to approve and the gate doesn't block.
Admins can see every owner problem from the last sync in the repository's Branch protection settings, grouped as errors, warnings and info with the owner, pattern and line. People without write access see each rule's state on the pull request but not the problem detail.
Require status checks to pass blocks merging a pull request into the default branch until required checks pass. If you don't name any specific checks, merging is blocked until at least one commit status is reported and every reported status is green; naming specific check contexts narrows that down to only those checks mattering for merge.
UnityFreak doesn't run CI itself — external CI reports results by posting to a commit-status API using an API key with the repo:write scope:
curl -X POST https://unityfreak.com/api/v1/repos/{owner}/{repo}/statuses/$COMMIT_SHA \
-H "X-API-Key: $UNITYFREAK_TOKEN" \
-H "Content-Type: application/json" \
-d '{"state":"success","context":"build","targetUrl":"https://ci.example.com/run/123"}'Valid state values are pending, success, failure, and error. The context is the check's name — the same string you'd add as a required status check context above to make that specific check mandatory.
Set merge and push-protection rules once and apply them across every targeted repository at once — targeted by visibility, an explicit repo list, or a name pattern — instead of configuring each repository by hand. Rulesets compose with a repository's own settings on a strictest-wins basis. An admin can bypass a blocked merge only when their role is explicitly allowed to for every ruleset in play, and every bypass is written to your audit log.
A repository governed by an org ruleset shows which rulesets are contributing to its floor directly in its own Branch protection section — you can still configure that repository to be stricter than the floor, but never looser.