Recovery
Stale-agent reconnect for Docker and VM runtimes, destroy semantics
Cockpit Recovery
Runtimes and agents fail independently: a container or VM can be perfectly healthy while its agent's registration with the executor has dropped (idle transport drops, executor restarts, soft-locks). Cockpit's recovery surface is built around that distinction.
Stale agents: `agent unreachable`
When a runtime is running but its agent is not registered (or its session backends report unavailable), Inventory and Sessions keep the row visible with the health state `agent unreachable` instead of hiding it — and expose Reconnect.
Reconnect is rendered for running rows of runtime kind `docker`, `container`, `vm`, `qemu`, or `kvm` whose agent is missing. Host targets are deliberately excluded from the button (see Host runtimes below).
A Reconnect never creates a replacement instance and never destroys the running runtime — it only attempts to restore the missing agent registration.
What the Bridge tries, in order
`POST /api/instances/:id/reconnect` walks three paths:
1. Executor-owned reconnect — the sandbox's own reconnect endpoints (v2 admin first, then legacy candidates). If the executor handles it, done. 2. Docker/container fallback — `docker exec <container> agent-reconnect`, which SIGHUPs the in-container agent so it re-registers in place without restarting the container. Requires sandbox images that ship the `agent-reconnect` helper (agentic-sandbox v2026.7.5+); on failure the response says to repull/rebuild the image. 3. VM fallback (new in 2026.7, roctinam/aiwg#1778) — for `vm`/`qemu`/`kvm` instances the Bridge delivers the same SIGHUP through the libvirt guest-agent channel:
virsh qemu-agent-command <domain> guest-exec → pkill -HUP -x agent-client
The sandbox VM images bake qemu-guest-agent for exactly this kind of in-guest exec, and the agent handles SIGHUP as reconnect-in-place on every runtime, so no VM image change is needed. The libvirt domain name is the instance's launch name. Requirements: the Bridge host needs `virsh` access to the domain, and the guest-agent channel must be up — a 502 names whichever is missing.
If none of the paths apply, the 409 response spells out the manual host-side command (`pkill -HUP -x agent-client`).
What survives a reconnect
Session survival depends on the agent version inside the runtime, not on Cockpit:
- agentic-sandbox 2026.7.8+ agents: transport reconnect is
state-preserving — the agent no longer kills tracked workloads on stream loss, all session types (managed multiplexer and direct pty / headless tasks) survive, and output produced while disconnected buffers and flushes after re-register. Server-side reconcile is the sole kill authority.
- Older agents (pre-2026.7.8): only sessions backed by a **detached
multiplexer** (managed tmux) survive and are re-adopted; the agent SIGTERMs everything else as part of its reconnect cycle. This was the root cause chain fixed upstream in agentic-sandbox#633 (VM idle drop) and agentic-sandbox#634 (kill-on-reconnect).
A VM keeps its baked agent binary until the image is rebuilt or the VM is reprovisioned — so a running fleet can mix both behaviors. If sessions vanish after a reconnect, check the agent version in that runtime before suspecting Cockpit. On older agents, prefer managed session backends for long-running work.
After a successful reconnect: refresh Inventory, then attach from Sessions.
Host runtimes
Host targets don't get a Reconnect button — the agent runs directly on the Bridge host, so the recovery lever is the host-runtime daemon itself. Start Cockpit with the daemon when working host targets:
AIWG_COCKPIT_START_HOST_DAEMON=1 npm run cockpit:up
The Inventory host-daemon column shows the daemon's status and the documented operator command when action is needed; Cockpit never starts or installs the daemon silently. Manual agent recovery on a host is `pkill -HUP -x agent-client`.
Destroy
`DELETE /api/instances/:id` is defensive about executor/runtime state skew:
- Tries the executor's v2 and legacy destroy surfaces.
- For Docker rows, reconciles with `docker rm -f <name>` even after admin
success (current sandbox builds can list Docker rows the lifecycle verbs don't know), and falls back to it when the admin surface returns instance-not-found.
- An already-removed target reports success with an `already_gone` marker
instead of failing the operator's intent.
- A stopped Docker row's Destroy removes the container directly — the UI
tooltip says so before you click.
Audit
Every recovery action lands in the local audit log: `instance.reconnect.requested`, `instance.destroy.requested`, with targets and results (secrets redacted). See Trust & Security → Audit log.
See also
- Sessions — backends and what "managed" buys you
- upstream: roctinam/agentic-sandbox#633 (VM idle-drop root cause),
roctinam/agentic-sandbox#634 (session survival across reconnect)