Skip to content

Engineering · 3 min read

Project structure

How our repos are laid out: each product owns its own, its README is the map, and the map stays true.

There's no single Flagon codebase to map. Each product owns its own repo (or repos), laid out however suits it, and the team that owns the product owns the layout too. So this page isn't a map. It's the rules every map follows, so that when you land in any of our repos you know where the map is, and you can trust it.

The README is the map

Every repo's README is the source of truth for that repo. Not this handbook, not a wiki, not the person who set it up. A good README answers, in order:

  • What this is, in a sentence or two, and where it runs.
  • Where things are: a short layout, one line per top-level directory, saying what lives there.
  • How to run it, from a fresh clone (the bar for that is in developing locally).
  • How to check a change before you push it.
  • How it ships.

If a newcomer has to ask a person any of those, the README has a bug.

Group by what changes together

When pieces of a product change together, they live together, so a change that crosses them lands in one reviewable pull request instead of several that have to merge in a careful order. That usually means one repo per product, with its apps, services and shared packages side by side. When pieces don't change together, they don't need to share a repo just because the same company owns them.

Two real maps

g1t is one repo holding everything it ships, hosted on g1t itself:

apps/web          the site: server-rendered React on a Worker, holds no data
apps/docs         the documentation site, with the API explorer
apps/api          the REST API and MCP server (Rust)
services/*        identity, repos, work, events, runner: one Worker and database each
crates/*          Rust shared by the services, and the program that runs in a sandbox
packages/*        TypeScript contracts and the shared design tokens

This website is a single Next.js app, and its repo, flagon, is about as small as a map gets:

content/handbook  the handbook, one .mdx per page, grouped in folders by department
content/blog      the blog, one .mdx per post
src/app           routes
src/components    site chrome and MDX rendering
src/lib           content loaders and config

Both READMEs carry these maps, and both are more current than this page will ever be. Read the README, not this.

How to find your way in

The fastest way to understand a repo isn't to read the whole tree, it's to follow one request end to end. Pick something small and trace it: the page that renders it, the call it makes, the thing that owns the data behind that call, and back. In g1t that means a route in apps/web asking a service for something; here it means a URL resolving to an .mdx file through a loader in src/lib. One thread like that teaches you more than an afternoon of browsing, and it makes who owns the data concrete instead of abstract.

When you can't find where something goes

If a change doesn't have an obvious home, that's worth surfacing in review, not silently forcing. The usual question is which side of the data boundary it belongs on: is this logic that belongs with the thing that owns the data, or is it presentation? When that's unclear, the confusion is information.

Keeping the map true

Structure rots when nobody tends it. If you move things, update the README in the same pull request. A map that quietly stops matching the territory is worse than no map, because people trust it and get lost. Keeping it honest is part of owning what you build.