Kite AI
Architecture v2 · design note
Proposal · not shipped · supersedes the app ⇄ repo model when accepted

One team. One laptop.
The UI just looks at it.

The current architecture is website-centric: one Kite app, one linked repo, explicit sync endpoints, drafts and state baked into our database. This note proposes the opposite center of gravity: the team. Every team gets exactly one sandbox — the team's laptop in our cloud — where all drafts and the codebase live under plain git, and every operation happens on that laptop, nowhere else. The web UI becomes what Conductor is to a fleet of agents: a visualiser of a machine that is already the truth, not a second copy of it.

The core principle
The UI is a view layer over the sandbox — and every operation is delegated to the sandbox.
Nothing else holds state, nothing else does work. If the UI ever computes, stores or syncs something itself, that's a bug in the architecture. Throughout this page, laptop = the team's sandbox: one machine per team, in our cloud.
01

The problem I'm facing

Three symptoms, one disease. Each new capability in v1 costs a disproportionate amount of plumbing, and the plumbing exists only to keep multiple copies of state agreeing with each other.

Symptom 1

Every feature is machinery

Sync, Pull, import, drafts — each shipped as an endpoint + queue + retries + UI state. Adding one user-visible operation costs a week of boilerplate before it delivers any product value.

Symptom 2

Three copies of one truth

The database, the app and the repo each hold state, and our sync code arbitrates between them. Drift and consistency bugs are a standing tax that grows with every new surface.

Symptom 3

Built around the wrong unit

v1 is shaped around a website. Customers now work as a team with agents — many drafts, one codebase, shared context. We keep bending the old shape instead of changing it.

⏱ Observed first-hand
On our current EFS-backed storage, a single git status took ~10 seconds. One command, one repo, no real load. A network filesystem under every team's working set doesn't just make v1 slow — EFS will take us down. The laptop model puts each team's repo on the laptop's own local disk, where git is designed to run: milliseconds, not tens of seconds.
02

Why change at all

One reason, three faces: complexity. We built boilerplate to control operations we can now simply ask an LLM to perform — and the LLM is easier to steer than our own orchestration code is to maintain.

Focus shifted

Website → team

Before, the unit of everything was a website. Now the unit is a team doing work — many drafts, one codebase, shared context. The architecture should be shaped like the new unit, not the old one.

Control inverted

LLM steers better than we do

Every operation we hard-coded (sync, pull, import, replace) is a workflow the agent can run itself with a prompt and a shell. Prompting an LLM is cheaper and more adaptable than maintaining bespoke endpoints.

State duplicated

One laptop, one truth

Today state lives in the database and in the repo and in the app — kept consistent by sync code. One laptop with git on it makes the filesystem the only truth; consistency stops being our job.

03

The model

The mental model is Conductor: agents work on real machines; the UI is a window onto them. Here the machine is the team's laptop — one sandbox per team — and Kite's web app is the window. Reads are views. Writes are prompts. Every operation happens on the laptop — no ceremony calls routed around it, no state mirrored out of it.

Web UI · stateless
The visualiser
  • Renders what the laptop has, live
  • Draft list = git branches
  • File tree & preview = laptop FS
  • History = git log
  • Stores nothing of its own
Sandbox · one per team
The team's laptop
  • The codebase, a plain git repo on local disk
  • All drafts = branches / worktrees
  • The agent with a real shell
  • git operations run here, natively
  • Builds, previews, dev servers run here
Database · shrinks to pointers

Only routing & identity: team → laptop, members, billing. No drafts, no code, no site state baked in. If the row and the laptop disagree, the laptop is right.

GitHub · a remote, nothing more

The laptop's repo has customer GitHub as an ordinary git remote. Push/pull is the agent running git push / git pull — not a product feature with its own endpoints.

04

How things are served

Four paths cover the whole product, and all four end on the team's laptop. Reads translate a URL into a git command on the laptop and stream the answer back untouched. The preview is a reverse-proxy to a dev server already running there. Changes and sync are prompts the agent executes with a shell. The database appears in none of them.

BROWSER KITE UI · STATELESS TEAM LAPTOP · THE TRUTH what the user touches translate & proxy · stores nothing agent · shell · git — where everything runs PATH 1 · READ — DRAFTS · FILES · DIFFS · HISTORY Open the team drafts · files · history GET /t/:team/… URL → git command no DB lookup · no cache exec on the team's laptop git answers git for-each-ref refs/heads/draft/* git show draft/pricing:app/page.tsx git diff main...draft/pricing streamed back as-is — the UI shows exactly what git said PATH 2 · PREVIEW — A RUNNING DRAFT Preview iframe pricing--team-a .preview.kite.ai Reverse-proxy only subdomain → laptop port nothing rendered on our side Dev server per draft worktree :3001 → draft/hero-copy :3002 → draft/pricing HTML + hot-reload streamed live from the team's laptop PATH 3 · CHANGE — A PROMPT, NOT AN ENDPOINT Chat “make the hero bolder” Forward the prompt no business logic here Agent works on the branch edit app/hero.tsx git commit -m "bolder hero" no write-back to any DB — the commit is the new state · UI re-reads via PATH 1 PATH 4 · SYNC — GITHUB IS JUST A REMOTE Chat “push pricing to github” Forward the prompt still no endpoint, no queue Agent runs git git push origin draft/pricing-page (pull works the same way, in reverse) Customer GitHub an ordinary git remote — not a product feature not on any path above: the database — it stores pointers (team → laptop), never content. nothing to serve, nothing to drift.
05

