Under the hood
Local-first, verifiable, and honest about it
Most privacy pages ask you to take a policy on faith. This one describes structure: what the client does by construction, what it refuses to do, and where the honest limits are. Every claim below is a mechanism, and several come with a stated cost — the same register the security page keeps.
Local by default; egress is the consented moment#
Local execution is the default. A workflow runs, a model trains, and a commit lands without any server being reachable — the platform enhances collaboration and distribution, but solo compute never requires it. No network I/O happens without explicit consent, and every granted consent is stamped into the run's provenance, so what left the device, when, and to where is a record rather than a memory. Consent itself is offline-first: granted locally, synced later, never blocking on a server.
Direction matters. A connector that pulls your own data in is a consented fetch whose bytes then simply reside on your device — still local-first. Data leaving the device is different: egress is a separate, stronger, destination-named consent, and it never rides on an ingress consent. Pulling a dataset in does not quietly authorize sending anything out — a distinction the connectors are built around.
No analytics, one allowlist#
The Studio ships zero third-party analytics — no tag, no beacon, no session replay. That is not just restraint; the browser enforces it. The production Content-Security-Policy carries a single connect-src allowlist, derived from the platform's own configuration and covered by a test: the platform API origins, plus the built-in LLM providers you can opt into with your own key. A request to any other origin is refused by the browser itself.
# Production CSP, connect-src — one derived allowlist (illustrative shape):
connect-src
'self' # the app's own origin
<platform API origins> # catalog sync + content objects
<built-in LLM providers> # only with your own key, behind a consented effect
# No analytics host. No telemetry host.
# Any other origin: the browser refuses the request before it leaves.Because the allowlist is derived rather than hand-written, adding a connect target is a deliberate code change with a failing test on the other side — not a quiet edit.
Credentials never leave the device#
Secrets you hand to a connector — API keys, OAuth tokens, SSH keys — are held client-side in an encrypted store: WebCrypto AES-256-GCM under a device-bound, non-extractable key by default. They are never synced, never placed in the sync queue, and never stamped into provenance; the machinery that replicates your work is structurally unable to carry your secrets along with it. Two OAuth flows are stored in opposite places on purpose: a third-party service token stays on your device while the platform acts only as a stateless broker during the exchange, whereas signing in to Scellis itself delegates identity to GitHub OAuth with a short-lived server-side session. Opposite threat models, opposite storage. The one named exception — a relay that must authenticate as you for protocols a browser cannot speak — is consented per connection and holds the credential only in memory.
Signed Packs, delegated identity#
A Pack is signed and verified. Import is hash-verifying — the bytes must match the content hash they claim — and signatures are checked against a registry of trusted signing keys. Trust signals are policy inputs: they inform what a workspace policy will allow, and never grant ambient capability on their own. Your signing key is an Ed25519 pair generated in the browser, and its private half never leaves the device. Combined with client-side credentials, that has an honest consequence:
Note
Lose the device and your identity survives — sign back in with GitHub OAuth on new hardware. The device-local secrets do not: connector credentials and the private signing key are re-entered and re-registered, not recovered. Nothing secret lives server-side, so nothing secret can be recovered server-side. That is a security property, stated — not an apology.
Erasure destroys a key, not history#
Sync rides on append-only surfaces — change events, run logs — and append-only is a promise you cannot quietly break. So those surfaces carry no raw personal identifiers at all: the actor reference is a salted, keyed commitment, resolvable only through a per-person key. Erasure under GDPR destroys that key. History is not rewritten — it becomes permanently unreadable as you, which is what makes an erasure guarantee compatible with an append-only log.
The honest edges#
The honest edges are written down rather than hidden. A hash of personal data is still personal data — pseudonymized, not anonymized — and the design never pretends otherwise. Records the law requires keeping are access-restricted rather than erased, expiring at their statutory retention. Content you published is kept under an anonymized author tombstone so that anything built on it does not break — and the server keeps all of it rather than guess which pieces have dependents, which is the safe direction and the honest one to state. Everything private shreds with your key; and copies already synced to someone else's device cannot be recalled. The full list lives on the honest-limits page.
Honesty in federated mode#
Scellis can train a model across many devices without moving the raw data. The tempting claim — “your data never leaves” — is exactly the kind of claim this page refuses to make loosely.
Warning
The raw dataset never leaves the device, but model updates do — and an update is a lossy, sometimes invertible function of the data. “Data never leaves” is true of the bytes and false of the information, unless differential privacy, gradient clipping, and secure aggregation are engaged.
So federated mode does not treat those as options. Sending an update is itself a consent-gated, provenance-stamped egress, and it requires accounted differential privacy with clipping, always — governed by a monotonic (ε, δ) privacy-budget ledger that refuses overspend instead of warning about it. Secure aggregation is layered on wherever cohort size and churn make it feasible; the regulated regime runs permissioned peers only. When the budget is spent, the round does not run. This is the trust boundary the distributed-compute path is built on.
Consent tiers and the caller class#
The same discipline governs who may act. Every request to the platform carries a server-derived caller class — UI, Copilot, headless, API key, login-free, or external agent — that no client can forge, and every verb is classified read, write, or destructive. Reads are auto-allowed; a write needs an explicit consent token that shows the concrete proposed operation; a destructive action needs confirmation and a rate limit. Money-moving verbs sit outside that ladder entirely: they are UI-only and refuse every non-UI caller, so no agent — yours or anyone's — can ever spend your money. How one API surface serves the UI, the Copilot, and external agents alike is the subject of the agent surface. That is the shape of the whole page: the guarantee is structural wherever it can be, and wherever it cannot be, the limit is stated in plain text.