Architecture · Technical deep dive

How Haven is built.

Haven is a desktop agent that finds the sensitive things you forgot you had — passwords in old emails, tax returns shared with the whole internet, ID scans in forgotten folders — and fixes them with one reversible click. It was designed backwards from a single constraint: your content must never leave your device to be protected. This page is the full technical picture — every machine, every model, every byte that crosses a wire.

On this page
Haven at a glance

A privacy product where the architecture is the promise.

Haven is a native desktop application — a Rust workspace wrapped in a Tauri shell with a React dashboard — that connects to your email, cloud storage, and local files, scans them on your own machine, and walks you through cleaning up what it finds. Detection runs in three escalating tiers, two of which never touch the network. The few bytes that do leave are bounded, logged on-device before they're sent, and verifiable by anyone with a packet sniffer. Three features — Trace, Settle and Prepare — go further and assemble a signed document you can hand to someone else, still without uploading the mail it was built from.

28
Rust crates in the agent workspace
46
Tier 1 detectors · regex + checksums
18
Tier 2 ML classes · on-device ONNX
31B
Tier 3 model params · Haven's own GPU
7
Source types scanned
3
Signed delivery channels · Ed25519
≤2%
Of items ever need the cloud tier
30d
Undo window on every action
3
Features that end in a signed document
2
Ed25519 signatures per record folder
System map

Five surfaces, one trust boundary.

The whole product is five deployable surfaces. One of them — the desktop agent — holds all user content. The other four are deliberately designed so they couldn't hold it: a static marketing site, a static artifact CDN, a counters-only backoffice, and two GPU services that process bounded payloads in memory and forget them.

Marketing site havenprotect.app static · nginx · zero user data no connection to the agent — ever Signed artifact CDN models · rules · updates .havenprotect.app — nginx static signed manifests + model bytes Tier 3 inference inference.havenprotect.app vLLM · Gemma 4 · 31B · FP8 zero retention · in-memory only ≤1,500-char excerpt ⇄ verdict Image safety image.havenprotect.app ShieldGemma 2 · Haven-owned GPU in-memory · images never written image check (on by default) · scored in memory, then gone Backoffice backoffice.havenprotect.app Node · Express · SQLite aggregate counters — never content daily aggregate counters feedback · scrubbed errors trust boundary — all content lives inside Haven desktop agent Tauri 2 · Rust · React 19 scanning · ML · encrypted store — all local Windows MSI · macOS DMG
Animated wires show the only traffic that exists. The marketing site has no wire at all — it cannot see users.
  • Desktop agent — the product. Everything sensitive happens here: scanning, classification, the encrypted findings store, remediation, undo.
  • Signed artifact CDN — three static nginx channels that only ever send: detection rules, ML model bytes, and update manifests, each Ed25519-signed before it leaves CI.
  • Tier 3 inference — Haven-controlled GPU running an open-weights model behind an OpenAI-compatible API. Receives bounded excerpts, returns verdicts, retains nothing.
  • Image safety — a second, Haven-owned GPU for the explicit-photo detector (on by default; turn it off per connector), built specifically so users' intimate photos are never processed by a third party.
  • Backoffice — the operations plane. Accepts aggregate telemetry counters, tester feedback, and scrubbed error reports; serves the team an OTP-gated dashboard.
Technology stack

Boring where it should be, sharp where it counts.

The agent is systems software — Rust end to end, with ML inference embedded in-process. The supporting services are deliberately minimal: static file serving, one small Node app, and two GPU boxes running open-weights models Haven controls outright.

Agent core — Rust workspace, 28 crates
Rs
Rust 2021
28-crate workspace · AGPL-3.0
Ta
Tauri 2
native shell · tray · notifications
To
Tokio
async runtime
Sq
SQLite + SQLCipher
encrypted local store · key in OS keychain
Ox
ONNX Runtime
in-process ML · ort + HF tokenizers
Ed
ed25519-dalek
signature verification, compiled-in keys
Agent UI
Re
React 19
dashboard · drawer · Ask Haven
TS
TypeScript 5.8
strict
Vi
Vite 7 + Tailwind 4
build & styling
Inference
vL
vLLM
Gemma 4 · 31B · FP8 · Tier 3
SG
ShieldGemma 2
4B · image safety · FastAPI
Ca
Caddy + HAProxy
TLS · admission control · systemd
Delivery & operations
GH
GitHub Actions
self-hosted runners · sign-in-CI
Ng
nginx
static CDN · reverse proxies · LE certs
No
Node 20 + Express
backoffice · better-sqlite3 WAL
Detection pipeline

