What Telemetry Data Is Stored Locally vs Sent Remotely in No-Mistakes
No-mistakes stores high-frequency CLI surface fingerprints in $(NM_HOME)/telemetry-gate.json locally to throttle network requests, while event and pageview metadata are transmitted via HTTP POST to a configured Umami analytics endpoint.
In the kunchenguid/no-mistakes CLI, telemetry is architected to minimize redundant network traffic while maintaining observability. Understanding what telemetry data is stored locally vs sent remotely helps users audit data residency and developers implement custom instrumentation. The system separates local state persistence from remote transmission through two distinct mechanisms: a disk-based gating system for read-only commands and an asynchronous HTTP client for event submission.
Local Telemetry Storage
Local telemetry exists solely to deduplicate high-frequency read operations. The system writes a small JSON file that tracks when specific CLI surfaces were last emitted, preventing duplicate remote requests for identical operations.
ReadSurfaceGate Implementation
The ReadSurfaceGate type defined in internal/telemetry/readgate.go manages local state persistence. This gate is consulted before sending any read-only telemetry event to determine if sufficient time has elapsed since the last identical emission.
The gate writes to $(NM_HOME)/telemetry-gate.json atomically using os.Rename to prevent partial writes during crashes. According to the source analysis, the implementation limits the file size by enforcing maxReadSurfaceEntries = 64; when this threshold is exceeded, older entries are automatically pruned (see lines 46-71 of readgate.go).
File Location and Format
The local telemetry file contains a JSON map tracking fingerprints of read-only CLI surfaces such as axi-status, axi-home, status, and runs. Each entry stores the fingerprint together with the Unix timestamp of the last successful remote emit.
The gate file is updated only when ReadSurfaceGate.ShouldEmit returns true, which happens when either the fingerprint changes or the configured interval (default 30 seconds) has elapsed since the last emission.
gate := telemetry.NewReadSurfaceGate(
filepath.Join(os.Getenv("NM_HOME"), "telemetry-gate.json"),
30*time.Second, nil,
)
if gate.ShouldEmit("axi-status", fingerprint) {
telemetry.Pageview("/status", nil)
}
Remote Telemetry Transmission
While local storage merely tracks emission timestamps, the actual telemetry content flows to a remote Umami analytics host. The Client type in internal/telemetry/telemetry.go handles all HTTP communication asynchronously.
Event Tracking via Track
When pipeline steps or CLI commands execute significant operations, they call telemetry.Track with an event name and arbitrary key-value fields. This method constructs a collectRequest payload and dispatches it via goroutine to prevent blocking the CLI.
telemetry.Track("run", telemetry.Fields{
"step": "review",
"status": "success",
"duration_ms": 1234,
})
Pageview Tracking via Pageview
For command invocations that represent user navigation (such as viewing status dashboards), the system uses telemetry.Pageview, recording the virtual path and associated metadata.
telemetry.Pageview("/status", telemetry.Fields{
"runs_total": 5,
})
Request Payload Structure
Every remote request includes static metadata regardless of the specific method called. The JSON payload sent to the Umami /api/collect endpoint contains:
{
"type":"event",
"payload":{
"website":"<website-id>",
"hostname":"cli",
"title":"no-mistakes CLI",
"url":"app://no-mistakes/run",
"name":"run",
"data":{"step":"review","status":"success","duration_ms":1234},
"timestamp":1721163425
}
}
The default host resolves from environment variables or falls back to https://a.kunchenguid.com/api/send, with the website ID sourced from buildinfo constants.
Controlling Telemetry Collection
Users can completely disable both local and remote telemetry by setting the environment variable NO_MISTAKES_TELEMETRY=off. When this variable is present, telemetry.Default() returns a noopSink implementation that silently discards all tracking calls without creating the local gate file or issuing HTTP requests.
Summary
- Local storage persists only high-frequency CLI surface fingerprints in
telemetry-gate.json(maximum 64 entries) to throttle redundant network requests. - Remote transmission sends event names, pageview paths, caller-supplied fields, and static metadata (version, OS/arch, hostname) to the configured Umami analytics host.
- Implementation files are located in
internal/telemetry/telemetry.go(HTTP client) andinternal/telemetry/readgate.go(local gating). - Privacy control is available via the
NO_MISTAKES_TELEMETRY=offenvironment variable, which switches to a no-operation sink.
Frequently Asked Questions
Where does no-mistakes store its local telemetry data?
No-mistakes stores local telemetry data in $(NM_HOME)/telemetry-gate.json. This file is created and managed by the ReadSurfaceGate struct in internal/telemetry/readgate.go. It contains a JSON map of CLI surface fingerprints and their last emission timestamps, never exceeding 64 entries.
What specific data is sent to remote analytics servers?
Remote telemetry includes event names (e.g., run, command), pageview paths (e.g., /status), and arbitrary key-value fields supplied by the caller. Every request also transmits static metadata: the application name (no-mistakes), version, operating system, architecture, hostname (cli), and a Unix timestamp. The data is sent to an Umami host via POST request to /api/collect.
How can I completely disable telemetry in no-mistakes?
Set the environment variable NO_MISTAKES_TELEMETRY=off before running any commands. This causes telemetry.Default() to return a noopSink instance, ensuring no local telemetry-gate.json file is created and no HTTP requests are dispatched to analytics servers.
Does the local telemetry file grow indefinitely?
No, the local telemetry file does not grow indefinitely. The ReadSurfaceGate enforces a hard limit of maxReadSurfaceEntries = 64 and automatically prunes older entries during write operations. The file is updated atomically using os.Rename to prevent corruption.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →