accelerando.wiki ↗ app ↗ github

Architecture

Four layers, two runtimes, one canonical artifact.

                ┌──────────────────────────────────────────────┐
                │              THE .AGI TREE                   │
                │   data/<tenant>/<Entity>/<id>.agi            │
                │   one text file per record, RECORD blocks    │
                └──────────────────────────────────────────────┘
                         ▲                       ▲
            writes       │                       │     reads
                         │                       │
       ┌─────────────────┴─────────┐   ┌────────┴───────────────┐
       │       GitStore (TS)       │   │   Projection (TS)      │
       │  create / read / edit /   │   │  SQL read-model        │
       │  transaction(message, fn) │   │  rebuilds from tree    │
       └─────────┬─────────────────┘   └────────┬───────────────┘
                 │                              │
   StorageBackend interface           ProjectionBackend interface
                 │                              │
       ┌─────────┴─────────┐         ┌─────────┴─────────┐
       │   NodeFsBackend   │         │  SqliteBackend    │   ← local dev
       │   fs + isogit     │         │  better-sqlite3   │
       └───────────────────┘         └───────────────────┘
       ┌───────────────────┐         ┌───────────────────┐
       │    R2Backend      │         │   D1Backend       │   ← production
       │   bucket + ETags  │         │  cloudflare D1    │
       └─────────┬─────────┘         └───────────────────┘
                 │
                 │ every */15 min
                 ▼
       ┌───────────────────┐
       │  GitHubSyncer     │   ← reconciles R2 → real git
       │  Git Data API     │     commits on github.com
       └───────────────────┘

The layers

  1. The .agi tree is the canonical system of record. Every record is a text file. The directory structure encodes tenant and entity type.
  2. GitStore owns the create/read/edit/transaction API. It does not know whether it's running on Node or Workers.
  3. Backends plug into GitStore. The Node pair (NodeFsBackend + SqliteBackend) runs in tests and local dev. The Workers pair (R2Backend + D1Backend) runs in production.
  4. GitHubSyncer is the bridge from R2's commit-log entries to actual git history on GitHub, batched into one real commit every fifteen minutes via the Git Data API.

The runtime split

The same code compiles to both runtimes. The only thing that changes is which backend you construct:

// Node — used in tests and CLI scripts
const store = new GitStore({ backend: new NodeFsBackend({ root: "./data" }) });
const proj  = new Projection(new SqliteBackend("./projection.db"));

// Workers — wired inside the fetch handler
const store = new GitStore({ backend: new R2Backend({ bucket: env.AGI_TREE }) });
const proj  = new Projection(new D1Backend(env.PROJECTION));

The interface is small enough that adding a third runtime (browser? Deno? Bun?) is a hundred lines of TypeScript — see Two runtimes, one core.

The HTTP surface

The Cloudflare Worker exposes:

Every non-OPTIONS request that touches data goes through the auth check first. See Per-tenant API keys.

Why this shape

Three decisions are doing most of the work:

Each of those gets its own page in this wiki.