Three tiers. Two never touch the network.

Every message, file, and attachment flows through an escalating pipeline. Tier 1 is deterministic pattern matching. Tier 2 is a transformer running inside the app process. Only when both of those are genuinely uncertain — a low single-digit percentage of items — does a bounded excerpt cross the trust boundary to Tier 3 for a second opinion.

everything you connect mail · drive · files · chats TIER 1 Deterministic 46 detectors · regex + Luhn & ABA checksums microseconds per item on-device TIER 2 DistilBERT · ONNX 17 sensitive classes 512-token window runs in the app process on-device TRUST BOUNDARY TIER 3 Gemma 4 · 31B · FP8 in: ≤1,500-char excerpt out: confirmed · refuted · insufficient (no change) ~220-token response cap Haven GPU · zero retention the overwhelming majority resolves here, on your machine ≤2% — ambiguous items only
Watch the dots: green resolves at Tier 1, gold at Tier 2. Only the rare orange dot crosses the boundary — as a bounded excerpt, never a whole document.
Tier 1 · deterministic

46 detectors, zero guesswork

  • API keys & tokens — 35+ provider formats: AWS, GitHub, Stripe, OpenAI, Slack, Google, and more
  • Financial — card numbers (Luhn-validated), ABA routing numbers, bank accounts
  • Identity — SSNs, plaintext passwords, JWTs
  • Tax documents — W-2, 1099, K-1, 1040
  • Account takeover — rogue forwarding rules, suspicious mail filters
  • Sharing posture — public links, domain-wide and stale external shares
Tier 2 · on-device ML

Context, not just patterns

A fine-tuned DistilBERT runs inside the app via ONNX Runtime and reads what regex can't — classifying content into 17 sensitive categories:

tax documentmedical recordcredential contextlegal strategyprivate financialgovernment IDimmigrationemploymentinsuranceestatefinancial statementbackground checkreal estatedomestic relationsminor's databiometricintimate content · on by defaultbenign
Tier 3 · second opinion

Bounded, logged, forgotten

  • Only Tier-2-flagged ambiguity ever reaches it — a ≤1,500-character excerpt, never the document
  • Verdicts only: confirmed elevates, refuted drops the finding, insufficient changes nothing
  • Nothing persisted server-side: no request logs, no caches, no cross-call state
  • Never used to train anything, by anyone
  • Every call appears in the on-device Network Activity log — excerpt hash, destination, size, latency
Why this shape? Recall comes from Tier 1 (cheap, exhaustive), precision from Tier 2 (context-aware, still private), and the hard cases get a frontier-quality answer from Tier 3 without ever giving up the document. Each tier also improves independently: rules ship weekly, the classifier ships monthly, and the Tier 3 model upgrades server-side with zero client changes.
The trust boundary

What leaves the device — exactly, and nothing else.

Most privacy products ask you to trust a policy. Haven's claim is structural: there is exactly one code path that can reach the network, it only accepts a fixed list of payload shapes, and it writes every outbound request to an on-device log before the bytes leave. A continuous CI lint fails the build if any other crate so much as links an HTTP client.

Never leaves your device yours
  • Raw message bodies & files

    The full body or file is never uploaded — only a bounded, redacted excerpt of a flagged item ever crosses (see right).

  • OAuth tokens

    Held in the OS keychain; sent only to the provider that issued them.

  • The values of your findings

    Haven records that a password exists — not the password.

  • The encrypted findings store

    SQLCipher database, key in your OS keychain.

  • Ask Haven questions

    Parsed by an on-device grammar. No ML, no network.

  • Your inferred context profile

    Computed locally to rank findings; stays local.

  • The text of a record's messages

    Trace, Settle and Prepare assemble the document on your machine. No message body is sent to build one.

