The original CODEOWNERS model was designed for a world where every commit had a human author who could be paged at 2am. That world is gone. By Q1 2026, internal telemetry from large engineering organisations shows 30-50% of merged PRs containing at least one commit authored by an autonomous coding agent — Copilot Workspace, Cursor Agent, Claude Code, Devin, Replit Agent, or an in-house orchestrator built on the Claude Agent SDK or LangGraph.
When the author field reads [email protected] or github-copilot[bot], the question "who owns this code?" stops having a clean answer. The agent doesn't get paged. The agent doesn't remember the change next quarter. The agent isn't accountable in a postmortem. Yet ownership — for review, for incident response, for compliance — still has to land somewhere.
This article maps the historical CODEOWNERS pattern onto the agent reality, and gives you a concrete model for assigning ownership when the author isn't human.
The Three Ownership Roles in an Agent-Authored Codebase
Pre-agent code ownership had one role: the author was the owner. Agent-authored code splits that role into three:
- Operator — the human who initiated, prompted, or supervised the agent run. They chose the model, set the temperature, accepted (or didn't) each suggestion. They are the closest analog to the historical "author."
- Reviewer — the human (or sometimes second agent) who approved the PR. In agent-authored code, the reviewer often does more cognitive work than the operator, because the operator may have batch-accepted dozens of suggestions.
- Maintainer — the team responsible for the affected module long-term. Independent of who triggered the agent run, the team that owns
src/billing/still owns the consequences when an agent touches it.
A healthy CODEOWNERS strategy assigns all three. A failing one assigns none and hopes git blame produces a name.
Why the Old CODEOWNERS File Breaks
Consider a typical pre-agent CODEOWNERS entry:
src/billing/** @org/payments-team
The implicit contract: anyone who modifies billing code routes through the payments team for review. With humans, this works because the human author had to read the code, think about the change, and write it. The PR author has context. The reviewer adds a second pair of eyes.
Now an agent run touches 14 files including src/billing/refund_processor.py. The operator's prompt was "add structured logging across the API layer." The agent took that to mean every module with an HTTP handler — including billing. The operator skimmed the diff, hit accept, opened the PR.
The CODEOWNERS rule still routes payments-team for review. But now:
- The operator has no billing context (they were thinking about logging)
- The reviewer has to do the full thinking job and trust an agent's interpretation
- The maintainer (payments-team) inherits a change they didn't request
The rule still fires, but the cognitive load distribution is wrong. The fix is not to delete CODEOWNERS — it's to upgrade it to handle the three-role model.
A CODEOWNERS Pattern for Agent-Authored Code
The minimum upgrade: every sensitive path gets two reviewer groups, one of which must be human. Add a separate rule for agent-bot accounts:
# Default: maintainer-only review
* @org/engineering-leads
# Critical paths: maintainer + a second human reviewer
src/billing/** @org/payments-team @org/staff-engineers
src/auth/** @org/security-team @org/staff-engineers
src/crypto/** @org/security-team @org/staff-engineers
# Agent-authored PRs: route to a "human-in-the-loop" group regardless of path
# (enforced by the agent-pr-router workflow, not CODEOWNERS itself)
CODEOWNERS alone cannot conditionally route based on PR author. To enforce "if author is agent, add the operator + a senior reviewer," you need a GitHub Actions workflow that runs on pull_request.opened and uses gh pr edit --add-reviewer to inject the right reviewers based on the author's email domain. We cover the routing workflow in detail in Reviewer Assignment When Half Your Team Is an Agent.
Detecting Agent Authors at the Git Layer
Before you can route on author identity, you need agent commits to be identifiable. The most reliable method is configuring agents to use a deterministic email suffix. Run this once in any repo where agents commit:
# List unique commit authors over the last 90 days, grouped by domain
git log --since="90 days ago" --format="%ae" \
| awk -F@ '{print $2}' \
| sort | uniq -c | sort -rn
A healthy agent-aware repo will show distinct buckets like:
847 company.com
312 cursor-agent.local
188 users.noreply.github.com
142 copilot-agent.local
44 claude-code.local
If you see only company.com, your agents are committing under human identities — which means your CODEOWNERS rules cannot distinguish them, and your audit trail conflates the two.
To fix this in the agent's git config:
git config user.name "Cursor Agent (operated by [email protected])"
git config user.email "[email protected]"
The +alice suffix is a plus-addressing trick that preserves the operator identity inside the agent email. Now both the agent and the operator are recoverable from a single field.
The "Operator of Record" Pattern
For autonomous or scheduled agent runs (CI bots, dependency-update agents, refactor agents that run on cron), there is no individual operator at commit time. You still need an accountable human. The pattern here is the operator of record — a human who signs up to babysit a particular agent.
Concretely, this lives in a YAML file at the repo root:
# .github/agent-operators.yaml
agents:
- id: cursor-agent
email_pattern: "cursor-agent+*@company.local"
operator_of_record: [email protected]
backup: [email protected]
review_sla_hours: 24
- id: dependabot
# Dependabot's canonical commit email is `49699333+dependabot[bot]@users.noreply.github.com`.
# The leading `*` covers the user-id prefix; the bracket characters are
# part of the literal local-part, not a glob.
email_pattern: "*+dependabot[bot]@users.noreply.github.com"
operator_of_record: "@org/security-team"
review_sla_hours: 72
- id: claude-code-refactor-bot
email_pattern: "[email protected]"
operator_of_record: [email protected]
backup: [email protected]
review_sla_hours: 48
When the agent-pr-router workflow sees a PR from [email protected], it can:
- Add
[email protected]as a required reviewer (she initiated the run) - Add the path-based CODEOWNERS for the affected files
- Add
[email protected]as backup if alice is OOO
When it sees a PR from dependabot[bot], there is no individual operator, so it falls back to the operator_of_record group.
Bus Factor with Agents in the Mix
Bus factor — the number of people who would have to leave before a module becomes unmaintainable — gets distorted when agents author code. The naive calculation looks at git log and sees one author wrote 80% of the file. Looks fine. But if that "author" is cursor-agent, the bus factor is effectively zero: no human carries the context.
The corrected calculation weights commits by author type:
- Human commits: weight 1.0
- Agent commits with named operator: weight 0.5 (operator has partial context)
- Autonomous agent commits: weight 0.1 (no carrier of context)
A module that's 90% agent-authored with no clear operator should flag as bus-factor-1 even if git log shows ten distinct contributors. We've seen teams hit this in dependency-management code that's been touched almost exclusively by Renovate and Dependabot — when the underlying tool changes behaviour, no human on the team can reason about why their lockfile looks the way it does.
Compliance Implications
NIST SSDF practice PS.3.2 ("Collect, safeguard, maintain, and share provenance data for all components of each software release") and PO.2.1 ("Create new roles and alter responsibilities for existing roles") together require both attributable change records and clearly assigned roles for production code. (EU AI Act Article 12 sometimes gets cited here, but it governs operational logging of high-risk AI systems themselves — not the source-code commits produced with AI tools. The downstream coding agents are not Annex III high-risk systems; Article 12 is the wrong cite.) "An agent did it" does not satisfy either. The operator of record is the human attribution. Your CODEOWNERS strategy needs to make that attribution mechanical, not aspirational.
A reasonable acceptance criterion: pick any commit hash in your last quarter. Within 30 seconds, can you name (1) the agent or human that produced it, (2) the human operator if it was an agent, and (3) the maintainer team for the affected files? If yes, your model works. If you find yourself reading commit messages and guessing, the model is broken.
What to Change This Week
- Run the
git log --format="%ae"audit above. Confirm agents have distinct emails. - Create
.github/agent-operators.yamlwith at least one operator of record per agent. - Add
@org/staff-engineers(or equivalent) as a co-reviewer on your top 3 critical paths. - Audit your top 10 highest-churn files for the corrected bus factor — flag anything where human-weighted contributions fall below 50%.
These four steps don't require new tooling. They require treating the agent as a distinct contributor class in the data you already have.