Under the hood
The database replaces the filesystem
Most scientific tooling lives on a filesystem: an install directory, an environment of packages, a folder of scripts whose exact versions nobody quite remembers. Scellis removes that layer. There is no install directory — every block, op, kernel, model, workflow, and viewer is a catalog entity, delivered from a database at runtime and cached on your machine. This article is about that spine, and why one delivery path, hash identity, and a strict split between truth and delivery make the work durable and shareable. The engine reads it; nothing else does.
One source, one path#
At runtime, every catalog entity is fetched exclusively from the database — the local database in your browser, the cloud database on the platform. The compiled app bundles no catalog: no static JSON, no baked-in block list, no file fallback quietly aging in the app bundle. If you can use it, it came through the database. The strictness is the point: two sources of truth always drift, and “which copy am I actually running?” is a question scientific work cannot afford. One path also means every entity — built-in or user-authored — passes through the same visibility, trust, and sync machinery on its way to you, which is why freshly published content can hot-plug into a running session with no app update.
Four conceptual layers#
Underneath, the spine is four layers, each with a different mutability rule. Write-once Objects are large immutable bytes stored under a content hash. Mutable References are the human-facing names — “the current version of this workflow” — that point at objects. Append-only Events are the sync log: nothing is ever rewritten, only appended. And Derived views — search indexes, catalog listings — are rebuildable projections that can always be thrown away and recomputed. Knowing which layer a thing lives in tells you exactly what can change about it and what never can.
Identity is a hash#
The object layer is content-addressed. Large immutable bytes — weights, datasets, compiled implementations — are stored under the SHA-256 hash of their content, and bytes at a hash never change. A cached blob that fails verification is not treated as stale; it is treated as corruption and refetched. Around those objects, published entities are immutable by version: a semantic change is a new version, and versions coexist.
{
"block_id": "user/normalize",
"version": 2,
"spec_hash": "3f61c0a94b7e58d2…" // the machine's name for the bytes
}Two names for one entity#
A catalog row names an entity twice: once for humans (id plus version) and once for machines (the hash of its content). The name is for finding; the hash is what the machine trusts. Together they make a hard promise: nothing you built on can be rewritten underneath you. When someone improves a block you depend on, that ships as a new version — the one you pinned still resolves to exactly the bytes it always did. This is the same hash identity that makes a run reproducible.
Git is truth; the database is delivery#
For the built-in catalog, the source of truth is not the database at all — it is a git repository of specs. A delivery pipeline reads those specs, compiles implementations into content-addressed blobs, and writes rows and objects into the database, idempotently: run it twice and you get the same state. For built-in content, the database is pure delivery — never a second author. That split keeps recovery boring — the built-in catalog can always be reconstituted from git, exactly — and it keeps the platform honest about equality: from the database onward, built-in content travels the same road as anything a user publishes. One catalog, one path, no privileged side door for the maintainers' own content.
On demand, never wholesale#
The catalog is designed to grow past a million user-authored entities, so “fetch everything” cannot be the model. What lives on your machine is partitioned deliberately into two tiers:
- Guaranteed-local: the engine plus everything you have used, installed, or pinned — including the full transitive closure of every saved workflow and model. Hash-verified, durable, and runnable network-unplugged forever.
- Discovery: the rest of the global catalog. Browsing and searching it — in the Marketplace — requires the network; individual entities are fetched on demand, the moment you need them.
Use is what promotes content: opening, running, forking, or installing something pulls it — and everything it depends on — into your local working set. Before a workflow saves, its full closure is guaranteed local, which is why a saved workflow always runs offline. Demand-fetching is confined to browsing and authoring time; it never sits on the run path. Your local footprint is bounded by your own activity, not by how large the global catalog grows.
Offline-first writes that sync in the background#
Reads come from the local database; so do writes. Every mutation applies optimistically to your local store first and syncs to the platform in the background through a sync queue — you never wait on a round-trip to keep working. When two people change the same shared entity, the conflict surfaces explicitly, offering accept-server, rebase, or merge. Silent last-write-wins on shared content is treated as an anti-pattern, not a convenience: the platform would rather ask than quietly discard someone's edit.
Bootstrap once, then offline indefinitely#
Your first visit is the one moment the network is required: a bootstrap of a few seconds populates the local database with a minimal working set — the engine, your own and installed content, and the closure of anything you open. From then on, everything you have runs fully offline, indefinitely. This is not a degraded offline mode; it is the same engine reading the same local database it always reads. Only discovery of new global content needs a connection, and offline search says so plainly, degrading to a clearly labelled index of what you already have.
Note
Failure is loud by design. Opening a workflow offline whose dependencies you never fetched fails with the exact list of missing content — never by silently dropping a node or substituting a “nearest” version.
You collaborate on a draft; you cite a commit#
Sharing rides directly on hash identity. A shared link names the content-addressed artifacts of a commit — the program, the weights, the dataset — so wherever it is opened, it resolves the identical bytes, hash-verified on arrival. That is what reproducible by URL means here: the artifacts themselves are identical everywhere. The last piece is deliberate — a live collaborative session is never hashed. While you and others edit together, the draft is a moving thing, and pretending otherwise would poison every link that pointed at it. When the work is worth citing you commit it, and that commit is the immutable artifact a link resolves. You collaborate on a draft; you cite a commit — a citation in Scellis never points at a moving target.