Crosses the wire — bounded & logged accounted for
  • Aggregate telemetry counters

    Daily rollups from a fixed slug vocabulary — free-form strings are unrepresentable in the schema.

  • Signed-manifest checks

    "Is there a new rules pack / model / update?" — version metadata only.

  • Tier 3 excerpts

    ≤1,500 characters of a flagged item, one round-trip, discarded after the verdict.

  • Record-building model calls

    Who wrote — sender name, domain, a few subject lines — and the finished register at export. Scrubbed, and logged with the domain on the row.

  • Explicit-photo image checks

    On by default (off per connector). Image attachments to Haven's own GPU, scored in memory, never written to disk.

  • Scrubbed crash reports

    Panic events pass a scrubber that strips paths, locals, and anything matching Tier 1 patterns.

  • Tester feedback

    What you typed in the feedback box — after the same scrubber.

One chokepoint, enforced by the compiler and CI

scanner · tiers 1–3 connectors · OAuth telemetry aggregator updates · rules · models feedback · error reports haven-egress the single network chokepoint closed payload allowlist one destination per payload logged on-device before send Google · Microsoft APIs (your mail) *.havenprotect.app services signed-artifact CDN crash ingest (scrubbed) …and nothing else. unknown host = no code path CI lint: HTTP anywhere else fails the build
The allowlist is an enum, not a config file — adding a destination requires a code change, a review, and a release users can diff.
Verify it yourself. Inside the app, the Logging page shows every outbound request — payload type, destination, size, and timing — written before the request fires. A security researcher with a proxy can confirm the page tells the truth without any cooperation from Haven. That's the standard we hold ourselves to: architecture, not a promise.
Record-producing features

Three features that end in a document, not a dashboard.

Most of Haven ends in a finding you can act on. Trace, Settle and Prepare end in something you can hand to a person — a lawyer, an executor, a claims adjuster, whoever opens your affairs after you. All three ride the same connectors, the same egress chokepoint and the same export path: a folder containing a Word document, a signed manifest of everything that went into it, and the files the messages carried.

Trace · your question

Trace Dossier

You describe the chapter in your own words — "my 2021 lease with…". An on-device planner compiles that sentence into provider-native searches: a Gmail query, a Graph filter, an IMAP UID SEARCH.

  • Fast — planning is pure local string work. The sentence never leaves the machine.
  • Deep — expands provider-side from the correspondents Fast found, with a hard ceiling on model calls per run.
  • ≤200 hits ingested per account; every item keeps a bounded match-context excerpt.
Settle · after a death

Estate Record

No question to plan. Settle runs one fixed nine-category sweep over an inherited mailbox and rolls the result up into a register of institutions, not messages.

  • Recurring charges · financial · insurance · utilities · property & vehicles · professional contacts · obligations · government · digital accounts.
  • Pass one classifies from metadata alone; pass two fetches in full only the few messages the record reproduces.
  • Categories are closed tables of tells — a compile-time exhaustive match forces every provider to render every handle.
Prepare · before one

Personal Record

The same sweep engine pointed at your own mailbox, while you are still around to correct it. The output is the list everyone means to make and nobody finishes.

  • A re-run compares against your last finished record and carries forward the rows you already fixed.
  • A mailbox connected for Settle can't be swept as Prepare, and vice versa — the agent refuses the mix-up by name.
  • A map, not a key: it records that an account exists and who to contact, never a credential.
One sweep worker, two record kinds — Settle and Prepare differ in whose mail it is, not in what the code does.

What a model is shown — and what it isn't

No message is adjudicated by a model. The mail is read on your device; the only things that ever cross are a description of who wrote and, at export, the finished register. Concretely, classification sees the sender's name and address, the message count, up to five subject lines, and the closing lines of up to two messages. Summaries see the register and nothing else. Both are run through the scrubber first.

  • No new payload shape. These calls ride the existing Tier 3 variant under class slugs — investigate:*, settle:classify:<domain>, settle:summary. Adding a record feature adds a slug, never a destination.
  • Logged call by call. Every one lands in the on-device Network Activity log with the institution's domain on the row, written before the bytes leave.
  • The document says so too. The record's Method & Provenance section states exactly what the model saw, in the same words as this page. If that ever changes, the document changes with it.
  • Prose is gated. A generated summary is withheld if it names a figure that isn't in the register, asserts a status, gives advice, or clips an institution's name — and the record lists the withholding under known gaps. Stored summaries are re-checked on every re-export.

