feat(api)!: model CPU and memory as portable resource requirements
@elezar is already working on this.
Since Sep 1, 2026.
- Dominant language
- Rust
- Stars
- 8.7k
- Forks
- 1.3k
- Avg merge
- 2d 11h
- Merged PRs (30d)
- 253
Description
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 no longer requires backend-shaped template resource 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.- The gateway extracts
limits.cpu,limits.memory,requests.cpu, andrequests.memoryfromSandboxTemplate.resourcesinto internalDriverResourceRequirements. - Drivers consume CPU and memory from
DriverSandboxTemplate.resources, while GPU is consumed fromDriverSandboxSpec.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.
This issue is intentionally a breaking API change: CPU and memory fields under SandboxTemplate.resources should stop being interpreted as portable sandbox sizing.
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.
The breaking behavior is intentional. Keeping legacy CPU/memory interpretation in SandboxTemplate.resources would preserve the same overloaded API surface this issue is meant to remove.
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 {
// CPU limit for the sandbox workload, using Kubernetes-style CPU quantity
// strings such as "500m", "1", or "2.5".
optional string cpu = 1;
// Memory limit for the sandbox workload, using Kubernetes-style memory
// quantity strings such as "512Mi", "4Gi", or "8G".
optional string memory = 2;
}
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 4Gipopulatesresource_requirements.compute.cpuandresource_requirements.compute.memory.openshell sandbox create --gpucontinues to populateresource_requirements.gpu.--gpuwithout a count continues to mean a present GPU request with driver-default count semantics.- Kubernetes maps typed compute requirements to pod container requests and limits, preserving today's limit-to-request mirroring.
- 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 must not silently ignore typed portable requirements.
SandboxTemplate.resourcesremains available only as a platform-native escape hatch for non-portable resource fields during the API transition.SandboxTemplate.resources.limits.cpu,SandboxTemplate.resources.limits.memory,SandboxTemplate.resources.requests.cpu, andSandboxTemplate.resources.requests.memoryare no longer supported and should be rejected with clear errors that direct callers tospec.resource_requirements.compute.
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
- Public protobufs model CPU and memory as typed portable resource requirements under
SandboxSpec.resource_requirements.compute. - Compute-driver protobufs model CPU and memory under the driver resource requirements envelope.
- CLI
--cpuand--memorypopulate typed compute requirements instead ofSandboxTemplate.resources. - Existing
--gpubehavior remains user-compatible. - Gateway translation passes CPU, memory, and GPU through resource requirements.
- Gateway no longer extracts CPU or memory from
SandboxTemplate.resources. - Requests containing
SandboxTemplate.resources.limits.cpu,SandboxTemplate.resources.limits.memory,SandboxTemplate.resources.requests.cpu, orSandboxTemplate.resources.requests.memoryare rejected with clear migration errors. - Kubernetes, Docker, and Podman consume typed compute requirements with behavior equivalent to today's CLI-generated CPU/memory limits.
- VM behavior for typed CPU/memory is explicit: implemented sizing or clear rejection.
- SDKs expose typed CPU/memory fields without requiring raw
Structconstruction. - Docs explain portable resource requirements versus platform-native template resources and call out the breaking change for legacy CPU/memory-in-template callers.
- Tests cover CLI request construction, gateway translation, driver validation, driver realization, and legacy template CPU/memory rejection.
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.
Retain SandboxTemplate.resources CPU/memory extraction as a compatibility path. This avoids breaking existing raw API clients, but it keeps two public ways to express the same portable intent and leaves SandboxTemplate.resources overloaded. This issue intentionally rejects that compatibility path.
Add top-level cpu and memory fields to SandboxSpec. This is simpler, but it repeats the older GPU-specific pattern and does not scale as cleanly as a typed resource envelope.
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 coherent breaking 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
--gpubecomesGpuResourceRequirementsand is wrapped inSandboxSpec.resource_requirements. - CLI
--cpuand--memorybecomeSandboxTemplate.resources.limitsentries. - The public
ResourceRequirementsmessage currently contains only GPU. - The gateway extracts CPU/memory from
SandboxTemplate.resourcesintoDriverResourceRequirements. - 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.
Desired direction from maintainers: remove the legacy CPU/memory handling from SandboxTemplate.resources rather than retaining it as compatibility. This is an intentional breaking API cleanup.
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Assessment
This issue has not been assessed yet.