# How the Daemon Singleton Lock Prevents Concurrent Daemon Instances in No-Mistakes

> Learn how the no-mistakes daemon singleton lock prevents concurrent instances using OS level file locks for reliable single execution per NM_HOME.

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

---

**The no-mistakes daemon guarantees single-instance execution per `NM_HOME` by acquiring an OS-level exclusive file lock at startup that automatically releases when the process terminates.**

The **daemon singleton lock** in the [kunchenguid/no-mistakes](https://github.com/kunchenguid/no-mistakes) repository ensures exactly one live daemon process can manage a given workspace directory at any time. Unlike fragile PID-file schemes, this mechanism leverages kernel-managed file locks through platform-specific syscalls, eliminating race conditions and stale lock scenarios during crashes.

## Core Lock Acquisition Mechanism

The singleton enforcement begins in [`internal/daemon/lock.go`](https://github.com/kunchenguid/no-mistakes/blob/main/internal/daemon/lock.go) (lines 33‑52) with the `acquireSingletonLock` function. This function opens the lock file via `p.LockFile()` and delegates to the platform-specific `tryLockFile` implementation.

If another process already holds the lock, the call returns `ErrSingletonLockHeld` immediately. The error includes diagnostic metadata about the current holder, allowing administrators to identify the blocking instance without requiring external process inspection tools.

```go
func startDaemon(p *paths.Paths) error {
    lock, err := acquireSingletonLock(p)
    if err != nil {
        // Another daemon is already running – report and exit
        return fmt.Errorf("cannot start daemon: %w", err)
    }
    // Ensure the lock is released on exit
    defer lock.Release()

    // … continue with daemon initialization …
    return runDaemon()
}

```

## Platform-Specific Implementations

The implementation adapts to Unix and Windows kernel locking semantics while maintaining identical Go interfaces.

### Unix Advisory Locks via `flock`

On Linux and macOS, [`internal/daemon/lock_unix.go`](https://github.com/kunchenguid/no-mistakes/blob/main/internal/daemon/lock_unix.go) invokes `syscall.Flock` with the `LOCK_EX|LOCK_NB` flags. This requests a **non-blocking exclusive advisory lock** on the open file descriptor.

- The lock is advisory, meaning cooperating processes must explicitly attempt acquisition
- The kernel automatically releases the lock when the file descriptor closes or the process terminates
- No cleanup scripts are required after crashes because the OS cleans up the lock state

### Windows Mandatory Locks via `LockFileEx`

The Windows implementation in [`internal/daemon/lock_windows.go`](https://github.com/kunchenguid/no-mistakes/blob/main/internal/daemon/lock_windows.go) uses the `LockFileEx` syscall on a byte range at offset `0xFFFFFFFF`. This creates a **mandatory lock** that the kernel enforces for all processes accessing that file region.

Like the Unix variant, Windows releases this lock automatically when the owning process handle terminates, providing the same self-cleaning guarantee across platforms.

## Diagnostic Records and Self-Cleaning Safety

While the safety guarantee relies solely on the OS lock mechanism, [`internal/daemon/lock.go`](https://github.com/kunchenguid/no-mistakes/blob/main/internal/daemon/lock.go) (lines 53‑62) writes a small JSON diagnostic record containing the `PID` and `StartedAt` timestamp to the lock file. This metadata aids debugging when `ErrSingletonLockHeld` occurs.

**Crucially**, the singleton property does not depend on this JSON file existing or being parseable. Because the lock lives in kernel memory attached to the file descriptor, a crashed daemon cannot leave a stale lock behind. The next startup attempt will successfully acquire the lock regardless of any leftover file contents.

## Integration in the Daemon Lifecycle

The daemon acquires the singleton lock **before** performing any destructive startup work. Specifically, the lock is held prior to:

- Stale-run recovery operations
- Work-tree cleanup procedures
- IPC socket binding

This ordering prevents race conditions where two concurrent daemon instances might attempt simultaneous cleanup or socket binding. The following pattern demonstrates proper error handling when the singleton lock is already held:

```go
if errors.Is(err, daemon.ErrSingletonLockHeld) {
    fmt.Println("A daemon is already running for this NM_HOME.")
    // Optionally log the holder information from the error message
}

```

## Summary

- **The `acquireSingletonLock` function** in [`internal/daemon/lock.go`](https://github.com/kunchenguid/no-mistakes/blob/main/internal/daemon/lock.go) coordinates singleton enforcement by opening the lock file and attempting platform-specific acquisition.
- **Unix systems** use `flock` with `LOCK_EX|LOCK_NB` for advisory locking, while **Windows** uses `LockFileEx` at offset `0xFFFFFFFF` for mandatory locking.
- **Kernel-managed lifecycle** ensures the lock releases automatically on process termination, preventing stale lock scenarios without manual intervention.
- **Diagnostic metadata** (PID and start time) is stored in the lock file for troubleshooting, but the safety guarantee depends entirely on the OS-level lock.
- **Strict acquisition ordering** ensures the lock is held before any stateful operations, eliminating race conditions during daemon startup.

## Frequently Asked Questions

### What prevents the singleton lock from becoming stale if the daemon crashes?

The lock is managed by the operating system kernel, not the application. When the daemon process exits or crashes, the kernel automatically releases the file lock associated with the process's file descriptors. This self-cleaning property applies to both the Unix `flock` implementation and the Windows `LockFileEx` implementation, ensuring no manual cleanup is required after unexpected terminations.

### How does the daemon handle startup attempts when another instance is already running?

When `acquireSingletonLock` detects that another process holds the lock, it returns `ErrSingletonLockHeld` immediately without performing any destructive startup operations. The calling code can check for this specific error using `errors.Is` and gracefully exit, optionally logging the diagnostic information (PID and start time) embedded in the error message to identify the blocking instance.

### Why does no-mistakes use an OS-level lock instead of a PID file?

Traditional PID files create race conditions between checking for file existence and writing the new PID, and they require cleanup mechanisms when the owning process crashes. The **daemon singleton lock** uses kernel-managed file locks that are atomic at the syscall level and automatically released on process termination, providing stronger guarantees without the fragility of PID-file schemes.

### Where is the lock file located relative to the NM_HOME directory?

The lock file resides at the path returned by `p.LockFile()`, which resolves to `daemon.lock` within the `NM_HOME` directory structure. This location ensures that separate workspace directories can each run their own daemon instance, while a single `NM_HOME` cannot host concurrent daemons due to the exclusive lock on that specific file.