# How the no-mistakes Update Checker Notifies Users of New Versions

> Learn how the no-mistakes update checker notifies users of new versions by querying GitHub, caching releases, and displaying colored alerts on startup. Stay up-to-date effortlessly.

- Repository: [Kun Chen/no-mistakes](https://github.com/kunchenguid/no-mistakes)
- Tags: how-to-guide
- Published: 2026-07-02

---

**The no-mistakes CLI spawns a background process on every startup that queries the GitHub Releases API, caches the latest version in a JSON file, and prints a colored notification to stderr if a newer release exists.**

The `no-mistakes` repository implements a self-contained update notification system that runs transparently without blocking command execution. This mechanism checks for new versions by comparing the running binary against the latest GitHub release, ensuring users stay current without manual polling. The entire flow is orchestrated through five distinct steps that balance immediacy with API rate limit protection.

## The Notification Flow

The update checker operates through a coordinated foreground-background process that minimizes startup latency while ensuring fresh version data.

### Initialize the Updater

When the CLI starts, it immediately calls `defaultUpdater` in [`internal/update/update.go`](https://github.com/kunchenguid/no-mistakes/blob/main/internal/update/update.go). This function creates an `updater` struct containing the application name, the current binary version (pulled from [`internal/buildinfo/version.go`](https://github.com/kunchenguid/no-mistakes/blob/main/internal/buildinfo/version.go)), a path to a JSON cache file, and writers for stdout and stderr.

### Spawn a Background Check

If the binary is not a development build, the updater launches a detached subprocess via [`internal/update/background.go`](https://github.com/kunchenguid/no-mistakes/blob/main/internal/update/background.go). This subprocess executes the same binary with the special `--update-check` flag, allowing the version check to run asynchronously without blocking the main CLI operation.

### Query GitHub for Releases

The background process executes `u.checkLatest`, which utilizes the GitHub Releases API through `fetchLatestRelease` in [`internal/update/release.go`](https://github.com/kunchenguid/no-mistakes/blob/main/internal/update/release.go). The system specifically filters for the newest **non-prerelease** tag to ensure stability. The result is then written to `<cachePath>/update-check.json` by the cache layer in [`internal/update/cache.go`](https://github.com/kunchenguid/no-mistakes/blob/main/internal/update/cache.go).

### Cache Reading and Comparison

Back in the foreground process, `maybeNotifyAndCheck` loads the cached version data early in the startup sequence. It compares the `LatestVersion` field from the cache against the current binary version to determine if an update is available.

### Display the Notification

If a newer version exists and the user is not already running the `update` command or the `--update-check` flag, the updater prints a colored message to **stderr**:

```go
fmt.Fprintf(u.stderrWriter(),
    "%sA new version of %s is available: %s -> %s\nRun \"%s update\" to update%s\n",
    u.yellow(),
    u.appName,
    u.currentVersion,
    cache.LatestVersion,
    u.appName,
    u.reset())

```

The output appears as:

```bash
⚠️  A new version of no-mistakes is available: v1.2.2 -> v1.2.3
Run "no-mistakes update" to update

```

## Key Implementation Details

Several implementation choices ensure the update checker remains lightweight and non-intrusive.

**Cache File Management** – The [`internal/update/cache.go`](https://github.com/kunchenguid/no-mistakes/blob/main/internal/update/cache.go) file stores the JSON payload in [`update-check.json`](https://github.com/kunchenguid/no-mistakes/blob/main/update-check.json) with fields including `LatestVersion` and `CheckedAt`. This prevents hammering the GitHub API on every CLI invocation by respecting a reasonable time window between checks.

**Background Flag** – The literal `--update-check` string (defined as `backgroundFlag`) distinguishes the background runner from normal CLI invocations, ensuring the subprocess terminates after updating the cache rather than executing user commands.

**Terminal Colors** – The `yellow()` and `reset()` helper methods emit standard ANSI color escape sequences, making the notification visually prominent without breaking terminal compatibility.

**Daemon Coordination** – Before replacing the binary during an actual update, the system calls `ensureDaemonUsesCurrentExecutable` from [`internal/update/daemon.go`](https://github.com/kunchenguid/no-mistakes/blob/main/internal/update/daemon.go). This verification prevents version mismatches between the CLI binary and any running daemon processes.

## Code Examples

### Automatic Notification on Startup

When you run any standard command, the notification appears automatically on stderr:

```bash
$ no-mistakes status
⚠️  A new version of no-mistakes is available: v1.2.2 -> v1.2.3
Run "no-mistakes update" to update

```

This notice prints to stderr specifically so it remains visible even when stdout is piped to other programs.

### Performing the Update

Users can trigger the actual update process with:

```bash
$ no-mistakes update
Downloading v1.2.3…
Extracting…
updated no-mistakes from v1.2.2 to v1.2.3

```

If active pipeline runs exist, the [`active_runs.go`](https://github.com/kunchenguid/no-mistakes/blob/main/active_runs.go) logic will prompt for confirmation before proceeding with the binary replacement.

### Internal Implementation

The following simplified Go code demonstrates how the check is triggered during CLI initialization:

```go
func main() {
    // Set up stdout/stderr writers
    upd, _ := defaultUpdater(os.Stdout, os.Stderr)
    
    // Run the background check without blocking
    go upd.startBackgroundCheck(context.Background())
    
    // Later, after parsing CLI args:
    upd.maybeNotifyAndCheck(os.Args[1:])
    
    // Continue with normal command handling…
}

```

## Summary

- The `no-mistakes` update checker runs a background process on every CLI startup via [`internal/update/background.go`](https://github.com/kunchenguid/no-mistakes/blob/main/internal/update/background.go).
- It queries the GitHub Releases API for the latest non-prerelease tag and stores the result in a local JSON cache managed by [`internal/update/cache.go`](https://github.com/kunchenguid/no-mistakes/blob/main/internal/update/cache.go).
- The foreground process compares cached versions using `maybeNotifyAndCheck` in [`internal/update/update.go`](https://github.com/kunchenguid/no-mistakes/blob/main/internal/update/update.go).
- Notifications print to stderr using yellow ANSI color codes to ensure visibility without interfering with piped output.
- The system includes safeguards in [`internal/update/daemon.go`](https://github.com/kunchenguid/no-mistakes/blob/main/internal/update/daemon.go) to ensure daemon-binary version consistency before performing updates.

## Frequently Asked Questions

### How often does no-mistakes check for updates?

The background check spawns on every CLI invocation, but the actual GitHub API query respects the cache timestamp stored in [`update-check.json`](https://github.com/kunchenguid/no-mistakes/blob/main/update-check.json). If the cache is fresh (typically within a few hours), the background process reads the existing cache rather than hitting the API, preventing rate limit issues while keeping version information relatively current.

### Where does no-mistakes store the update cache?

The cache file location is determined during `updater` initialization in [`internal/update/update.go`](https://github.com/kunchenguid/no-mistakes/blob/main/internal/update/update.go). The system writes to a JSON file named [`update-check.json`](https://github.com/kunchenguid/no-mistakes/blob/main/update-check.json) in a platform-specific cache directory, storing fields like `LatestVersion` and `CheckedAt` to track when the last successful API query occurred.

### Why does the notification print to stderr instead of stdout?

According to the implementation in [`internal/update/update.go`](https://github.com/kunchenguid/no-mistakes/blob/main/internal/update/update.go), the notification specifically uses `u.stderrWriter()` rather than standard output. This design choice ensures that users see update warnings even when piping command output to files or other processes, and it prevents the notification text from contaminating structured data streams.

### What happens if I run no-mistakes update while the daemon is active?

The updater calls `ensureDaemonUsesCurrentExecutable` from [`internal/update/daemon.go`](https://github.com/kunchenguid/no-mistakes/blob/main/internal/update/daemon.go) before replacing the binary. This function verifies that any running daemon instance is using the same executable file that is about to be updated. If version mismatches are detected, the system handles coordination to prevent inconsistent states between the CLI and background daemon processes.