Skip to content

Architecture

How g1t is put together, from the four public Workers at the edge to the nineteen services behind them, the event bus that connects them, and the platform each one runs on.

g1t is a set of small programs, each with one job, that run on Cloudflare Workers. A few face the internet. Almost all the rest can be reached only by the Workers that are bound to them. Every service that keeps data keeps it in its own database, and services learn what happened elsewhere from events instead of calling each other to find out.

This section is for developers: people building on g1t, contributing to it, or running it themselves. It names the files, bindings and limits that decide how g1t behaves, so you can read the code next to it.

g1t at a glance: clients reach four public Workers, which reach the core services through service bindingsDiagram: g1t at a glance: clients reach four public Workers, which reach the core services through service bindings - Clients: Browsers and apps (site, desktop, phone); git (clone, fetch, push); Coding agents, CLI (REST, MCP, OAuth); Self-hosted runners (outbound HTTPS only); Visitors to your apps (.g1t.page, your domains) - Edge: the public Workers: Site (apps/web · g1t.sh); Status (apps/status); API and MCP (apps/api); Pages (services/pages) - Core services: reached through service bindings: identity (Rust); repos (Rust); work (Rust); events (Rust · the bus); actions (Rust); runner (TypeScript · sandboxes); deployments (TypeScript); packages (Rust); security (Rust); search (Rust); projects (TypeScript); chat (TypeScript); artifacts (TypeScript); notify (TypeScript); telemetry (TypeScript); billing (Rust); integrations (Rust); webhooks (Rust); og (TypeScript · cards) - Platform: Cloudflare’s primitives, each behind a port: D1 (a database each); Durable Objects (live rooms); Queues (the event bus); R2 and KV (packs, packages, files); Artifacts (git repositories); Containers (one sandbox per job) Arrows: - Browsers and apps → Site: HTTPS - git → Site: smart HTTP - Coding agents, CLI → API and MCP: REST, MCP - Self-hosted runners → API and MCP: long poll - Visitors to your apps → Pages - Site → Core services: reached through service bindings: POST /rpc/<method> - API and MCP → Core services: reached through service bindings: POST /rpc/<method> - Core services: reached through service bindings → Platform: Cloudflare’s primitives, each behind a port: bindingsClientsEdge: the public WorkersCore services: reached through service bindingsPlatform: Cloudflare’s primitives, each behind a portBrowsers and appssite, desktop, phonegitclone, fetch, pushCoding agents, CLIREST, MCP, OAuthSelf-hosted runnersoutbound HTTPS onlyVisitors to your apps*.g1t.page, your domainsSiteapps/web · g1t.shStatusapps/statusAPI and MCPapps/apiPagesservices/pagesidentityRustreposRustworkRusteventsRust · the busactionsRustrunnerTypeScript · sandboxesdeploymentsTypeScriptpackagesRustsecurityRustsearchRustprojectsTypeScriptchatTypeScriptartifactsTypeScriptnotifyTypeScripttelemetryTypeScriptbillingRustintegrationsRustwebhooksRustogTypeScript · cardsD1a database eachDurable Objectslive roomsQueuesthe event busR2 and KVpacks, packages, filesArtifactsgit repositoriesContainersone sandbox per jobHTTPSsmart HTTPREST, MCPlong pollPOST /rpc/<method>POST /rpc/<method>bindings
g1t at a glance: clients reach four public Workers, which reach the core services through service bindings
g1t at a glance: clients reach four public Workers, which reach the core services through service bindings
g1t at a glance: clients reach four public Workers, which reach the core services through service bindingsDiagram: g1t at a glance: clients reach four public Workers, which reach the core services through service bindings - Clients: Browsers and apps (site, desktop, phone); git (clone, fetch, push); Coding agents, CLI (REST, MCP, OAuth); Self-hosted runners (outbound HTTPS only); Visitors to your apps (.g1t.page, your domains) - Edge: the public Workers: Site (apps/web · g1t.sh); Status (apps/status); API and MCP (apps/api); Pages (services/pages) - Core services: reached through service bindings: identity (Rust); repos (Rust); work (Rust); events (Rust · the bus); actions (Rust); runner (TypeScript · sandboxes); deployments (TypeScript); packages (Rust); security (Rust); search (Rust); projects (TypeScript); chat (TypeScript); artifacts (TypeScript); notify (TypeScript); telemetry (TypeScript); billing (Rust); integrations (Rust); webhooks (Rust); og (TypeScript · cards) - Platform: Cloudflare’s primitives, each behind a port: D1 (a database each); Durable Objects (live rooms); Queues (the event bus); R2 and KV (packs, packages, files); Artifacts (git repositories); Containers (one sandbox per job) Arrows: - Browsers and apps → Site: HTTPS - git → Site: smart HTTP - Coding agents, CLI → API and MCP: REST, MCP - Self-hosted runners → API and MCP: long poll - Visitors to your apps → Pages - Site → Core services: reached through service bindings: POST /rpc/<method> - API and MCP → Core services: reached through service bindings: POST /rpc/<method> - Core services: reached through service bindings → Platform: Cloudflare’s primitives, each behind a port: bindingsClientsEdge: the public WorkersCore services: reached through service bindingsPlatform: Cloudflare’s primitives, each behind a portBrowsers and appssite, desktop, phonegitclone, fetch, pushCoding agents, CLIREST, MCP, OAuthSelf-hosted runnersoutbound HTTPS onlyVisitors to your apps*.g1t.page, your domainsSiteapps/web · g1t.shStatusapps/statusAPI and MCPapps/apiPagesservices/pagesidentityRustreposRustworkRusteventsRust · the busactionsRustrunnerTypeScript · sandboxesdeploymentsTypeScriptpackagesRustsecurityRustsearchRustprojectsTypeScriptchatTypeScriptartifactsTypeScriptnotifyTypeScripttelemetryTypeScriptbillingRustintegrationsRustwebhooksRustogTypeScript · cardsD1a database eachDurable Objectslive roomsQueuesthe event busR2 and KVpacks, packages, filesArtifactsgit repositoriesContainersone sandbox per jobHTTPSsmart HTTPREST, MCPlong pollPOST /rpc/<method>POST /rpc/<method>bindings
Layer What is in it Reached by
Clients Browsers, the desktop and phone apps, git, the CLI, coding agents, self-hosted runners, and visitors to apps deployed on g1t. The internet
Edge Four Workers with public routes: the site (apps/web), the API and MCP server (apps/api), the status page (apps/status) and the app dispatcher (services/pages). Their hostnames
Core Nineteen services, each a Worker with workers_dev off. Seventeen have no route at all; telemetry takes OTLP at otel.g1t.sh and og draws social cards at og.g1t.sh. Service bindings from the Workers that name them
Platform D1, Durable Objects, Queues, R2, KV, Artifacts for git, and Containers for sandboxes. The one service that owns each, through its bindings

