User Story
As an OpenShell CLI, SDK, or direct API user, I want CPU, memory, and GPU requirements to use one typed portable resource model, so that sandbox workload intent is consistent across drivers and does not require backend-shaped template passthrough.
Problem Statement
OpenShell currently models GPU requests as portable resource intent, but CPU and memory take a different path.
Today:
--gpu populates SandboxSpec.resource_requirements.gpu.
--cpu and --memory populate SandboxSpec.template.resources.limits as a free-form google.protobuf.Struct.
- The gateway extracts
limits.cpu, limits.memory, requests.cpu, and requests.memory from SandboxTemplate.resources into internal DriverResourceRequirements.
- Drivers consume CPU and memory from
DriverSandboxTemplate.resources, while GPU is consumed from DriverSandboxSpec.resource_requirements.
This makes common portable resources split across two public API surfaces. It also leaves SandboxTemplate.resources acting as both a platform-native escape hatch and the stable path for portable CPU/memory intent.
Impact / Why This Matters
The current model is harder for SDK users, API users, and future template work to reason about. GPU is represented as typed workload intent, while CPU and memory require constructing a Kubernetes-shaped struct even when the target driver is Docker, Podman, or VM.
This also complicates future API cleanup work around sandbox workload templates. First-class templates should be able to store reusable workload resources, but created sandboxes should still persist the resolved portable resource intent in their own spec. A typed compute requirement model gives both inline creates and template-based creates the same resource shape.
Proposed Design
Extend ResourceRequirements with a typed compute resource message for CPU and memory.
Illustrative public proto shape:
message ResourceRequirements {
// Existing GPU requirements. Presence indicates a GPU request.
GpuResourceRequirements gpu = 1;
// Portable CPU and memory requirements.
ComputeResourceRequirements compute = 2;
}
message ComputeResourceRequirements {
string cpu_request = 1;
string cpu_limit = 2;
string memory_request = 3;
string memory_limit = 4;
}
Mirror the same semantics in compute_driver.proto, so compute drivers receive CPU, memory, and GPU through DriverSandboxSpec.resource_requirements.
Expected behavior:
openshell sandbox create --cpu 2 --memory 4Gi populates resource_requirements.compute.cpu_limit and resource_requirements.compute.memory_limit.
openshell sandbox create --gpu continues to populate resource_requirements.gpu.
--gpu without a count continues to mean a present GPU request with driver-default count semantics.
- Kubernetes maps typed compute requirements to pod container requests/limits, preserving today's limit-to-request mirroring when only limits are supplied.
- Docker and Podman apply supported CPU and memory limits from typed compute requirements.
- VM must either map typed CPU/memory requirements to VM sizing or reject unsupported requirements clearly; it should not silently ignore typed portable requirements.
SandboxTemplate.resources remains available temporarily for compatibility and platform-native passthrough.
- If both typed compute requirements and template CPU/memory resources are provided for the same sandbox, validation should reject conflicting values instead of silently choosing one.
If the sandbox workload template work from #2833 lands first, this issue should align inline sandbox creates and resolved sandbox specs with the typed resource shape used by workload templates. If the breaking cleanup direction from #2781 is pursued, this issue should fold naturally into SandboxWorkloadConfig.resources.
Acceptance Criteria
Alternatives Considered
Keep CPU and memory in SandboxTemplate.resources. This preserves today's behavior but keeps portable resource intent coupled to a platform-native struct and makes SDK usage awkward.
Add top-level cpu and memory fields to SandboxSpec. This is simpler, but it repeats the older GPU-specific pattern and does not scale to request/limit semantics or future resource domains.
Use only the SandboxResources shape from workload templates. That may be the right end-state after template cleanup, but the current API already has SandboxSpec.resource_requirements as the portable resource envelope. Adding compute there is the smallest compatible step.
Expose a JSON resource flag. RFC 0004 explicitly avoids JSON-formatted portable resource requests because common resources should be typed.
Agent Investigation
Current local code shows the split:
- CLI
--gpu becomes GpuResourceRequirements and is wrapped in SandboxSpec.resource_requirements.
- CLI
--cpu and --memory become SandboxTemplate.resources.limits entries.
- The public
ResourceRequirements message currently contains only GPU.
- The gateway extracts CPU/memory from
SandboxTemplate.resources into DriverResourceRequirements.
- Docker and Podman apply CPU/memory from driver template resources.
- Kubernetes renders CPU/memory from driver template resources and GPU from driver resource requirements into pod container resources.
- VM uses GPU requirements for GPU-specific validation/sizing, but currently accepts CPU/memory template resources as a no-op.
User Story
As an OpenShell CLI, SDK, or direct API user, I want CPU, memory, and GPU requirements to use one typed portable resource model, so that sandbox workload intent is consistent across drivers and does not require backend-shaped template passthrough.
Problem Statement
OpenShell currently models GPU requests as portable resource intent, but CPU and memory take a different path.
Today:
--gpupopulatesSandboxSpec.resource_requirements.gpu.--cpuand--memorypopulateSandboxSpec.template.resources.limitsas a free-formgoogle.protobuf.Struct.limits.cpu,limits.memory,requests.cpu, andrequests.memoryfromSandboxTemplate.resourcesinto internalDriverResourceRequirements.DriverSandboxTemplate.resources, while GPU is consumed fromDriverSandboxSpec.resource_requirements.This makes common portable resources split across two public API surfaces. It also leaves
SandboxTemplate.resourcesacting as both a platform-native escape hatch and the stable path for portable CPU/memory intent.Impact / Why This Matters
The current model is harder for SDK users, API users, and future template work to reason about. GPU is represented as typed workload intent, while CPU and memory require constructing a Kubernetes-shaped struct even when the target driver is Docker, Podman, or VM.
This also complicates future API cleanup work around sandbox workload templates. First-class templates should be able to store reusable workload resources, but created sandboxes should still persist the resolved portable resource intent in their own spec. A typed compute requirement model gives both inline creates and template-based creates the same resource shape.
Proposed Design
Extend
ResourceRequirementswith a typed compute resource message for CPU and memory.Illustrative public proto shape:
Mirror the same semantics in
compute_driver.proto, so compute drivers receive CPU, memory, and GPU throughDriverSandboxSpec.resource_requirements.Expected behavior:
openshell sandbox create --cpu 2 --memory 4Gipopulatesresource_requirements.compute.cpu_limitandresource_requirements.compute.memory_limit.openshell sandbox create --gpucontinues to populateresource_requirements.gpu.--gpuwithout a count continues to mean a present GPU request with driver-default count semantics.SandboxTemplate.resourcesremains available temporarily for compatibility and platform-native passthrough.If the sandbox workload template work from #2833 lands first, this issue should align inline sandbox creates and resolved sandbox specs with the typed resource shape used by workload templates. If the breaking cleanup direction from #2781 is pursued, this issue should fold naturally into
SandboxWorkloadConfig.resources.Acceptance Criteria
--cpuand--memorypopulate typed compute requirements instead ofSandboxTemplate.resources.--gpubehavior remains user-compatible.SandboxTemplate.resourcesis retained only as a compatibility path, with clear precedence or conflict validation.Structconstruction.Alternatives Considered
Keep CPU and memory in
SandboxTemplate.resources. This preserves today's behavior but keeps portable resource intent coupled to a platform-native struct and makes SDK usage awkward.Add top-level
cpuandmemoryfields toSandboxSpec. This is simpler, but it repeats the older GPU-specific pattern and does not scale to request/limit semantics or future resource domains.Use only the
SandboxResourcesshape from workload templates. That may be the right end-state after template cleanup, but the current API already hasSandboxSpec.resource_requirementsas the portable resource envelope. Adding compute there is the smallest compatible step.Expose a JSON resource flag. RFC 0004 explicitly avoids JSON-formatted portable resource requests because common resources should be typed.
Agent Investigation
Current local code shows the split:
--gpubecomesGpuResourceRequirementsand is wrapped inSandboxSpec.resource_requirements.--cpuand--memorybecomeSandboxTemplate.resources.limitsentries.ResourceRequirementsmessage currently contains only GPU.SandboxTemplate.resourcesintoDriverResourceRequirements.