You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
The daemon can hot-swap its own binary to a newer release WITHOUT
interrupting running agents. It re-execs in place (same PID) via
unix.Exec, inheriting the held repo flock and the API listener sockets
through CLOEXEC-cleared fds, and re-adopts the still-running agent child
processes — so only the control-plane binary changes underneath them,
with no lock gap and no dropped connection.
New internal/upgrade package:
- source: GitHub releases by default, or a mirror via AGENTENV_UPDATE_URL
(latest.txt + agentenv_<ver>_<os>_<arch>.tar.gz + checksums.txt)
- verify: SHA256 against checksums.txt, then a `<new-binary> version`
smoke test — either failing keeps the old daemon serving
- schedule: poll every AGENTENV_UPDATE_INTERVAL (default 1h), apply
inside AGENTENV_UPDATE_WINDOW (e.g. 02:00-04:00), or on demand
- handoff: CLOEXEC clearing, proc manifest, atomic binary rename with
rollback, and the execve
Triggers: automatic in the maintenance window, or `agentenv upgrade
[--version X]` / `agentenv ctl upgrade` on demand (bypasses the window).
Dev/commit builds don't auto-upgrade (no comparable version); a manual
--version still works. supervise is out of scope (foreground PTY agent).
Supporting changes:
- repo: AdoptProc (per-PID Wait4 reaper — never a global wait4(-1) that
would steal os/exec's cmd.Wait exit status), LockFromFD, Kill/killAll
handle adopted procs (unix.Kill by pid)
- api: Gate (shared writer lock so a hot upgrade can't fire mid-mutation),
ServeListener / ServeHTTPListener (daemon owns the listeners for fd
handoff), and the out-of-band "upgrade" op via an UpgradeHandler
interface (breaks the api→upgrade import cycle)
- cli: cmdDaemon gains a resume path (rebuild lock/listeners from inherited
fds, re-adopt procs); Run skips AcquireLock on the re-exec path; new
`upgrade` command with transparent ctl routing
- protocol: Version/Force request fields, Message response field
Verified end-to-end on Linux (scripts/e2e_upgrade.sh): daemon re-execs
v0.3.0 -> v0.4.0 keeping the same PID, the socket stays served, the flock
is never released, and a spawned agent is re-adopted and keeps running
uninterrupted across the swap.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
0 commit comments