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.

148 linesCodeBlameRaw
1---
2title: Services and contracts
3description: Every unit g1t deploys, what each one does, what it owns and what it calls, and how a call between two services works, down to the wire.
4---
5
6g1t deploys twenty-five units, listed once in `deploy/stack.jsonc`. Each is
7a Worker with its own `wrangler.jsonc`, which names its database, its
8queues and the services it calls. This page puts all of them in one
9place.
10
11## Every unit
12
13**Calls** lists the services each unit binds to, which are the only ones
14it can reach. A test, `npm run test:deploy`, reads every `wrangler.jsonc`
15and fails if this table and the bindings disagree.
16
17| Unit | Language | Stage | What it does | Owns | Calls |
18| --- | --- | --- | --- | --- | --- |
19| `apps/web` | TypeScript | front | The site on `g1t.sh`: pages, git over HTTPS and the package registries passed to their services, and `g1tusercontent.com` | The downloads bucket | `actions`, `artifacts`, `billing`, `chat`, `deployments`, `events`, `identity`, `integrations`, `notify`, `og`, `packages`, `projects`, `repos`, `search`, `security`, `telemetry`, `webhooks`, `work` |
20| `apps/api` | Rust | edge | REST, MCP, OAuth, the runner protocol, OTLP ingest, Actions toolkit and OIDC | Nothing; writes Actions cache and artifact files | `actions`, `artifacts`, `billing`, `deployments`, `events`, `identity`, `integrations`, `packages`, `projects`, `repos`, `runner`, `search`, `security`, `telemetry`, `webhooks`, `work` |
21| `apps/status` | TypeScript | edge | `status.g1t.sh`: probes every minute and keeps incidents | D1 `g1t-status` | `billing`, `repos` |
22| `apps/sudo` | TypeScript | front | g1t.sh's staff console, behind Cloudflare Access | Nothing | `actions`, `billing`, `events`, `identity`, `projects`, `status`, `telemetry` |
23| `apps/docs` | Astro | front | `docs.g1t.sh`, these pages | Nothing | none |
24| `services/identity` | Rust | core | Accounts, sessions, workspaces, members, teams, repository roles, tokens, OAuth, device sign-in, 2FA | D1 `g1t`, the avatars KV | `artifacts`, `billing`, `chat`, `events`, `notify`, `projects`, `repos` |
25| `services/repos` | Rust | core | Repositories and git: smart HTTP, pre-receive checks, caches, forks, landing merges, releases, backups | D1 `g1t-repos`, the git store, the git cache KV, the packs and backups buckets | `billing`, `events`, `identity`, `security`, `work` |
26| `services/work` | Rust | core | Issues, pull requests, comments, reviews, labels, milestones, rulesets, checks, statuses, CODEOWNERS, the merge queue | D1 `g1t-work` | `actions`, `events`, `identity`, `repos` |
27| `services/events` | Rust | core | The event bus and log, the audit log, the inbox | D1 `g1t-events`, the `g1t-events` queue and its subscriber queues | `billing`, `identity`, `notify`, `repos`, `work` |
28| `services/actions` | Rust | core | Workflows: reading them, triggering runs, planning jobs, secrets, self-hosted runners, logs | D1 `g1t-actions`; lists and expires the Actions cache bucket | `billing`, `deployments`, `events`, `identity`, `notify`, `projects`, `repos`, `runner`, `work` |
29| `services/runner` | TypeScript | core | Sandboxes on Cloudflare Containers, one per job, with their egress | The Container classes | `actions`, `billing`, `deployments`, `events`, `identity`, `repos`, `work` |
30| `services/deployments` | TypeScript | core | Builds and serves apps on `g1t.page`, previews, custom domains | D1 `g1t-deployments`, the domains KV, the dispatch namespace | `actions`, `billing`, `events`, `identity`, `og`, `projects`, `repos`, `runner`, `telemetry`, `work` |
31| `services/pages` | TypeScript | edge | The dispatcher for `*.g1t.page` and custom domains | Nothing; reads the domains KV | none |
32| `services/packages` | Rust | core | npm, Cargo, Composer, Maven, NuGet, RubyGems, Go and container images | D1 `g1t-packages`, the packages bucket | `billing`, `events`, `identity`, `repos` |
33| `services/security` | Rust | core | Secret scanning, dependency alerts and updates, code scanning, the supply chain | D1 `g1t-security` | `actions`, `billing`, `events`, `identity`, `repos`, `runner`, `work` |
34| `services/search` | Rust | core | Site search over repositories, issues, pull requests, people and code | D1 `g1t-search`, its jobs queue | `billing`, `identity`, `repos`, `work` |
35| `services/projects` | TypeScript | core | Projects and what they depend on | D1 `g1t-projects` | `deployments`, `events`, `identity`, `og`, `packages`, `repos` |
36| `services/chat` | TypeScript | core | Channels, direct messages and threads, live | D1 `g1t-chat`, a Durable Object per channel | `identity`, `integrations`, `notify` |
37| `services/artifacts` | TypeScript | core | Docs written together, live, with their spaces, sharing and search | D1 `g1t-docs`, its files bucket, two Vectorize indexes, a Durable Object per open doc | `billing`, `events`, `identity`, `notify`, `repos`, `work` |
38| `services/notify` | TypeScript | core | Notifications, live pages, presence, browser and phone push | A Durable Object per person, per workspace and per repository | `identity` |
39| `services/telemetry` | TypeScript | core | Logs, traces, metrics and errors for projects, at `otel.g1t.sh` | A Durable Object per project | `billing` |
40| `services/billing` | Rust | core | Usage, holds and settlements, limits, Stripe | D1 `g1t-billing` | `identity`, `packages`, `repos` |
41| `services/integrations` | Rust | core | Model providers, alert sources, issue trackers, the GitHub App, Ask g1t | D1 `g1t-integrations` | `identity`, `projects`, `repos`, `work` |
42| `services/webhooks` | Rust | core | Webhook subscriptions and signed deliveries with retries | D1 `g1t-webhooks` | `identity`, `repos` |
43| `services/og` | TypeScript | core | Social cards and page screenshots, at `og.g1t.sh` | The screenshots bucket | `billing`, `identity`, `projects`, `repos`, `work` |
44
45Calls go both ways in places, `repos` and `work` for one. That is allowed:
46bindings only have to respect the deploy stages, and every service is in
47the same one ([How g1t ships](/architecture/shipping/)).
48
49## A call, on the wire
50
51A service binding is a direct connection from one Worker to another in the
52same data centre, with no trip over the public internet. g1t uses it as
53plain HTTP:
54
55```http
56POST https://work/rpc/get_pull
57content-type: application/json
58
59{"repo": {"namespace": "acme", "name": "app"}, "number": 12, "viewer": {"id": "usr_…", "workspaces": […], …}}
60```
61
62The hostname is ignored; the method is the path. The arguments are that
63method's struct in the contracts, here `ViewArgs` in
64`crates/contracts/src/work.rs`. `viewer` is the person or token asking, or
65`null` for someone signed out. The answer is always JSON:
66
67```json
68{ "ok": true, "value": { … } }
69```
70
71or, for anything the caller should handle, still with status 200:
72
73```json
74{ "ok": false, "error": { "code": "not_found", "message": "No pull request #12." } }
75```
76
77| Status | Means | The caller gets |
78| --- | --- | --- |
79| 200 with `ok: true` | It worked | The value |
80| 200 with `ok: false` | An expected failure, with a code from `FailureCode` | A value to handle, such as `Result` in TypeScript or `Outcome` in Rust |
81| 404 | No such method | An error |
82| 503 | A store is busy, with `Retry-After` | An error |
83| 500 | Something threw | An error |
84
85On the Rust side, `g1t_kit::call(&binding, "method", &args)` sends a call
86and `rpc_method`, `args` and `reply` serve one (`crates/kit/src/lib.rs`).
87On the TypeScript side, the clients in `packages/contracts/src/clients.ts`
88do both. Two Workers expose Worker RPC entrypoints instead: `og`'s
89`Screenshots` and `status`'s `StatusAdmin`.
90
91There is no secret between services. A service can be called only
92through a binding, because none of them is published on `workers.dev`
93and only `og` and `telemetry` have routes, for their own public endpoints.
94That makes the binding list in each `wrangler.jsonc` the complete list of
95who can call it.
96
97## Contracts
98
99Services share types, never code. Each one depends on the contracts, and
100none on another service's crate or package.
101
102| Package | Holds |
103| --- | --- |
104| `crates/contracts` (`g1t-contracts`) | A module per service with its data and its methods' arguments; `Outcome` and `Failure`; the event envelope and every event's data; `ROUTES`, which says which events each subscriber queue gets; `access`, the access rules every service compiles in; `scopes`; ids |
105| `packages/contracts` (`@g1t/contracts`) | The same for TypeScript: each service's API type (`IdentityApi`, `ReposApi`, …), typed clients, `Result` and `FailureCode`, events, scopes, rate limits, the D1 session helper. TypeScript source, with no build step. |
106| `crates/kit` (`g1t-kit`) | Plumbing for Rust Workers: the call protocol, D1 sessions and `Server-Timing` (`d1.rs`), rate limits that fail open, billing's platform pause, the snake_case converter, and handlers every service shares for renames, transfers and deletions |
107
108Where the two languages must agree exactly, a Rust test reads the
109TypeScript file and compares: the access table (`access.rs`), scopes, and
110the shapes that have shared fixtures in JSON. Keep both in the same pull
111request.
112
113### Ids
114
115Ids are TypeIDs: a prefix that says what the thing is, then a UUIDv7 in
116Crockford base32, such as `evt_01jb…` for an event or `usr_…` for a person.
117They sort by the time they were made, and are monotonic within one process
118and millisecond (`crates/contracts/src/ids.rs`).
119
120## Shared crates
121
122| Crate | What it is |
123| --- | --- |
124| `crates/rules` | The rulesets engine, with no I/O: which rules apply to a ref, and whether a push or a merge passes them |
125| `crates/scan` | Detectors for secrets, a git pack reader, lockfiles, OSV, the dependency graph, SPDX and SARIF |
126| `crates/secrets` | `Sealer`, AES-256-GCM with the row's id as associated data, and HMAC signatures |
127| `crates/blobstore` | The `BlobStore` port, with R2 and S3 adapters |
128| `crates/actions` | Workflow syntax, expressions, filters, matrices and cron, with no I/O, used by both the `actions` service and the sandbox |
129| `crates/runner` | `g1t-runner`, the binary every sandbox and self-hosted runner runs |
130| `crates/g1t` | [The g1t CLI](/guides/cli/) |
131| `crates/sshd` | An SSH front end for git, not deployed yet |
132
133## Adding a service
134
1351. Make it under `services/<name>`, with its `wrangler.jsonc`: its D1
136 database if it keeps data, and `"workers_dev": false`.
1372. Put its types in `crates/contracts` or `packages/contracts`, and its
138 client in `packages/contracts/src/clients.ts` if the site calls it.
1393. Add it to `deploy/stack.jsonc` with its kind, stage, secrets and
140 `self_host`, then to the table above and to [How a self-hosted g1t
141 runs](/guides/self-hosting-architecture/#each-part).
1424. If it reacts to events, give it a `g1t-events-<name>` queue and a
143 `SUBSCRIBER_*` binding on `events`, and add its event types to `ROUTES`
144 ([Events](/architecture/events/#subscriber-queues)).
1455. Run `npm run test:deploy`. It says what is missing.
146
147[Deploy g1t to Cloudflare](/guides/deploy-to-cloudflare/) covers the
148manifest's fields and a unit's first deploy.