Privacy
Every network connection the app can make.
Stalkrr records meetings, calls, your screen, and (optionally) your messages. The only
honest privacy policy for software like this is one you can check against the code, so
this document lists every network connection the app can make, what crosses it, what
turns it on, and where it lives in the source. If you find any byte leaving the machine
that this page doesn't account for, that's a security bug — report it per
SECURITY.md.
Default posture: nothing you captured leaves this Mac. Out of the box, transcription
runs on-device (vendored whisper.cpp), extraction runs on a local model (auto-managed
Ollama on localhost), and the archive is a local SQLite file under ~/.stalkrr/.
Outbound connections that can carry captured data
These exist only if you explicitly select a cloud provider (a paid Premium feature — the deliberate friction is the point), and they receive only what the stage needs:
| What is sent | Where | When | Code |
|---|---|---|---|
| Meeting audio (transcoded m4a) | api.groq.com or api.openai.com |
Only when you set the transcription engine to Groq/OpenAI in Preferences (default: local Whisper). The Preferences card says "audio is uploaded" whenever this is on. | app/Sources/StalkrrPipeline/CloudWhisperTranscriber.swift |
| Meeting audio (transcoded m4a) | api.soniox.com |
Only when you set the transcription engine to Soniox (Premium; the card says "audio is uploaded"). The uploaded file is deleted from their storage right after transcription. | app/Sources/StalkrrPipeline/SonioxTranscriber.swift |
| Redacted transcript text (post-PII-redaction) | api.anthropic.com, api.openai.com, generativelanguage.googleapis.com, or api.groq.com |
Only when you set the text/vision provider to that cloud (default: local Ollama). | app/Sources/StalkrrPipeline/Providers/Providers.swift, Providers/Vision.swift |
| Redacted transcript text (text-extraction backup) | same as above | Only when "If local AI fails" is set to a named provider in Settings (default Off). | app/Sources/StalkrrApp/BackupExtractor.swift |
| Screen/camera frames (JPEG) — the whole display or a webcam still, not redacted | same as above | Only when you explicitly select a cloud vision provider (default: local Ollama, nothing uploaded). | app/Sources/StalkrrPipeline/Providers/Vision.swift |
The redaction stage (app/Sources/StalkrrPipeline/Redact.swift) masks PII in transcript
text before it is sent. It does not touch images — frames are sent as captured.
Outbound connections that never carry captured data
| Purpose | Where | What is sent | Code |
|---|---|---|---|
| Update check | github.com (StalkrrOS/stalkrr-releases) |
A plain GET for appcast.json; downloads the signed update zip. No identifiers, no telemetry. Toggle: "Install updates automatically" in Preferences. |
app/Sources/StalkrrApp/UpdateChecker.swift |
| Whisper model download | huggingface.co |
A GET for the model file, once per model. | app/Sources/StalkrrPipeline/WhisperTranscriber.swift |
| Local-AI runtime download | github.com (ollama releases) + the Ollama model registry |
GETs for the pinned Ollama build and the local model, once. | app/Sources/StalkrrApp/OllamaManager.swift |
| Self-hosted inference (optional) | your own localhost/LAN URLs for Ollama or vLLM |
Redacted text, to servers you run. | endpoint prefs in app/Sources/StalkrrApp/PreferencesWindow.swift |
Things that are local by construction
- Transcription default: whisper.cpp runs in-process (Metal/Core ML). The fallback
Apple engine sets
requiresOnDeviceRecognition = true(app/Sources/StalkrrPipeline/Transcriber.swift) — dictation audio never goes to Apple. - License activation is offline. Keys are Ed25519-verified locally
(
app/Sources/StalkrrCore/License.swift); activating never calls a server. - The UI cannot reach the network. Every window is a WKWebView locked with
Content-Security-Policy: default-src 'none'(app/Sources/StalkrrApp/WebUI/*.html) and served from a custom local scheme (app/Sources/StalkrrApp/Web/) that only reads bundled assets and your own media files. - The MCP server is stdio-only (
app/Sources/StalkrrMCP/) — your agent reads your memory through a local pipe, not a port. - No telemetry, no analytics, no crash reporting. There is nothing to opt out of.
- Storage: recordings, transcripts, and memory live in
~/.stalkrr/(SQLite + media files, plus a thumbnail cache under~/.stalkrr/cache/thumbs/); API keys and your license live in the macOS login keychain. - Erase means erase. Deleting a recording (Timeline → Delete, or the MCP tool) or
everything (Erase all) removes the database rows in one transaction, then the files the
database recorded for it — verified, and reported honestly: the app tells you if a file
could not be removed and finishes the job at the next launch
(
app/Sources/StalkrrMemory/MeetingEraser.swift). A deleted recording is tombstoned so work still running in the background cannot recreate it and a crash cannot resurrect its audio. The database runs withsecure_delete(erased rows are overwritten) and is vacuumed after Erase all, so erased content is gone from the file, not just from queries. Caveat honesty: SSD wear-levelling means no software can promise that old blocks are physically unrecoverable — FileVault is the answer to that.
How to audit this yourself
- Enumerate every URL in the code:
bash grep -rhoE "https://[a-zA-Z0-9./_-]+" app/Sources --include="*.swift" | sort -uCompare against the tables above. (URLSession is the only HTTP client; there are no third-party networking dependencies to hide in — the dependency list isapp/Package.swift, and the single vendored library is whisper.cpp.) - Build it yourself (
cd app && swift build && ./scripts/build-app.sh) and run your own bundle — seeapp/README.md. - Watch it live with Little Snitch/LuLu: with default settings you should see only the update check and one-time model downloads listed above.