Privacy

Saykeep is a local-first application. Your audio, recordings, transcripts, and speaker labels are processed on your machine and stored only in your configured storage folder; summaries come from an OpenAI-compatible endpoint you configure — a local server by default, or a service of your choice with your own API key. This is not a promise you have to trust — it is a property you can verify.

Recording is always visible — there is no covert mode

Saykeep records out in the open. Whenever meeting capture is active, an always-on indicator shows it: the menu-bar icon, a status line with elapsed time and live audio meters, and the recording card. No setting or code path can suppress it. There is no hidden, discreet, or low-visibility recording mode in the product; this is a locked, test-enforced invariant, not a UI default that could be quietly changed. The first meeting you record also opens a consent notice, because in some places every participant must agree before you record (see the FAQ). Obtaining that consent is your responsibility; Saykeep’s job is to make recording impossible to miss.

You decide what’s kept

Saykeep doesn’t hoard recordings. Once a meeting is transcribed, it can delete the audio for you — asking after every meeting, or automatically cleaning up audio older than a number of days you choose. The guard rail: audio is deleted only when a successful transcript exists, and transcripts and summaries are never deleted automatically. You can also delete any meeting entirely from the recordings browser, or erase your Saykeep content — recordings, models, settings — in one guarded step (you type ERASE to confirm). It’s all plain files in your own folder; what stays is up to you.

The short version

During normal use, nothing leaves your machine except — if you enable meeting summaries — the transcript text sent to the endpoint you configure (a local server on 127.0.0.1 by default). On first run, the speech models download once (full list below).
No accounts, no login, no cloud sync. There is no Saykeep server.
No telemetry, analytics, crash reporting, or usage tracking. None of it is in the code.
No license phone-home. License keys are verified offline against a compiled-in public key — there is no activation server and no network call.
The diagnostics export writes a local file you choose whether to share; it makes no network call and it redacts secrets.

The one exception during normal use — the update check

Saykeep can check whether a newer version exists. This check is off by default and never opens a connection unless you turn it on. When enabled, it makes at most one anonymous request per day to GitHub Releases — no version string, no machine id, no identifier of any kind. It only notifies you; it never downloads or installs anything on its own. Leave it off and Saykeep makes no update calls at all.

How to verify

1. Watch it live. On macOS run Little Snitch; on Linux run sudo ss -tunp | grep saykeep or lsof -i -a -p <pid>. With summaries pointed at a local endpoint and models already downloaded, you will see zero outbound connections during normal use.
2. Inspect your config. Settings → Advanced → “Export diagnostics…” shows your resolved LLM endpoint URL (credentials redacted) so you can confirm exactly where a summary would go.
3. Read the full list below. Every connection the app can make is enumerated in the annex — it is the same file we keep in the source tree, reproduced below in full — byte for byte.
Codename note: the document below is Saykeep’s in-repo trust artifact, reproduced verbatim so it stays a single source of truth. It refers to the app by its internal codename, “Whisperer” — that is the same application as Saykeep. Every socket, host, and guarantee below applies to Saykeep exactly as written.
# NETWORK.md — every connection Whisperer can make

Whisperer is a **local-first** application. Your audio, recordings, transcripts, and summaries are
processed on your machine and stored only in your configured storage folder. This document is an
exhaustive, behavior-verifiable inventory of **every** network connection the app is capable of
making — nothing else happens. You do not have to take our word for it: run a network monitor
(Little Snitch on macOS, `lsof -i` / `ss -tunp` on Linux, a firewall log on Windows) and confirm the
app opens only the connections listed here.

*This file is kept in sync with the code. If you find an outbound connection not listed here, that is
a bug — please report it.*

## The complete list

