Repository navigation
Description
User Story
I use OpenShell (0.1.3 and stock 0.1.5) on macOS with both the MicroVM and the Docker drivers available, one at a time, under a host-side policy agent (DefenseClaw, Apache-2.0).
I switched a gateway from compute_driver = "vm" to "docker" while a stopped, kept VM sandbox still held unpulled work. On v0.1.5 the gateway removed that sandbox from its store about 66 seconds after the switch. When I switched back to "vm", the VM driver still had the sandbox's disk, but OpenShell no longer listed it and could not start it, so the work was lost.
This affects anyone who changes the compute driver of a gateway that has kept sandboxes.
Problem Statement
The store reconcile loop compares every store record with the active driver's ListSandboxes. A record that the active driver does not list is treated as a vanished resource, even when that record was created by a different driver. The record carries the internal.openshell.ai/compute-driver annotation, which names its driver.
On the first sweep after the change, a Stopped, Stopping or Starting record is moved to Error with reason ComputeResourceMissing, and the gateway logs "Retained sandbox resource disappeared from the compute driver". On the next sweep the Error record is removed from the store, and a cleanup DeleteSandbox is sent to the new driver.
The grace period is measured from the record's creation time, not from when it went missing. Any sandbox older than five minutes is therefore removed within about two reconcile intervals.
Impact / Why This Matters
- A stopped, kept sandbox, and any work in it that was not pulled out, is lost after a driver change, even though the old driver's resources still exist.
- There is no warning at the switch and no way to keep the record.
- The workaround is to pull every sandbox's work out and delete the sandboxes before changing the driver. That is easy to miss, and it is not documented.
Acceptance Criteria
- After a change from driver A to driver B, records created by A are not moved to a terminal phase or deleted, and no cleanup for them is sent to B.
- Such records are listed with a clear non-ready reason that names the driver that created them, for example "created on vm; the gateway runs docker".
- Start, stop and exec on such a record fail with a clear precondition error.
sandbox deletestill removes the record. - After switching back to driver A, the sandbox can be started and its files are intact.
- Records without a driver annotation keep today's behavior.
Reproduction Steps
- Start a gateway with
compute_driver = "vm". - Run
openshell sandbox create --name keep --keep -- sh -c 'echo work > /sandbox/work.txt; sleep 600'from another terminal, thenopenshell sandbox stop keepwhile it is Ready. Wait until the sandbox is more than five minutes old. On v0.1.5 the originalecho-only command entered Completed, so the sleep keeps it running until the stop. - Stop the gateway, set
compute_driver = "docker", and start it again. - Watch the gateway log and
openshell sandbox list:- within about one minute the log shows
Retained sandbox resource disappeared from the compute driver, andkeepis in Error; - about one minute later the log shows
Removing sandbox from store, andkeepis gone.
- within about one minute the log shows
- Set
compute_driver = "vm"and restart the gateway.openshell sandbox listdoes not showkeep, andopenshell sandbox start keepreports that it is not found. The VM driver's state directory still holds the sandbox's disk.
The same should reproduce on Linux by switching between docker and podman. I have not run that variant.
Expected: keep survives the switch in a non-destructive state and starts again after switching back.
Actual on v0.1.5: keep moved to Error on the first sweep and was deleted from the store 66 s after the switch (at record age 407 s).
Suggested UX (if applicable)
$ openshell sandbox list
NAME PHASE REASON
keep Unavailable created on compute driver "vm"; this gateway runs "docker"
$ openshell sandbox start keep
error: sandbox "keep" was created on compute driver "vm"; switch the gateway back to "vm" to start it
Environment
- Stock OpenShell 0.1.5 release binaries, checksum verified.
- macOS 15.8 (Darwin kernel 24.6.0), Apple silicon, Apple Hypervisor.framework/libkrun MicroVM driver; Docker Desktop 29.8.2; Podman not used.
- One isolated local gateway on port 27670 with a SQLite store. The driver was changed in
gateway.tomlbetween restarts. The Docker phase ran under the local Docker Desktop user against the same isolated store; the VM disk remained in the isolated VM state directory.
Logs
2026-10-20T22:34:40.001901Z WARN reconcile{otel.name="reconcile.sandboxes" driver.name=docker backend_count=0 store_count=3}: openshell_server::compute: Retained sandbox resource disappeared from the compute driver sandbox_id=<sandbox-id> sandbox_name=keep2 phase=Stopped
2026-10-20T22:35:40.017079Z INFO reconcile{otel.name="reconcile.sandboxes" driver.name=docker backend_count=0 store_count=2}: openshell_server::compute: Removing sandbox from store after it disappeared from the compute driver snapshot sandbox_id=<sandbox-id> sandbox_name=keep2 age_secs=407
Error: × code: 'Some requested entity was not found', message: "sandbox not found"The last line is openshell sandbox start keep2 after switching back to VM. The old VM overlay disk was still present. The test used keep2 because the first, echo-only keep sandbox entered Completed.
Activity
letv1nnn commentedon Oct 22, 2026
Assessment: confirmed in source on
main(39d95b42); one premise in the issue does not hold for the reported VM → Docker case.The User Story is first-hand (stock 0.1.5, real driver switch, logs). The deletion path matches current code in
crates/openshell-server/src/compute/mod.rs:reconcile_store_with_backend(:4810) sends every store record the active driver'sListSandboxesdoesn't return toprune_missing_sandbox. It never looks at which driver created the record.prune_missing_sandbox(:5960) measures the grace period fromcreated_at_ms, not from when the record went missing, so any record older thanORPHAN_GRACE_PERIOD(5 min) is acted on in the first sweep. AStopped/Stopping/Startingrecord moves toErrorwithComputeResourceMissing. On the next sweep theErrorrecord falls through tospawn_driver_sandbox_cleanupand deletion. That matches the logged 66 s.Gap: the issue says each record carries
internal.openshell.ai/compute-driver. Onmainthat annotation is only written bypersist_runtime_binding(:2321), which runs only when the driver reportssupports_sandbox_authentication. Of the first-party drivers, only Kubernetes does. Docker, Podman, VM and MXC reportfalse. So VM-created records have no annotation, and with the fifth acceptance criterion ("records without a driver annotation keep today's behavior") the reported scenario would still delete the sandbox.A fix would therefore need to record the creating driver for every sandbox, not only authenticated ones, and decide what happens to existing records that have none. The annotation is also compared during sandbox authentication (
grpc/auth_rpc.rs:136), so writing it more broadly should be checked against that path, or the driver name stored separately.Not reproduced end-to-end here (no VM + Docker switch run); the evidence above is source inspection plus the reporter's logs.
Next human decision: whether a gateway should preserve records across a compute-driver change, and if so whether the creating driver is recorded for all sandboxes going forward and how legacy unannotated records are treated.
letv1nnn commentedon Oct 22, 2026
hey @vineethsai7, I'd like to work on this one, unless you've already started
vineethsai7 commentedon Oct 29, 2026
@letv1nnn , I haven't started on this yet. Feel free to take it :)
vineethsai7 commentedon Nov 2, 2026
Thanks for offering. I already have a fix for this one. It was #5071, which the bot closed before I was vouched. I'm opening a fresh PR today with the review feedback addressed and will link it here.
vineethsai7 commentedon Nov 2, 2026
Fresh PR with the review feedback addressed: #5133.