Architecture
How Bowline keeps your code folder everywhere using a local Rust daemon, a cloud control plane, and an encrypted byte store you never have to manage.
Bowline is a local engine with a thin cloud behind it. A Rust daemon on each machine does the real work: encryption, hashing, hydration, and conflict resolution. The cloud is split into a control plane that holds metadata and a byte store that holds encrypted packs. Everything sensitive is encrypted on your machine before it leaves, so the cloud never sees your plaintext. This page explains how the pieces fit so you understand what's happening underneath, even though you never have to manage any of it.
Overview
Bowline runs as a background daemon on every Authorized Device. The daemon is the engine: it watches ~/Code, captures changes, encrypts them, and reconciles them against what other machines and agents have done. The cloud exists only to coordinate and to store encrypted bytes.
The cloud has two distinct planes, plus a separate web surface:
- The Cloud Control Plane holds metadata, decisions, and pointers. It runs on hosted Convex.
- The Byte Plane holds immutable encrypted packs and manifests. It runs on Cloudflare R2.
- The Web Runtime runs your account, billing, and status surfaces. It is not the sync engine.
Nothing in the cloud holds your plaintext code or environment values. The daemon encrypts everything sensitive client-side before upload, so the control plane and byte plane only ever handle ciphertext and metadata.
The local daemon
The daemon is where sync correctness lives. It owns local encryption, content hashing, chunking, hydration, filesystem reconciliation, conflict detection, and Automatic Merge decisions. When you edit a file, the daemon coalesces the raw filesystem events into a settled version, hashes the content, encrypts it, packs it, and proposes a new Workspace Head. When another machine advances the head, the daemon imports those changes and merges what it safely can.
The daemon talks to the cloud only through one product-shaped Rust boundary, the ControlPlaneClient. Raw Convex schema names, function names, and document shapes must not spread through the local sync code. That boundary keeps the filesystem semantics independent of the cloud provider, so the control plane can change underneath without touching how sync behaves.
The CLI and TUI never talk to the cloud directly. They talk to the daemon over a local Unix socket, and the daemon is the single authority on state. The same socket serves editor plugins and agents, so every surface reads one consistent, event-backed view of your workspace.
Under the hood, the daemon uses Rust and Tokio for the async runtime, SQLite in WAL mode for local metadata and the locator cache, BLAKE3 for content identity, whole-file hashing for ordinary source files, and FastCDC-style chunking only for large files where whole-file hashing is wasteful.
When you save a file, the write path runs entirely on your machine before the cloud is involved:
- Coalesce the noisy editor and watcher events into one settled version.
- Hash the content and skip anything whose Content ID already exists.
- Pack and compress the new content, then seal it with authenticated encryption.
- Upload the immutable encrypted packs and the snapshot manifest to the Byte Plane.
- Commit the object metadata and propose the ref advance through the
ControlPlaneClient.
If the compare-and-swap fails because another writer moved first, the uploaded packs are left unreferenced and garbage-collected later, so a lost race never corrupts anything.
Namespace Projection
Namespace Projection is the mounted ~/Code view. It shows you the full workspace tree before every byte is local, so a fresh machine looks complete almost immediately instead of waiting on a long download. The directory structure, project layout, and file names are there first; the bytes follow.
Cold files hydrate on touch. The first time you open a file that isn't local yet, the daemon resolves its location, issues a signed range read for that one record, decrypts and verifies it, and caches it. Hot projects, the ones you're actively working in, behave like boring local directories because aggressive local caching and background prefetch keep their bytes warm. Running cd ~/Code/foo && pnpm dev sees ordinary files at the ordinary path.
A Projection Backend is the OS-specific filesystem adapter behind this view. It's invisible to you and preserves the same ~/Code contract on every operating system. You never select a backend or a sync mode; the right one for your platform is already in use.
The Cloud Control Plane
The Cloud Control Plane is hosted Convex. It owns metadata, status, and decisions, never code bytes. Its job is to coordinate machines and to hold the small, authoritative records that say what the current state of a workspace is.
The control plane owns:
- accounts, workspaces, and device records
- Device Approval Requests and encrypted device grants
- Recovery Key envelopes
- workspace refs and machine refs
- policies, env records, and env restrictions
- agent leases
- compact events and status
- manifest and object pointers
Ref advancement uses compare-and-swap, so exactly one writer wins a race and the other gets a clean stale-ref result to retry. Reactive queries return compact status and event pointers, not the full workspace tree, which keeps the control plane fast and cheap. It coordinates approvals and grants without ever holding plaintext workspace keys.
What the control plane deliberately does not do matters as much as what it does. It does not store raw file bytes, bulk manifests, chunk contents, or index packs, and it does not proxy bulk byte transfer. Those live in the Byte Plane, and the daemon moves them to and from R2 directly over signed URLs.
The Byte Plane
The Byte Plane is Cloudflare R2. It stores immutable encrypted byte packs and encrypted manifests, and nothing else. There is no plaintext code in R2, and there is never one object per source file.
A source path never maps directly to an R2 object key. Instead, a path maps to a Content ID, a workspace-scoped keyed BLAKE3 identity for the normalized file bytes:
path -> contentId -> packId + offset + lengthA Pack Locator then maps a Content ID to packId + offset + length inside an encrypted manifest and the local SQLite locator cache. Keyed hashing gives deduplication inside a workspace without creating a cross-user content oracle:
contentId = BLAKE3_keyed(workspace_content_key, normalized_bytes)R2 object keys must not leak project paths, filenames, repo names, env filenames, or your directory structure. Keys live under random-looking, workspace-scoped prefixes:
/v1/ws/<workspace-id>/manifests/<manifest-id>.bowlinem
/v1/ws/<workspace-id>/packs/<pack-prefix>/<pack-id>.bowlinepBecause identity is a keyed hash and object names are workspace-scoped, the byte store can't tell that two users have the same dependency, and it can't reconstruct your folder layout from object keys alone.
The Web Runtime
The Web Runtime is TanStack Start on Cloudflare Workers. It powers your account, billing, dashboard, support, and status surfaces. It is not the sync engine, and it is not the product center.
The dashboard exists for the workflows that are awkward in a terminal, such as managing billing or viewing account-level status. It does not compute sync truth, launch conflict repair, accept Resolution Overlays, or replace the headless CLI and TUI path. Sync correctness stays in the daemon; the web surface only reads and presents.
Encryption and privacy
Encryption happens on your machine, before anything is uploaded. The daemon seals source packs, index packs, and snapshot manifests with authenticated encryption using a fresh nonce per envelope. The control plane and the byte plane only ever see ciphertext, hashes, sizes, and pointers.
Device trust is built the same way. When you approve a new device, an existing Authorized Device wraps the workspace key material for the new device's public key and uploads only that encrypted grant. The cloud coordinates the request but never receives plaintext workspace keys. Account sign-in proves your identity; it does not release decryption access on its own.
Important
The Cloud Control Plane and the Byte Plane never see your plaintext code or environment values. If you lose every Authorized Device and your Recovery Key, Bowline can recover your account through your identity provider, but it cannot decrypt that workspace's data. There is no default server-side key escrow.
What this means for you
The machinery above is deliberately invisible. In practice:
- Your code and environment values are end-to-end encrypted, sealed on your machine before upload.
- The cloud can't read your code, can't reconstruct your folder layout, and can't tell two users apart by content.
- A new machine shows the full
~/Codetree right away and fills in bytes as you touch them. - A lost write race is harmless: nothing is overwritten, and the daemon retries against the current head.
- You never pick a backend, manage packs, copy keys, or move env files. The daemon does all of it.
Components at a glance
Each layer has one clear responsibility and one technology behind it. You interact with the daemon through the CLI, TUI, and ~/Code; the rest stays underneath.
| Layer | Responsibility | Technology |
|---|---|---|
| Daemon | Local encryption, hashing, chunking, hydration, filesystem reconciliation, conflict detection, and Automatic Merge | Rust, Tokio, SQLite WAL, BLAKE3 |
| Namespace Projection | Presents the full ~/Code tree before bytes are local and hydrates files on touch | OS-specific Projection Backend |
| Cloud Control Plane | Metadata, status, device trust, refs, policies, env records, leases, events, and object pointers | Hosted Convex |
| Byte Plane | Immutable encrypted byte packs and encrypted manifests only | Cloudflare R2 |
| Web Runtime | Account, billing, dashboard, support, and status surfaces | TanStack Start on Cloudflare Workers |
Next steps
- Workspace model: how Workspace Snapshots and the Workspace Head define your project state.
- Sync and continuity: how edits become snapshots and how Automatic Merge advances the head.
- Device trust: how a new machine earns workspace decryption access.
- Environment sync: how project env follows your machines and agents.
- Status and health: how the daemon's event-backed status surfaces in the CLI and TUI.
- CLI overview: the commands you use to drive the daemon.