Request → response, in 3D

The same architecture as a live stack — drag it to rotate, scroll or pinch to zoom, double-click to reset. The panel on the right walks one concrete request through the layers, in sync with the falling packet: the browser asks for the drafts list, the UI translates it to a git command, the team's laptop executes it on local disk — and the response climbs back up the other side, untouched. The database isn't a layer in the stack; it stands beside it, holding pointers.

TEAM LAPTOP · THE TRUTH exec: git · agent · :3001
KITE UI · STATELESS URL → git · subdomain → port
BROWSER GET /t/team/… · a prompt
DATABASE team → laptop ✗ never consulted — pointers only
BROWSER — asks
KITE UI — translates · stores nothing
TEAM LAPTOP — executes · the truth
DATABASE — pointers only
EXAMPLE · A GIT REQUEST, SERVED — ON LOOP
01GET /t/acme/draftsthe browser asks — a plain URL, no payload
02→ git for-each-ref refs/heads/draft/*Kite UI translates the URL — no DB, no cache
03exec on local disk · ~4 msthe team laptop runs git natively (EFS today: ~10 s)
04⇡ ["hero-copy", "pricing"] · as-isstreamed back untouched — the drafts list renders
request ↓ response ↑ · as-is
drag — rotate · scroll / pinch — zoom · double-click — reset
06

Three principles

P1

One team, one laptop — everything in git

A team's laptop — one dedicated sandbox — holds the codebase and every draft, versioned by plain git on local disk. A draft is not a database row; it's a branch (or worktree) in the team's repo. Creating, comparing, merging and discarding drafts are all operations git already does perfectly — we stop re-implementing them.

team/ ├── repo/ # the codebase · git │ ├── main # the live site │ ├── draft/hero-copy │ └── draft/pricing-page └── (agent + shell + toolchain)
P2

The UI serves what the laptop has — nothing baked in a database

The web app reads the team's laptop and renders it, the way Conductor renders a workspace. Draft list, file contents, diff views, history — all derived live from git and the filesystem, never cached into our database as a second copy. The database keeps pointers (team → laptop) and identity, and that's all.

This is also the discipline on the write path: no unnecessary operation goes through extra layers. The UI doesn't proxy work through a backend that mirrors state — reads are direct views; every real operation (agent runs, git, builds) executes on the laptop.

P3

More prompting, less boilerplate

Operations we shipped as product machinery become prompts to an agent that has a shell. Git operations happen on the laptop: "sync to GitHub" is the agent running git push; "pull latest" is git pull; "import that repo" is git clone plus a stack check the agent performs by reading the project. The product defines intent and guardrails; the LLM executes.

before: POST /apps/:id/sync-to-github (endpoint, queue, retries, UI state) after: "push the pricing draft to github" → agent: git push origin draft/pricing-page
07

What this replaces

Concretely, against the shipped v1 model:

Concern
v1 · today
v2 · this proposal
Unit of the product
A website (Kite app)
A team and its laptop
Where drafts live
App state, backed by our DB
Git branches on the team's laptop
Where the code lives
Kite app + linked GitHub repo, kept in sync — on EFS
One repo on the laptop's local disk; GitHub is just a remote
Sync with GitHub
Explicit product feature: Sync to GitHub / Pull endpoints
The agent runs git push / git pull on the laptop
What the DB stores
Apps, drafts, sync state, site metadata
Pointers only: team → laptop, members, billing
What the UI is
The workspace itself — edit, preview, publish in-app
A visualiser of the laptop, Conductor-style
New operations cost
New endpoint + queue + UI state per operation
Mostly a new prompt, sometimes a guardrail
08

What it costs — the honest cons

This is not free. The trade-offs, stated plainly so the decision is made with open eyes:

AvailabilitySingle point of failure
One laptop per team means its death is a team-wide outage. v1 degrades gracefully; this doesn't — recovery speed is unproven.
Persisted disk + git remotes as cold recovery (§09). Must be designed and drilled before rollout (§10).
CostAlways-on compute per team
A machine per team costs more than database rows. Idle teams keep a laptop powered on for nothing.
Pause idle laptops to a filesystem-only snapshot, wake on first request (§09). Still needs a cost model.
LatencyReads become execs
Every read is a command on a remote box, not an indexed query. List views may get slower, and cross-team search and analytics lose their central store.
Local-disk git already beats today's 10-second EFS git status (§01); add ephemeral caches as views (never truth) and emit events for analytics.
PredictabilityPrompts are less deterministic
Endpoints do the same thing every time; agents don't. The same ask can take different paths on different days.
Guardrails on destructive ops + a full audit log of every shell and git action the agent takes.
SecurityBigger blast radius
An agent with a shell, repo write access and (today, undecided) secrets on the same laptop. One compromise reaches everything the team has.
Per-team isolation, scoped GitHub tokens, secrets design resolved before any external team (§10).
09

How laptops sleep & wake

Two of the cons above are named but not mechanised: idle laptops cost compute (§08) and a dead laptop is a team outage (§08 → §10). E2B's filesystem-only snapshots give the mechanism — and they fit this model almost by definition.

A sandbox can pause two ways. A full snapshot also freezes RAM and running processes so it resumes instantly. A filesystem-only snapshot (pause({ keepMemory: false })) keeps only the disk: the box reboots from disk on resume — files survive, processes don't. Because P1 already declares the filesystem the only truth, throwing RAM away costs us nothing: the dev server, agent runtime and shell are all reconstructible by rebooting and re-running. The mode whose only downside is "processes die" is free here — and it's cheaper to store and quicker to pause than a full memory snapshot.

Aspect
Full snapshot
Filesystem-only · what we use
Disk (the git repo & drafts)
Preserved
Preserved
RAM & running processes
Frozen & restored
Discarded — reboots from disk
Resume
Instant restore
Reboot, reconnect, re-start services
Cost to pause / store
~4s per GB RAM; stores the RAM
Cheaper — no RAM to store
Retention while paused
Kept indefinitely — no TTL
Kept indefinitely — disk waits for the next request

The lifecycle, end to end:

idle > timeout → onTimeout: pause(keepMemory:false) # compute billing stops; disk persists first request → DB pointer team→laptop → Sandbox.connect(id) → reboot from disk → re-start git/agent/dev-server → serve recovery → replacement laptop boots the persisted disk; git remote is the real backstop

Idle cost — the "hibernate idle laptops" mitigation, made real

Set lifecycle: { onTimeout: { action: 'pause', keepMemory: false } }. An idle team's laptop pauses to disk after the timeout and stops billing compute; the disk is kept indefinitely. The cost model collapses from always-on compute per team to idle disk + a cold-start budget.

!

Cold start is now on the first read

Resume is a reboot, not an instant restore, so the first request after idle pays boot + service-start on top of the exec. Mitigation: pre-warm on intentconnect() the laptop when the user opens the app, before they ask for the drafts list, so the reboot overlaps their attention. Boot-to-first-git status on a team-sized repo is a number the pilot must measure.

!

A snapshot is not a backup

Pausing keeps the disk indefinitely, but it's still single-copy on E2B's infra — pause/resume, not a durable, multi-region backup. It cuts how often we cold-rebuild; it does not by itself answer §10. Git remotes remain the real recovery layer, and reboot-from-disk pushes secrets toward inject-at-boot (nothing in RAM survives), which is the cleaner answer to §10 anyway.

10

Open — explicitly not designed yet

Two things this note deliberately does not answer. Both must be resolved before v2 is more than a direction.

⚠ Note · unresolved

The laptop dies — how do we resync fast?

If the whole team's state lives on one machine, that machine's death is the whole team's outage. §09 covers the planned pause/wake path; unplanned death and hard recovery are still not drilled.

A filesystem-only snapshot persists the disk (§09), but it's single-copy — so git remotes remain the real backstop if E2B loses the snapshot. Cold-start time, volume locking and partial-write corruption on reboot-from-disk are all still unexamined.

⚠ Note · unresolved

Managing secrets

v1 keeps secrets in the vault, in the database. If nothing is baked in the DB and the laptop is the truth, where do env vars and credentials live — on the laptop's disk (then they die and leak with it), injected at boot from a vault we still run, or something else? Reboot-from-disk (§09) tilts this toward inject-at-boot, since nothing in RAM survives a wake anyway.

Also unanswered: keeping secrets out of git in a world where the agent freely commits, and scoping them per-draft vs per-team.

For the CTO & the team · the ask

Agree the direction. Prove it small.

The bet is a single inversion: stop mirroring the world into our database and start pointing the UI at the world. One team, one laptop, git as the state model, prompts as the operation model. Everything we delete — sync endpoints, draft tables, consistency code — is bought with the risks in §08 and the two unknowns in §10. I'm not asking to rewrite the product; I'm asking to run the experiment that tells us whether we can.

The ask

Green-light a pilot: one internal team behind a flag. v1 stays untouched and remains the default. Two-week spike first, focused only on the §10 unknowns — recovery and secrets.

Prove before rollout

A kill-the-laptop drill recovers in minutes with zero data loss; wake-from-snapshot boot-to-first-git status stays inside the read budget (§09); the secrets design passes security review; local-disk reads beat today's EFS numbers for a team-sized repo.

If it holds

We delete the sync endpoints, draft tables and consistency code — and every future operation ships as a prompt plus a guardrail, not a service. That's the payoff: v2 is mostly deletion.