# Updating agents

Server updates are a `docker compose pull && up -d` away.
Agents update via the control plane.

## Single-host update

Each host's detail page shows an **Update agent** button when
the agent's reported version is older than the server's. The
button:

1. Dispatches a `command.update` to that host.
2. The agent fetches the appropriate binary from
   `$RM_SERVER/agent/binary?os=…&arch=…` to
   `<binary-path>.new`.
3. Copies the running binary to `<binary-path>.old` (one
   revision back, in case rollback is needed).
4. Atomic-renames `.new` over the running binary.
5. Exits cleanly. systemd's `Restart=always` (or Windows SCM)
   brings the process back on the new binary.

A 90-second timer on the server side waits for a hello at the
target version and marks the update succeeded — or, if the
agent doesn't reconnect at the expected version in time, marks
the update **failed** and raises an `update_failed` alert.

## Fleet update

The admin-only **Settings → Fleet update** page drives a rolling
update across every host in the fleet:

- One host at a time.
- Wait for hello-with-target-version (max 95s).
- On any host failing, **halt** the rollout, raise a
  `fleet_update_halted` alert, leave the rest of the fleet on
  the old version. No surprise mass-failures.

You can cancel an in-progress fleet update; the worker stops
after the current host finishes.

## TLS and corruption

Updates rely on the reverse proxy's TLS to detect corruption in
transit. There's no separate sha256 verification step — we
chose the simpler model on the basis that the same TLS already
gates every other byte the server hands to the agent.

If you'd like a separate signature step before applying updates,
that's a future-phase enhancement (see `tasks.md` Phase 6
candidates).
