# No-Mistakes Environment Variables: Complete Guide to NM_HOME, Logging, and Daemon Control

> Master No-Mistakes environment variables to control NM_HOME, logging, and daemon behavior. Get the complete guide for seamless configuration and operation.

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

---

**The no-mistakes CLI and daemon are controlled by environment variables including `NM_HOME` for state directory resolution, `NM_DEMO` for demo mode, and `NM_TEST_*` variables for test harness configuration, all read via `os.Getenv` or the `upsertEnv` helper in the Go source.**

The `kunchenguid/no-mistakes` repository relies on a small, well-documented set of environment variables to locate per-user state and configure daemon behavior. These variables are read directly from the process environment using standard library calls like `os.Getenv` and custom helpers, providing fine-grained control over data persistence, service lifecycle, and network proxy configuration.

## Core State and Runtime Variables

### NM_HOME – Root Directory for State

The **`NM_HOME`** variable defines the root directory for all persistent files, including the database, daemon socket, configuration, and logs. If unset, the code in [`internal/paths/paths.go`](https://github.com/kunchenguid/no-mistakes/blob/main/internal/paths/paths.go) defaults to `$HOME/.no-mistakes`.

Path resolution flows through `paths.New()` → `paths.WithRoot()` → `paths.Root()`, ensuring all I/O operations are scoped consistently. When the daemon registers as a managed service (launchd, systemd, or Windows Task), the service name incorporates a hash of `NM_HOME` via `serviceInstanceSuffix`, preventing collisions between different state directories.

### NM_DEMO – Demo Mode Configuration

Setting **`NM_DEMO=1`** enables demo mode, where pipeline steps skip real network calls and return static data. This mode is implemented in [`internal/pipeline/steps/demo.go`](https://github.com/kunchenguid/no-mistakes/blob/main/internal/pipeline/steps/demo.go) and is used primarily for recorded end-to-end demonstrations.

### NM_DAEMON – Daemon Process Flag

The **`NM_DAEMON`** variable is set internally by the main binary when it re-executes itself as a background process (`NM_DAEMON=1`). As implemented in [`internal/daemon/selfexec.go`](https://github.com/kunchenguid/no-mistakes/blob/main/internal/daemon/selfexec.go), this flag signals the entry point to run the daemon loop rather than the CLI, allowing the same binary to serve both interactive and background roles.

## Daemon Control and Test Harness Variables

### Bypassing Service Management in Tests

**`NM_TEST_START_DAEMON`** acts as an escape hatch for the test harness. When set to `1`, the function `defaultServiceManagerBypassed()` in [`internal/daemon/service.go`](https://github.com/kunchenguid/no-mistakes/blob/main/internal/daemon/service.go) pretends the managed service is already running, avoiding interactions with system-level service managers like systemd or launchd.

### Daemon Startup Timing Controls

Two variables fine-tune the daemon startup polling behavior used during testing:

- **`NM_TEST_DAEMON_START_TIMEOUT`** – Overrides the default 5-second startup timeout (parsed via `durationFromEnv` in [`internal/daemon/selfexec.go`](https://github.com/kunchenguid/no-mistakes/blob/main/internal/daemon/selfexec.go))
- **`NM_TEST_DAEMON_START_POLL_INTERVAL`** – Controls how frequently the test harness polls the daemon for readiness

### Helper Process and Internal Flags

**`NM_DAEMON_HELPER_PROCESS`** is an internal flag used by the daemon's self-exec logic to spawn "helper" child processes. Valid values include `1` or `block`, which are consumed in [`internal/daemon/helpers_test.go`](https://github.com/kunchenguid/no-mistakes/blob/main/internal/daemon/helpers_test.go) and [`internal/daemon/service_test.go`](https://github.com/kunchenguid/no-mistakes/blob/main/internal/daemon/service_test.go) to force early exit or block the helper for testing purposes.

### Capturing NM_HOME for Verification

**`NM_CAPTURE_NM_HOME_FILE`** specifies a file path where the daemon writes the effective `NM_HOME` value it sees. This verification mechanism, used in [`internal/daemon/service_test.go`](https://github.com/kunchenguid/no-mistakes/blob/main/internal/daemon/service_test.go), ensures that a daemon launched under a different `NM_HOME` does not clobber another instance's state.

## Network and Logging Configuration

### Proxy Environment Variables

The daemon automatically forwards standard proxy variables into its managed service environment so agents can reach the internet through corporate proxies. The relevant keys are collected in `serviceProxyEnv` within [`internal/daemon/service.go`](https://github.com/kunchenguid/no-mistakes/blob/main/internal/daemon/service.go):

- `HTTP_PROXY` / `http_proxy`
- `HTTPS_PROXY` / `https_proxy`
- `NO_PROXY` / `no_proxy`
- `ALL_PROXY` / `all_proxy`

These values are written into the generated launchd, systemd, or Windows Task definition with mode `0600`, preventing accidental credential exposure.

### Test Logging Conventions

While the daemon itself writes to OS-managed logs (systemd journal, macOS Console, Windows Event Log), the test harness uses **`NO_MISTAKES_CALL_LOG`** (sometimes referenced as `NM_LOG_FILE` in documentation) to audit CLI invocations. As implemented in [`install_script_test.go`](https://github.com/kunchenguid/no-mistakes/blob/main/install_script_test.go), this variable specifies a path where the install script appends each CLI invocation, providing a simple audit trail for verification.

### Shell Environment Plumbing

Two internal variables coordinate the shell-env sub-process that safely captures grand-child processes:

- **`NM_SHELLENV_PIPE_HELPER`** – Set by the helper process
- **`NM_SHELLENV_PIPE_READY`** – Points to a pipe file the parent monitors

These are defined in [`internal/shellenv/shell_command_unix_test.go`](https://github.com/kunchenguid/no-mistakes/blob/main/internal/shellenv/shell_command_unix_test.go) and handle coordination between the CLI and its spawned shells.

## How Variables Interact at Runtime

At startup, the CLI builds a `paths.Paths` object by checking `NM_HOME` and falling back to the default. When starting the daemon:

1. The `daemon` command sets `NM_HOME` explicitly via `os.Setenv("NM_HOME", root)` before forking
2. The child process launches with `NM_DAEMON=1` to enter daemon mode
3. If `NM_TEST_START_DAEMON=1` is present, the service manager integration is bypassed
4. Proxy variables are captured once and baked into the service definition via `serviceProxyEnv`

This ensures that state isolation, network configuration, and service management are deterministic and testable.

## Practical Code Examples

Configure a custom state directory and run in demo mode:

```bash
export NM_HOME=$HOME/.no-mistakes-demo
export NM_DEMO=1
no-mistakes daemon start

```

Override daemon startup timeout during integration testing:

```bash
export NM_TEST_DAEMON_START_TIMEOUT=10s
export NM_TEST_DAEMON_START_POLL_INTERVAL=100ms
go test ./internal/daemon/...

```

Capture the effective NM_HOME for verification:

```bash
export NM_CAPTURE_NM_HOME_FILE=/tmp/captured_home
no-mistakes daemon start
cat /tmp/captured_home  # Outputs the path the daemon resolved

```

Launch with corporate proxy settings:

```bash
export HTTP_PROXY="http://proxy.example.com:3128"
export NO_PROXY="localhost,127.0.0.1"
no-mistakes daemon start  # Proxy env is embedded in service definition

```

Programmatically create a paths object in Go:

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

// Reads NM_HOME from environment automatically
p := paths.New("my/custom/home")
if err := daemon.Start(p); err != nil {
    log.Fatalf("daemon start failed: %v", err)
}

```

## Summary

- **`NM_HOME`** controls the root directory for all persistent state, defaulting to `$HOME/.no-mistakes` and processed through [`internal/paths/paths.go`](https://github.com/kunchenguid/no-mistakes/blob/main/internal/paths/paths.go)
- **`NM_DEMO`** enables static demo mode by skipping network calls in [`internal/pipeline/steps/demo.go`](https://github.com/kunchenguid/no-mistakes/blob/main/internal/pipeline/steps/demo.go)
- **`NM_DAEMON`** signals the binary to run as a background service via [`internal/daemon/selfexec.go`](https://github.com/kunchenguid/no-mistakes/blob/main/internal/daemon/selfexec.go)
- **`NM_TEST_START_DAEMON`** and **`NM_TEST_DAEMON_START_TIMEOUT`** provide test harness control over service lifecycle and timing
- **Proxy variables** (`HTTP_PROXY`, `HTTPS_PROXY`, etc.) are forwarded into managed service definitions in [`internal/daemon/service.go`](https://github.com/kunchenguid/no-mistakes/blob/main/internal/daemon/service.go)
- **`NO_MISTAKES_CALL_LOG`** supports CLI audit logging for test verification

## Frequently Asked Questions

### What happens if NM_HOME is not set?

If `NM_HOME` is empty, the code in [`internal/paths/paths.go`](https://github.com/kunchenguid/no-mistakes/blob/main/internal/paths/paths.go) automatically resolves the path to `$HOME/.no-mistakes`. All subsequent database, socket, and log operations are scoped under this default directory.

### How does no-mistakes handle corporate proxy settings?

The daemon reads `HTTP_PROXY`, `HTTPS_PROXY`, `NO_PROXY`, and `ALL_PROXY` (including lowercase variants) from the environment via `serviceProxyEnv` in [`internal/daemon/service.go`](https://github.com/kunchenguid/no-mistakes/blob/main/internal/daemon/service.go). These values are written into the generated systemd, launchd, or Windows Task configuration with restricted permissions (mode `0600`), ensuring the managed service routes traffic correctly without exposing credentials.

### Can I run the daemon without installing it as a system service?

Yes. Setting **`NM_TEST_START_DAEMON=1`** bypasses the managed service logic entirely. As implemented in `defaultServiceManagerBypassed()` within [`internal/daemon/service.go`](https://github.com/kunchenguid/no-mistakes/blob/main/internal/daemon/service.go), this flag causes the startup code to treat the daemon as already running, preventing interactions with system-level service managers while still executing the daemon loop.

### What is the difference between NM_DAEMON and NM_TEST_START_DAEMON?

**`NM_DAEMON=1`** is set by the binary itself when re-executing to become a background process, triggering the daemon entry point in [`internal/daemon/selfexec.go`](https://github.com/kunchenguid/no-mistakes/blob/main/internal/daemon/selfexec.go). In contrast, **`NM_TEST_START_DAEMON=1`** is a test harness flag that prevents the service manager from attempting to register or start the daemon via system facilities, allowing tests to manage the process lifecycle directly.