Architecture
How g1t ships
The monorepo's layout, how each kind of unit is built, how a push to main becomes a staged deploy on g1t's own Actions, the tests that guard it, and how this section stays true.
g1t is built on g1t. Its source is at g1t.sh/flagon-io/g1t, every change is a pull request with required checks, and its own workflows deploy it.
The repository
Section titled “The repository”| Folder | Holds |
|---|---|
apps/ |
What people open: web (the site), api, status, sudo, docs, and the desktop (Tauri) and mobile (Expo) apps |
services/ |
The services, one folder each, with their wrangler.jsonc and migrations |
crates/ |
Shared Rust: contracts, kit, rules, scan, secrets, blobstore, actions, the runner binary and the g1t CLI |
packages/ |
Shared TypeScript: contracts and theme (the design tokens) |
deploy/ |
stack.jsonc, the inventory; self-host, the Docker Compose installation; runner and sandbox, the self-hosted runner’s images |
scripts/ |
deploy.mjs and its helpers, releases, operations |
plugins/ |
The Claude Code plugin, and setup for other coding agents |
.g1t/workflows/ |
CI, deploys and releases, run by g1t Actions |
conformance/ |
Checks that a job’s environment matches what workflows expect |
Building
Section titled “Building”deploy/stack.jsonc gives each unit a kind, and each kind builds its own
way:
| Kind | Built by | Units |
|---|---|---|
rust-worker |
scripts/build-rust-worker.mjs: worker-build to WebAssembly, then wasm-opt |
The Rust services and apps/api |
ts-worker |
Wrangler’s bundler | The TypeScript services |
react-router |
vite build, then Wrangler |
apps/web, apps/sudo |
astro |
astro build |
apps/docs |
The runner’s image is built in two layers: a large base with every
toolchain, rebuilt only when its folder changes and recorded in
services/runner/base.json, and a thin layer on top with the static
g1t-runner binary.
Deploying
Section titled “Deploying”A push to main starts .g1t/workflows/deploy.yml, one run at a time,
never cancelled:
- Check and plan. The manifest is checked against every config and
npm run test:deployruns. Beside it,scripts/deploy.mjs planworks out which units changed since the commit each one is running. - Migrations. Every pending D1 migration, before any code.
- Core, edge, front. The units in each stage deploy in parallel; a stage starts only when the one before succeeded. A unit binds only to units in its own stage or an earlier one, which a test checks, so new code never calls a service that has not shipped yet.
- Smoke.
scripts/ops/smoke.mjschecks that sign-in and sign-up still work, without making an account.
Each run is one production deployment, shown on the commit as the
deploy / production status. Only units whose inputs changed are
deployed: their folder, or a crate or package they are built from, which
deploy.mjs reads from Cargo’s and npm’s workspace metadata.
Deploy g1t to Cloudflare covers the
tool, rollbacks and a first deploy.
Tests that guard the architecture
Section titled “Tests that guard the architecture”Some of what this section describes is enforced by tests, so a change that breaks it fails CI:
| Test | Fails when |
|---|---|
npm run test:deploy |
A unit is missing from stack.jsonc, a binding crosses stages the wrong way, a unit is missing from How a self-hosted g1t runs, or Services and contracts disagrees with a wrangler.jsonc |
cargo test -p g1t-contracts |
The Rust and TypeScript access rules or scopes differ |
cargo test -p g1t-api openapi |
The docs’ copy of the OpenAPI document is out of date |
app/lib/front-door-limits.test.ts in apps/web |
A wrangler.jsonc and packages/contracts/src/rate-limits.ts disagree |
npm test in apps/docs |
A diagram’s arrow names a box that does not exist, two boxes overlap, or a label does not fit its box |
CI (.g1t/workflows/ci.yml) runs the Rust tests, the TypeScript checks and
tests, and builds the site, sudo and these docs on every pull request.
Keeping this section true
Section titled “Keeping this section true”These pages describe the code on main. When you change how g1t is put
together, change them in the same pull request:
| If you change | Update |
|---|---|
| A service’s bindings, storage or job | Its row in Services and contracts and Data and storage |
| A request’s path, a limit or a deadline | How a request is served |
| An event type or a route to a subscriber | Events |
| The push, fetch or merge path | Git and Work and the merge queue |
| Sandboxes, runners or egress | Actions, runners and sandboxes |
| A new dependency on a Cloudflare product | Its port in Data and storage |
Diagrams are data, in apps/docs/src/diagrams/architecture.ts. Change the
spec, and both the picture and the page’s Markdown copy change with it.