Skip to content

Where people and agents ship software together. The open-source git platform for the whole job: issues, agents, checks and deploys to the edge.

189 linesCodeBlameRaw
1---
2title: How a request is served
3description: What happens between a request reaching g1t.sh or api.g1t.sh and its answer leaving, step by step, with the deadlines, caches, rate limits and timings along the way.
4---
5
6import Aside from "../../../components/Aside.astro";
7import Diagram from "../../../components/Diagram.astro";
8
9Two Workers answer almost everything you send g1t: the site, `apps/web`
10on `g1t.sh`, and the API, `apps/api` on `api.g1t.sh` and `mcp.g1t.sh`.
11Neither keeps data. Each works out who is asking, then calls the services
12that own the answer.
13
14## The site
15
16`apps/web/workers/app.ts` is the site's entry point. It sorts each request
17before any page code runs:
18
191. A request for `g1tusercontent.com` goes to `serveUsercontent`, which
20 never reads or sets the session cookie.
212. `go get` lookups get their meta page.
223. **git over HTTPS** (paths ending in `info/refs`, `git-upload-pack` or
23 `git-receive-pack`) passes the git rate limits, then goes to `repos`
24 whole, through `env.REPOS.fetch`. The site never parses git
25 ([Git](/architecture/git/)).
264. **Package registries** (`/v2/`, `/-/npm/`, `/-/cargo/` and the others)
27 go to `packages` whole. A 404 is tried once more under the workspace's
28 current name, so a renamed workspace's old URLs keep working.
295. Everything else passes the page rate limit and reaches React Router.
30
31### A page
32
33<Diagram name="page-request" />
34
35The root route's middleware, `viewerMiddleware` in
36`apps/web/app/lib/session.server.ts`, resolves the viewer once (steps 2
37and 3). The `g1t_session` cookie is 64 hex characters, `HttpOnly`,
38`Secure` and `SameSite=Lax`, and lasts 30 days; `identity` stores only its
39SHA-256. A request can send `Authorization: Bearer` with an access token
40that has the **website** permission instead of the cookie. The same
41middleware enforces the email confirmation, workspace and Code access
42gates.
43
44Loaders then call their services together (steps 4 to 7). They use the
45typed clients in `@g1t/contracts`, built in `app/lib/services.server.ts`,
46and pass the viewer in each call's arguments. Nothing waits on a call it
47does not need.
48
49When an in-app navigation takes more than five seconds, **Reload destination**
50opens the requested URL as a full page. It uses the pending destination,
51including its query and fragment, rather than the page still in the address bar.
52It is not offered while a form submission is still being sent.
53
54Artifacts caches completed workspace values across requests for 30 seconds;
55in-flight lookups are shared only within the request that started them. A
56document without a saved editor snapshot renders its saved text while its live
57room warms in the background, instead of holding the page response on that room.
58
59### Deadlines
60
61Each binding is wrapped by `instrumented()` in `app/lib/perf.server.ts`,
62which gives every call a deadline (`app/lib/deadline.ts`). A call that
63outlives it is aborted and throws `DeadlineExceeded`, so one slow service
64cannot hold a page forever.
65
66| Call | Deadline |
67| ---------------------------------------- | -------- |
68| A read | 15 s |
69| A write, or a read named in `SLOW_READS` | 60 s |
70| A long job, named in `LONG_CALLS` | 600 s |
71
72### Reading your own writes
73
74D1 has read replicas. The site uses D1's Sessions API with the services
75that support it (`identity`, `repos`, `work`, `search`, `billing`,
76`projects`, `deployments`) by sending an `x-d1-bookmark` header on each
77call. The latest bookmark is kept in the `g1t_d1` cookie for 5 minutes,
78and for 30 seconds after a write, reads go to the primary. You never see a
79page older than a change you just made. The service side is
80`crates/kit/src/d1.rs`; TypeScript services use
81`packages/contracts/src/d1.ts`.
82
83### The public page cache
84
85A signed-out `GET` with no cookie and no `Authorization` header, for a
86public page, can be answered from the colo's cache. It is fresh for 30
87seconds, then served stale while it refreshes in the background, for up
88to 5 minutes. Before a cached repository page is served, the site asks
89`repos` whether the repository is still public, so making it private
90takes effect at once.
91
92### Server-Timing
93
94Every page carries a `Server-Timing` header: the total, each loader, each
95service's calls and time, and the database time each service reports
96about itself (`svc`, `db` and `rpc`, from `Served` in
97`crates/kit/src/d1.rs`). A cached page says
98`cache;desc="hit, Ns old"`. Open your browser's network panel on any page
99to see where its time went.
100
101<Aside title="Where it runs">
102 Every Worker runs with placement off, in the data centre nearest the visitor. `scripts/perf/placement-probe.mjs` measures the alternative, and
103 CONTRIBUTING.md's **Speed** section has the rules this design follows: start calls together, add no round trips, and never wake a Durable Object for a read D1
104 can answer.
105</Aside>
106
107## The API and MCP
108
109`apps/api` serves both `api.g1t.sh` and `mcp.g1t.sh` from one Worker; a
110host starting `mcp.` is the MCP server. It sorts each request in this
111order (`apps/api/src/lib.rs`):
112
1131. OTLP at `/otlp/v1/*` goes to `telemetry` as it is.
1142. Requests that bring their own credentials are handled before any g1t
115 token is read: the Stripe webhook, inbound integration hooks at
116 `/hooks/<id>`, deployment build jobs, the Actions toolkit and OIDC
117 issuer, a job's artifacts, cache and brokered requests, and the runner
118 protocol at `/runners/*`.
1193. Rate limits.
1204. The token.
1215. OAuth.
1226. MCP, when the host says so.
1237. The REST routes.
124
125<Diagram name="api-request" />
126
127A token is sent as `Authorization: Bearer g1t_…` (or `token g1t_…`) and
128resolved by `identity` (step 3). A wrong or expired one gets a 401 with a
129`www-authenticate` header that points at the OAuth metadata, as RFC 9728
130describes, so an MCP client can start signing in by itself.
131
132### Scopes
133
134Scopes are written `resource:level`, and `admin` includes `write`, which
135includes `read`. They are defined in `crates/contracts/src/scopes.rs`, and
136`packages/contracts/src/scopes.ts` mirrors them. The token's scopes decide
137which operations it may call (step 5), and the MCP server lists only the
138tools those scopes allow. A workflow job's token carries the job's own,
139narrower scope.
140
141### One table for every operation
142
143`apps/api/src/operations.rs` lists every operation once. The REST routes,
144the MCP tools and the OpenAPI document at
145[`/openapi.json`](https://api.g1t.sh/openapi.json) are all generated from
146it; an operation without a description does not compile. The docs'
147[API reference](/reference/api/) is built from that document, and the
148CLI's command table from the reference, so the four cannot disagree.
149
150### snake_case at the edge
151
152Inside g1t, contracts are camelCase. The API's `reply()` turns every
153answer to snake_case on the way out (`g1t_kit::wire::snake_case`), leaving
154user-named keys such as inputs, env, secrets and headers as they were
155written. Errors keep one shape, `{"error": {"code", "message"}}`, with the
156status that the failure's code maps to.
157
158### OAuth 2.1
159
160The API is the OAuth issuer. It supports authorization code with PKCE for
161public clients only, with no client secrets, and dynamic registration at
162`POST /oauth/register`, whose client id encodes the client's name and
163redirect addresses. The person approves on the site, at
164`g1t.sh/oauth/authorize`; the token endpoint, `POST /oauth/token`, asks
165`identity` to exchange and refresh. Refresh tokens rotate.
166
167### MCP
168
169The MCP server speaks streamable HTTP with no session state: each `POST`
170gets one JSON-RPC answer. It supports protocol versions 2025-06-18,
1712025-03-26 and 2024-11-05. Its tools are resources with an `action`, as
172[MCP tools](/reference/mcp/) lists.
173
174## Rate limits
175
176Every limit is a Workers rate-limit binding, and
177`packages/contracts/src/rate-limits.ts` is the table of record: a test
178checks every `wrangler.jsonc` against it.
179
180| Where | Limit | Counted by |
181| -------------------------- | ------------------ | -------------------- |
182| The API, without a token | 60 a minute | The client's address |
183| The API, with a token | 1,000 a minute | The token, hashed |
184| REST and MCP | Counted separately | |
185| Sandbox and runner reports | Not counted | |
186
187When the limiter itself cannot answer, the request goes through: the
188limits fail open. The [rate limits page](/reference/rate-limits/) lists
189every limit you can hit.