Skip to content

feat: expose sandbox services during creation #3402

Description

@drew

User Story

As an OpenShell user launching a network service in a sandbox, I want to expose that service as part of sandbox creation, so that clients can connect without a separate post-create command or local SSH port-forwarding process.

Problem Statement

openshell sandbox create cannot currently declare a service endpoint. Users must wait for the sandbox to become ready and then run a separate service-exposure operation, or use local port forwarding. SDK callers likewise cannot express service exposure in their sandbox create request.

This makes service-oriented workloads harder to automate and creates a race between sandbox readiness and endpoint registration. It also complicates examples such as launching a Codex app server in an OpenShell sandbox and connecting a local Codex client to it.

Impact / Why This Matters

The current multi-step workflow requires extra lifecycle coordination, additional error handling, and knowledge of a second API. Local port forwarding also depends on a long-running client-side process and is not suitable when the gateway's routed service endpoint is the desired access path.

A create-time exposure declaration makes service workloads reproducible across the CLI and SDKs, eliminates avoidable orchestration, and gives users one stable endpoint workflow.

Proposed Design

Allow users to request one or more sandbox service exposures during sandbox creation.

The CLI should support an unnamed exposure with a workflow such as:

openshell sandbox create \
  --name codex-app-server \
  --expose 4500 \
  -- codex app-server --listen ws://0.0.0.0:4500

After the sandbox reaches Ready, the CLI should print the routed service URL. Requesting an exposure should keep the sandbox alive after its main command starts and should be incompatible with options that require immediate sandbox cleanup.

The public sandbox create API and the Rust, Python, TypeScript, and Go SDK create options should accept service exposure declarations containing a target port and an optional service name. Named exposures should use the same naming and routing behavior as the existing service-exposure command.

The routed service boundary should preserve the existing behavior of consuming gateway authentication and not forwarding the gateway Authorization header to the sandbox application. Application-level authentication should use a distinct credential mechanism.

Add an example under examples/ that runs the Codex app server inside an OpenShell sandbox and shows how a local Codex client connects through the exposed WebSocket URL.

Acceptance Criteria

  • openshell sandbox create --expose <PORT> requests an unnamed routed service endpoint as part of sandbox creation.
  • The CLI prints the service URL after the sandbox reaches Ready.
  • Create-time exposure keeps the sandbox and rejects conflicting immediate-cleanup options.
  • The create API supports one or more exposures with a target port and optional service name.
  • Invalid ports, invalid service names, duplicate service names, and excessive exposure counts are rejected before sandbox creation is persisted.
  • Rust, Python, TypeScript, and Go SDK callers can supply exposures in direct and template-based sandbox create operations.
  • Existing standalone service exposure behavior remains available and compatible.
  • Gateway authentication headers are not forwarded to the exposed sandbox service.
  • Documentation includes CLI and SDK examples.
  • An examples/ workflow launches a Codex app server in a sandbox and connects a local Codex client through the routed WebSocket endpoint.
  • Unit and integration tests cover API validation, endpoint registration, CLI request construction, and SDK request mapping.

Alternatives Considered

Continue requiring openshell sandbox service expose after creation. This preserves the existing API but forces every caller to coordinate readiness and perform a second mutation.

Use openshell sandbox create --forward exclusively. Port forwarding remains useful for local-only access, but it requires a persistent client-side forwarding process and does not provide a gateway-routed service endpoint.

Forward the gateway Authorization header to the workload. This would conflate gateway authentication with application authentication and disclose a gateway credential to sandbox code, so the service router should continue stripping it.

Agent Investigation

The existing gateway service router already supports named and unnamed ServiceEndpoint records and WebSocket upgrades. The create path can reuse the same exposure validation and endpoint persistence behavior. The maintained SDK surfaces are Rust, Python, TypeScript, and Go.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

area:cliCLI-related workarea:gatewayGateway server and control-plane workarea:sandboxSandbox runtime and isolation workarea:sdkSDK-related work

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions