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 slide | 1 | # Contributing to g1t |
| 2 | ||
| 3 | g1t 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 incidents | 4 | [g1t.sh/flagon-io/g1t](https://g1t.sh/flagon-io/g1t), required checks that prove |
| 5 | a change works, and a merge queue that keeps `main` passing. | |
| Sidebar: the panels really slide | 6 | |
| 7 | ## A change ships with its docs | |
| 8 | ||
| 9 | Documentation is part of the product, held to the same bar as the code. | |
| 10 | A pull request that changes what someone can do, see or call changes the | |
| 11 | docs 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-agent | 17 | | How agents behave | `guides/working-with-g1t.md`, and `apps/web/public/llms.txt` | |
| Sidebar: the panels really slide | 18 | | 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 | ||
| 21 | The style, in short: plain sentences, second person, no marketing words, | |
| 22 | sentence-case headings, a numbered list for steps, a table for options, and | |
| 23 | every API mention with its exact route or tool name. Examples are copyable | |
| 24 | and real. Nothing is documented that the code does not do. | |
| 25 | ||
| 26 | Check the docs build before you push: | |
| 27 | ||
| 28 | ```sh | |
| 29 | cd apps/docs && npm run build | |
| 30 | ``` | |
| 31 | ||
| Invite-only launch: sign in with GitHub, repository access and lifecycle, many emails, a new look | 32 | ## 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 slide | 48 | ## 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 workflow | 55 | |
| 56 | ## Deploying | |
| 57 | ||
| 58 | Pushes to `main` deploy themselves: `.g1t/workflows/deploy.yml` runs | |
| 59 | `scripts/deploy.mjs`, which deploys only the parts that changed, migrations | |
| 60 | first. 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. | 61 | or 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/) | |
| 65 | covers the tool, the workflow, rollbacks, adding a unit and first-time | |
| 66 | setup. | |
| 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 | ||
| 80 | Pages are a few rounds of service calls, and each round costs a trip to | |
| 81 | the 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 | |
| 98 | record, and the [rate limits page](https://docs.g1t.sh/reference/rate-limits/) | |
| 99 | is the public one: change both, and the binding in the Worker's | |
| 100 | `wrangler.jsonc`, together (`front-door-limits.test.ts` fails when they | |
| 101 | disagree). Limits fail open, keys hash anything secret, and each Worker | |
| 102 | takes its namespace ids from its own block of a hundred (41xx packages, | |
| 103 | 42xx web, 43xx repos, 44xx api, 45xx og, 46xx status). | |
| 104 | ||
| 105 | ## Operating g1t.sh | |
| 106 | ||
| 107 | For 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.