Repository navigation
Description
Summary
On the msb backend, kit startup commands do not re-run on a raw msb start / msb restart (or a host-reboot-driven guest restart). They re-run only when acq itself re-drives an apply (i.e. acq run <sandbox> → acq_backend_ensure_kits_applied). This means a sandbox that is stopped and started back up outside acq comes back without its kit-defined background services running.
This is the durability half of the problem that #239 explicitly parked — #239 is scoped as an adapter-internal hardening refactor ("stages commands at create time", "no change to observable behavior"), whereas this issue is a behavior-level lifecycle gap. Filing separately so the two don't get conflated; revisiting #239 is expected as part of the fix.
Why this matters (concrete failure)
The openchamber acq mixin kit (in agentic-coding-patterns, integrations/isolation/acq-kits/openchamber/) runs a long-lived, supervised stack — a shared opencode serve on :4096 and OpenChamber on :3000 — via a commands: [{phase: startup, background: true}] entry that launches openchamber-start.sh.
On msb this works while the sandbox keeps running (msb applies no idle_timeout, so the VM never idles out — confirmed in microsandbox crates/runtime/lib/heartbeat.rs: check(None) never reclaims). But after msb stop + msb start, or a host reboot followed by a raw msb start, the VM is back but openchamber-start.sh never re-runs, so the browser UI is dark until the user goes back through acq run.
Root cause (traced)
- microsandbox would re-run a persisted
LaunchConfig.startuponSandbox::start_detached()(used by bothmsb startandmsb restart— see microsandboxcrates/cli/lib/commands/start.rs,restart.rs). The mechanism exists guest-side. - acq never populates
LaunchConfig.startup.acq.backends/msb.shapplies kitstartupcommands imperatively viamsb execat provision time and on theacq runre-attach heal loop (acq_backend_ensure_kits_applied,msb.sh:2054-2078). The onlymsb createinvocation (msb.sh:1204) carries no startup/script flag. - acq has no
start/restart/resumeverb, so it never re-drives apply on a bare microsandbox restart. - The
background: truenohupdetach (msb.sh:848-869) and create-time-pports are provision-time constructs; the detached process does not survive a restart.
There is also a design-vs-implementation gap: docs/explorations/acq-design.md:196 states msb runs startup "after every msb start", but the shipped adapter achieves "after every acq re-apply", not after a raw msb start.
Proposed direction (to be designed; revisits #239)
Make msb kit startup (and initFiles) re-run on a microsandbox-native restart, without breaking the mid-life apply path. Candidate approaches to evaluate:
- Persist startup via microsandbox script registration — stage the kit's startup as a
--script/--script-pathatmsb createso microsandbox re-runs it on everystart_detached. This is exactly the create-time-only, script-file-bodied case that the msb adapter: use --script for kit-command injection instead of copy+sh -c #239 design note (msb.sh:406-412) called out as the one clean win for--scriptbut left parked. Keep the existingmsb execpath for the mid-life apply/heal case (the msb adapter: use --script for kit-command injection instead of copy+sh -c #239 timing objection); the two are complementary, not mutually exclusive. - Give acq a
start/restartverb that re-drivesacq_backend_ensure_kits_appliedso recovery through acq is a first-class, documented path. - Some combination — native persistence for the reboot/
msb startpath, acq re-apply for the in-place kit-add path.
Whichever lands needs an ADR (touches the #239 decision + ADR-0011/ADR-0014 command/lifecycle vocabulary) and must keep the neutral hybrid/v1 kit vocabulary and idempotency/marker semantics intact.
Acceptance criteria
- After
msb stop <sandbox>+msb start <sandbox>(noacqre-invocation), kitstartupcommands run again and background supervisors come back up. - The openchamber kit's UI is reachable after a stop/start (and after a reboot +
msb start) without anacq runre-attach. - Mid-life kit apply/heal (
acq runre-attach,acq kit apply) still works and stays idempotent (install-phase marker-gating preserved). docs/explorations/acq-design.md:196and the msb.sh msb adapter: use --script for kit-command injection instead of copy+sh -c #239 design note reconciled with the shipped behavior.- Regression coverage in
scripts/test-acq; live verification on a KVM host viascripts/verify-backends.
Related
- Parked half of msb adapter: use --script for kit-command injection instead of copy+sh -c #239 (msb
--scriptstaging — evaluated & keptmsb exec; design note atacq.backends/msb.sh:349-412) - Part of Epic: sbx↔msb backend parity #234 (sbx↔msb backend parity epic)
- Consumer/motivator: openchamber kit in
agentic-coding-patterns(integrations/isolation/acq-kits/openchamber/)
Key references
acq.backends/msb.sh:1204— the onlymsb create(no startup/script flag)acq.backends/msb.sh:2054-2078—acq_backend_ensure_kits_applied(acq-driven re-apply on re-attach)acq.backends/msb.sh:349-412— msb adapter: use --script for kit-command injection instead of copy+sh -c #239 design note (why exec-based; the parked--scriptwin)acq.backends/msb.sh:848-869—background: truenohup detach (provision-time only)docs/explorations/acq-design.md:196— design intent ("after everymsb start") not matched by implementation
Note: no idle_timeout-related work is needed — msb leaves it unset, so a running sandbox already keeps startup services alive indefinitely. This issue is strictly about the stop→start / reboot restart path.
AI-assisted (OpenCode); requires human review.
Activity
feat(msb): re-run kit startup on restart via acq start/restart (#260)
mogul commentedon Aug 6, 2026
Resolved by #260 (merged 2026-08-04, commit 7bbc999). Verified against
main:acq start/acq restartverbs exist (acq:676,acq:700) and re-drive the idempotent kit apply, which re-runs thestartupphase.acq run <stopped-sandbox>works end-to-end — the msb heal starts a stopped sandbox before healing/attaching (_acq_msb_is_running+acq_backend_start,acq.backends/msb.sh), blocking on exec-readiness so the heal never races the async boot.acq run/acq start/acq restart; the create-time--script-path acq-startupstaging from feat(msb): stage kit startup commands as a create-time script #259 is retained (_acq_msb_stage_startup_script).msb startre-reads the sandbox's--secret ENV@HOSTbindings via the shared_acq_msb_bind_secrets_into(values move via transient env vars, never argv).docs/explorations/acq-design.mdand ADR-0017 now state that resume is viaacq start/restart/runand that a rawmsb startoutside acq is not a supported resume path (it can't boot a secret-bound sandbox).Live verification (KVM host, per #260):
scripts/verify-backends0 failures; stop→start restored a background-startup kit's supervisor;acq run <stopped-sandbox>reattached cleanly.Note on the parked half: the general "move ALL kit-command injection off
sh -c" refactor (#239) was intentionally kept exec-based for the install + mid-life-apply phases (see the design note inacq.backends/msb.sh); only the create-time startup slice moved to--script-path. That distinction is tracked in #239.Closing as completed.