Expand description
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.
What reload cannot preserve (§2.8, stated once): in-flight turns
(checkpointed = cancelled; partial history + restart marker kept), pending prompts (answered
None), PTY/background shells (closed, announced), turn_replay,
input ownership (the owner reclaims it on
reconnect via was_owner). What it preserves — each session’s
Checkpoint{Reload} reply carries a SessionReloadRecord: its journal
and id (the rehydrated session continues the same journal), its
SessionConfig as created (cwd, system, prompt manifest, compaction
policy, auto-compact, …), its keep-warm pin, its lifecycle (a Parked
session comes back Parked), the non-persisted runtime knobs
(settings_replay: context window, compaction model, retries,
timeouts, tool-output cap, worker grants, /system), and the CURRENT
model/thinking (/model mid-session survives).
Structs§
- Prepared
- Steps 1–4 (§2.8): gate, drain, checkpoint, reload-state, announce.
Nothing irreversible has happened when this returns
Ok; the caller (the requesting connection) sends its ownBye{Reloading}, flushes, then callsexec. - Print
Version <exe> daemon --print-versionoutput.- Reload
Request - Reload
Session - One recorded session.
- Reload
State registry_dir()/daemon[-P].reload.jsonbody.
Enums§
Constants§
- DRAIN_
SECS_ ENV - Env: default drain budget in seconds.
- LOCK_
FD_ ENV - Env: inherited
daemon.lockfd (mandatory whenRELOAD_STATE_ENVis set). - RELOAD_
STATE_ ENV - Env: path of the reload-state file handed to the new image.
- RETRY_
AFTER_ MS - What clients are told to wait before reconnecting.
Functions§
- adopt_
from_ env - New-image side (
Daemon::start): whenRELOAD_STATE_ENVis set, the lock is ADOPTED fromLOCK_FD_ENV(mandatory — refuse to start without it, risk §6.8) and the recorded generation is returned. - exec
- Step 5: rewrite
daemon.json(generation+1, same pid), stop sidecars, hand the flock to the next image andexecv. Returns only on failure — thendaemon.json/reload-state are restored, extension discovery is re-spawned (the sidecars were stopped for the exec — M4: no zombie daemon without hooks), and the old image keeps serving (sessions checkpointed but alive; clients that gotByereconnect to THIS image — areconnect_of.generationmismatch is tolerated, the daemon answers with its own generation). - prepare
- probe_
version - Run
<exe> daemon --print-version(5 s) and parse it. - rehydrate
- reload_
state_ path - resolve_
exe - The executable to re-exec: argv[0] canonicalised (NOT
/proc/self/exe, which reads “(deleted)” after an in-place rebuild);current_exeonly as a fallback when argv[0] is not resolvable (e.g. bare name on PATH). - validate_
exe - M8:
--exemust be something we would trust toexecvin our own pid: an existing regular file (canonicalised), executable, owned by our uid (or root — package-installed binaries), not group/world-writable. Returns the canonical path. Same-uid 0600 socket → not a privilege boundary; this is a footgun guard, not a sandbox. - version_
gate - Directional gate (§2.1): new protocol ≥ ours (clients must still be able to reconnect) and new binary ≥ ours (newer OR EQUAL; same-version rebuilds are the common case).