| # | Host | When | What is sent | Contains your data? | Avoidable? |
|---|------|------|--------------|---------------------|------------|
| 1 | **The LLM endpoint you configure** (`llm.endpoint_url`; default `http://127.0.0.1:8080/v1` — a server on your own machine) | When a meeting summary is generated, and a `/models` health probe when you test the connection | The meeting **transcript text** (for summarization) or a models list request (for the probe) | **Yes — transcript text.** It goes only to the endpoint *you* set. By default that is a local server and nothing leaves your machine. If you point it at a cloud API, your transcript goes there **by your choice** | Yes — disable summaries / leave the endpoint unset. Meetings still record and transcribe fully locally |
| 2 | **huggingface.co** (and its model CDN) | First time a model is needed: the Whisper-family speech-to-text models and, if you enable diarization, the speaker models | A standard model **download** request; for the diarization models, your Hugging Face **token** in an `Authorization` header (only if you provide one) | No — these are downloads *to* your machine. Your token authenticates the download; no audio/transcript is uploaded | Partly — once models are cached locally they are not re-downloaded. Diarization is optional |
| 3 | **huggingface.co/api** (token check) | Only when you click "Test" on the Hugging Face token field in the wizard/settings | Your HF token in an `Authorization` header, to verify it can access the diarization model | No | Yes — it only runs when you test the token |
| 4 | **api.github.com** | At most once/day, ONLY if you enable Check-for-updates (off by default) | An anonymous latest-release request — no version string, machine id, or identifier | No | Yes — never runs unless you turn it on |

*Row 4 note: this check is off by default and never opens a socket while off.*

That is the entire list.

## What Whisperer **never** does

- **No telemetry, analytics, crash reporting, or usage tracking.** No analytics SDK is linked into
  the app — and you can hold us to it from the outside: the rows above are everything, and the wire
  is checkable.
- **No accounts, no login, no cloud sync.** There is no Whisperer server. Nothing is uploaded.
- **Your recordings, transcripts, and summaries are never sent anywhere** except the transcript text
  to the LLM endpoint *you* configured (row 1). They are stored only in your storage folder.
- **No license phone-home.** License keys are verified **offline** against a compiled-in public
  key — no activation server, no network call, ever.
- **The diagnostics export** (Settings → Advanced) writes a **local file** you choose whether to
  share; it makes no network call, and it redacts secrets.

## Local helpers are not network connections

Whisperer runs some local subprocesses — `pw-record` (Linux system audio), the bundled
`whisperer-syscapture` (macOS system audio), `osascript`/`caffeinate` (macOS), and your OS's
file-reveal command. These are **on-device** and open no network sockets.

## How to verify

1. **Watch it live:** macOS → Little Snitch; Linux → `sudo ss -tunp | grep whisperer` or `lsof -i -a -p <pid>`; Windows → Resource Monitor / firewall log. With summaries pointed at a local endpoint and models already cached, you will see **zero** outbound connections during normal use.
2. **Inspect your config:** Settings → Advanced → "Export diagnostics…" shows your resolved
   `llm.endpoint_url` (credentials redacted) so you can confirm where summaries would go.
3. **Hold us to the contract:** Whisperer is closed-source, so instead of "read the code," this file
   *is* the auditable surface — the only things that ever open a socket are the rows above. If you
   ever observe a connection that is not listed here, that is a bug; report it and we will treat it
   as one.

## Planned additions (not yet active in the app)

- **Self-hosted model mirror:** a Whisperer-controlled download host that will serve the diarization
  models **without a Hugging Face token**. Until it is live, diarization models come from
  huggingface.co (rows 2–3). Like rows 2–3, it would only ever *download* models to your machine —
  nothing is uploaded.

Verify it yourself — the walkthrough

macOS — Little Snitch

Install Little Snitch (or its free companion, Little Snitch Mini), open its network monitor, and use Saykeep normally — dictate, record a meeting, generate a summary against your local endpoint. Saykeep’s row stays at zero outbound connections.

Little Snitch — Saykeep
Outbound connections: 0
during a 42-minute recorded meeting

Linux — ss / lsof

$ sudo ss -tunp | grep saykeep
# (no output — zero sockets)
$ lsof -i -a -p $(pgrep saykeep)
# (no output — zero sockets)

If you ever see a connection that isn’t on the published list, that’s a bug — tell us.