# Understanding the Local vs Remote Split for no-mistakes Telemetry Data

> Learn the local vs remote split for no-mistakes telemetry data. Discover how read-surface telemetry stays private while write-surface data provides anonymized usage counts. Ensure data integrity and privacy.

- Repository: [Kun Chen/no-mistakes](https://github.com/kunchenguid/no-mistakes)
- Tags: deep-dive
- Published: 2026-07-19

---

**The `no-mistakes` CLI maintains a strict separation between local read-surface telemetry (stored in `$NM_HOME/telemetry-gate.json` for rate-limiting and never transmitted) and remote write-surface telemetry (sent to a self-hosted Umami instance as anonymized, high-level usage counts).**

The `kunchenguid/no-mistakes` repository implements a privacy-first telemetry architecture that distinguishes between local command usage patterns and remote analytics. Understanding this local vs remote split for no-mistakes telemetry data ensures developers can audit privacy implications while maintaining aggregated insights into feature adoption.

## Local Read-Surface Telemetry (Privacy-Preserving Cache)

The CLI employs a **local-only gate mechanism** to prevent flooding telemetry servers during repetitive read-only operations. When you execute commands like `axi status`, `runs list`, or `stats agents`, the tool records execution metadata strictly on your local filesystem to enforce rate limits without exposing usage patterns to remote servers.

### Gate File Implementation and Rate Limiting

The deduplication logic resides in [`internal/cli/telemetry.go`](https://github.com/kunchenguid/no-mistakes/blob/main/internal/cli/telemetry.go), where `telemetry.NewReadSurfaceGate` initializes a persistent gate backed by JSON state. The system writes timestamp fingerprints to `$NM_HOME/telemetry-gate.json` (resolved via `paths.TelemetryGateFile()` in [`internal/paths/paths.go`](https://github.com/kunchenguid/no-mistakes/blob/main/internal/paths/paths.go)), ensuring identical read-surface events emit no more than once per 10-minute window. This local storage acts as a circuit breaker, not a data collection mechanism.

### Guaranteed Local-Only Storage

Because read-surface commands perform no mutations, the captured events contain **zero network transmission logic**. The gate file exists solely to respect the user's computational resources and the project's infrastructure limits. According to the implementation in [`internal/cli/axi_telemetry_test.go`](https://github.com/kunchenguid/no-mistakes/blob/main/internal/cli/axi_telemetry_test.go), these events never invoke the `Track` method, guaranteeing that command history, file paths, and execution context remain confined to the host machine.

## Remote Write-Surface Telemetry (Anonymous Usage Analytics)

State-changing operations trigger the remote telemetry pipeline. When a run finishes, a wizard step completes, or a fix is applied, the CLI transmits high-level event signatures to a self-hosted analytics endpoint.

### Umami Integration and Build-Time Defaults

The remote destination is defined in [`internal/telemetry/telemetry.go`](https://github.com/kunchenguid/no-mistakes/blob/main/internal/telemetry/telemetry.go) through compile-time variables `TelemetryHost` and `TelemetryWebsiteID`. These default to the project's Umami instance but accept runtime overrides via environment variables:

- `TELEMETRY_HOST` – Redirects events to a custom analytics endpoint
- `TELEMETRY_WEBSITE_ID` – Specifies the target website identifier within the Umami instance
- `TELEMETRY_DISABLED` – Boolean flag to suppress all remote transmission

The `telemetry.Track` function marshals event structs and POSTs them to the configured host, but only after sanitization.

### Privacy-Safe Event Shaping

To enforce the local vs remote split, [`internal/agent/invocationmetrics.go`](https://github.com/kunchenguid/no-mistakes/blob/main/internal/agent/invocationmetrics.go) implements strict payload validation. Remote events contain only categorical counters (e.g., `"run finished"`, `"wizard action"`, `"fix auto"`) and deliberately exclude raw prompts, code diffs, file system paths, or secret values. The `TestAgentInvocations_PrivacySafeShape` test suite verifies that no sensitive data crosses the network boundary, ensuring compliance with the privacy-first design documented in [`docs/src/content/docs/reference/environment.md`](https://github.com/kunchenguid/no-mistakes/blob/main/docs/src/content/docs/reference/environment.md).

## Configuring the Telemetry Split

Developers can control both local and remote behavior through environment configuration.

Disable all telemetry (local gate updates and remote transmission):

```bash
export TELEMETRY_DISABLED=1
no-mistakes axi status   # No gate write, no network call

```

Redirect remote analytics to a self-hosted endpoint:

```bash
export TELEMETRY_HOST=https://umami.internal.example.com
export TELEMETRY_WEBSITE_ID=abcd1234-ef56-7890-abcd-1234567890ab
no-mistakes run          # Emits to your infrastructure only

```

Inspect the local gate file location programmatically:

```go
package main

import (
    "fmt"
    "github.com/kunchenguid/no-mistakes/internal/paths"
)

func main() {
    p := paths.New()
    gatePath := p.TelemetryGateFile()
    fmt.Println("Local gate:", gatePath)  // Output: $NM_HOME/telemetry-gate.json
}

```

Manually record a custom remote event (advanced usage):

```go
import "github.com/kunchenguid/no-mistakes/internal/telemetry"

func recordCustomEvent() {
    telemetry.Track("custom_feature", telemetry.Fields{
        "action": "demo_trigger",
        "count":  1,
    })
}

```

## Core Implementation Files

| File | Purpose |
|------|---------|
| [`internal/telemetry/telemetry.go`](https://github.com/kunchenguid/no-mistakes/blob/main/internal/telemetry/telemetry.go) | Defines `TelemetryHost`, `TelemetryWebsiteID`, and the `Track` function that dispatches remote events |
| [`internal/cli/telemetry.go`](https://github.com/kunchenguid/no-mistakes/blob/main/internal/cli/telemetry.go) | Implements `NewReadSurfaceGate` and manages local gate state for read-only commands |
| [`internal/paths/paths.go`](https://github.com/kunchenguid/no-mistakes/blob/main/internal/paths/paths.go) | Provides `TelemetryGateFile()` resolver for local JSON state persistence |
| [`internal/agent/invocationmetrics.go`](https://github.com/kunchenguid/no-mistakes/blob/main/internal/agent/invocationmetrics.go) | Enforces privacy-safe payload shapes before remote transmission |
| [`docs/src/content/docs/reference/environment.md`](https://github.com/kunchenguid/no-mistakes/blob/main/docs/src/content/docs/reference/environment.md) | Documents `TELEMETRY_HOST`, `TELEMETRY_WEBSITE_ID`, and `TELEMETRY_DISABLED` |
| [`internal/cli/axi_telemetry_test.go`](https://github.com/kunchenguid/no-mistakes/blob/main/internal/cli/axi_telemetry_test.go) | Validates that read-surface telemetry remains bounded and local-only |

## Summary

- **Local telemetry** uses a gate file (`$NM_HOME/telemetry-gate.json`) to deduplicate read-only CLI events within 10-minute windows, stored via [`internal/paths/paths.go`](https://github.com/kunchenguid/no-mistakes/blob/main/internal/paths/paths.go) and managed by [`internal/cli/telemetry.go`](https://github.com/kunchenguid/no-mistakes/blob/main/internal/cli/telemetry.go), with **zero network transmission**.
- **Remote telemetry** sends anonymized, categorical event counts to a configurable Umami endpoint via `telemetry.Track` in [`internal/telemetry/telemetry.go`](https://github.com/kunchenguid/no-mistakes/blob/main/internal/telemetry/telemetry.go), strictly excluding prompts, diffs, and secrets as enforced by [`internal/agent/invocationmetrics.go`](https://github.com/kunchenguid/no-mistakes/blob/main/internal/agent/invocationmetrics.go).
- **Configuration** happens through `TELEMETRY_DISABLED`, `TELEMETRY_HOST`, and `TELEMETRY_WEBSITE_ID`, allowing complete opt-out or self-hosted analytics while preserving the local/remote architectural boundary.

## Frequently Asked Questions

### How do I completely disable telemetry in no-mistakes?

Set the `TELEMETRY_DISABLED` environment variable to `1` before executing any command. This flag suppresses both local gate file updates and remote network calls, ensuring zero telemetry activity regardless of command type.

### What data is included in remote telemetry events?

Remote events contain only high-level categorical identifiers such as `"run finished"` or `"wizard step completed"`. As implemented in [`internal/agent/invocationmetrics.go`](https://github.com/kunchenguid/no-mistakes/blob/main/internal/agent/invocationmetrics.go), the payloads exclude all sensitive data including raw prompts, code diffs, repository paths, and environment secrets.

### Where is the local telemetry gate file stored?

The gate file is located at `$NM_HOME/telemetry-gate.json`, where `$NM_HOME` resolves to the user's no-mistakes configuration directory. The path is computed by the `TelemetryGateFile()` method in [`internal/paths/paths.go`](https://github.com/kunchenguid/no-mistakes/blob/main/internal/paths/paths.go) and persists the last emission timestamps for read-surface commands.

### Can I self-host the telemetry endpoint?

Yes. Override the default Umami instance by setting `TELEMETRY_HOST` to your self-hosted URL and `TELEMETRY_WEBSITE_ID` to your site's tracking ID. The `telemetry.Track` function in [`internal/telemetry/telemetry.go`](https://github.com/kunchenguid/no-mistakes/blob/main/internal/telemetry/telemetry.go) reads these variables at runtime and directs all write-surface events to your specified infrastructure.