Daemon & Worktrees
The daemon is a long-running background process that manages pipeline runs. The
installer prefers setting it up as a managed background service, and
no-mistakes, init, attach, rerun, and update keep that service
installed and running for you when that path is available.
Why a daemon exists
The daemon exists so git push no-mistakes stays fast and the gate can keep
working after your shell command returns.
- Git hands the push to the local gate repo.
- The hook notifies the daemon and exits immediately.
- The daemon owns the long-running work: worktrees, pipeline execution, TUI events, state, cleanup, and crash recovery.
flowchart LR push["git push no-mistakes"] --> gate["Gate repo hook"] --> daemon["Daemon"] daemon --> run["Run in detached worktree"] daemon --> state["Persist state + logs"] run --> tui["TUI can attach or detach"] run --> cleanup["Cleanup when run finishes"]
On macOS this is a per-user launchd agent, on Linux a per-user systemd service, and on Windows a Task Scheduler task. The installed artifact names are scoped by NM_HOME with a short stable suffix, so the paths and service identifiers look like ~/Library/LaunchAgents/com.kunchenguid.no-mistakes.daemon.<suffix>.plist, ~/.config/systemd/user/no-mistakes-daemon-<suffix>.service, and the Windows task no-mistakes-daemon-<suffix>. That keeps multiple no-mistakes installs from colliding when they use different NM_HOME roots. Those service managers keep the daemon available across CLI invocations and restart it after no-mistakes update replaces the binary. Before a managed daemon run starts, no-mistakes reloads the environment from your login shell on macOS and Linux so agent and tool discovery matches the shell you use interactively. On Windows it reuses the current process environment instead of shelling out to a login shell. If managed service install or startup is unavailable or fails, no-mistakes falls back to starting a detached daemon process instead.
Starting and stopping
Most people do not need to manage the daemon directly. The usual commands already make sure it exists when needed.
# Explicit managementno-mistakes daemon startno-mistakes daemon stopno-mistakes daemon restartno-mistakes daemon status
# Ensures the daemon is running, using the managed service when possibleno-mistakesno-mistakes initno-mistakes attachno-mistakes rerun
# Resets the daemon after replacing the binaryno-mistakes updateno-mistakes update stops and starts the daemon when it is running, or when stale daemon artifacts exist, so the new executable is used. It prefers the managed service path and falls back to a detached daemon if service startup is unavailable or fails. If the daemon is already running, update only proceeds when the daemon is using the same executable path as the binary running the update command; if that path cannot be determined or points to a different binary, the update aborts before replacing anything.
The daemon writes an identity record to ~/.no-mistakes/daemon.pid and listens on a Unix socket at ~/.no-mistakes/socket. On Windows, it uses a localhost TCP listener and a protected endpoint file at the same path.
What it does
When a push arrives via the post-receive hook:
- Creates a detached worktree at
~/.no-mistakes/worktrees/<repoID>/<runID>/ - Starts the pipeline executor in that worktree
- Streams events to any connected TUI clients
- Cleans up the worktree when the run finishes (success or failure)
Concurrent push handling
If you push to the same branch while a run is already active, the daemon:
- Cancels the in-progress run (reason: “cancelled: superseded by new push”)
- Waits for it to finish
- Starts a new run with the latest push
Pushes to different branches run concurrently.
This is another reason the daemon exists: branch-level coordination is easier to reason about in one long-lived process than inside independent hook invocations.
Crash recovery
On startup, the daemon checks for runs that were left in pending or running status (which means the daemon crashed while they were active):
- Marks those runs as
failedwith the message “daemon crashed during execution” - Reaps orphaned managed agent servers left behind by a crashed daemon or setup wizard
- Removes any orphaned worktree directories via
git worktree remove --force - Reapplies per-worktree gate hook-path isolation to existing bare repos when Git supports
config --worktree, so sharedcore.hookspathwrites cannot disablepost-receive
Logging
Daemon logs go to ~/.no-mistakes/logs/daemon.log. The setup wizard captures managed agent-server output in ~/.no-mistakes/logs/wizard-agent.log. Each pipeline step also writes to its own log at ~/.no-mistakes/logs/<runID>/<step>.log.
Set the log level in global config:
log_level: debug # debug | info | warn | errorShutdown
no-mistakes daemon stop stops the current daemon process without removing the managed service. The next no-mistakes daemon start, no-mistakes, init, attach, rerun, or update will start it again through the same service manager when available, or as a detached daemon otherwise.
- Cancels all active runs
- Waits up to 30 seconds for goroutines to finish
- Removes the PID file and socket