# How to Configure the No-Mistakes Daemon’s Home Directory Using NM_HOME

> Configure the no-mistakes daemon's home directory using NM_HOME by setting the environment variable or using the --root CLI flag. Learn how to manage your configuration paths efficiently.

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

---

**Set the `NM_HOME` environment variable to override the default `~/.no-mistakes` directory, or use the `--root` CLI flag which automatically sets `NM_HOME` for the current command.**

The **no-mistakes** daemon stores all persistent data—including SQLite state, Unix sockets, logs, configuration files, and work-trees—under a single root directory. By default, this location is `~/.no-mistakes`, but you can relocate it entirely by configuring the `NM_HOME` environment variable. This guide explains how the `kunchenguid/no-mistakes` repository implements this mechanism and how to use it for isolated testing, multiple daemon instances, or alternative storage locations.

## Understanding NM_HOME and the Default Path

When the no-mistakes daemon starts, it determines where to store its artifacts by checking the `NM_HOME` environment variable. If `NM_HOME` is unset or empty, the daemon falls back to the user's home directory and appends `.no-mistakes`.

This root directory acts as the single source of truth for all sub-paths. Components throughout the codebase—from configuration loaders to the SQLite database handler—resolve their locations relative to this root using helpers defined in [`internal/paths/paths.go`](https://github.com/kunchenguid/no-mistakes/blob/main/internal/paths/paths.go).

## How the Daemon Resolves NM_HOME

The path resolution logic lives in **[`internal/paths/paths.go`](https://github.com/kunchenguid/no-mistakes/blob/main/internal/paths/paths.go)**, specifically within the `New()` function. This function reads the environment variable and returns a `Paths` struct containing the resolved root directory.

```go
// internal/paths/paths.go
func New() (*Paths, error) {
    if env := os.Getenv("NM_HOME"); env != "" {      // ← reads NM_HOME
        return &Paths{root: env}, nil
    }
    home, err := os.UserHomeDir()
    if err != nil {
        return nil, err
    }
    return &Paths{root: filepath.Join(home, ".no-mistakes")}, nil
}

```

All higher-level components obtain their file paths from a `*paths.Paths` instance created by `paths.New()`. Because the root is derived from `NM_HOME`, changing this single environment variable automatically relocates **every** daemon artifact, including `state.sqlite`, the Unix socket, [`config.yaml`](https://github.com/kunchenguid/no-mistakes/blob/main/config.yaml), and the `logs/` directory.

## Daemon Initialization and Environment Handling

The daemon itself explicitly reads `NM_HOME` early in its execution to ensure consistency across its internal services. In **[`internal/daemon/daemon.go`](https://github.com/kunchenguid/no-mistakes/blob/main/internal/daemon/daemon.go)**, the daemon captures the environment variable at line 61 and later restores it upon exit to maintain process integrity.

```go
// internal/daemon/daemon.go
nmHome := os.Getenv("NM_HOME")                         // ← env read
...
if err := os.Setenv("NM_HOME", nmHome); err != nil {   // restore after daemon exit
    return fmt.Errorf("restore NM_HOME: %w", err)
}

```

This ensures that even if the daemon spawns child processes or modifies its environment, the original `NM_HOME` value remains intact for cleanup operations.

## CLI Flag Alternative: --root

For users who prefer command-line flags over environment variables, the top-level CLI wrapper in **[`cmd/no-mistakes/main.go`](https://github.com/kunchenguid/no-mistakes/blob/main/cmd/no-mistakes/main.go)** accepts a `--root` flag. When provided, the CLI writes the flag value directly into `NM_HOME` before executing any sub-command, achieving the same effect as setting the environment variable manually.

```go
// cmd/no-mistakes/main.go (excerpt)
if err := os.Setenv("NM_HOME", root); err != nil {
    return fmt.Errorf("set NM_HOME: %w", err)
}

```

You can choose whichever style fits your workflow—explicit environment export for persistent sessions, or `--root` for one-off commands.

## Practical Use Cases for Custom NM_HOME

Configuring a custom home directory is essential for several advanced workflows:

- **Isolated Testing**: Point the daemon at a temporary directory (`$TMPDIR/no-mistakes-test`) to ensure test runs never touch production state or the real user profile.
- **Multiple Installations**: Run separate daemon instances (e.g., stable release vs. development build) without name collisions in system service managers. The service names are automatically scoped using a short hash derived from the chosen `NM_HOME` path.
- **Alternative Storage Locations**: Move the daemon’s state to a fast SSD, network share, or encrypted volume to meet performance or security requirements.

## Implementation Examples

### Setting NM_HOME in a Shell Session

```bash

# Choose a custom location for the daemon’s state

export NM_HOME=$HOME/.no-mistakes-dev

# Start the daemon (it will pick up NM_HOME automatically)

no-mistakes daemon start

# Verify the daemon is using the custom directory

ls "$NM_HOME"

# → config.yaml  state.sqlite  socket  logs/  worktrees/ …

```

### Using the --root Flag

```bash

# One-off command that runs the daemon with a custom root

no-mistakes --root $HOME/.no-mistakes-dev daemon start

# The daemon will write its files under the supplied path.

```

### Isolating NM_HOME in Go Tests

```go
func TestMyFeature(t *testing.T) {
    tmp := t.TempDir()
    t.Setenv("NM_HOME", tmp)          // isolates all daemon state
    // … invoke CLI / daemon …
    // Verify that only the temporary directory was touched
    if _, err := os.Stat(filepath.Join(tmp, "state.sqlite")); err != nil {
        t.Fatalf("expected SQLite DB in %s", tmp)
    }
}

```

### Verifying the Effective Home at Runtime

The `axi status` command displays the current daemon socket path, which reveals the effective `NM_HOME` prefix:

```bash
$ NM_HOME=$HOME/.no-mistakes-dev no-mistakes axi status
daemon socket: /home/user/.no-mistakes-dev/socket

```

## Summary

- **`NM_HOME`** controls the root directory for all no-mistakes daemon data, defaulting to `~/.no-mistakes`.
- The resolution logic in **[`internal/paths/paths.go`](https://github.com/kunchenguid/no-mistakes/blob/main/internal/paths/paths.go)** checks `os.Getenv("NM_HOME")` and falls back to the home directory if unset.
- The daemon explicitly reads and preserves `NM_HOME` in **[`internal/daemon/daemon.go`](https://github.com/kunchenguid/no-mistakes/blob/main/internal/daemon/daemon.go)** to ensure consistent state across its lifecycle.
- Use the **`--root`** flag in **[`cmd/no-mistakes/main.go`](https://github.com/kunchenguid/no-mistakes/blob/main/cmd/no-mistakes/main.go)** as an alternative to setting the environment variable directly.
- Custom `NM_HOME` values enable isolated testing, parallel daemon instances, and flexible storage configurations.

## Frequently Asked Questions

### What happens if NM_HOME is not set?

If `NM_HOME` is undefined or empty, the daemon automatically uses `~/.no-mistakes` as the root directory. This fallback is handled in [`internal/paths/paths.go`](https://github.com/kunchenguid/no-mistakes/blob/main/internal/paths/paths.go) by calling `os.UserHomeDir()` and joining it with the default directory name.

### Can I use NM_HOME to run multiple daemon instances simultaneously?

Yes. Set distinct `NM_HOME` values for each instance (e.g., `~/.no-mistakes-stable` and `~/.no-mistakes-dev`). The daemon scopes its service names using a hash of the path, preventing conflicts in launchd, systemd, or Windows Task Scheduler while keeping all state completely isolated.

### Does the --root flag override an existing NM_HOME environment variable?

Yes. When you use `--root`, the CLI explicitly calls `os.Setenv("NM_HOME", root)` before executing the sub-command, overwriting any existing value for the duration of that process. This ensures the flag takes precedence over the environment.

### Where is the NM_HOME path actually used in the codebase?

The path is resolved in **[`internal/paths/paths.go`](https://github.com/kunchenguid/no-mistakes/blob/main/internal/paths/paths.go)** (function `New()`), read by the daemon in **[`internal/daemon/daemon.go`](https://github.com/kunchenguid/no-mistakes/blob/main/internal/daemon/daemon.go)** at line 61, and optionally set via the `--root` flag handler in **[`cmd/no-mistakes/main.go`](https://github.com/kunchenguid/no-mistakes/blob/main/cmd/no-mistakes/main.go)**. All file operations throughout the codebase reference the `*Paths` instance derived from this root.