One push per repository
A push reserved the whole repository. A second push to any other branch of it got a 409.
Before AM-1
Forges were built for people pushing a few times an hour. Agentic mode rebuilds Golf’s control path for many coding agents in one repository: concurrent Git, commits without a clone, scoped agent access and a landing policy. Still Git, measured on a hosted deployment at every step.
Developer preview · Cloudflare-native · October 2026Agents push, read and land changes continuously. Before agentic mode, these were Golf’s own limits on Cloudflare, and they are the same assumptions most forges make.
A push reserved the whole repository. A second push to any other branch of it got a 409.
Before AM-1One Workspace object served the deployment. Every clone, fetch and push to every repository ran alone; over 128 queued requests got a 429.
Before AM-1If a push’s outcome was unknown, the repository stayed locked. Nothing cleared it automatically.
Before AM-1No multi-file read, no server-side commit, no API tokens and no remote MCP. Merges only worked when the head already contained the base.
Before AM-1The target: at least 100 agents working in one repository without the forge or the reviewers becoming the bottleneck. Monorepo scale of tens of thousands of merges a day is not the target. The design follows two pieces of writing: Anthropic’s Redesigning source control ↗ and Enroute’s Everyone is doing Git on S3 wrong ↗.
The limits were never in storage. Cloudflare Artifacts already keeps Git on Cloudflare’s storage, so the work is in Golf’s own control path.
Clone, fetch and push over HTTPS at /git/<owner>/<name>.git. An agent can use the same API token as its Git password, so it needs no separate Git credential.
The Source API encodes blobs, trees and commits exactly as Git does and sends them through receive-pack. Locally, its trees equal Git’s own index for the same edits, and git fsck --strict is clean.
A push, a Source API commit and an MCP tool call meet the same branch rules, the same branch fence and the same pipeline intake. Rights are rechecked in the D1 statement that reserves the write.
Every request to a deployment passes one Workspace Durable Object. AM-1 splits its single queue into classes, so clones and pushes stop waiting for each other. The queue holds 512; beyond that, a 429 says “Workspace is busy. Retry with backoff.”
Source, history, diffs and search run side by side, alongside transfers.
Overlaps everything but exclusiveClone, fetch and push, plus Source API commits and branch updates. They overlap reads and each other; writes are ordered per branch by the D1 fence.
Clone · fetch · push · commitEverything else waits for every running request, transfers included, and fences later admissions. A revocation or settings change never overlaps a push.
Revocations · settings · mergesA push reserves its branch in git_ref_writes, in the same D1 batch that journals the write and under the same authority check: grant, identity and access versions, rules version and credential.
Two unsettled writes to one branch conflict. Writes to different branches proceed in parallel. A lost race to the same branch is answered with Git’s own report (“fetch first”), settled as not applied at once, and the repository is not fenced.
If a sent update does not read back, Golf resends the same compare-and-swap while the branch still holds the old commit: 5 attempts over about 3 seconds. If it stays unknown, only that branch stays fenced. A maintenance sweep reads the ref after 2 minutes and records it applied or not applied, with an audit row.
A pull request merge reserves the whole repository through write_pending, and a plain push refuses to start while that is set. Rule, settings and merge changes wait for a branch with an unknown outcome to settle.
On the hosted demo, 16 agents pushing to separate branches of one repository went from 0 of 32 pushes landing to 48 of 48; 64 agents went from 0 of 64 to 93 of 93.
POST /native/source/<action> with JSON. Commits and branch updates are transfers, ordered per branch by the same D1 fence as a push; reads are reads.
commitUp to 500 changes against an expected head: content, base64, mode, delete or move. Built as Git objects and sent as one receive-pack update.
Write · transferbranchCreate a branch from a commit or branch, or delete one with an expected head. The default branch cannot be deleted.
Write · transferfilesUp to 100 paths at one ref in one call. Text inline, binary as base64, or a reason it was skipped.
Read · 1 MiB a file, 4 MiB totaltreeA listing of a commit, sorted by path, up to 10,000 entries, with truncated shown.
Read · no cloneexpectedHead is the head your edits are based on, or empty plus base to create the branch. With onStale: "fail", the default, a moved branch returns 409 with currentHead.
With onStale: "merge", Golf merges three ways by path: the base is the expectedHead tree, ours is the current head, theirs is your edited tree. Paths changed on both sides differently return 409 with a conflicts list. There is no line-level merging yet.
If the head moves again or the provider refuses the update, the read, merge and push are retried, at most 3 attempts in all.
An idempotencyKey replayed with the same inputs returns the original response without a second commit; other inputs get 409. A sent write that cannot be read back holds the repository until maintenance settles it, within minutes; the same key then returns the original response.
POST /native/source/commit
Authorization: Bearer golf_pat_…
Content-Type: application/json
Connect-Protocol-Version: 1
{"repository": {"owner": "alice", "name": "project"},
"branch": "agent/fix-login",
"expectedHead": "<40-hex head you edited>",
"message": "Fix login redirect",
"changes": [
{"path": "src/login.js", "content": "export …\n"},
{"path": "bin/run", "content": "#!/bin/sh\n", "mode": "executable"},
{"path": "old.txt", "delete": true},
{"path": "docs/new.md", "from": "docs/old.md"}],
"onStale": "merge",
"idempotencyKey": "<uuid v4>"}{"repositoryId": "1", "branch": "agent/fix-login", "commitId": "…", "treeId": "…",
"previousHead": "…", "merged": false,
"changedPaths": [{"path": "src/login.js", "change": "modified"}]}previousHead is empty when the branch was created. With merged: true, changedPaths compares against the head that was merged onto. Author and committer are the caller’s account.
Limits: 500 changes, 8 MiB of decoded content in total, 4 MiB a file, 64 KiB messages, 12 MiB of JSON. Paths are literal, with no .git segment. Every limit refusal names the limit.
On the hosted demo, 16 writers committing to a branch each through the Source API made 48 of 48 commits at 1.85 per second, p50 8.3 s, with no clone. On one shared branch with onStale: "merge", merges could not keep up with 16 writers: 13 of 63 succeeded, and 49 were refused after 3 merge attempts. The landing queue in AM-4 addresses that case.
Coding agents reach Golf with a personal API token. The same token works for remote MCP, the Source API and HTTPS Git.
golf_pat_ tokensScoped to a list of up to 100 repositories or all you can access, read or write, and an optional write branch pattern such as agent/*. With a pattern, writes to other branches and to tags are refused. Lifetimes run from 1 hour to 90 days, with up to 50 active tokens per account.
Every call caps the token by its owner’s current grant; a write token never administers. Changing the account’s login, email or active state ends every token at once. Revocation, expiry and account changes take effect on the next request, and a revoked token mid-request writes nothing.
Tokens are accepted only on /mcp, /native/source/* and the three Smart HTTP Git routes, and refused with 401 everywhere else, including account routes. Only the SHA-256 is stored; the secret is shown once. Create, revoke and scope refusals are audited.
/mcp.A stateless Streamable HTTP server with JSON responses. Each tool builds a request to the route the web UI uses and runs it with the caller’s own credential, so grants, token scope, feature policy, branch rules, the ref fence and audit are exactly the UI’s.
repo_overview, list_tree, read_files, search_code, list_commits, compare, get_issue, list_issues, get_pull_request, pull_request_diff, pipeline_status.
search_code is semantic search and needs the index.
commit_changes, create_branch, open_pull_request, comment.
Only write tokens see them. commit_changes and create_branch are transfers; other writes are exclusive. A refusal carries Golf’s message and data such as currentHead or conflicts. Results are capped at 256 KiB with a truncated flag.
claude mcp add --transport http golf <origin>/mcp --header "Authorization: Bearer <token>"Verified on hosted: Claude Code was connected to the hosted demo’s /mcp with a token limited to one repository and agent/*, with no Access headers. Using only MCP tools it read the repository, created agent/mcp-subtract, committed a function with tests, opened a pull request and commented on it. A commit to main was refused by the branch scope, and /mcp without a token and the token on a browser route both answered 401. The token page also shows Codex and OpenCode setups; those have not been run against Golf.
Agentic mode is a per-repository setting, off by default. Golf evaluates every open pull request against it and shows the result in a Landing panel. It does not land, queue or revert anything on its own yet.
Native merges now use a three-way tree merge from the single merge base. Squash writes one commit with the base as its only parent. Paths both sides changed differently are refused before any write, up to 50 listed with reasons. Lines inside a file are never merged.
A pure function returns land, needs_person, waiting_checks or blocked, with every reason. Risk is sensitive if any path matches a sensitive pattern, low if every path matches a low-risk one, and normal otherwise.
Only writers’ reviews count. A qualifying approval comes from a writer who is not the author and not an agent, and only for the current head. Any writer’s requested changes cancel approvals. API tokens cannot submit reviews.
| Field | Default | Meaning |
|---|---|---|
enabled | Off | Evaluate pull requests against this policy. While off, every pull request needs a person. |
lowRiskPaths | docs/**, **/*.md | Patterns for low-risk paths. |
sensitivePaths | .github/**, .forgejo/**, .gitlab-ci.yml, deploy/**, **/CODEOWNERS | Always need approval by a writer who is not the author and not an agent. |
landWithoutPerson | Off | A change may land without a reviewer only if every changed path is low-risk and every required check passed. |
requiredChecks | None listed | Names of checks that must pass. Empty means every pipeline that ran on the head commit. |
revertOnFailure | On | Stored for automatic reverts. Golf does not revert anything yet. |
A feature policy at installation, organization or repository level can turn agentic mode off, never require it. Path patterns use an anchored matcher with *, ? and whole-segment **; it never builds a regular expression.
Land merges onto the current base head with the tree merge. The base update is a compare-and-swap: if stale, Golf retries up to 5 times against the new head. Overlapping paths go to needs_rebase. Different branches never wait on each other.
The base push starts pipelines as usual. If a required check fails on a landed agent change and revertOnFailure is on, Golf commits a revert through the Source API, comments on the pull request and raises an issue for the original requester.
In progress. The repository’s agents page becomes an inbox, with live updates from the repository activity stream.
In progress, ready to land, needs a person (sensitive paths, conflicts or failed checks), and recently landed with revert. Approve and land selected items in one batch.
Workers AI writes, for each agent pull request, what the change is for, which areas it touches and which risks it may have. Marked as AI-written, regenerated on a new head, and never a replacement for the diff.
Agent and token-pattern branches are hidden from the default branch list behind a toggle, and deleted automatically after landing or closing.
Measured on the hosted demo with the agent speed bench against eight repositories, 20 seconds per step. The evidence files are checked into the product repository.
| Scenario | Agents | Baseline | After |
|---|---|---|---|
| S2 · branch per agent, one repository | 16 | 0 of 32 | 48 of 48 |
| S2 · branch per agent, one repository | 64 | 0 of 64 | 93 of 93 |
| S3 · a repository per agent | 16 | 21 of 24 at 0.38/s, p50 24 s | 48 of 48 at 2.19/s, p50 7.6 s |
| S3 · a repository per agent | 64 | 51 of 64, p50 76 s | 93 of 93 at 1.6/s, p50 37 s |
| S4 · shallow clones under push load | 16 | p50 19.6 s | p50 10.3 s; background pushes 39 of 39 |
| S4 · shallow clones under push load | 64 | 62 of 166 (104 refused, 429) | 70 of 70; background pushes 75 of 75 |
| S6 · Source API commits, branch per writer | 16 | New in AM-2 | 48 of 48 at 1.85/s, p50 8.3 s |
| S6 · Source API commits, branch per writer | 64 | New in AM-2 | 61 of 93; 32 client timeouts at 60 s |
| S6 · Source API commits, one shared branch | 16 | New in AM-2 | 13 of 63; 49 refused after 3 merge attempts |
The ceiling: total throughput levels off near 2 writes per second for a deployment. That is the single Workspace object plus the provider. The next step is a per-repository RepositoryWrites Durable Object for transfers, with the D1 fence and authority checks staying authoritative. Not yet measured on hosted: the AM-4 merges and landing panel, and API reads under push load.
Agentic mode is built on the Cloudflare-native deployment: Artifacts for Git, D1 for the fence and journals, and Workers with Durable Objects for admission.
Concurrent Git, the Source API, API tokens, remote MCP and the land policy run there today. When Cloudflare Access protects an installation, token requests on /mcp, /native/source/ and /git/ pass to the Worker with cookies stripped; every other request still needs Access.
The Docker and Kubernetes track has a local, read-only MCP server in the golf CLI, over stdio. Remote MCP, the Source API and agentic mode are not part of it today. Self-hosted track ↗
Field-level behavior, error codes and the current status live in the documentation.
The setting, path patterns, policy rules and milestones.
Read the guide ↗Connecting MCP clients and how Golf credentials are scoped.
MCP docs ↗ API credentials ↗What has shipped, what has been verified on hosted and what is still open.
Read the status ↗See the milestones as they land, or connect the coding agents you already use.