The folder, and the two signatures

Export writes a folder — never into an existing one; it takes -2, -3 — holding the .docx, a .manifest.json, a plain-text note explaining what the manifest is for whoever opens it, and an attachments/ directory. The document is rendered with fixed zip timestamps so its bytes stay deterministic: the same record, exported twice, still matches its manifest.

  • Signature one covers the per-exhibit digests — "did Haven, on this device, assemble these exact messages?" It has to be computable before the document exists, because it is printed into the document.
  • Signature two covers the finished document's hash, bound to the manifest's own identity — "is this .docx the one produced from them, unmodified since?" A hash nobody signed would be evidence of nothing, and a document signature can't be transplanted between manifests.
  • Self-signed, and it says so. The Ed25519 key is generated on your machine and never held by Haven, so the public key travels in the manifest. That makes this evidence of integrity, not third-party attestation — the same weight as any document a person signs themselves. The record states that plainly rather than leaving a recipient to work it out.
  • The scope statement says what was not searched. A record that silently omits a connected-but-excluded account is worse than no record at all.
Anyone can check one. A recipient with neither Haven nor a Haven account can verify a record two ways: the in-browser checker at havenprotect.app/verify, which reads the folder locally and never uploads it, or the standalone Python script that implements the identical check. Both must change together with the agent — that's a rule, not an aspiration.
Infrastructure

Where it all actually runs.

Five pieces of hardware, each with one job. The interesting choice: both GPU services run open-weights models on machines Haven controls — no third-party AI API ever sees user content, and the explicit-photo detector got its own dedicated box precisely because that content deserves the strongest possible custody.

Your computer
the only place your content exists
The agent installs from a signed MSI (Windows) or DMG (macOS) and does all scanning, classification, and storage locally.
Tauri 2 shell · Rust workspace
SQLCipher store · ONNX in-process
Windows shipping · macOS in flight
Tier 3 inference GPU
inference.havenprotect.app
Dedicated bare-metal GPU host (US) running vLLM. Admission control in front, TLS termination at the edge, nothing written behind it.
Gemma 4 · 31B · FP8
vLLM · HAProxy · Caddy
zero-retention configuration
Image-safety GPU
image.havenprotect.app
Haven-owned box for the explicit-photo detector (on by default; off per connector). Built so users' most intimate content is scored in memory on our hardware — never a third-party API. Images are never written to disk, never logged.
RTX 6000 Ada · 48 GB
ShieldGemma 2 · 4B · FastAPI
bearer-gated · in-memory only
Static artifact CDN
models · rules · updates .havenprotect.app
Three nginx doc-roots serving signed envelopes: detection rules, ML model bytes, and update manifests. No compute, no state, nothing to breach.
nginx static · Let's Encrypt
no-cache manifests
previous versions kept for rollback
Backoffice VM
backoffice.havenprotect.app
The operations plane: telemetry aggregates, feedback inbox, alpha invites, release artifact intake. Behind nginx with strict CSP and per-endpoint rate limits.
Node 20 · Express
better-sqlite3 · WAL
OTP-gated dashboard
Signed delivery & auto-updates

Everything that changes the agent is signed.

Detection rules, ML models, and the application itself all ship through independent channels — and the agent refuses anything whose Ed25519 signature doesn't verify against keys compiled into the binary. A compromised CDN can't hurt users: a bad signature means the agent silently keeps what it has.

