Repository navigation
feat: support ephemeral job-style sandboxes #2879
Description
User Story
As an automation user, I want to create an ephemeral sandbox that runs one finite command, so that I can execute isolated jobs and determine their outcome from the command's exit status without managing a long-lived sandbox.
Problem Statement
OpenShell's canonical main-process lifecycle treats every main-process exit as a terminal sandbox error, including a successful exit with code 0. This is appropriate for persistent, deployment-style sandboxes whose canonical process is expected to remain running, but it prevents finite commands from completing successfully as part of sandbox creation.
OpenShell needs an explicit job-style lifecycle for finite workloads, distinct from the existing persistent lifecycle established by #2710.
Impact / Why This Matters
One-shot commands such as build steps, tests, batch processing, and automation tasks cannot use sandbox creation as a successful finite operation. A command that completes normally is reported as a runtime failure, so callers cannot distinguish successful job completion from provisioning or runtime failure.
The current workaround is to create a retained sandbox, run the command with sandbox exec, capture its result, and then delete the sandbox manually. That workflow is not atomic, requires extra lifecycle coordination, can leak resources when automation is interrupted, and does not provide a single job result.
Proposed Design
Allow users to explicitly create an ephemeral, job-style sandbox. The sandbox runs a finite command without requiring a long-lived, health-checked canonical process.
The user-visible lifecycle should behave as follows:
- A command exit code of 0 completes the job successfully.
- A nonzero command exit preserves and reports the command's failure status.
- The command's stdout and stderr remain available to the caller.
- The CLI and API status clearly distinguish successful command completion, command failure, and sandbox provisioning or runtime failure.
- Resources are cleaned up according to the documented ephemeral lifecycle after command completion.
- Docker, Podman, Kubernetes, and VM sandboxes expose consistent job semantics.
Persistent, deployment-style sandboxes retain their existing canonical-main-process behavior, including health checks and the expectation that the main process remains running.
Acceptance Criteria
- A user can explicitly request an ephemeral/job-style sandbox through the supported CLI and API workflows.
- The sandbox can run a finite command without requiring a long-lived, health-checked canonical process.
- A command that exits with code 0 is reported as successful completion rather than a sandbox error.
- A command that exits nonzero reports the command's failure status to the caller.
- The caller can access the command's stdout and stderr.
- CLI and API status distinguish successful completion, command failure, and provisioning or runtime failure.
- Ephemeral sandbox resources are cleaned up according to the documented lifecycle, including when the command fails.
- Persistent/deployment-style canonical-main-process behavior remains unchanged.
- Job-style behavior is consistent across Docker, Podman, Kubernetes, and VM drivers.
- User-facing lifecycle documentation explains how to choose between persistent and job-style sandboxes.
Alternatives Considered
Infer job semantics from any command supplied at creation
Treating every explicit command as a job would make finite commands convenient, but it would make long-running service commands ambiguous and could change the persistent canonical-main-process contract. An explicit lifecycle keeps intent clear.
Treat exit code 0 as success for every canonical main process
This would erase the distinction between a successfully completed job and a deployment-style sandbox whose required process unexpectedly stopped. The lifecycle mode should determine whether process exit represents completion or loss of service.
Create a retained sandbox, use sandbox exec, then delete it
This is the current workaround. It requires multiple non-atomic operations, burdens callers with cleanup, and can leak retained resources when automation is interrupted.
Activity
krishicks commentedon Aug 21, 2026
The agent called this a feature, but it's actually a regression.
This workflow used to work:
But now it returns an error:
drew commentedon Aug 21, 2026
drew commentedon Aug 21, 2026
Implementation Plan
Issue type:
fixComplexity: High
Confidence: Medium-high — lifecycle mapping is clear; short-command output needs a bounded terminal-drain handshake.
Summary
Restore the existing
sandbox create -- <command>finite-command contract without adding a job RPC or selector. The canonical main process remains lifecycle authority: exit 0 becomesCompleted, nonzero becomesStopped/MainProcessFailed, andErrorremains reserved for infrastructure failures. Foreground create streams the existing main session and propagates its exact exit status;--no-keepdeletes after output/result drain.Scope
proto/openshell.protoand SDKs: appendSANDBOX_PHASE_COMPLETED = 9; update conversions and rendering without renumbering existing values.crates/openshell-server: persist zero/nonzero main results with distinct phases and conditions; make Completed sticky, watch-terminal, restartable, and safe against stale exit and snapshot races.crates/openshell-supervisor-processand relay authorization: keep short-process output attachable through a bounded terminal-drain window and preserve exact stdout, stderr, and TTY behavior.crates/openshell-cli: attach explicit commands regardless of terminal detection unless--detach; stream output, return the main exit code, and delete--no-keepsandboxes after drain.Implementation Steps
--no-keeppost-drain cleanup using existing APIs.Test Plan
--no-keepdeletes after success and failure.Risks & Open Questions
Documentation Impact
Update
architecture/sandbox.md,architecture/gateway.md,architecture/compute-runtimes.md,docs/sandboxes/manage-sandboxes.mdx, relevant compute-driver guidance, and.agents/skills/openshell-cli/. No gateway TOML or Helm configuration documentation change is required. LSM behavior is unchanged because process identity and enforcement boundaries remain unchanged.Revision 1 — Completed phase and existing-API foreground command contract
drew commentedon Aug 21, 2026
Implemented in #2884.
The final contract is:
CompletedwithMainProcessCompletedand exit code 0StoppedwithMainProcessFailedand the exact normalized exit codeError--detachis set--no-keepdrains output/result before deletion, with a gateway-side ephemeral cleanup fallbackCompletedand failedStoppedsandboxes can be started againThe supervisor continues to own the canonical process. It now registers and retains the main-output relay long enough for fast commands to attach and drain, rather than suppressing the relay when the command exits before SSH is ready.
Validation includes the full server unit suite, pre-commit, SDK tests, and Docker lifecycle E2E covering successful and failed commands, output streaming, retained terminal state, reconnect replay, and ephemeral cleanup.