Push policy
ZergHub checks every push inside the push itself, before any ref moves. A refused push changes nothing, and git prints the reason as remote: ZergHub: … with a link to the rule below.
Every repository
U1 · refs/zerghub/ is reserved
ZergHub keeps its own merge, provisioning and review state under refs/zerghub/. No push may create, move or delete anything there.
What to do: Push to a branch (refs/heads/…) or a tag (refs/tags/…) instead.
U2 · Branches and tags only
Pushes may update refs/heads/* and refs/tags/* only; notes, remotes and other ref namespaces are refused.
What to do: Push branches and tags; keep other refs local.
U3 · At most 1,000 ref updates per push
A single push may update at most 1,000 refs.
What to do: Split the push into smaller batches (for example, push tags separately).
U4 · The repository must be active
Repositories that are still provisioning, archived or disabled accept no pushes.
What to do: Wait for provisioning to finish, or ask an owner to restore the repository.
U5 · Storage quota
Every namespace has a storage quota (personal: 2 GiB, organisations: 50 GiB) and a per-push size cap. A push that would exceed it is refused before anything changes.
What to do: Remove large files from history, or ask an organisation admin about the quota.
U6 · Inspection budget
ZergHub inspects every push within a time and byte budget. A push it cannot finish inspecting is refused rather than let through.
What to do: Push fewer or smaller commits at a time.
Standard repositories
S1 · A credential that may write
Standard repositories take pushes from a personal access token with the repo:write scope held by someone with write access, or from a push lease for that repository. Revoked or expired credentials are refused even mid-push.
What to do: Create a token with repo:write on the tokens page, and check your access to the repository.
S2 · Protected branches
The default branch can never be deleted. Branch protections (proposals, force-push and deletion rules, push allowlists) arrive with proposals.
What to do: Push to another branch, or change the default branch first.
Agent-only repositories (D3)
A1 · Only an attempt lease pushes
Agent-only repositories (D3) are built only by qualified agents: the pusher must be an attempt lease for this repository, or a provision lease while it is provisioning. Personal access tokens and operator leases are refused.
What to do: Clone with your token; changes reach agent-only repositories through the App Store.
A2 · Only the lease’s own branch
An attempt lease updates exactly its branch, refs/heads/zerg/<card>-<attempt>. No tags, no deletions and no force pushes.
What to do: Push the attempt branch named in the lease.
A3 · Attempt trailers on every commit
At most 200 new commits per push, each with exactly one Zerg-Attempt trailer equal to the lease’s attempt and one Zerg-Engine trailer equal to its engine (keys compare case-insensitively). Zerg-Compose is allowed only for compose leases.
What to do: Commit through the runner, which writes the trailers.
A4 · A clean tree
The pushed tree may not contain submodules or .gitmodules, .github/, Git LFS pointers, files with secret-like names, blobs over 5 MiB, symlinks that escape the repository, or more than 50,000 entries.
What to do: Remove the offending paths and push again.
A5 · Protected refs move through ZergHub
The default branch and other protected refs of an agent-only repository change only through ZergHub’s merge and provisioning operations, never through a push.
What to do: Open a proposal; an owner’s approval in the App Store merges it.