Skip to main content
A CODEOWNERS file tells GitHub who owns which files. When a pull request changes a file, GitHub asks its owners to review it, and a ruleset can require their approval before merging. It is a plain text file of lines like /docs/ @my-org/docs. The trouble is that GitHub quietly ignores lines it does not understand. A typo in a team name, or a pattern GitHub does not support, and nobody is asked to review. The codeowners feature does two things about that:
  • Checking: on a pull request that changes CODEOWNERS, it reports every line GitHub rejects or ignores, and every rule that can never apply.
  • Generating: it can write owners you list in the smartcloud config into a marked block of the file, so a shared preset can set owners across many repositories.

Turn it on

1

Run smartcloud on pull requests and pushes

Checking needs pull_request events. Generating runs on push, schedule and workflow_dispatch. The workflow in Getting started has all of them.
2

Grant the permissions

Checking needs checks: write for its check run and pull-requests: write for the report comment it posts or updates when a finding needs action. Generating also pushes a branch and opens a pull request, so it needs contents: write as well.
3

Add a codeowners section

An empty section only checks the file you already have:
.github/smartcloud.yml
Add rules to generate owners too (see Options).
4

Require the check

To block a pull request that breaks CODEOWNERS, require the smartcloud / codeowners check in a ruleset, or use the required feature’s single aggregate check.

Options

About patterns and keys:
  • A rule with no owners leaves its paths without an owner, overriding an earlier rule, as GitHub documents. That is useful for vendored code.
  • GitHub does not support ! (negation), [ ] (character ranges) or a pattern starting with an escaped \#, so the config rejects them.
  • Write a space in a path as \ , as in docs/My\ Files/.
  • A rule’s key must not be a whole number such as 2: such a key is always read first, so its rule would be written before the others.

Complete example

.github/smartcloud.yml

How it works

Checking

On a pull request that changes CODEOWNERS, unless check is false, smartcloud checks the file at the pull request’s head: GitHub’s own CODEOWNERS errors come first. They need only read access, so they also work for pull requests from forks; when they cannot be read, smartcloud’s own checks still run. A pull request that does not touch CODEOWNERS is not checked, so a problem already on the default branch does not fail unrelated pull requests. On a schedule, a manual dispatch or a push, the file on the default branch is checked the same way, and its problems are warnings, since no pull request caused them.

Generating

When rules has an entry, smartcloud writes them between two markers on a schedule, a manual dispatch or a push, and proposes the result as one pull request from branch, titled chore(codeowners): generate CODEOWNERS from the smartcloud config:
.github/CODEOWNERS
  • Everything outside the markers is kept. The first generation adds the block at the end of the file, or just above a block the sync feature manages (house:managed:begin), which stays last so synced owners always apply. A block found below the synced one is moved above it.
  • When path is set but GitHub reads an existing file before it, such as .github/CODEOWNERS before docs/CODEOWNERS, nothing is generated and a codeowners.generate error names the file GitHub uses.
  • Rules are written in the order the config gives them, and later rules win, as they do everywhere in CODEOWNERS. A repository’s own rules come after its presets’ rules.
  • When the file is already up to date, nothing is proposed.
  • The same pull request is updated on later runs, since the branch is force-updated.

What you will see on GitHub

  • Check run: smartcloud / codeowners. It fails when a problem at error level is found, is neutral with only warnings, and passes otherwise. Each problem is an annotation on the CODEOWNERS line it is about.
  • Report comment: errors and warnings also appear in smartcloud’s single report comment on the pull request.
  • Pull request: when generating, one pull request from smartcloud/codeowners (or your branch) into the default branch. Merge it to apply the owners.
  • Job summary: the problems found, and “Proposed the generated <path> on <branch> in pull request #N” when it opened or updated one.

Forks and restricted runs

Checking a pull request from a fork works: GitHub’s CODEOWNERS errors need only read access. In a restricted run, writing the check run or report comment may be refused and is then listed under Restricted access in the job summary; the job’s own summary and annotations still show every problem. Generating runs on pushes and schedules, which never come from a fork. A token that cannot push, such as a workflow token with contents: read, skips the proposal with a codeowners.generate warning rather than failing the run.

Troubleshooting

GitHub uses only the first CODEOWNERS file it finds, in the order .github/CODEOWNERS, CODEOWNERS, docs/CODEOWNERS. Delete the earlier file, or set codeowners.path to it. Nothing is generated until you do.
The proposal branch is force-updated, so it can never be the branch pull requests merge into. Leave branch unset or choose another name.
The token cannot push or open pull requests. Grant the job contents: write and pull-requests: write.
The block between the smartcloud:codeowners markers is written from the config. Undo the hand edit and change codeowners.rules instead; smartcloud regenerates the block. To stop generating entirely, remove rules.
Two lines have the same pattern, and the last matching line wins, so the earlier one does nothing. Merge the owners into one line or remove the earlier one.
That comes from GitHub: the user or team does not exist, is misspelled, or has no write access to the repository. Give the team write access, or fix the name.
Only pull requests that change one of the CODEOWNERS locations are checked. Problems already on the default branch are reported as warnings on the next push or scheduled run.
Last modified on September 27, 2026