The system under description
Model a repository as shared mutable state and each contributor as a concurrent actor issuing transactions (commits, merges) against it. Git is the coordination substrate: an append-only, content-addressed log with a set of mutable refs. GitHub adds a serialization surface (PRs, required checks, branch protection) on top.
With a single actor, this is trivial — there is no concurrency. Every rule in this document exists to manage concurrent writers, and each has a cost. The engineering question is never "is this rule good?" but "does the concurrency I have justify this rule's cost?" Hold that question through all eight sections.
Coordination overhead should be a function of contention, not of aspiration. Zero contention wants zero protocol.
Identity: many minds, one credential
AI agents typically commit under a single VCS identity (one token, one bot account). This collapses the free property distributed systems usually get for nothing: attribution. When every write is signed by the same principal, "who did this" is no longer answerable from the commit metadata — the layer that normally carries it is degenerate.
The consequence is that identity and authorization must be re-implemented at the application layer. A claim ("I am taking task X") is not a VCS primitive; it is an advisory record you must publish and honor. Blame and credit cannot be inferred from "who was active when the change appeared" — that is a race condition dressed up as evidence. They must be read from the diff, the branch topology, and the log.
Attribute by evidence, not inference. Under a shared credential, temporal correlation is not causation — it is the absence of the information you actually need.
Channels: the log and the lossy bus
Actors coordinate over two categories of channel with opposite guarantees. Inter-agent messages behave like an unreliable, unordered bus: a note sent now may arrive after the decision it was meant to inform, may be dropped when the transport is down, and may be read in a different order than it was sent. Repository artifacts — PR comments, commit statuses, branch state — behave like a linearizable, append-only store: durable, ordered, and readable by every actor with the same result.
This is the same discipline as choosing a consistent log over best-effort multicast for anything that must be agreed upon. An instruction that contradicts fresher state in the durable store is, by construction, stale.
Consistency: green at the branch is not green at the merge
CI on a feature branch is a read of an isolated snapshot. It validates state S_B. But the integration target advances underneath it — other merges move main to S_main. The state that actually ships is S_merge = S_B ⊕ S_main, which neither run ever observed. A green check on S_B is an optimistic read; treating it as a guarantee at merge time is a lost-update bug.
Conflicting transactions must be serialized: when two PRs touch the same files, merge one, re-validate against the new tip, then the next. Disjoint transactions commute and need no re-cycle — the cost is paid only where there is actual contention.
The serialization point
Route all integration through one writer. A single merger is a linearization point: it imposes a total order on integration events, which is what makes "re-validate against the current tip" well-defined. Parallel mergers reintroduce the lost-update problem at the top level — they stack changes whose combination nobody validated.
This is the single-writer principle, and it has the usual tradeoff: the serialization point bounds integration throughput (an Amdahl ceiling). You accept that ceiling in exchange for a consistency guarantee. Raise it, when you must, by making changes smaller and more disjoint — not by adding writers.
A convention only enforced by goodwill is not a safeguard. An advisory lock in a system where no one checks it is decoration — a lock nobody honors is not a lock. Enforce the serialization point mechanically (required status checks, branch protection), not by agreement.
Delivery semantics & acknowledgement
Treat every remote mutation as at-least-once. A merge request that times out on the client can still have committed on the server; retrying blind double-applies. The fix is the standard one: make operations idempotent, or read state before you retry — GET the PR, see if it already merged, act on the truth.
And there is no negative acknowledgement. The absence of an objection carries no information: a reviewer who has not responded has not approved, they have simply not responded. Approval must be an explicit positive artifact — a comment, a status, an ACK — re-read immediately before the irreversible act, because it may have arrived, or been revoked, since you last looked.
Silence is never consent. Design for explicit ACK; treat missing signals as unknown, never as yes. And note the dual: arming an automated irreversible action (auto-merge) is the action — it will fire without re-reading the room.
The economics of coordination
Every mechanism above buys consistency with latency and cognitive load. The return depends on contention, which scales super-linearly with the number of concurrent writers on overlapping files. Below a threshold — a single developer with an assistant, or a few agents on disjoint areas — the protocol costs more than the collisions it prevents.
So the protocol must be incident-derived, not designed up front. Each rule should trace to a specific failure it prevents; a rule whose failure you have never seen is speculative complexity. And the corollary architects forget: when a rule's originating failure becomes impossible — you dropped to one writer, you changed the identity model — the rule is now pure cost. Remove it. A gate that is perpetually pending and never catches anything is a smell, not a safeguard.
Right-size the process. Add a mechanism when a real failure demands it; retire it when its cause is gone. This is the one principle that governs all the others — including whether you should have read this page at all.
A minimal protocol
The smallest set that covers the failure classes above, for a team that genuinely has concurrent writers:
| mechanism | failure class it closes | from |
|---|---|---|
| Isolated worktrees | concurrent writes to one tree (lost updates) | §1 |
| Claim-before-build | duplicated work under a shared identity | §2 |
| Durable coordination | lost / reordered messages | §3 |
| Re-validate at merge state | green-in-isolation, broken-combined | §4 |
| Single mechanical merger | unserialized integration | §5 |
| Read-before-retry; explicit ACK | at-least-once delivery; false consent | §6 |
Adopt the rows you have collisions for. Delete them when you stop. The companion, Architecture, covers the other half: how a single agent's context is structured so it behaves well before any of this is needed.