# Architecture

How Switchyard is built, in enough detail to reason about what it does with your code. Everything runs on Cloudflare; the core is Apache-2.0.

## One coordinator per project

Each project has its own coordinator, a Durable Object with a SQLite database. It holds the project's history, its tasks and their plans, the warnings, the rules in force and the merge queue. Every action is written to the history before it is acknowledged, in the same transaction as the change it records; the history is the source of truth, and the older part of it is archived to R2 in chunks. A board connection is a WebSocket to the coordinator, which pushes change notices; the board reads everything else through the same API agents use.

## Git storage of its own

A project's Git data lives in Switchyard's own store: packs in R2, which are never rewritten, and the branches with the list of packs and every branch move in the project's engine object, with the moves logged by version and time. A push is stored before it is accepted: the pack is written to R2, then the branch moves in a transaction that also queues the notice to the coordinator, then the client is answered. Two pushes to the same branch cannot both win.

The engine serves Git to clones and pushes from a container that keeps a warm copy rebuilt from R2, and runs the Git operations the coordinator asks for: the merge preview of main with every task, restacks, splits and squashes, the file and code rules for conflicts, blame and diffs. It is written in Rust on jj-lib, gix and tree-sitter. Losing the container loses nothing: it is rebuilt from the store.

## The merge queue and its checks

The coordinator drives the merge queue. It builds a test build, main plus the next submitted tasks in order, and runs each check in a fresh container with the tree checked out and no credentials at all; results are kept by the hash of the tree they ran on, so a tree that passed is not run again for a day, or for the check's own cache time. A failure runs once more to rule out a flake, then the batch is split to find the task to blame, and only that task is sent back. Eight tasks are tested together, up to thirty-two while builds keep passing. Projects whose tests run on GitHub Actions can have a check wait for GitHub's result instead.

## GitHub

A project can follow a GitHub repository through the Switchyard App. GitHub holds main; a merge moves the branch on GitHub first and Switchyard's copy second. Pushes to GitHub arrive as webhooks and are routed to the project through a registry that is consulted on every event; a push that arrives in the moment between connecting a repository and the registry hearing of it is still found, through a strongly consistent record of which project follows which repository.

## Accounts

People sign in with GitHub or with an emailed link. Accounts, organizations, teams, roles, sessions and keys live in a D1 database with read replicas near the person; a revoked session is refused at once at the primary and within replication lag elsewhere. Usage is counted by the coordinator in the same write as each billable action and reported to D1 every minute.

## Agents and models

Agents reach a project three ways: plain Git with a key in a header, the `yard` CLI, and the MCP server. Conflict proposals call Anthropic directly with the organization's own key, and only when one is set; judge rules call a separate judgment service. Text written by agents is carried as data and never as instructions.

## What can fail, and what happens

- A coordinator restarts: nothing is lost, since every action was durable before it was acknowledged, and a sync or merge in flight is restarted from the record.
- An engine container dies: the store is intact; the next request rebuilds the warm copy from R2, and a push whose notice was in flight reaches the coordinator within a minute.
- GitHub is unreachable: merges on a followed repository wait; tasks keep working on Switchyard's copy.
- A project is deleted: its full record is kept for thirty days before anything is removed, and its Git data stays.

The [guarantees](/guarantees) page states these as promises with tests behind them; the [limits](/limits) page gives the numbers.
