Skip to content

Shared Daemon

Stefan R. Steiner edited this page Jun 7, 2026 · 1 revision

The Shared hyperd Daemon

By default, all hyperdb-mcp clients on a machine share one hyperd process per user, managed by a small background daemon. Multiple AI clients (Claude Code, Cursor, VS Code Copilot) then talk to the same engine and the same persistent databases instead of each spawning their own hyperd. Pass --no-daemon to opt out and get a private per-session hyperd (legacy behavior).

This page explains how the daemon is discovered, how it stays out of your way, and the knobs for the rare cases where you need to intervene.


What the daemon is (and where its state lives)

The daemon owns the hyperd process and advertises how to reach it in a small JSON file:

~/.hyperdb/daemon.json      # discovery file (override dir with HYPERDB_STATE_DIR)
~/.hyperdb/logs/            # hyperd logs
{
  "pid":            12345,
  "hyperd_endpoint": "127.0.0.1:54321",  // where SQL goes (the database)
  "health_port":     7485,               // the daemon's control/lock port
  "started_at":     "2026-06-06T10:20:35Z",
  "version":        "0.4.0"
}

Two ports, two owners — don't conflate them:

Field Owned by Purpose
hyperd_endpoint hyperd The libpq endpoint your queries connect to.
health_port the Rust daemon wrapper Single-instance lock and a control channel (PING / HEARTBEAT / STOP / STATUS).

The health port doubles as the lock: binding it succeeds for exactly one process per user, which is how "single instance" is enforced cross-platform.


How a client finds the daemon

A starting client resolves the daemon in this order:

  1. Read daemon.json and verify the daemon is really alive (see identity check below). If it checks out, connect.
  2. Scan the port range if the file is missing or stale: probe ports upward from the base, looking for a live daemon.
  3. Spawn a new daemon on the first free port if none is found.

Identity check (not just "is the port open?")

A client doesn't trust a port merely because something accepts a TCP connection there. It sends PING and requires the reply to be exactly:

PONG hyperdb-mcp <version>

An unrelated process occupying the port (it answers TCP but not this protocol) is classified as camped and skipped. A stale daemon.json pointing at a dead or foreign port is detected and removed, and the client moves on to scan or spawn. This prevents a client from ever mistaking some other service for the daemon.

Port scanning and pinning

  • Default: scan upward from 7485 (16 ports: 7485..=7500) and use the first free one. 7485 was chosen deliberately — the older default 7484 collides with hyperd's conventional gRPC port, which is exactly the kind of process that would otherwise be mistaken for a daemon.
  • Pin an exact port: set HYPERDB_DAEMON_PORT=<port>. This disables scanning — the daemon uses exactly that port, and clients look only there.

The daemon stays resident

By default the daemon — and the hyperd it owns — stay running once started. Keeping hyperd warm means the next tool call connects instantly instead of triggering a cold start and the "hyper is restarting, please retry" round-trip.

If you want the daemon to shut itself down after a period of inactivity (for example on CI), opt in:

hyperdb-mcp daemon --idle-timeout 1800      # shut down after 30 min idle
# or
export HYPERDB_DAEMON_IDLE_TIMEOUT=1800     # same, via env

With neither set, the daemon only stops on an explicit stop, an OS signal, a newer-version takeover (below), or repeated hyperd startup failures (3 within 60 seconds, which trips a safety shutdown so a broken binary doesn't spin forever).


Upgrades: newer clients take over

When you upgrade hyperdb-mcp, the next client built from a strictly newer version automatically takes over: it stops the old daemon (which also stops the old hyperd) and starts a fresh one on the same port. You don't have to manually kill anything — the upgrade takes effect on the next client start.

Equal or older versions reuse the running daemon and never downgrade-kill it. Note that the version compared is the crate's semantic version, so two local builds of the same version (e.g. two dev builds of 0.4.0) are considered equal and won't take over each other — use hyperdb-mcp daemon stop to force a replacement in that case.


Managing the daemon by hand

The daemon is normally invisible. For diagnostics:

hyperdb-mcp daemon status   # PID, hyperd endpoint, health port, started_at, version
hyperdb-mcp daemon stop     # gracefully stop the running daemon
hyperdb-mcp daemon          # run as a daemon explicitly (rarely needed)

status and stop locate the running daemon automatically (read daemon.json, then scan), so they work even if the daemon landed on a non-default port. Pass --port <PORT> to target a specific port explicitly.

Recovering from a wedged hyperd

The daemon detects a crashed hyperd (process exited) within ~5 seconds and restarts it, updating daemon.json with the new endpoint; clients reconnect transparently. A client that notices the failure first can fast-path the signal so the restart doesn't wait for the polling tick.

A hung-but-alive hyperd (still listening, but not answering queries) is the one case the daemon can't auto-detect. Because the daemon now stays resident by default, there's no idle timeout to eventually reap it. Recovery is:

hyperdb-mcp daemon stop      # then let the next client spawn a fresh one

Environment variables

Variable Effect
HYPERDB_STATE_DIR Directory for daemon.json + logs (default ~/.hyperdb/).
HYPERDB_DAEMON_PORT Pin the health/lock port exactly (default: scan from 7485).
HYPERDB_DAEMON_IDLE_TIMEOUT Opt into idle shutdown after N seconds (default: stay resident).