GitHub Actions self-hosted runners build · validate · sign release key rules-signing key updates.havenprotect.app update manifest + installer bytes staged rollout percentage per release rules + models .havenprotect.app rules pack · weekly cadence Tier 2 ONNX bundle · ~267 MB each file pinned by SHA-256 manifest + .sig envelope + .sig agent verifies pubkey baked into binary then installs on restart agent verifies fail-closed: a bad sig = keep the prior pack
Two independent keys: compromising the release pipeline doesn't grant control of detection rules, and vice versa.
  • App updates — the agent checks a signed manifest, downloads only when the SHA-256 matches, and respects a staged rollout percentage so a bad release reaches 5% of the fleet, not 100%.
  • Rules packs — new detectors ship weekly without an app release. The pack carries its own minimum-agent-version gate, so old agents never load rules they can't run.
  • Model bundles — Tier 2 classifier upgrades arrive the same way: signed manifest, per-file hashes, atomic activation, prior version kept for rollback.
  • Everything is opt-out-able — update checking is a user preference, and the Network Activity log shows every check the agent makes.
Connectors & local store

Eight kinds of sources, one encrypted store.

Each connector is its own Rust crate speaking the provider's native protocol — OAuth 2.0 with PKCE for the cloud sources, IMAP with an app password for Yahoo and AOL, direct database reads for iMessage, plain file I/O for local folders. Tokens live in the OS keychain. Sync is incremental, so after the first deep scan Haven only reads what's new.

G
Gmail
OAuth + PKCE · History API sync
D
Google Drive
sharing-permission metadata only
O
Outlook & M365
OAuth + PKCE · incl. mail rules
1
OneDrive
sharing-posture audit
P
Proton Mail / IMAP
via Proton Bridge · any IMAP host
Y
Yahoo & AOL Mail
IMAP · app password · archive & trash
i
iMessage
macOS · local chat.db read
T
This device
PDF · DOCX · XLSX · text extraction

The local store

Everything Haven learns lands in a single SQLCipher-encrypted SQLite database on the user's disk. The 32-byte key is generated on first launch and held in the OS keychain — Haven's servers couldn't read the store even with a copy of the file.

  • Findings & verdicts — what was found, where, and every action taken, with the 30-day undo trail.
  • The Network Activity log — the on-device record of every byte that ever left, kept in the same transaction as the send itself.
  • Signed artifacts — the active rules pack, model manifests, and update manifests, stored as the exact signed bytes that were verified.
  • Schema discipline — 29 additive migrations and counting; upgrades never rewrite or expose prior data.
Ask Haven — the natural-language search shipped in 0.3.97 — is a deliberate showcase of the architecture: questions are parsed by an on-device grammar in the haven-query crate and run against finding metadata. No ML, no generation, no network round-trip. The question never leaves the machine, and the answer is honest about what the index can't know.
Backoffice & operations

An ops plane that can't see your data.

The backoffice exists so a small team can run an alpha fleet: watch aggregate health, read tester feedback, issue invites, and stage releases. Its most important property is what it doesn't receive — the telemetry schema is a fixed vocabulary of counter slugs, so message content is not just unsent, it's unrepresentable.

Agent fleet ~25 alpha testers Release CI signed MSI / DMG Haven team browser bearer keys upload key email OTP backoffice.havenprotect.app POST /v1/telemetry/aggregate POST /v1/feedback/submit POST /v1/client-errors/submit POST /v1/release/upload POST /v1/license/validate · heartbeat rate-limited · size-capped · Helmet CSP SQLite · WAL aggregates · feedback · invites OTP dashboard fleet intel · invites · kill-switch
Three caller types, three separate auth schemes — agents and the team never share a credential path.

What the team can actually do

  • Fleet dashboard — daily aggregate charts: scans run, findings by severity band, remediation counts, version adoption. Counters, not content.
  • Alpha lifecycle — invite by email, issue license keys and download tokens, and remotely pause a license (the kill-switch): a paused agent's writes are refused fleet-wide.
  • Release intake — CI uploads each signed installer; the backoffice keeps the latest plus recent versions per OS for the download links and the update channel.
  • Feedback inbox — every in-app "send feedback" lands here, already scrubbed on the client before it was sent.
The closing argument. Every box on this page was placed to make one sentence true: Haven can grow — new detectors weekly, new models monthly, new surfaces over time — without ever widening what leaves the user's machine. The egress allowlist is the contract; everything else is implementation.