| 1 | --- |
| 2 | title: Services and contracts |
| 3 | description: 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 | |
| 6 | g1t deploys twenty-five units, listed once in `deploy/stack.jsonc`. Each is |
| 7 | a Worker with its own `wrangler.jsonc`, which names its database, its |
| 8 | queues and the services it calls. This page puts all of them in one |
| 9 | place. |
| 10 | |
| 11 | ## Every unit |
| 12 | |
| 13 | **Calls** lists the services each unit binds to, which are the only ones |
| 14 | it can reach. A test, `npm run test:deploy`, reads every `wrangler.jsonc` |
| 15 | and 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 | |
| 45 | Calls go both ways in places, `repos` and `work` for one. That is allowed: |
| 46 | bindings only have to respect the deploy stages, and every service is in |
| 47 | the same one ([How g1t ships](/architecture/shipping/)). |
| 48 | |
| 49 | ## A call, on the wire |
| 50 | |
| 51 | A service binding is a direct connection from one Worker to another in the |
| 52 | same data centre, with no trip over the public internet. g1t uses it as |
| 53 | plain HTTP: |
| 54 | |
| 55 | ```http |
| 56 | POST https://work/rpc/get_pull |
| 57 | content-type: application/json |
| 58 | |
| 59 | {"repo": {"namespace": "acme", "name": "app"}, "number": 12, "viewer": {"id": "usr_…", "workspaces": […], …}} |
| 60 | ``` |
| 61 | |
| 62 | The hostname is ignored; the method is the path. The arguments are that |
| 63 | method'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 | |
| 71 | or, 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 | |
| 85 | On the Rust side, `g1t_kit::call(&binding, "method", &args)` sends a call |
| 86 | and `rpc_method`, `args` and `reply` serve one (`crates/kit/src/lib.rs`). |
| 87 | On the TypeScript side, the clients in `packages/contracts/src/clients.ts` |
| 88 | do both. Two Workers expose Worker RPC entrypoints instead: `og`'s |
| 89 | `Screenshots` and `status`'s `StatusAdmin`. |
| 90 | |
| 91 | There is no secret between services. A service can be called only |
| 92 | through a binding, because none of them is published on `workers.dev` |
| 93 | and only `og` and `telemetry` have routes, for their own public endpoints. |
| 94 | That makes the binding list in each `wrangler.jsonc` the complete list of |
| 95 | who can call it. |
| 96 | |
| 97 | ## Contracts |
| 98 | |
| 99 | Services share types, never code. Each one depends on the contracts, and |
| 100 | none 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 | |
| 108 | Where the two languages must agree exactly, a Rust test reads the |
| 109 | TypeScript file and compares: the access table (`access.rs`), scopes, and |
| 110 | the shapes that have shared fixtures in JSON. Keep both in the same pull |
| 111 | request. |
| 112 | |
| 113 | ### Ids |
| 114 | |
| 115 | Ids are TypeIDs: a prefix that says what the thing is, then a UUIDv7 in |
| 116 | Crockford base32, such as `evt_01jb…` for an event or `usr_…` for a person. |
| 117 | They sort by the time they were made, and are monotonic within one process |
| 118 | and 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 | |
| 135 | 1. Make it under `services/<name>`, with its `wrangler.jsonc`: its D1 |
| 136 | database if it keeps data, and `"workers_dev": false`. |
| 137 | 2. Put its types in `crates/contracts` or `packages/contracts`, and its |
| 138 | client in `packages/contracts/src/clients.ts` if the site calls it. |
| 139 | 3. 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). |
| 142 | 4. 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)). |
| 145 | 5. Run `npm run test:deploy`. It says what is missing. |
| 146 | |
| 147 | [Deploy g1t to Cloudflare](/guides/deploy-to-cloudflare/) covers the |
| 148 | manifest's fields and a unit's first deploy. |