What Local Intelligence does.
Local Intelligence (LI) gives you semantic search and pattern surfacing over your own writing — find an entry by what it's about, not just by its words. The main user-visible affordance is ⌘K ("find by meaning"), plus the ability for reflections to cross-reference past writing when something rhymes.
Behind it: each journal entry, reflection, and inbound letter is broken into ~1,200-character chunks. Each chunk is sent over localhost (never the network) to Ollama — a local AI runtime running on your machine — which returns a numerical embedding vector. Vectors live in memory only. When you search, your query is embedded the same way and compared against the in-memory vectors.
What stays on this device.
Verifiable in code:
- Every query you type into ⌘K (semantic search).
- Every embedding vector LI produces.
- Every chunk of journal text the embedding model sees.
- The model name you've configured.
Nothing in that list leaves the machine. The Ollama endpoint is
a hardcoded http://localhost:11434 with no
configuration surface — there is no way to redirect to a remote
URL via settings or environment. A build-time check (see
src-tauri/src/intelligence/mod.rs) refuses to
compile if any cloud HTTP client (reqwest,
hyper, ureq, raw
TcpStream) is ever added inside the intelligence
module. That's a mechanical guard against accidental future
regression.
Per-request shape: requests carry only the chunks being embedded (max 32 per batch) plus the model name. No auth headers, no device-identifying User-Agent, no telemetry headers.
What gets wiped when you lock the vault.
When you lock (manually with ⌘⌥⇧L, or via auto-lock):
- The in-memory semantic index is dropped via the
*g = Nonepattern on aRwLock<Option<Index>>. - The Rust
zeroizecrate then firesDropon every embedded chunk — both the chunk text (Zeroizing<String>) and the embedding vector (Zeroizing<Vec<f32>>) are zeroed in RAM before deallocation. - Two regression tests (
embedded_chunk_text_and_vector_are_zeroizing_wrappedandoption_index_set_to_none_drops_indexinsrc-tauri/src/intelligence/build.rs) catch the two ways a future refactor could silently break this contract.
On unlock, the index rebuilds from scratch — there is no on-disk cache that could survive a lock cycle.
What we cannot fully protect against.
These are real limitations. They aren't bugs in LI; they're properties of the operating environment that no application can fully control.
macOS memory swap
Under heavy memory pressure, macOS may write pages of RAM to disk in a swap file. Our wiping logic runs when we drop the data — but if macOS already swapped a page before that, the bytes can persist on disk briefly.
Active memory while unlocked
While the vault is open, your journal text and embeddings are in your machine's RAM. An attacker with physical access to your unlocked machine — or one who has compromised your user account — can read that memory.
Defenses:
- Lock the vault when you step away (
⌘⌥⇧L). - Set auto-lock in Settings to a value you trust (15 minutes is the default we suggest).
- Configure macOS to require password immediately on screensaver/sleep (System Settings → Lock Screen).
Third-party Ollama clients
If you have a separate AI chat app installed that also talks to your local Ollama (e.g., a Mac chat wrapper), that app sees its own conversations — it does not see Human Layer's traffic or your journal. We don't share an Ollama session with anything else; HTTP calls are independent connections.
That said: if you have such an app and you manually paste journal content into it, what happens with that content is up to that app's privacy contract, not ours.
Recommended companion protections.
A short checklist:
- Turn on FileVault (System Settings → Privacy & Security → FileVault). Protects swap and at-rest data.
- Configure macOS to require password immediately on screensaver/sleep (System Settings → Lock Screen).
- Use auto-lock in Human Layer Settings so the vault locks itself when you step away.
- Don't paste sensitive journal text into third-party AI tools — Human Layer keeps everything local; other tools may not.
- Use the in-app
⌘⌥⇧Lhotkey to lock instantly when you need to.
For paranoid users — deeper cleanup checklist.
We've intentionally kept LI's "Forget index / Purge" action focused: it clears the in-memory index immediately and removes the LI configuration from your vault. After that, LI is in the same state as if you had never enabled it.
We deliberately do not reach into other applications' data — that would be invasive and brittle. If you want to scrub adjacent surfaces, you can do these yourself:
- Ollama's own logs (separate from Human Layer): on macOS these typically live at
~/.ollama/logs/. Human Layer does not write to or read from those. - Shell history: may include
ollama pullcommands if you've run them by hand. Clean with the normal shell-history tools of your choice (e.g.,history -cfor bash,history -pfor zsh). Human Layer doesn't write to your shell history. - Third-party Ollama wrapper apps: if you've installed one, consult its documentation for clearing its conversation history. Human Layer has no visibility into these.
For people who want to verify.
Source-of-truth files in the repo:
src-tauri/src/intelligence/mod.rs— Index + EmbeddedChunk data types (Zeroizing wrappers); the build-time no-egress guard test.src-tauri/src/intelligence/build.rs— index rebuild + zeroize function; the two lock-zeroize regression tests.src-tauri/src/ollama.rs— every Ollama HTTP call. Endpoint is hardcoded localhost on line 12. Request shapes are minimal.src-tauri/src/lib.rs—vault_lockcommand; callsintelligence::build::zeroizeon every lock.
Spot-check yourself: git grep for http://
in src-tauri/src/ and confirm every result is
localhost. Same in src/.
Last reviewed: v0.3.13 privacy audit. Reach out if you find anything that doesn't match what's documented here — that's a bug we want to hear about. Email joe@thehumanlayer.co.