Your conversations never leave your machine.
Not a promise — a property we enforce in continuous integration. Drift is measured locally; the only thing that ever reaches a server is your account identity. Here's the exact boundary, and how it's guaranteed.
The boundary
Stays on your device
In local SQLite. Never sent anywhere.
- Your AI conversations & prompts
- Your goal & constraints (the baseline)
- Every drift signal & score
- Re-anchor snapshots
Reaches the server
Accounts & billing (Supabase + Stripe), plus opt-in Team config.
- Your email
- Your plan
- Subscription status
- On Team, if you share: rule packs & rule counts
- No chat content. Ever.
Model calls (the relay, the optional judge) go straight to your own provider with your own key — never through a Drifterr server.
Line by line
| Data | Where it lives |
|---|---|
| Conversations & prompts | Your device (local SQLite) |
| Goal, constraints, decisions | Your device |
| Drift signals & scores | Your device |
| Re-anchor snapshots | Your device |
| Model / judge calls | Your provider, your key |
| Email, plan, subscription | Server (accounts only — and only if you sign up) |
| Shared rule packs (Team, opt-in) | Server — the rule text you wrote, e.g. "Never use any types" |
| Rule counts (Team, opt-in) | Server — a rule name and a number, nothing about what triggered it |
| Offending spans, goals, session ids, file paths, model names | Your device — never shareable, on any plan |
The app and this website are not the same thing
Worth being blunt about, because "local-first" gets used loosely: the boundary is the app binary, and it is absolute.
No analytics, no telemetry, no crash reporting, no usage counters, no heartbeat. There is no account required to run it, and with no account there is no Drifterr server in the picture at all. The 14-day Pro trial is tracked in your own local database.
On a Team plan you can share rule packs (config you wrote) and how often each rule fired. That is the whole list. No offending spans, no goal, no prompts or replies, no session ids, no file, repo or branch names, no model names, and nothing timestamped finer than a day. Rules you stated in conversation are withheld too — their ids were derived from your own messages, so publishing even the id would reveal that you said something.
Settings → Team sharing → “Show exactly what would be shared” prints the payload verbatim, plus a sentence naming what was withheld and why. Nothing uploads until you act. The boundary is enforced in three independent places: the filter that builds the payload, a database constraint that rejects anything else, and a CI test that drives a real violation through the engine and fails if any of it appears.
drifterr.app measures its own funnel — which page you landed on, which download button got clicked, which platform. It is first-party (our own /api/event, no third-party script), cookieless, carries no visitor identifier of any kind, and stores no IP or user agent. Event names and values come from a fixed allowlist, so no URL or free text is ever recorded. Do Not Track and Global Privacy Control are honored — with either set, nothing is sent.
Because we shipped unsigned builds without saying so on the download page, and had no way to see how many people hit the OS warning and gave up. Counting button clicks on a public web page is a different thing from reading your conversations — and we'd rather draw that line out loud than claim a purity we don't have.
Proven, not promised
Three invariants run on every build. If any byte of conversation were wired to leave, the build would fail.
The crates that hold or parse your conversation — engine, store, adapters, tokenizer, embeddings, intervention — have zero network dependencies. Adding one fails CI.
The proxy (relay) and the judge only ever talk to the model provider you configured — no analytics, telemetry, or Drifterr backend domain appears in their code.
A canary buried in a relayed message reaches the configured upstream and nowhere else — a decoy endpoint standing in for "anywhere else" receives nothing.
Enforced by crates/proxy/tests/egress.rs, run on every push and pull request.