Egress disclosure — every byte that can leave your machine
Wyrm is local-first: the default install answers every memory operation from ~/.wyrm/wyrm.db with zero cloud dependency, and the core test suite runs with the network killed (a CI invariant). This page is the complete inventory of network calls Wyrm can make, what gates each one, and what the payload is — so "local-first" is a checkable claim, not a slogan. If an outbound call exists and is not on this table, that is a bug; report it.
The per-recall determinism receipt enforces this at runtime: dataEgress is 'none' only when nothing left the box, and names every remote host that scored your text otherwise. GET /health?check_dependencies=1 reports the live egress posture of the active providers.
Default ON (and how to turn each off)
| Destination | Trigger | Payload | Off switch |
|---|---|---|---|
registry.npmjs.org | Daily version poll | Package name only — no memory data, no identifiers beyond the HTTP request itself | WYRM_NO_VERSION_CHECK=1 (explicit wyrm_check_update still works) |
127.0.0.1 (wyrm-loop daemon) | Daemon write forwarding | Loopback only | Don't run the daemon |
Explicit opt-in — retrieval providers (memory text egress)
These send query and/or candidate memory text to a remote scorer. None is reachable from the auto chain; each requires you to set the env vars yourself. A NIM container on loopback counts as local (no egress).
| Destination | Gate | Payload |
|---|---|---|
integrate.api.nvidia.com (or WYRM_NIM_BASE_URL) | WYRM_VECTOR_PROVIDER=nim + NVIDIA_API_KEY/WYRM_NIM_API_KEY | Text being embedded (indexing: each captured memory; searching: your query) |
ai.api.nvidia.com (or WYRM_RERANK_URL) | WYRM_RERANK_PROVIDER=nim + WYRM_RERANK_MODEL + WYRM_RERANK=1 | Query + top-K candidate texts per reranked recall |
api.openai.com | WYRM_VECTOR_PROVIDER=openai + OPENAI_API_KEY | Text being embedded |
Ollama (OLLAMA_URL, default localhost:11434) | WYRM_VECTOR_PROVIDER=ollama only. Deprecated. The default (auto) never probes Ollama; it uses the bundled local model | Memory text. Loopback by default, so no egress; if OLLAMA_URL points at a remote GPU box, that text egresses to it, and the recall receipt names the host |
api.anthropic.com | wyrm_ask with WYRM_ASK_ALLOW_CLOUD=1 or an explicit model_override: 'anthropic:...', plus ANTHROPIC_API_KEY | The question + retrieved context (your memory) |
api.openai.com | wyrm_ask with WYRM_ASK_ALLOW_CLOUD=1 or an explicit model_override: 'openai:...', plus OPENAI_API_KEY | The question + retrieved context (your memory) |
integrate.api.nvidia.com | wyrm_ask with WYRM_ASK_ALLOW_CLOUD=1 or an explicit model_override: 'nim:...', plus an NVIDIA key | The question + retrieved context (your memory) |
Explicit opt-in — sync, replication, sharing
All of these are commands or configurations you run deliberately, and every one is additionally gated by the per-project grove sync_policy (private by default — a private grove never egresses regardless of the feature flags below).
| Destination | Gate | Payload |
|---|---|---|
| Your R2/S3 endpoint | wyrm_cloud_backup / wyrm_cloud_sync with credentials you supply | AES-256-GCM-encrypted snapshot (encrypted before leaving the machine) |
| Peer devices you enroll | wyrm_replication / wyrm_events_replicate with peer URL + WYRM_-prefixed token | Live-Memory events for cloud/team groves; failures always stay private (is_shared=0) |
| Peers you name | wyrm_share federation pull | The shared subset you selected |
wyrm.ghosts.lk (or WYRM_CLOUD_URL) | wyrm cloud login / cloud sync / cloud export, and the cloud daemon (repeats on its interval while running) | Bearer-authenticated sync payloads: the semantic rows your grove policy selects. This is the paid Cloud tier and is off until you log in |
account.ghosts.lk (or WYRM_ACCOUNT_URL) | wyrm login (one-time CLI auth) | Auth handshake + version header — no memory data |
account.ghosts.lk (or WYRM_ACCOUNT_URL) | Server boot + once a day, only when a license key is installed (~/.wyrm/license.json); also wyrm license | GET /api/v1/license/revocations — no payload beyond the request; the signed revocation list comes back. Off switch: WYRM_LICENSE_REFRESH=0 |
account.ghosts.lk (or WYRM_ACCOUNT_URL) | Same trigger, and only when a paid key is within 14 days of expiry (or lapsed ≤30 days) and an account token exists (~/.wyrm/account-token, written by wyrm login) | POST /api/v1/license/refresh with the account token as a bearer + version header — no memory data. Off switch: WYRM_LICENSE_REFRESH=0 |
huggingface.co, fallback models.ghosts.lk | wyrm-setup (unless --no-model) and wyrm vectors download — a one-time model fetch | Plain GET of the pinned nomic-embed-text-v1.5 int8 ONNX artifacts (~138 MB, sha256-pinned). Nothing is sent. Skip with --no-model; the free tier then stays keyword-only |
The local dashboard (wyrm ui / wyrm serve --ui) makes no off-box request: it uses the fonts already on your machine, and its Content-Security-Policy allows no remote host.
Never
- No telemetry, no analytics beacons, no crash reporting.
- No memory content in any default-ON call.
wyrm_call_externalspawns local stdio MCP processes — network behavior is that of the server you configure, and it never inherits Wyrm's secret env (hardened 6.14.1).
Questions or a call you can't map to this table: legal@ghosts.lk.