Telemetry
What Memtrace ships home, what it never touches, and how to turn any of it off — four content-free, opt-out streams and a hard list of things that never leave your machine.
Memtrace ships telemetry to help fix bugs and understand usage patterns, and every stream is built around one rule: content never leaves your machine. What ships is shape, category, and counters — never source code, search text, or file paths. All four streams are opt-out, and one env var turns off the whole pipeline.
The four streams#
Everything is queued locally first and shipped in batches to https://www.memtrace.io/api/telemetry/ingest, authenticated with the same bearer session token your license already uses. There are four independent streams:
| Stream | What it carries | Fires |
|---|---|---|
| Usage events | Structured signals like start and mcp_call — event name, ok/error status, duration, result count, never arguments or results. | On lifecycle moments and every MCP tool call |
| Sanitised WARN/ERROR lines | Log lines from the tracing subscriber, run through a sanitiser first, then fingerprint-deduplicated so a noisy repeating warning increments a counter instead of flooding rows. | Any WARN or ERROR event, from any target |
| Crash reports | Panic message, sanitised backtrace (capped at 16 KB), and source location. | On a panic, queued locally and shipped on the next run |
| Rail shadow buckets | Category-only fields: mode, query shape, hit/miss, score bucket — never the search text or matched files. | Async, off the critical path, while Rail is in observe mode |
The sanitiser runs before anything touches disk, on every WARN/ERROR line:
- Absolute paths under your home directory collapse to
~/… - Token- and API-key-shaped strings are stubbed to
<redacted-token> - Email addresses are stubbed to
<redacted-email>
Recurring errors are aggregated by fingerprint into a single row with an occurrences counter, rather than one row per occurrence — a noisy warning doesn't turn into a flood of near-identical records.
Rail's shadow telemetry exists to answer one question — can Memtrace be trusted to route code discovery instead of raw grep/find? — without ever transmitting what you searched for. Every field it ships is a locally-derived category or bucket (query shape, hit-or-miss, a coarse score bucket), computed on-device; the query text and matched files are inspected locally and discarded, never serialized.
What never leaves your machine#
This is an explicit list, not a "we try to avoid" list. None of the following are ever put on the wire by any telemetry stream:
| Never collected | Why it matters |
|---|---|
| Source code | File contents are never read into a telemetry payload. |
| Search text | What you searched for, in Rail or anywhere else. |
| Matched files/symbols | Result identities stay local — only categories ship. |
| Embeddings | Vector data never leaves the embedding cache. |
| Repo names/paths/URLs | Not in usage events, error lines, or crash reports. |
| Branch/commit data | Never included in any payload. |
| Env values | Environment variable contents are never captured. |
| IP addresses | Not logged by the client-side telemetry pipeline. |
Turning it off#
There is one telemetry kill switch, read at startup:
| Variable | Default | Description |
|---|---|---|
MEMTRACE_TELEMETRY | on | Set to off, 0, false, disabled, or no(case-insensitive) to disable the whole pipeline: the tracing capture layer becomes a no-op, event recording short-circuits, and the background flusher never sends anything. |
$ MEMTRACE_TELEMETRY=off memtrace start # disables usage events, error capture, and crash shipping for this run
Even with MEMTRACE_TELEMETRY=off, the panic hook still installs and appends a crash breadcrumb to the local queue file on a crash — it just never ships. This is local-only diagnostic data that stays on disk for your own troubleshooting; nothing from it reaches memtrace.io while telemetry is disabled. Every other stream — usage events, error capture, and shadow measurements — is fully gated by the switch above and produces nothing at all.
The local queue is yours to inspect#
Every stream writes through the same local queue before anything ships, one JSON record per line:
$ cat ~/.memtrace/telemetry/queue.jsonl # one JSON object per line — inspect it any time
A background task drains the queue every 60 seconds. If a flush fails — no network, ingest endpoint down — the queue simply stays on disk and is retried on the next tick, and nothing blocks the work you're actually doing. The queue file is capped at 4 MB, though: if it grows past that (a prolonged outage, or a burst of WARN/ERROR volume) the oldest half of the queued records is dropped to bound disk usage, so a short blip loses nothing but a sustained one can. Because the file is plain JSONL, you can read exactly what would be sent before it ships, or delete it to discard anything queued.