# How the no-mistakes Daemon Ensures a Singleton Instance: OS-Level File Locking Explained

> Learn how the no-mistakes daemon ensures a singleton instance using OS level file locking This prevents duplicate daemons by acquiring and releasing exclusive locks automatically

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

---

**The no-mistakes daemon guarantees a singleton instance by acquiring an exclusive, non-blocking OS-level file lock on `<NM_HOME>/daemon.lock` before any initialization work, automatically releasing it when the process exits to prevent duplicate daemons.**

The **no-mistakes** daemon uses a robust singleton pattern to ensure only one live process manages a given `NM_HOME` directory at any time. According to the `kunchenguid/no-mistakes` source code, this implementation relies on kernel-enforced file locking rather than PID files, eliminating stale lock scenarios while providing clear diagnostic feedback when conflicts occur.

## The Singleton Lock Architecture

### OS-Level File Locking Mechanism

At the core of the singleton guarantee is the `acquireSingletonLock` function defined in [`internal/daemon/lock.go`](https://github.com/kunchenguid/no-mistakes/blob/main/internal/daemon/lock.go). This function opens the lock file at `<NM_HOME>/daemon.lock` and attempts to obtain an exclusive, non-blocking lock using platform-specific helpers (`tryLockFile` and `unlockFile`). 

The kernel automatically releases this lock if the owning process exits, crashes, or is killed. This **kernel-enforced cleanup** removes the need for separate "is the holder still alive?" checks that traditional PID-file approaches require, making the mechanism significantly more reliable.

### Diagnostic Record for Observability

Once the lock is acquired, the daemon writes a small JSON diagnostic record into the lock file containing its PID and start time. As implemented in lines 53–62 of [`internal/daemon/lock.go`](https://github.com/kunchenguid/no-mistakes/blob/main/internal/daemon/lock.go), this record provides human-readable context:

```go
record := lockHolderRecord{PID: os.Getpid(), StartedAt: time.Now().UTC()}
if data, err := json.Marshal(record); err == nil {
    _ = f.Truncate(0)
    _, _ = f.WriteAt(data, 0)
    _ = f.Sync()
}

```

**Important:** This JSON metadata is strictly for diagnostics. The actual safety guarantee comes from the exclusive OS lock itself, not the contents of the file.

## Integration with the Daemon Lifecycle

### Early Acquisition in RunWithOptions

The singleton guard is placed at the very beginning of `RunWithOptions` in [`internal/daemon/daemon.go`](https://github.com/kunchenguid/no-mistakes/blob/main/internal/daemon/daemon.go) (lines 19–28). This early acquisition ensures the lock is held **before** any destructive startup work—such as stale-run recovery, orphan-worktree cleanup, or IPC socket binding—begins execution.

```go
func RunWithOptions(p *paths.Paths, d *db.DB, stepFactory StepFactory) error {
    // Singleton guard: only one live daemon may own this NM_HOME at a time.
    lock, err := acquireSingletonLock(p)
    if err != nil {
        return err
    }
    defer lock.Release()
    // ... rest of daemon startup …
}

```

If another daemon already holds the lock, `acquireSingletonLock` returns `ErrSingletonLockHeld` wrapped with the holder's PID and start time. This allows the second daemon to abort immediately with a clear error message, preventing race conditions that could corrupt run metadata or delete active worktrees.

### Automatic Release and Safety Guarantees

The daemon defers `lock.Release()` immediately after acquisition (lines 31–33 of [`daemon.go`](https://github.com/kunchenguid/no-mistakes/blob/main/daemon.go)). The `Release` method unlocks and closes the file descriptor, and is **safe to call on a nil receiver**—a property validated in [`internal/daemon/lock_test.go`](https://github.com/kunchenguid/no-mistakes/blob/main/internal/daemon/lock_test.go) lines 74–80. This safety ensures the deferred cleanup executes correctly even if lock acquisition fails, preventing resource leaks.

## Error Handling Implementation

When the singleton lock is already held, the daemon surfaces detailed diagnostics to the user. The error handling around lines 28–32 of [`daemon.go`](https://github.com/kunchenguid/no-mistakes/blob/main/daemon.go) wraps `ErrSingletonLockHeld` with the competing process's PID and start time, enabling administrators to identify the running instance without needing external process inspection tools.

## Summary

- **Kernel-enforced exclusivity**: The `acquireSingletonLock` function in [`internal/daemon/lock.go`](https://github.com/kunchenguid/no-mistakes/blob/main/internal/daemon/lock.go) uses OS-level file locking that automatically cleans up on process termination.
- **Early validation**: Lock acquisition occurs at the start of `RunWithOptions`before any destructive operations, preventing race conditions.
- **Rich diagnostics**: The lock file contains a JSON record with PID and start time, wrapped in `ErrSingletonLockHeld` when conflicts occur.
- **Safe cleanup**: The `Release` method handles nil receivers safely, ensuring deferred unlocks execute correctly via `defer lock.Release()`.

## Frequently Asked Questions

### What happens if the no-mistakes daemon crashes while holding the singleton lock?

The kernel automatically releases the file lock when the process exits, regardless of whether the exit is clean or due to a crash. This behavior eliminates the stale lock problems common to PID-file-based singleton implementations, ensuring the next daemon startup can acquire the lock immediately without manual intervention.

### Can two daemons run simultaneously on different NM_HOME directories?

Yes. The singleton lock is scoped to a specific `NM_HOME` directory via the `<NM_HOME>/daemon.lock` file path. Two daemons targeting different `NM_HOME` directories operate on separate lock files and therefore do not conflict, allowing concurrent daemon instances for different data roots.

### How does the daemon distinguish between a held lock and other file errors?

The `acquireSingletonLock` function returns the specific sentinel error `ErrSingletonLockHeld` when the lock is already acquired by another process. This error includes the holder's diagnostic information (PID and start time), allowing calling code to distinguish singleton conflicts from permission errors or disk failures and present appropriate user messages.

### Is the singleton lock mechanism portable across operating systems?

Yes. The implementation uses platform-specific helper functions (`tryLockFile` and `unlockFile`) that abstract OS differences while providing the same exclusive, non-blocking lock semantics. The [`internal/daemon/lock.go`](https://github.com/kunchenguid/no-mistakes/blob/main/internal/daemon/lock.go) file handles these platform variations, ensuring consistent singleton behavior across supported operating systems.