CLI / TTY
cli.rs · cli_ui.rs
Operator shell; TTY-side pack forms, selects, confirms, input, and progress.
LOCALThe whole system on three plates: every surface and the host it reaches, the route a turn takes to a committed head, the store and engine underneath, and Spindle for Browser, which runs the same engine inside your browser.
Seven surfaces and the preview sandbox, one host boundary, one schema-20 store, and the four Dext engine crates underneath. The browser and the web app are first-class here, not side notes.
cli.rs · cli_ui.rs
Operator shell; TTY-side pack forms, selects, confirms, input, and progress.
LOCALagent.rs · api.rs
Embeddable Session API and stable JSON forms for events, messages, settings, status, and reads.
API v1api/stdio.rs
NDJSON protocol, one worker per session, 64 MiB lines, 4 MiB prompts, 32 queued steers.
STDIOserve/mod.rs · serve/v1.rs
Loopback default, optional public origin, bearer/device/API tokens, and SSE event rings.
WEBchrome/ · spindle-embed
MV3 for Chrome, Edge and Brave: side panel, offscreen engine, WASM host, OPFS, page tools, browser Linux, optional host.
0.1.7store/ui · serve
The host-served web app. Talks to the host's private /api routes and their SSE stream (not part of API v1); its service worker handles notifications, not caching.
embed/ · store/src/embedded
WASM/JS host for apps, with Node and OPFS storage and the shared protocol.
EMBEDchrome/preview.html · serve/preview.rs
Sandboxed page output, served (by the extension's service worker, or the host) under a sandbox CSP and a Connection-Allowlist, which Chrome 152+ enforces.
BROWSERserve/* · serve/connect.rs
V1 routes, pairing, Access, preview, self-edit, sync, threads, tar, disk, pack UI, and PKCE browser tokens.
agent.rs · agent/*
Prompt, steering, resume, provider catalog, durable cost ledger, host tools, app tools, pack turn boundaries.
driver.rs · driver_api.rs
Decides the next step from the committed head and commits it; sends, execution, clocks, and waits belong to the host.
broker.rs
Reserve attempt, then dispatch model, strict workspace, host tool, image, job, pack, or turn effect. No retry loop.
jobs.rs · code_mode.rs · code_http.rs
16 jobs running per process, 32 kept per session; 1,024 code calls; 64 HTTP grants; 640 KiB response ceiling.
pack_runtime.rs
Stateful Pack Runtime v1, ledger anchors, continuation accounting, promoted tools, and UI rounds.
store/src/embedded/* · embed/
Sessions an app drives: backend, code, storage, host, places, WASM JS surface, Node and OPFS adapters.
rewind.rs · ownership.rs
Execution cuts, forks, scope trees, services, waits, suspensions, epoch confirmation.
lib.rs · transition.rs
WAL + FULL, owner lock, migrations from 14–19, previous schema 19, validation watermark, provider refusals.
1M ADMITScodec.rs
Pure-Rust deflate and content-defined 4–64 KiB chunks; 16 KiB inline; every chunk checked by digest.
DEDUPartifact.rs · workspace.rs
64 MiB object cap, 16 GiB total, 50,000-file maps, 64 MiB files, immutable manifests and staging pins.
IMMUTABLEview.rs · reads.rs
Read-only query_only view, no owner lock; stable message, file, state, and rewind-target reads.
durable.rs
Temp write, fsync, rename, parent sync. Apple uses fullfsync; disk-full is an ambiguous fence.
CRASH-SAFElib.rs · durable.rs
A native open migrates schema 14–19 in place after copying the store to authority.vN.sqlite; browser stores and imports migrate 19 in one checked transaction.
spindle-reference · schema 2 · 14 operations · 8 entries per record map · 16 commits · no I/O · no live dispatch. It is not a store dependency and cannot authorize work.
View reads committed history without the owner lock; the writer remains the sole owner of the store.One checked route from transport to head; browser traffic uses the same embedded driver when it runs locally.
CLI, HTTP /v1 (the web app through /api), stdio, Rust API, the browser extension, or the embed SDK.
cli.rs · serve/v1.rs · api/stdio.rsPairing/device tokens; optional Cloudflare Access; browser PKCE connect for a host token.
serve/auth.rs · serve/access.rs · serve/connect.rsOpen the session, take the owner lock, restore the head continuation; reads use View.
agent.rs · driver.rs · view.rsDTA1 action and next state form a proposal: expected revision, workspace root, up to eight intents.
turn.rs · transition.rsSQLite checks epoch and scope revision; consume observation, append revision, write intents, move head.
lib.rs · transition.rsBroker verifies retained bindings and reserves an attempt. CommittedEffect is the dispatch ticket.
broker.rsModel transport, strict workspace, host tools, jobs, packs, granted HTTP, image read, or embedded host work.
broker.rs · embedded/host.rsReceipt adoption advances the head; rewind forks the line; jobs die with the process; pack ledger follows ancestry.
rewind.rs · view.rs · pack_runtime.rsThe illustrated host plate: API and browser gate, session/driver, schema-20 vault, codec, object silo, broker, effect yard, rewind, and the Dext engine.
CLI, HTTP, stdio, Rust API, the extension and embed share the API v1 contract; the web app talks to the host's /api. Pairing/device tokens and optional Access sit in front.
WAL + FULL, owner lock, migrations from 14–19 (a copy kept first), 32 MiB steps, one million admissions.
Proposal → revision and intents → broker attempt → effect → receipt → head. The driver sends and runs nothing itself: the host does.
The host plate shows the shared session/store/engine machine. The browser plate is a distinct local-first extension running the embedded WASM host in OPFS.
CAPABILITIES still advertises no native execution, no durable rewind, and no power-loss certification. The modules exist; the published contract stays narrower.
The browser extension is not the served web app. It is a local-first WASM Spindle running in the browser profile, beside a host-served PWA and a reusable embed package.
A standalone side panel in Chrome, Edge or Brave. A WASM host, OPFS sessions, encrypted vault, page tools, local Linux, and optional remote host.
chrome/ · chrome/dist/
Loaded from spindle serve. Uses the host's private /api and its SSE stream for a host session; its service worker handles notifications, not caching.
store/ui/
The reusable WASM/JS host package: backend, protocol, places, Node VFS and browser OPFS.
embed/ · store/src/embedded/
The side panel never holds the engine. It talks over BroadcastChannel to a dedicated worker in the offscreen document. That worker loads spindle_embed_bg.wasm, keeps sessions in OPFS, and continues running turns while the panel is closed.
Reading and acting on pages are separate switches, both off until you turn them on. Page tools are accepted only from engine.html; actions use chrome.debugger. Under Before acting (Auto or Ask), an action you allow is done only while the tab still shows the page, part or dialog the question showed you (new in 0.1.7). Provider keys, host tokens, and site secrets are sealed by AES-GCM in the vault.
preview.html is a manifest-sandboxed page with no extension APIs. The service worker serves it under the sandbox CSP and a Connection-Allowlist, which Chrome 152+ enforces for the page and every frame and worker it makes. On older Chrome a preview shows without its scripts, frames or outside links until you run it, and then runs uncontained.
A browser can connect to a running Spindle host through the PKCE /connect flow, obtaining a browser token for /v1. Local threads can move to the host; embedded threads use the browser's WASM host.
From panel input to a local OPFS session, then through the selected executor and back as events.
The side panel reads a prompt, files, page mode, vault state, and the thread's local/remote runner.
panel.html · panel.mjsBroadcastChannel carries requests and event fanout; operations serialize per thread, while turns remain in the worker.
engine-worker.mjsThe embedded host opens the thread directory on the OPFS pool and reads the committed head.
spindle_embed_bg.wasm · OPFSThe shared driver decides the next model or tool need from the committed state; the browser host performs it.
driver.rs · embedded/host.rsProvider HTTPS, local WASM Linux/v86, page tools through the service worker, or a remote host /v1.
linux-runner.mjs · page-tools.mjsThe embedded store commits the result and the worker sends the event back to every open panel.
embedded/backend.rsPreview responses come from the service worker with sandbox CSP and a restrictive Connection-Allowlist.
background.js · preview.htmlA thread can move between browser and a connected host; the host runs its own sandbox when it owns the turn.
host-moves.mjs · serve/threads.rsThe illustrated browser plate: Chrome shell, service worker, offscreen engine, WASM/OPFS, vault, page tools, preview, local Linux, providers, and remote host.
The side panel holds threads, files, settings, spend, page switches, vault state, and the local/remote runner choice.
The dedicated worker runs every thread. It loads spindle_embed_bg.wasm over OPFS and continues while the panel is closed.
Page tools go through the service worker and debugger; models use direct HTTPS; commands use local WASM Linux/v86 or an optional host.
Service-worker CSP and Connection-Allowlist contain previews where Chrome enforces the list (152+). Older Chrome shows a preview without its scripts until you run it.
Device keys are non-extractable IndexedDB keys; passphrase vaults wrap the key with AES-KW and PBKDF2-SHA-256 at 600,000 rounds. Provider, site, and host records are AES-GCM sealed.
The hard numbers behind the maps, plus the boundaries that keep the browser, host, embedded package, and engine from being confused.
SCHEMA = 20, LEGACY_SCHEMAS = [14,15,16,17,18,19], PREVIOUS_SCHEMA = 19. A native open migrates in place after copying the store to authority.vN.sqlite; browser stores and imports migrate 19 in one checked transaction. WAL and synchronous=FULL remain the store profile.
CAPABILITIES advertises transactional receipts and revision-pinned file maps, but still says no native execution, no Dext engine, no durable rewind, no power-loss certification, no backup restore. The code exists; the public contract is deliberately conservative.
The host has a shared turn driver and embedded host, reads helpers, protocol/meta/spend modules, connect and thread services, browser PKCE onboarding, and the browser extension's WASM host. The store still owns the atomic admission → revision → intent → attempt → receipt chain.
The browser extension is not spindle serve; the PWA is not the extension; spindle-reference is not a runtime; dext app is not a spindle-store dependency.
The four below describe Spindle for Browser 0.1.7. What 0.1.7 added to them: approvals held to the page, slot names a crash cannot split, imports checked from disk, a thread too large to bring back left on the host, and background tasks spared by a parent's Stop.
Before acting is Full (the default), Auto (asks before what sends or submits) or Ask (before every action). An action you allow carries what the question showed: the tab, the page's document (where Chrome says which it is; else its address), the part's description, or the dialog. The service worker checks it just before acting; if the page reloaded or moved on, nothing is done and the thread is told.
Each slot header this version writes carries a CRC-32 right after its path (in the first 512-byte sector, for paths under about 470 bytes), and every rename writes a record of itself first. A crash at any byte or sector of a header write reopens with each file whole under one of its two names and a directory never split: tested by cutting every byte and every set of sectors in a model of the storage, not a physical power-loss proof.
A thread moves between browser and host by bundle and lives in one place: sealed where it left, staged where it arrives. A host unpacks an import into a private staging directory and checks every store there, one import at a time, holding no store in memory; it says a thread's size first, and the browser leaves one over 1 GB on the host. Browser tokens see only their own threads.
A step cut off is recorded as stopped or unknown, never sent again on its own (unless the session opted in, resend_unknown): Retry sends it once, Take back returns its message. A page action interrupted mid-way is reported unknown. In a thread run in the browser, a parent's Stop leaves its background tasks running, their page actions too.
core/src/*.rsPure model wait, turn, response, and recovery decisions. No host I/O; unsafe code forbidden.
transcript/src/*.rsMessages, blocks, checkpoints, runtime, continuations, and tool results.
provider/src/*.rsCatalog, auth/OAuth, wire shaping, request contracts.
native/src/*.rsSSE, streaming, model transport, strict/host runners, jobs, cgroups, process tree, image policy.
src/main.rs + modulesFull app; not linked by spindle-store.
native/src/limits.rs, strict.rs): 64 MiB files, 2 GiB trees, 1,800 s runs, 16 jobs per process. Toolchain memory and process limits are separate from the Spindle admission model.spindle-reference remains the bounded in-memory lifecycle model: schema 2, 14 operations, 8 entries per record map, 16 commits, no live dispatch. It is not the store schema and not the browser engine.