You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Sandbox creation currently requires users to manually specify environment variables, clone repos, and attach providers on every invocation. For repeatable workflows — such as running multiple parallel Claude Code sandboxes against the same repo with Vertex AI — this means re-typing the same flags each time, or scripting around the CLI.
Two concrete pain points:
No git checkout on init. Users who want code in a sandbox must either --upload local files or manually exec a git clone after creation. There is no way to declaratively say "this sandbox starts with repo X checked out."
Provider-adjacent env vars have no home. If a generic ADC/Google metadata provider were to replace the current google-vertex-ai provider (see discussion), Anthropic-specific Vertex env vars (CLAUDE_CODE_USE_VERTEX, ANTHROPIC_VERTEX_PROJECT_ID, etc.) would no longer belong in the provider's resolution logic — they are consumer config that sits on top of the credential layer. Today there is nowhere to put them except manual exec or custom images.
A named sandbox template stored on the gateway solves both: define once, create many sandboxes from the same template, with environment, git checkout, and default providers bundled together. Templates are purely a convenience — users can always create sandboxes without one, specifying flags inline as they do today.
Related Issues
feat(cli): investigate sandbox specs and openshell apply -f #1520 — feat(cli): investigate sandbox specs and openshell apply -f. Investigates file-based declarative sandbox definitions. Complementary: a YAML file could be the authoring format for a named template, and apply -f could create/update templates on the gateway.
feat: warmpool support for OpenShell sandboxes #1447 — feat: warmpool support for OpenShell sandboxes. Warm pools need a specification for what to pre-create — named templates are a natural fit. Note: feat: warmpool support for OpenShell sandboxes #1447 references the agents.x-k8s.ioSandboxTemplate CRD, which is a Kubernetes-level pod templating concept (image, resources, volumes). The NamedSandboxTemplate proposed here is an OpenShell gateway-scoped concept at a higher abstraction level (environment, git checkout, bundled providers). They share a name but operate at different layers and could compose: OpenShell templates define what to create, the K8s CRD defines how to schedule it.
SandboxTemplate already exists at proto/openshell.proto:335-363 with image, labels, annotations, environment, resources, and driver_config fields. But it is a flat struct embedded in SandboxSpec — not a named, reusable, gateway-persisted entity. SandboxSpec.environment also exists and flows through the gateway and compute drivers, but is not exposed by the CLI sandbox create command.
Driver-controlled env — identity, callback, security-critical vars (always override)
Provider credential env — fetched at runtime by supervisor, injected as placeholders
Environment merge semantics with templates
When a named template is used, environment variables merge in this order (later layers win):
Provider credential env — base layer from bundled (and any additionally attached) providers
Template environment — merges on top of provider env, allowing templates to override or supplement provider-injected vars
Inline --env flags (future work) — would merge on top of template env for per-sandbox overrides
This means a template can set consumer-specific env vars (e.g., CLAUDE_CODE_USE_VERTEX=1) that sit on top of what the provider injects (e.g., GCP_PROJECT_ID), without modifying the provider itself.
Where git checkout happens today
Nowhere. The only related mechanism is --upload (tar-over-SSH of local files post-creation). No git clone during init.
Templates are a convenience, not a requirement. Users who don't need reusability continue using inline flags exactly as they do today. A template simply pre-populates what would otherwise be specified on every sandbox create invocation.
Git checkout: gateway-side clone (outside the sandbox)
Recommended: the gateway or compute driver clones the repo using credentials from a bundled provider (e.g., a github provider's token), then mounts/copies the checkout into the sandbox filesystem. Benefits:
No git credentials inside the sandbox — the sandbox never sees the git token. The agent can read/edit code but cannot git push.
Simpler lifecycle — no dependency on proxy being up, no network namespace concerns.
Writable checkout — the agent can modify files; the .git directory could optionally be stripped or made read-only.
Composes with --upload — both the template's git checkout and the user's --upload path work together (upload overlays on top of checkout).
Trade-off: the sandbox cannot git pull or git push without separate git access. Agent output would be extracted via sandbox exec, file download, or diff export.
Code References
Location
Description
proto/openshell.proto:309-332
SandboxSpec: has environment, template, providers fields
proto/openshell.proto:335-363
SandboxTemplate: flat struct with environment, image, resources
Template overrides at creation time deferred to future work
Compute drivers:
Accept git checkout directory/volume and mount into sandbox filesystem
Docker: bind mount or copy into container
K8s: init container or volume mount
VM: include in rootfs or mount
Python SDK:
Template CRUD methods on the client
Alternative Approaches Considered
Option A: Extend SandboxSpec inline (no named templates). Add --env and --git-repo flags to sandbox create. Simpler, but no reusability — you retype everything each time. Doesn't satisfy the "5 parallel sandboxes from the same config" use case well.
Option B: CLI-side config files only. Store templates as local YAML files, expand them client-side before sending to the gateway. Simpler (no new RPCs/persistence), but not shareable across machines or team members. #1520 explores this direction — the two could converge.
Option C: Named gateway-scoped templates (recommended). Full CRUD on the gateway. Reusable, shareable, composable with providers. More implementation work but the right long-term abstraction.
Patterns to Follow
Provider CRUD in crates/openshell-server/src/grpc/provider.rs — same pattern for template CRUD
Provider persistence in the gateway store — same pattern for template persistence
Provider CLI commands — same pattern for template CLI commands
--upload tar-over-SSH in crates/openshell-cli/src/run.rs:5669-5706 — git checkout should compose with this
Proposed Approach
Introduce NamedSandboxTemplate as a gateway-persisted domain object with environment, git checkout, bundled providers, and optional image override. Templates are managed via CLI CRUD commands and referenced by name at sandbox creation time. Git checkout happens at the gateway/driver level before the sandbox starts, so git credentials never enter the sandbox. The --upload path remains supported and composes with template-driven checkout. Template environment merges on top of provider-injected env vars, giving templates a natural place for consumer-specific config that doesn't belong in the provider itself. Template overrides at sandbox creation time are deferred to future work.
Scope Assessment
Complexity: High — new domain object, CRUD RPCs, persistence, CLI surface, git checkout orchestration across three compute drivers
Confidence: Medium — core design is clear, but git checkout mechanics vary significantly across Docker/K8s/VM drivers
Git checkout across drivers — Docker bind mounts, K8s init containers/volumes, and VM rootfs injection are three different mechanisms. Need to define the driver interface for "make this directory available in the sandbox."
Git credential scoping — if the template bundles a github provider, the gateway can use that provider's token for the clone. But the clone happens outside the sandbox, so the gateway needs access to provider credentials at clone time, not just at sandbox runtime.
Template + provider interaction — when a template bundles providers, does the user need to have those providers already created? Or can the template reference provider types and auto-create instances?
Upload + git checkout ordering — if both are specified, upload should overlay on top of the git checkout. Need to define sequencing.
Template mutability — can a template be updated after creation? Do running sandboxes reflect updates, or are they snapshots?
Problem Statement
Sandbox creation currently requires users to manually specify environment variables, clone repos, and attach providers on every invocation. For repeatable workflows — such as running multiple parallel Claude Code sandboxes against the same repo with Vertex AI — this means re-typing the same flags each time, or scripting around the CLI.
Two concrete pain points:
No git checkout on init. Users who want code in a sandbox must either
--uploadlocal files or manuallyexecagit cloneafter creation. There is no way to declaratively say "this sandbox starts with repo X checked out."Provider-adjacent env vars have no home. If a generic ADC/Google metadata provider were to replace the current
google-vertex-aiprovider (see discussion), Anthropic-specific Vertex env vars (CLAUDE_CODE_USE_VERTEX,ANTHROPIC_VERTEX_PROJECT_ID, etc.) would no longer belong in the provider's resolution logic — they are consumer config that sits on top of the credential layer. Today there is nowhere to put them except manualexecor custom images.A named sandbox template stored on the gateway solves both: define once, create many sandboxes from the same template, with environment, git checkout, and default providers bundled together. Templates are purely a convenience — users can always create sandboxes without one, specifying flags inline as they do today.
Related Issues
feat(cli): investigate sandbox specs and openshell apply -f. Investigates file-based declarative sandbox definitions. Complementary: a YAML file could be the authoring format for a named template, andapply -fcould create/update templates on the gateway.SandboxTemplate.environmentenv vars not applied to container. Bug: the existingSandboxTemplate.environmentproto field doesn't flow through to the sandbox. Must be fixed before templates can set env vars.feat: warmpool support for OpenShell sandboxes. Warm pools need a specification for what to pre-create — named templates are a natural fit. Note: feat: warmpool support for OpenShell sandboxes #1447 references theagents.x-k8s.ioSandboxTemplateCRD, which is a Kubernetes-level pod templating concept (image, resources, volumes). TheNamedSandboxTemplateproposed here is an OpenShell gateway-scoped concept at a higher abstraction level (environment, git checkout, bundled providers). They share a name but operate at different layers and could compose: OpenShell templates define what to create, the K8s CRD defines how to schedule it.Technical Context
Current state of the proto
SandboxTemplatealready exists atproto/openshell.proto:335-363withimage,labels,annotations,environment,resources, anddriver_configfields. But it is a flat struct embedded inSandboxSpec— not a named, reusable, gateway-persisted entity.SandboxSpec.environmentalso exists and flows through the gateway and compute drivers, but is not exposed by the CLIsandbox createcommand.Current sandbox creation flow
Where env vars are set today
Four layers, in precedence order:
SandboxSpec.environment— proto field exists, flows correctly, CLI never populates itSandboxTemplate.environment— proto field exists, [Question] SandboxTemplate.environment environment variables not applied to container #863 reports it's brokenEnvironment merge semantics with templates
When a named template is used, environment variables merge in this order (later layers win):
--envflags (future work) — would merge on top of template env for per-sandbox overridesThis means a template can set consumer-specific env vars (e.g.,
CLAUDE_CODE_USE_VERTEX=1) that sit on top of what the provider injects (e.g.,GCP_PROJECT_ID), without modifying the provider itself.Where git checkout happens today
Nowhere. The only related mechanism is
--upload(tar-over-SSH of local files post-creation). Nogit cloneduring init.Affected Components
proto/openshell.protoNamedSandboxTemplatemessage,GitCheckoutmessage, CRUD RPCscrates/openshell-server/src/grpc/sandbox.rscrates/openshell-server/src/(store layer)crates/openshell-cli/src/main.rs,crates/openshell-cli/src/run.rstemplate create/list/get/deletecommands,sandbox create --templateflagcrates/openshell-driver-{docker,kubernetes,vm}/python/openshell/Technical Investigation
Architecture Overview
Named sandbox templates would be a new gateway-scoped domain object, similar to how providers are managed today:
Templates are a convenience, not a requirement. Users who don't need reusability continue using inline flags exactly as they do today. A template simply pre-populates what would otherwise be specified on every
sandbox createinvocation.Git checkout: gateway-side clone (outside the sandbox)
Recommended: the gateway or compute driver clones the repo using credentials from a bundled provider (e.g., a
githubprovider's token), then mounts/copies the checkout into the sandbox filesystem. Benefits:git push..gitdirectory could optionally be stripped or made read-only.--upload— both the template's git checkout and the user's--uploadpath work together (upload overlays on top of checkout).Trade-off: the sandbox cannot
git pullorgit pushwithout separate git access. Agent output would be extracted viasandbox exec, file download, or diff export.Code References
proto/openshell.proto:309-332SandboxSpec: hasenvironment,template,providersfieldsproto/openshell.proto:335-363SandboxTemplate: flat struct withenvironment,image,resourcesproto/openshell.proto:1089-1103GetSandboxProviderEnvironmentResponse: provider env resolutioncrates/openshell-server/src/grpc/sandbox.rs:117-224handle_create_sandbox_inner(): validates providers, resolves templatecrates/openshell-server/src/grpc/provider.rs:430-539resolve_provider_environment(): provider credentials → env var mapcrates/openshell-cli/src/main.rs:1162-1293sandbox createcommand — no--envor--templateflagscrates/openshell-cli/src/run.rs:1740-1920sandbox_create(): CLI-side creation logiccrates/openshell-driver-docker/src/lib.rs:1634-1710build_environment()crates/openshell-sandbox/src/lib.rs:370-425crates/openshell-sandbox/src/process.rs:194-258inject_provider_env()+ child process spawnCurrent Behavior
When
sandbox createis called:--provider,--from,--policyflags — no--envor--templatesupportSandboxSpecis persisted with emptyenvironmentmap (CLI never populates it)What Would Need to Change
Proto layer:
NamedSandboxTemplatemessage with metadata, environment, git_checkout, providers, imageGitCheckoutmessageCreateTemplate,GetTemplate,ListTemplates,DeleteTemplateCreateSandboxRequestgains atemplate_namefield (or reuse existingtemplatefield)Gateway:
CLI:
openshell template create/list/get/deletecommandsopenshell sandbox create --template <name>flagCompute drivers:
Python SDK:
Alternative Approaches Considered
Option A: Extend SandboxSpec inline (no named templates). Add
--envand--git-repoflags tosandbox create. Simpler, but no reusability — you retype everything each time. Doesn't satisfy the "5 parallel sandboxes from the same config" use case well.Option B: CLI-side config files only. Store templates as local YAML files, expand them client-side before sending to the gateway. Simpler (no new RPCs/persistence), but not shareable across machines or team members. #1520 explores this direction — the two could converge.
Option C: Named gateway-scoped templates (recommended). Full CRUD on the gateway. Reusable, shareable, composable with providers. More implementation work but the right long-term abstraction.
Patterns to Follow
crates/openshell-server/src/grpc/provider.rs— same pattern for template CRUD--uploadtar-over-SSH incrates/openshell-cli/src/run.rs:5669-5706— git checkout should compose with thisProposed Approach
Introduce
NamedSandboxTemplateas a gateway-persisted domain object with environment, git checkout, bundled providers, and optional image override. Templates are managed via CLI CRUD commands and referenced by name at sandbox creation time. Git checkout happens at the gateway/driver level before the sandbox starts, so git credentials never enter the sandbox. The--uploadpath remains supported and composes with template-driven checkout. Template environment merges on top of provider-injected env vars, giving templates a natural place for consumer-specific config that doesn't belong in the provider itself. Template overrides at sandbox creation time are deferred to future work.Scope Assessment
featRisks & Open Questions
SandboxTemplate.environmentis currently broken. Template env vars flowing through is a prerequisite.githubprovider, the gateway can use that provider's token for the clone. But the clone happens outside the sandbox, so the gateway needs access to provider credentials at clone time, not just at sandbox runtime.openshell template create --from-file template.yamloropenshell apply -f template.yaml.Test Considerations
--uploadcomposition — verify both git checkout and uploaded files are presentCreated by spike investigation. Use
build-from-issueto plan and implement.