Skip to content
124 linesCodeBlameRaw

Pick any line to see why it is the way it is: the commit, the pull request and issue it came from, and what the agent was thinking.

Sidebar: the panels really slide1# Contributing to g1t
2
3g1t is built the way it asks others to build: issues and pull requests on
Fast pages, required checks on the branch, self-hosted runners, honest incidents4[g1t.sh/flagon-io/g1t](https://g1t.sh/flagon-io/g1t), required checks that prove
5a change works, and a merge queue that keeps `main` passing.
Sidebar: the panels really slide6
7## A change ships with its docs
8
9Documentation is part of the product, held to the same bar as the code.
10A pull request that changes what someone can do, see or call changes the
11docs in the same pull request:
12
13| If you change | Update |
14| --- | --- |
15| Something a person does on g1t.sh | The guide for it in `apps/docs/src/content/docs/guides/` |
Merge branch 'worktree-agent-ab2e39e11a6493412'16| An API route, a field, or an MCP tool | `apps/api/src/operations.rs` descriptions (they feed the OpenAPI document and the API reference), the example and notes for it in `apps/api/src/reference.json`, `reference/mcp.md`, and any guide that shows the call. Then refresh the docs' copy of the OpenAPI document with `G1T_WRITE_OPENAPI=1 cargo test -p g1t-api openapi`; `cargo test` fails until you do. |
g1t is one name: its agent's work, commits and comments show as @g1t, and nobody can claim g1t or g1t-agent17| How agents behave | `guides/working-with-g1t.md`, and `apps/web/public/llms.txt` |
Sidebar: the panels really slide18| Settings, limits or prices | The page that names them, and the table it is in |
19| A new feature | A section in the guide that owns it, linked from the docs home if it is a new task |
20
21The style, in short: plain sentences, second person, no marketing words,
22sentence-case headings, a numbered list for steps, a table for options, and
23every API mention with its exact route or tool name. Examples are copyable
24and real. Nothing is documented that the code does not do.
25
26Check the docs build before you push:
27
28```sh
29cd apps/docs && npm run build
30```
31
Invite-only launch: sign in with GitHub, repository access and lifecycle, many emails, a new look32## Icons
33
34- **Interface icons come from [Lucide](https://lucide.dev/icons).** In the
35 apps, import them from `lucide-react`. In the docs, use `@lucide/astro`:
36 import an icon component, or give `apps/docs/src/components/Card.astro`
37 and `Aside.astro` a Lucide name such as `icon="git-branch"`. Starlight's
38 own `<Card>`, `<LinkCard>` and `<Aside>` draw Starlight's icon set, so the
39 docs import the wrappers in `apps/docs/src/components/` instead.
40- **Brand marks come from [Simple Icons](https://simpleicons.org)**
41 (`simple-icons`), and follow each brand's own usage guidelines. Add the
42 dependency with the first one you show.
43- **The g1t logo and illustrations are our own artwork**, in
44 `apps/web/app/components/logo.tsx` and `art.tsx`.
45- Never hand-copy an icon's SVG paths into a file. If Lucide lacks the
46 icon you need, pick the closest one that it has.
47
Sidebar: the panels really slide48## Before you push
49
50- `cargo test` in the crate or service you changed.
51- `npx tsc -b --force` in `apps/web` (the incremental build misses changes
52 in `packages/contracts`).
53- Look at what you changed in a browser. Screenshots catch what type
54 checks do not.
Deploys as code: a manifest of every Worker, a deploy tool that ships only what changed in parallel stages, and a g1t Actions workflow55
56## Deploying
57
58Pushes to `main` deploy themselves: `.g1t/workflows/deploy.yml` runs
59`scripts/deploy.mjs`, which deploys only the parts that changed, migrations
60first. Every deployable part is listed in `deploy/stack.jsonc`; a new service
The docs folder is gone, and what it held lives where people read it: how a self-hosted g1t runs and how to deploy g1t to Cloudflare are pages on docs.g1t.sh under Run g1t yourself, and speed, rate limits and operating g1t.sh are sections of CONTRIBUTING.md; code that cited a file in docs/ now points to the page or section that covers it, or says what it means itself, and applied migrations and the runner images are left as they were.61or app goes there, and in the table on
62[How a self-hosted g1t runs](https://docs.g1t.sh/guides/self-hosting-architecture/#each-part)
63(`npm run test:deploy` says what is missing).
64[Deploy g1t to Cloudflare](https://docs.g1t.sh/guides/deploy-to-cloudflare/)
65covers the tool, the workflow, rollbacks, adding a unit and first-time
66setup.
67
68- **Migrations run before the code**, so the old code reads the new schema
69 for a minute or more. Add tables and columns; change what rows mean in
70 two deploys (code that reads both forms first); never drop what live code
71 still reads.
72- **The self-hosted runner** is released, not deployed: bump `version` in
73 `crates/runner/Cargo.toml`, merge, and push a `runner-v<version>` tag.
74 `.g1t/workflows/runner-release.yml` builds, signs and publishes it, and
75 runners update themselves to it. `scripts/runner-release.mjs` does the
76 same by hand.
77
78## Speed
79
80Pages are a few rounds of service calls, and each round costs a trip to
81the databases, so start calls together and add no rounds.
82
83- Every page answers with `Server-Timing`: each loader, each service's
84 calls and their database time. Look at it in DevTools when a page feels
85 slow.
86- `scripts/perf/measure.ps1` times pages from your machine (`-BrowserUA`
87 for signed-out pages as a browser sees them). A page that only reads
88 must not set the `g1t_d1` cookie: a new read-only service method goes in
89 `READS` in `apps/web/app/lib/perf.ts`.
90- Targets from the US: signed-out pages under 200 ms to first byte,
91 signed-in pages under 400 ms, streamed panels within a second.
92- Workers run without Smart Placement; `scripts/perf/placement-probe.mjs`
93 measures a placement before you pin one.
94
95## Rate limits
96
97`RATE_LIMITS` in `packages/contracts/src/rate-limits.ts` is the table of
98record, and the [rate limits page](https://docs.g1t.sh/reference/rate-limits/)
99is the public one: change both, and the binding in the Worker's
100`wrangler.jsonc`, together (`front-door-limits.test.ts` fails when they
101disagree). Limits fail open, keys hash anything secret, and each Worker
102takes its namespace ids from its own block of a hundred (41xx packages,
10342xx web, 43xx repos, 44xx api, 45xx og, 46xx status).
104
105## Operating g1t.sh
106
107For Flagon staff.
108
109- **Incidents** are declared, updated and resolved in sudo, under
110 **Platform → Incidents**, and appear on status.g1t.sh within 30 seconds.
111 Declare as soon as people are affected, and pick the higher severity
112 when unsure. SEV1 (down for most people, or data at risk) gets an update
113 at least every 30 minutes and SEV2 (a core part broken for many) at least
114 hourly; both email subscribers and need a blameless postmortem within
115 five working days.
The artifacts service is services/artifacts, the Worker g1t-artifacts, bound as ARTIFACTS by the API, the site and the agents; its live rooms move to it with a Durable Object transfer from g1t-docs-service, and its database, bucket, indexes and queue keep their names. The git store's binding and settings are GITSTORE, its ops scripts gitstore-*, and workflow run artifacts keep their compatible API under run_artifacts modules. The deploy tool puts a Worker that has never deployed before the Workers in its stage that bind to it, and the deploy guide gives the cutover runbook.116- **An Artifacts outage:** `scripts/ops/gitstore-namespaces.mjs` shows a
The docs folder is gone, and what it held lives where people read it: how a self-hosted g1t runs and how to deploy g1t to Cloudflare are pages on docs.g1t.sh under Run g1t yourself, and speed, rate limits and operating g1t.sh are sections of CONTRIBUTING.md; code that cited a file in docs/ now points to the page or section that covers it, or says what it means itself, and applied migrations and the runner images are left as they were.117 failing namespace. After 15 minutes, serve it read-only from the fallback
118 git store (`scripts/ops/restore-to-gitstore.mjs restore`, then the repos
119 Worker's secret `GIT_FALLBACK_NAMESPACES`) and open an incident. To
120 switch back, `reconcile` anything the fallback took, then delete the
121 secret. The script's header has every step.
122- **Costs and margin**, model prices, credits and the platform pause are
123 in sudo, under **Costs & margin**. The code is in `services/billing/src`
124 (`costs.rs`, `margin.rs`, `pricing.rs`, `budget.rs`, `platform.rs`).

This file's history is long; its oldest lines are credited to the oldest commit read.