This document is an honest, complete disclosure of what Loki Mode collects, what it never collects, and how to turn collection off. If anything here does not match the code, the code is the bug; please open an issue.
loki telemetry off /
LOKI_TELEMETRY=off / LOKI_TELEMETRY_DISABLED=true / DO_NOT_TRACK=1 /
~/.loki/config: TELEMETRY_DISABLED=true. Conversely loki telemetry on
force-enables even inside CI/enterprise if you want to send us diagnostics.When Loki Mode hits an unexpected error (an uncaught exception, an unhandled promise rejection, a nonzero process exit, or an explicit friction signal such as a retry loop, a rate-limit loop, or a quality-gate failure), it captures a scrubbed diagnostic report.
Phase 0 behavior:
.loki/crash/<id>.json in your
project directory.loki crash lists local reports.loki crash show <id> prints one report exactly as stored.loki crash submit [<id>] prints the full scrubbed payload and a prefilled
GitHub issue URL so you can submit it manually if you choose. Loki Mode does
not submit anything for you in this version.Loki Mode sends anonymous usage telemetry via PostHog. It is ON by default for an
ordinary individual install, and AUTO-OFF in enterprise, CI, air-gapped, and
non-interactive contexts (see the precedence below). It is gated by the same
switch as crash reporting, so a single opt-out (loki telemetry off /
DO_NOT_TRACK=1) disables everything, and it never sends your code, prompts,
paths, keys, or repo names – only anonymous diagnostics.
https://us.i.posthog.com/capture/ (override with
LOKI_TELEMETRY_ENDPOINT). The PostHog project key is a public ingest key.install (on npm install), session_start, session_end,
cli_command, and dashboard_start.os (uname system), arch (CPU arch),
version (Loki Mode version), channel (npm / docker / homebrew / skill /
source), and a random per-machine distinct_id (a uuid4 stored in
~/.loki-telemetry-id, never an email or name). The install event also adds
node_version and providers_installed (which provider CLIs were detected,
e.g. “claude,codex”). Some events add a small free-of-PII property such as the
command name. No code, prompts, paths, keys, repo names, emails, or IPs.The loki welcome page (assets/welcome/welcome.html) shows an optional form.
It NEVER sends anything on page load and is rendered inert unless you have opted
in. If you have opted in AND you choose to fill in and submit the form, it sends
these additional self-reported fields to PostHog: your role, company size, and
the tools you use, plus the same anonymous distinct_id. It still never sends
your name, email, or IP. In headless / Docker / CI environments there is no
browser, so this path never runs.
A build_verified event that reports how a build turned out. Unlike crash
reporting and usage telemetry (which default ON for individuals), this path is
OFF by default even for users who have telemetry enabled – it requires a
SECOND, explicit opt-in:
LOKI_ANALYTICS=on (or LOKI_POSTHOG=on), orANALYTICS_ENABLED=true to ~/.loki/config.It fires once when a build finishes, reading a FIXED allowlist of already-
computed scalars from the run’s Evidence Receipt (proof.json). The allowlist
(autonomy/lib/proof-analytics-props.py) is the single source of truth; any
field not named there is never read, so a schema change cannot silently start
sending something new. Fields sent:
It NEVER sends your spec/PRD text, file paths or names, code, or diffs. Because
it sits below the base telemetry gate, every telemetry opt-out (loki telemetry
off / LOKI_TELEMETRY=off / DO_NOT_TRACK=1) also disables it – opt-out
always wins.
A first_run_blocked event naming which CLASS of dependency stopped a first
run, sent at most ONCE per install. It sits behind the same strict second
opt-in as build-outcome analytics above (LOKI_ANALYTICS=on), so it is off by
default even with telemetry enabled.
It exists because we could see that a first run was ATTEMPTED and nothing about
whether it succeeded, which made “why does a trial not convert” unanswerable.
A real example we found and fixed: on a machine with no AI provider CLI, one
route ended with a dead end instead of pointing at loki tour (which needs no
provider, no key and no spend). Nobody could see that happening.
The ONLY field is blocker, clamped to this fixed enum:
no_provider | node | python3 | jq | git | curl | disk | skill_symlink | other
Anything not on that list becomes other. It is deliberately coarse: node is
enough to act on, and a version string or an install path would be a leak. It
NEVER sends paths, versions, hostnames, spec text, or command lines – a test
(tests/test-first-run-blocked-signal.sh) feeds a filesystem path through the
real emitter and fails the build if anything but other reaches the payload.
This document and the first-run notice describe ALL paths. The model is unified: opt-out always wins and disables everything; crash reporting and usage telemetry opt in together (default ON for individuals); build-outcome analytics and the first-run blocker each need an explicit second opt-in on top (default OFF).
Crash reports contain ONLY the following fields. Anything not on this list is dropped, not merely redacted:
~; paths are not whitelisted)Because the report is whitelist-only (deny by default), free-text fields such as prompts, briefs, and diffs can never reach the payload even if a redaction rule were to miss something. Secrets are additionally scrubbed by the shared redactor before whitelisting.
Anonymous diagnostics are ON by default for an ordinary individual install. To turn them off at any time, use ANY one of the following. Opt-out always wins, so setting one of these guarantees nothing is collected or sent:
loki telemetry off (persists TELEMETRY_DISABLED=true to ~/.loki/config)LOKI_TELEMETRY=offDO_NOT_TRACK=1 (the cross-tool community convention)LOKI_TELEMETRY_DISABLED=trueTo FORCE it on (for example to send us diagnostics from a context that would otherwise auto-disable, like CI), use ANY one of:
loki telemetry on (persists TELEMETRY_ENABLED=true to ~/.loki/config)LOKI_TELEMETRY=on (exact word on, case-insensitive)loki telemetry on / LOKI_TELEMETRY=on /
TELEMETRY_ENABLED=true) is set, collection is ON (this overrides the
enterprise/CI/air-gapped auto-off below).In all enabled cases, if curl is unavailable there is no egress.
A default install in an air-gapped, CI, or non-interactive environment sends us
no telemetry or diagnostics: collection AUTO-DISABLES there (step 3 above), so
there is nothing to turn off. To make collection impossible across a fleet
regardless of context, bake LOKI_TELEMETRY_DISABLED=true (or DO_NOT_TRACK=1)
into your base image or CI environment; opt-out always wins over everything,
including a stray loki telemetry on.
This same gate covers ALL paths: the npm install event, CLI session and
command events, the dashboard event, the welcome form, and local crash capture.
loki telemetry enable [endpoint] and LOKI_OTEL_ENDPOINT configure optional
OpenTelemetry tracing to an endpoint YOU run. There is no default endpoint, so
this never egresses to us; it is opt-in by definition and points only where you
tell it to.
Scrubbed crash reports live in .loki/crash/ inside your project directory. You
can open these files in any text editor or use loki crash show <id>. In Phase 0
this directory is the only place crash data exists; it is yours to read or
delete at any time.
The project_id_hash is a SHA-256 hash of your git remote origin URL, after
normalizing it (scheme removed, .git suffix removed, trailing slash removed,
host lowercased). It does NOT hash your local filesystem path, so it carries no
/Users/<name>/ style information.
The hash is unsalted on purpose. An unsalted hash lets two users who hit the same bug in the same public repository collapse to a single triage entry, which is the entire point of deduplication and occurrence counting. A per-user salt would defeat that. The cost of leaving it unsalted is that, for a known PUBLIC repository, someone could hash candidate repo URLs and check for a match. But the only thing that would reveal is which public repository was involved, which is already public information, so the privacy cost is acceptable. For a PRIVATE repository, the origin still hashes to an opaque value that leaks no path or name. We chose cross-user dedup over per-user unlinkability, and we are stating that choice plainly so you can decide whether to opt out.
loki telemetry off /
DO_NOT_TRACK=1) always wins and disables everything..loki/crash/.Open an issue at https://github.com/asklokesh/loki-mode/issues and we will clarify or correct this document.