The Forge Comes Home
On June 23rd, every merge in our organization stopped for several hours. Nothing had crashed. No disk had filled, no test had failed. A billing setting had tripped on someone else’s computer, and until a human noticed and fixed it, an autonomous fleet that ships around the clock sat with its hands folded. Today we moved our monorepo’s source of truth onto our own disk.
We build a local-first database. The pitch, compressed: your data should live on hardware you control, and anything else is a courtesy someone extends to you until they don’t. It took an outage to notice how selectively we’d been applying our own thesis. The company’s most valuable data — the repository, every line we’ve ever written — lived entirely on a rented forge, behind an account, behind a billing page.
A single point of someone else
A hosted forge is a fine landlord until you notice how much you’ve moved in. Ours held the code, yes — but also the merge queue, the CI, the release pipeline, and therefore the tempo of the whole operation. Our development loop is run by agents; they open pull requests, prove them, and merge them at all hours (the loop, the gate). Every one of those motions was routed through a single external service. The June freeze wasn’t even hostile — it was a spending limit doing its job, as we’d earned. That’s what made it clarifying. Availability wasn’t the vendor’s promise to us; it was coupled to a setting, and the setting outranked the fleet.
Repositories are data too
The local-first argument doesn’t have a carve-out for git. A repository is the most carefully curated dataset a software company owns; hosting it exclusively on someone else’s machine is the same wager we tell users not to make with their notes and their photos. The honest version of our thesis had to include the forge: hot on our own disk, mirrored outward as a courtesy — not the other way around.
Hybrid, not heroic
The move itself was deliberately boring. A self-hosted forge — Forgejo, a single small binary with a SQLite database, installed from Homebrew, listening only on localhost — now holds the monorepo as its source of truth. The agents open and merge pull requests there, over the loopback interface, against hardware in the room. No account. No billing page. No one else’s maintenance window.
GitHub was not fired; it was demoted. Once a day the forge pushes the monorepo back out to it, so the mirror stays warm and everything downstream that keys off the hosted copy — dependent repos, deploy workflows — keeps firing exactly as before. Every other repository stayed put: GitHub remains their source of truth, and the forge pulls them hourly so a complete copy of the org sits on disk regardless. The whole arrangement is reversible in an afternoon, which is precisely what let us do it in an evening. A cutover you can undo is a cutover you can start.
Migrating the work in flight was less drama than the phrase “forge migration” suggests. Twenty pull requests were open at cutover. We closed each on GitHub with a forwarding note and recreated it on the forge — same branch, same title, same body. The branches were already there; a PR is just a pointer with opinions. Within the hour, sixteen of the twenty had been driven to merge on the new forge by the same loop that would have driven them on the old one. The fleet, to its credit, did not notice it had emigrated.
What the mirror ate
One lesson, paid for the honest way. A push mirror does not add your changes to the target — it makes the target match the source, deletions included. Our first sync ran while a few hundred branches existed only on the target, and the mirror did exactly what a mirror does: reflected their absence. Most were long-merged stubble we wanted gone anyway; a handful were live, and we spent an hour fishing tips back out of closed-PR refs. Parity-check both sides before the first sync — the mirror’s definition of tidy is total.
A second, quieter one: if your history is squash-merged, “is this branch merged into main” is unanswerable by ancestry — the tip was never an ancestor of anything. Staleness lives in the PR record, not the commit graph. Ask the ledger, not the tree.
What we deliberately left unsolved
The forge does not run CI yet. The runner is being stood up now, and until it’s in place the merge gate is the fleet running the test suites locally before landing — the same proof obligations, enforced by discipline instead of machinery. We’d rather ship the honest interim than pretend the cutover included a piece it didn’t. The gap is a card on the board with a dependency chain, not a surprise for a future incident writeup.
The larger point stands without it. The outage that motivated all this was nobody’s villainy — just the ordinary physics of building on machines you don’t own. Your database should sit on your disk. So, it turns out, should your forge.
Built with Brain and Kanban — open-source apps on LastDB — inside our autonomous build loop.