The edge does three things: it works out who is asking, enforces rate limits, and turns a request into calls to the services that own the answer. It keeps no state of its own. The services do the work and own the data.

Hostname Worker Serves
g1t.sh g1t (apps/web) The site, git over HTTPS, and the package registries, which it passes whole to repos and packages
g1tusercontent.com g1t (apps/web) Raw files, avatars and attachments, on a domain that never sees the session cookie
api.g1t.sh, mcp.g1t.sh g1t-api (apps/api) The REST API, the MCP server, OAuth, the runner protocol, and OTLP
*.g1t.page and custom domains g1t-pages (services/pages) Apps deployed on g1t
otel.g1t.sh g1t-telemetry OpenTelemetry from your software
status.g1t.sh g1t-status (apps/status) The status page, with a database of its own so it answers when the rest does not
docs.g1t.sh g1t-docs (apps/docs) These pages

sudo.g1t.sh, g1t’s staff console, sits behind Cloudflare Access and is not part of what you can call.

Three rules shape the code:

  • A service owns its data. Each of the sixteen D1 databases is bound by exactly one Worker. To read another service’s data, you call that service. Three stores are deliberately shared, each with one writer: the avatars KV, the custom domains KV, and the Actions cache bucket (Data and storage).
  • Calls are for answers; events are for news. When the site needs a pull request, it calls work. When a push lands, repos does not call the dozen services that care: it publishes git.push, and each of them gets its own copy on its own queue (Events).
  • The viewer travels with the call. The edge resolves the person or token once, and passes the result to every service in the call’s arguments. Each service decides access itself with the same rules, compiled in, rather than asking identity again (Identity and access).

A call is an HTTP request over a service binding: POST /rpc/<method> with a JSON body. An expected failure, such as “not found” or “not allowed”, comes back as a value, { "ok": false, "error": { "code", "message" } }, with status 200. Only something unexpected, a thrown error or a busy store, becomes a non-200 status (Services and contracts).

The services that hold accounts, repositories, work, events, money and the API are written in Rust, compiled to WebAssembly with worker-build. The web apps and the services built around Durable Objects and live rooms are TypeScript.

Rust TypeScript
identity, repos, work, events, actions, packages, security, search, billing, integrations, webhooks, and apps/api runner, deployments, projects, chat, artifacts, notify, telemetry, og, pages, and apps/web, apps/sudo, apps/status

Both sides share their types through contracts: crates/contracts in Rust and packages/contracts in TypeScript. Where the two must agree exactly, such as the access rules and the scopes, a Rust test reads the TypeScript file and fails if they differ.

The same source runs on g1t.sh and in a self-hosted installation. Each Cloudflare product a service uses sits behind a port, and the self-hosted build binds an open adapter in its place: bare repositories served by git http-backend for Artifacts, any S3 store for R2, Mailpit for email. The service code does not change. Data and storage shows each one.