g1t/apps/docs/src/content/docs/about/open-letter-to-cloudflare.md

150 lines7,588 bytesCodeBlame
1---
2title: An open letter to Cloudflare
3description: From the team at Flagon, Inc. building g1t, a git platform that runs entirely on Cloudflare. What works, where we hit walls, and what we'd ask for.
4---
5
6Dear Cloudflare,
7
8We're the small team at Flagon, Inc. building g1t, a git platform where
9people and coding agents work in the same issues, pull requests and merge
10queue. Every part of it runs on you: about twenty Workers, a D1 database for
11each service that keeps data, Artifacts for every repository and every pull
12request's fork, Containers for agents and CI, R2, KV, Queues, and Cloudflare
13for SaaS for our customers' domains. We have no servers.
14
15This is a thank-you, and a list of what would help us most next.
16
17## Why we built on you
18
19A git platform is usually a fleet: storage nodes, a job system, a database
20cluster, a CDN in front, and people on call for all of it. We wanted to run
21one for thousands of teams with a handful of people. You offered a global
22platform where the unit of work is a request, the unit of storage is a
23Durable Object, and nothing costs money while nobody is using it.
24
25Artifacts is the reason g1t exists in this shape. One Durable Object per
26repository is the right isolation unit: a busy repository doesn't slow its
27neighbours, and there is nothing to shard by hand. It speaks real git, so
28stock clients cloned, fetched and pushed through our proxy from the first
29day. `fork()` is a single call, and per-pull-request isolation for agents
30fell out of it almost for free. Scoped tokens that expire on their own let
31us hand a sandbox a credential that dies with it. The read binding powers
32every page we render, blame, mergeability and search, without a git client
33anywhere.
34
35The rest of the platform held up too. Rust compiled to WebAssembly runs most of
36our services, and TypeScript the rest. D1's read replication is free and good. Containers gave us
37sandboxes in three sizes. With a cached credential and ref listing, a
38`git fetch` with nothing new answers in under half a second, and most of
39our pages answer in under 250 ms. We went from an empty repository to a
40launch on this stack, and most of it worked the first time.
41
42## Where we hit walls
43
44Running a real platform for many teams found the edges. None of these
45stopped us. Each one costs us code, latency or certainty, and each one will
46cost the next team building on you the same.
47
48**What a billable operation is.** Artifacts pricing names "repo operations,
49such as create, push, pull, and clone", and the metrics list a different set
50of event names. Neither says whether binding reads, token mints or ref
51listings count. We price from cost, so this decides what our customers pay.
52Depending on the answer, our model for a few thousand workspaces lands
53anywhere between about $1.8k and $31k a month. Today we count every clone,
54fetch and push ourselves, and hope it matches.
55
56**What a fork stores.** Forks are the natural primitive for a pull request,
57and agents open pull requests by the thousand. We can't find whether a fork
58shares objects with its source or copies them. If it copies, an agent-heavy
59account reaches the 1 TB account limit in days (it can be raised on
60request, but only by asking), and at that point every push
61in the account fails, for every customer at once. We keep forks for now,
62and are measuring it ourselves.
63
64**A write path and a pre-receive hook.** The binding reads, but it can't
65list refs, move them, or write objects. So to land a pull request we speak
66git's wire protocol to our own storage from inside a Worker, buffering packs
67in an isolate with 128 MB to share. With no hook before refs move, branch
68protection and secret scanning only hold for pushes through our proxy, which
69parses each pack in WebAssembly before forwarding it, up to the size an
70isolate can hold. We wrote a second
71implementation of git's pack format to get there.
72
73**Ref-change events and the cost of a credential.** Push events need one
74subscription per repository, which doesn't scale to tens of thousands of
75repositories and forks. We record ref changes ourselves, and a test scans
76our own source to make sure every code path that moves a ref says so. Every
77git credential takes three binding calls and about 0.8 s to mint, so we
78cache sealed tokens across isolates in KV.
79
80**Placement that follows data.** Smart Placement once ran our site in
81Amsterdam for a visitor in Denver, while every D1 primary we have is in
82western North America. Every query crossed the Atlantic, and our Explore
83page took 0.85 s instead of 0.17 s. We turned placement off everywhere and
84measure each Worker by hand.
85
86**D1 sessions across service bindings.** Read replicas need a bookmark to
87give read-your-writes. Our site reads from seven services, each with its
88own database, so we built a header protocol to carry bookmarks through service
89bindings into a cookie and back.
90
91**Containers that build images and keep disks.** We found no supported way
92to run Docker or BuildKit in a Container, so our own CI can't rebuild our
93sandbox image; that waits for a machine outside. Container disk is
94ephemeral, so the self-hostable git store we'd like as a warm fallback has
95to live off Cloudflare.
96
97**Inbound TCP for SSH.** Git users expect `git@host:owner/repo`. Workers
98take no inbound TCP, so g1t is HTTPS only. We've applied for the beta and
99are waiting.
100
101## What we built in the meantime
102
103A per-workspace operation counter that is our best guess at your invoice. A
104smart HTTP
105client inside a Worker for landing, catch-up, mirrors and imports. Our own
106push policy in front of Artifacts. A versioned ref cache with a test that
107guards it. Two layers of credential caching. A bookmark protocol for D1.
108A probe that deploys throwaway Workers to measure placement, and a
109`Server-Timing` header on every response so we see the next regression.
110Image builds on a laptop.
111
112All of it works. Most of it is code we'd happily delete. Next is a fork
113sweep, to switch on once we know what forks cost.
114
115## What we're asking for
116
1171. A published definition of a billable Artifacts operation, with
118 per-repository metrics that use the same names as the invoice.
1192. Documented fork storage, an expiry on `fork()`, a repository's stored
120 bytes in `info()`, and a warning before the account storage limit, with
121 failures per repository rather than account-wide.
1223. Ref listing, atomic compare-and-swap ref updates and streaming pack
123 writes in the binding.
1244. A pre-receive hook that a Worker answers.
1255. Account-level ref-change events to a Queue, a read-after-write guarantee
126 for refs, and git forwarding authenticated by the binding, with no token
127 to mint.
1286. Placement that accounts for D1 primaries and service bindings, and D1 as
129 a placement target.
1307. D1 sessions that travel across service bindings.
1318. Image builds and persistent volumes for Containers.
1329. Inbound TCP, so git can run over SSH.
13310. A support path during the beta, snapshot restore and export for
134 repositories, and a date for general availability with an SLA.
135
136## Let's work on it together
137
138We chose you on purpose, and we'd choose you again. A small team running a
139global git platform with no servers is the promise of what you've built,
140and g1t shows that it mostly holds. We'd like to help close the
141rest of the gap: traces, test repositories, early builds to try, or a call
142with the teams involved. Whatever is useful.
143
144You can reach us through [g1t.sh](https://g1t.sh/support). Our code lives
145at [g1t.sh/flagon-io/g1t](https://g1t.sh/flagon-io/g1t), on the platform
146it describes.
147
148With thanks,
149
150The team at Flagon, Inc.