Skip to content

cli-daemon: serve/mcp daemons never reclaim the per-project CLI socket — no handover, no bind retry #619

@justrach

Description

@justrach

Problem

The long-lived daemons (serve / mcp) and the auto-spawned cli-daemon all want the same per-project Unix socket (/tmp/codedb-<uid>-<hash16>.sock), and the loser of the bind race simply gives up:

  • An auto-spawned cli-daemon that loses the bind sets shutdown and exits promptly (good).
  • A long-lived serve / mcp daemon that loses the bind permanently disables its CLI proxy (cliDaemonListen logs bind … failed — proxy disabled and returns; the serve/mcp daemons pass a shutdown flag they never watch).

So the common sequence — warm cli-daemon already running, then the user starts a long-lived codedb <root> serve or an MCP client spawns codedb mcp — leaves the older, idle-timeout-bound cli-daemon owning the socket while the newer long-lived daemon (with the freshest index and no idle exit) can never serve CLI calls. When the cli-daemon eventually idle-exits, the socket goes away entirely: the serve daemon never retries the bind, and every subsequent CLI call falls back to a cold re-index until something respawns a cli-daemon.

This is the "serve-vs-cli-daemon socket handover" item parked in the session todo.

Expected

Socket ownership should hand over to the longest-lived / freshest daemon:

  1. A starting serve / mcp daemon that loses the bind should be able to ask the current owner to yield (e.g. a handover request over the socket; the cli-daemon unlinks + closes and exits, the new daemon retries the bind), and
  2. A long-lived daemon whose bind failed should retry periodically (cheap: on the existing 1 s watchdog tick) so it picks the socket up when the previous owner exits, instead of leaving CLI calls cold forever.

Failing test

Per the repo rule this needs a failing test before implementation; the testable seam today:

test "issue-XX: serve daemon retries the cli socket bind after the owner exits" {
    // 1. bind the project socket from the test (stand-in for a live cli-daemon)
    // 2. start cliDaemonListen for a serve-mode explorer -> bind fails, proxy disabled
    // 3. close + unlink the test socket
    // 4. expect cliDaemonListen to acquire the socket within ~2 watchdog ticks
    //    (currently: never — it returned at step 2)
}

(Requires extracting the bind/retry loop from cliDaemonListen enough to drive it from a test; the current single-shot shape returns before step 3 can be observed.)

Fix

Sketch in Expected. Retry-on-watchdog-tick (2) is the small, safe half and removes the cold-fallback cliff; explicit handover (1) is the full fix.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions