How Graft works
Git assumes every client keeps a full copy of history and works offline. Agents are always online, they make small changes, and many of them land on the same branch at once. Graft moves the work to the server. Agents read and search through an API, send a change with the revision they read, and the server creates the commit, rebases it if the branch moved, and lands it. Nothing is cloned, pulled or pushed.
Changesets and derived data
A changeset records only the paths that changed relative to its first parent, each pointing at a blob hash. Commit cost depends on the size of the change, not the size of the repository. Everything else (the full file tree, blame, path history) is derived from parents when it is first asked for, then cached. Full trees are checkpointed every 64 generations, so a cold server never walks more than 64 changesets to rebuild one.
The two loops an agent runs
The biggest difference is where the retry loop runs. When two agents race to the same branch, a Git agent loses the push, fetches, rebases locally, possibly resolves a conflict, and pushes again: every turn of that loop is several Git processes plus a round trip to the remote. A Graft agent sends one request. If the branch moved, the server rebases the change in memory and retries the compare-and-swap itself, in microseconds. Only a real textual conflict comes back to the agent.
Workspaces for agents that need files
Agents that run tests need real files. graft clone --sparse src/ asks the server for the file list under the paths it needs, fetches only the blobs the machine's cache is missing, and copies them into place with copy-on-write clones where the filesystem supports it. graft commit sends small changes inline with the commit request. After a fast-forward there is nothing to fetch; after a rebase the server returns the list of paths that differ, and only those are updated.
graft add-sparse pulls more later. Committing a new file that already exists upstream outside the sparse list is refused (one of the bug-scan fixes).The experiment
Every agent owns one page of a small hash-routed web app, the Field Guide, and lands three changes in order. The first creates its page module; the other two touch files that every agent edits. Two of those shared files take insertions at sorted positions, so concurrent edits usually land on different lines. The other two take everyone's additions at the same spot, so they produce real textual conflicts in both systems.
Three backends ran the identical scripted workload: graft over the HTTP API (what MCP agents use), the graft CLI with a workspace per agent, and git with a clone per agent pushing to a local bare repository. Everything ran on one Mac with no network, which favors Git: a real remote adds round-trip time to every turn of its retry loop.
Results: scripted swarms
What agents look like, on one time axis
Each row is one agent; time runs left to right and all three panels share the same scale. Gray is the agent thinking. Everything colored is time spent in source control.
Where the time goes, per operation
Results: real Claude agents
GRAFT_TRACE on the other.Bug scan
Before the experiment, every module was read for defects, and every CLI command and MCP tool was exercised against a live server, including the error paths. Each fix below is pinned by a regression test; the suite went from 11 to 18 tests, all passing.
Method and limits
- One machine (), all processes local. Git pushed to a local bare repository and Graft ran as a separate server process; neither paid network latency.
- Scripted agents think for a uniformly random 0.4–1.6 s before each step. Real agents ran on Claude Haiku in two teams at the same time, so both teams saw the same machine load.
- Git ran with a hermetic configuration: no global config, hooks or commit signing. The Git loop is the standard agent loop: pull --rebase before editing, push, and on rejection pull --rebase again; on a rebase conflict, take upstream and re-apply.
- The Graft CLI pays roughly 100 ms of Node.js startup per command. That is most of its gap to the API path, and it widens the window in which another agent can land first.
- Both systems treat two insertions at the same line as a conflict. A union merge for append-only files (Git's
merge=union) would remove most conflicts for both, and is a natural next feature. - This is Graft, an independent implementation of ideas Anthropic published about its internal system, Scion. No Scion code or numbers are used here.
Reproduce
npm install && npm run build && npm test node dist/src/swarm/dashboard.js # live view on http://localhost:7300 swarm/run-matrix.sh 8 16 32 48 # scripted swarms, all backends node dist/src/swarm/export.js # → docs/data/results.json node docs/build-report.mjs # → docs/graft-swarm-report.html