Skip to main content

Module daemon

Module daemon 

Source
Expand description

Daemon front-end (synaps daemon): UDS listener, per-connection pump, registry file, lifecycle (PLAN-phase2 §2.11). Lives in agent-engine (S289 D-1 amended) — agent-tui must never appear in this graph.

On by default: the first --attach/attach client auto-spawns the daemon (ensure_running); SYNAPS_DAEMON=0 disables every daemon feature (exit 3 with a one-line reason). Safety properties that are NEVER stubbed: the flock liveness oracle, the ready-fd pipe, socket perms 0700/0600, the spawn lock (one spawner per registry dir).

Modules§

conn
Per-connection pump: handshake → control loop → attach → pump.
lifecycle
Daemon shutdown: end every session concurrently inside ONE wall budget, then shut the shared extension host down.
listener
UDS listener: bind with 0600, accept until shutdown, one task per connection.
registry
daemon.json / daemon.lock / daemon.pid under registry_dir() (PLAN-phase2 §2.11). The flock on daemon.lock is THE liveness oracle (jcode socket.rs:89-139): a daemon is alive iff someone holds the lock. A socket file with no lock holder is stale and gets unlinked. Nobody unlinks on ECONNREFUSED alone.
reload
synaps daemon reload (PLAN-phase3 §2.8, C3): version gate → drain → Checkpoint{Reload} every session → reload-state → announce Reloading/Bye{Reloading} → execv self (same pid, adopted flock, CLOEXEC listener) → new image rehydrates sessions from reload-state BEFORE accepting.

Structs§

Daemon
A running daemon (bound socket, lock held, accept loop spawned).
DaemonOpts
DaemonState
Shared by the accept loop and every connection.

Enums§

EnsureError
Why ensure_running could not hand back a live daemon.
Ensured
Result of ensure_running.

Constants§

AUTOSPAWN_IDLE_EXIT
Default idle grace for auto-spawned daemons.
DISABLED_NOTICE
One-line reason used by every attach path when the flag is off.
EXIT_DAEMON_LOST
The daemon was lost (SIGKILL / crash) and reconnection failed within the budget (SYNAPS_TUI_ATTACH_RECONNECT_SECS).
EXIT_REFUSED
Exit code when the daemon refuses to start (flag off / legacy MCP).
EXIT_VERSION
Exit code for a protocol/version refusal on the client side.
READY_FD_ENV
Env var carrying the write end of the ready pipe to a spawned daemon.
SPAWN_READY_TIMEOUT
How long spawn_detached waits for the child’s ready byte.

Functions§

allow_legacy_mcp_env
SYNAPS_DAEMON_ALLOW_LEGACY_MCP=1 (§4.4).
autospawn_enabled
SYNAPS_DAEMON_AUTOSPAWN: ON unless 0/false/off/no. Off means an attach with no live daemon fails with the “no daemon running” message instead of starting one.
autospawn_idle_exit
SYNAPS_DAEMON_IDLE_EXIT_SECS for auto-spawned daemons: default 10 s — when the last client disconnects and no turn is running, the daemon is holding ~100 MB for one reason only: a re-launch inside the window skips extension boot. Ten seconds covers “oops, wrong window”; 0/never → never exit on idle.
daemon_is_idle
Idle = zero connections AND every live session between turns, held for idle continuously. Clients count first so a probe is never sent while someone is attached.
enabled
SYNAPS_DAEMON feature flag: ON unless set to 0/false/off/no. SYNAPS_DAEMON=1 is accepted (no-op, kept for older scripts).
ensure_running
Attach-path entry: a live daemon or a freshly spawned one (jcode model — first client spawns via setsid + ready-fd; the daemon holds the flock). The spawn lock (<stem>.spawn.lock next to the flock) serialises concurrent first-clients: the loser blocks on it, then re-probes the flock and finds the winner’s daemon. Never touches the socket on ECONNREFUSED alone — reap_stale + the flock decide.
host_factory
The default factory for a booted host: EngineHost::create_session (A1) — the real SessionActor owning one Runtime + ConversationState.
legacy_mcp_conflict
Refuse-to-start check (§2.11): legacy McpTool connections would be shared across sessions.
run_foreground
synaps daemon --foreground body: gate → boot host → extension discovery once → start → wait for SIGTERM/SIGINT/Shutdown frame/idle.
session_is_idle
Whether handle’s actor is between turns. Asks Query{Status} under the reserved crate::session::wire::IDLE_PROBE_QUERY_ID (transports swallow it) and reads streaming. A no-answer inside [IDLE_PROBE_TIMEOUT] — the actor is inside compact()/preflight, or its queue is full — counts as busy: the daemon never exits under a running turn (jcode mistake #1).
signal_ready
Child side of the ready pipe: write R to SYNAPS_DAEMON_READY_FD (if set), close it, and scrub the env so tool subprocesses do not inherit it.
spawn_detached
Parent side: current_exe daemon --foreground … in its own session (setsid), stdout → null, stderr → pipe; waits ≤ 5 s for R on the ready pipe. EOF before R = child died → error with its stderr tail.

Type Aliases§

SessionFactory
Builds a session for Attach::Create: host_factory (real actor) or echo_factory (tests).