Skip to content

Never let an automated actor write to a protected branch

Problem

An automated actor with commit access to the default branch is one prompt away from an unreviewed change in production. Not through malice — through a generation that was slightly wrong, an ambiguous instruction, or a retry that ran twice.

Restricting the credential is the usual answer and it is not enough: the actor often needs write access to do useful work. The question is not whether it can write, but where.

Technique

Route every automated write through the same path a person uses.

  1. Create a timestamped branch — a name that identifies the actor and the run, so an abandoned branch is attributable and a retry does not collide.
  2. Commit there.
  3. Open a merge request with a description saying what was changed and why.
  4. Stop. A human — or an explicit gate ladder — decides.

Enforce it in the writer class, not in policy. If the only write method available creates a branch, no caller can bypass it by accident, and no future maintainer can add a "quick" direct-commit path without visibly removing the guard.

Grant the actor maintainer rights if it needs them. The protection is the code path, not the permission level — a read-only credential just moves the problem to a human pasting the output in manually.

When it applies

Every automated writer: documentation generators, dependency bots, refactoring tools, code generators, agents with repository access.

When it does NOT apply

Genuinely ephemeral branches the actor owns end to end — a scratch branch it creates, pushes to and deletes — need no MR, since nothing merges.

It is also not the right shape for high-frequency mechanical writes where a per-change MR would drown review. Batch those into one periodic MR instead, which keeps the review gate and drops the volume.

Note it protects the branch, not the content. An MR nobody reads is a formality, which is why this pairs with an explicit gate ladder rather than standing alone.

Evidence

An automated documentation writer holds maintainer access to the repositories it maintains, and has never committed directly to a default branch, because the only write path it exposes creates a branch and opens an MR.

The design decision that made this hold was putting the constraint in the writer rather than in the credential. Reviewing that code, the guard is impossible to miss and awkward to remove — which is the property you want, since the pressure to add a direct-commit path always arrives eventually and always with a good reason.

See also