Skip to main content

Telemetry

raid ships an opt-in, anonymous CLI telemetry pipeline so the team can prioritize features against real usage signal — which task types matter, which commands fail, which features go unused — without ever capturing what you actually run.

Off by default. A fresh install never sends anything to the telemetry endpoint until you explicitly run raid telemetry on (or accept the first-run prompt). The one narrow exception is the follow-up question: if you decline the first-run prompt and then explicitly answer yes to the follow-up, raid sends exactly one anonymous raid_telemetry_opt_out event and then stays off forever. Answering no to the follow-up (or skipping it for any reason) means raid still sends nothing. When opted out, raid makes zero further telemetry / PostHog requests, and there's an integration test that pins this contract. (raid still performs an unrelated GitHub release-version check on normal invocations regardless of telemetry state — that request is independent of this pipeline.)

What raid collects

EventProperties (sanitized)
raid_first_runos, arch, raid_version, install_method (best-effort)
raid_command_executedcommand_name, task_count, task_types[], duration_ms, success
raid_command_failedcommand_name, error_code (from the errors table), duration_ms
raid_task_executedtask_type, duration_ms, successsampled at ~10% to bound volume
raid_telemetry_opt_outreason — either "prompt-declined" (set automatically when you accept the follow-up question) or the free-text string from raid telemetry off --why "...". Optional; absent when neither path was used.

Every event also carries: distinct_id (anonymous UUIDv4 from ~/.config/raid/telemetry-id), raid_version, os (e.g. darwin/linux/windows), arch (e.g. arm64/amd64).

What raid never collects

  • Command bodies. cmd:, path:, runner:, src:, dest:, url: — never sent.
  • Variable values. Anything set by a Set task or passed in env vars.
  • Argument values. RAID_ARG_*, declared args, declared flag values. The one exception is the explicit opt-out reason: raid telemetry off --why "..." sends the free-text string you typed as the reason property on raid_telemetry_opt_out — and only on that event. raid never collects argument or flag values implicitly.
  • Stdout / stderr. Task output is never captured by the telemetry layer.
  • Identifiers. Username, hostname, IP, MAC, OS version beyond darwin/linux/windows, terminal emulator — none.
  • File paths beyond their kind. task_types: ["shell", "shell", "print"] is fine; the actual paths are not.

The source of truth is the src/internal/telemetry package. Every event builder is a tiny pure function — read them yourself.

On your first interactive raid <command> invocation after install, raid prints the consent prompt to stderr:

raid would like to send anonymous usage telemetry to help prioritize features.
We never collect: file paths, command contents, env values, or anything that could identify you.
See: https://raidcli.dev/docs/telemetry

[y] yes, send telemetry [N] no, leave it off [?] what's collected
>

Default is no (capital N). [?] shows the long-form disclosure inline and re-asks.

Follow-up: may we record the denial?

If you decline the first prompt, raid asks one follow-up question:

Telemetry is off. May raid send a single anonymous event recording your decision?
This is the only event raid would ever send; it helps the project measure how
many users opt out vs. opt in. Same anonymity guarantees as above.

[y] yes, send once [N] no, send nothing at all
>

Default is no again. Answering yes fires exactly one raid_telemetry_opt_out event (with reason: "prompt-declined") and then leaves telemetry permanently off — that's the whole transaction. Answering no (or hitting Enter) skips the network entirely; raid touches zero endpoints for the remainder of the install.

The follow-up exists because opt-out rate is the most useful single signal for the project: without it, we can't tell whether a quiet user has opted out actively or just never finished setup. It's also why the follow-up exists only on the explicit-decline path — when you skip the first prompt for any other reason (non-TTY, headless, DO_NOT_TRACK, etc.), raid never asks anything further.

Non-interactive contexts skip the prompt entirely and leave telemetry off. Specifically, raid does not prompt when:

  • DO_NOT_TRACK=1 is set in the environment (cross-tool standard — consoledonottrack.com).
  • -y, --yes, or --headless is on the command line (see Headless mode).
  • --json is on the command line (machine-readable output mode).
  • stdin isn't a TTY (CI runners, pipes, agent hosts).
  • This raid build wasn't compiled with a PostHog API key (dev builds — telemetry is dead code).
  • The invocation is a raid telemetry ... subcommand (so you can run raid telemetry on without being prompted to opt in first).

In each of these cases raid records the decision as off-by-default so it won't try to prompt later either. Switch back on explicitly with raid telemetry on.

Managing telemetry

raid telemetry on # opt in
raid telemetry off # opt out
raid telemetry off --why "ci runner" # opt out + record an anonymous reason
raid telemetry status # show current state, anonymous ID, ID file path
raid telemetry status --json # same, as JSON
raid telemetry purge # delete the anonymous ID file (breaks linkage to past events)
raid telemetry preview # render a sample event payload — does not send

raid telemetry preview is the recommended way to see exactly what raid would post before opting in. The API key is automatically redacted in the preview output so you can paste it anywhere.

Three ways to opt out

  1. raid telemetry off — persists the choice; future runs stay off.
  2. DO_NOT_TRACK=1 — env var; overrides the persisted state for the current process and any child it spawns. Honored on every run regardless of telemetry on.
  3. Never opt in. The first-run prompt defaults to off, and non-interactive contexts skip the prompt entirely.

You can purge the anonymous machine ID at any time with raid telemetry purge — that breaks linkage between future events and any sent before. Useful if you've been opted in for a while and want to reset.

Destination

  • PostHog US Cloud, project Raid (id 403603).
  • Endpoint: https://us.i.posthog.com/i/v0/e/.
  • The PostHog publishable project key is baked into release builds at compile time via a ldflag. Dev / go run builds have no key and never send.

Network failures are always silent. A 2-second HTTP timeout, fire-and-forget goroutines, and a 1.5-second flush deadline at process exit mean a stuck network can't slow raid down or break a command.

Source code

The entire telemetry implementation is in src/internal/telemetry:

FileRole
telemetry.goCapture, Flush, the HTTP send path, PreviewPayload
consent.goConsent state (read/write via viper) + DO_NOT_TRACK honor
id.goAnonymous UUIDv4 generation + persistence + purge
events.goEvent builders. Every builder is a few lines — easy to audit.
sampling.goPer-task sample rate
prompt.goFirst-run consent prompt flow

The test file telemetry_test.go pins the contracts above: zero network calls when opted out, zero network calls under DO_NOT_TRACK, sanitization of every event builder, UUIDv4 format of the anonymous ID, and the redacted-key preview output.