How Openship Handles Resource Configuration (cpuCores, memoryMb) Across Different Runtimes

Openship normalizes resource allocation through a three-layer architecture that parses manifest inputs, validates them against runtime-agnostic constraints, and translates them into platform-specific settings for Docker, Cloud, or bare metal environments.

The oblien/openship repository implements a unified resource model that accepts CPU, memory, and disk specifications in openship.json, then adapts these values to the target runtime's native resource control mechanisms. This approach ensures consistent configuration semantics whether deploying to local Docker containers or managed cloud workspaces.

The Three-Layer Resource Architecture

Openship treats resource configuration as a first-class citizen by processing requirements through distinct parsing, modeling, and translation stages.

Manifest Parsing and Validation

Resource constraints originate in the openship.json manifest. The parseResources function in packages/core/src/openship-config/parse.ts (lines 33-38) validates incoming values against strict ranges:

  • CPU cores: 0.25 to 4 cores
  • Memory: 128 to 8192 MiB
  • Disk: 64 to 204800 MiB

Invalid configurations trigger explicit errors during the parsing phase, preventing malformed resource requests from reaching the runtime adapters.

Runtime-Agnostic Modeling

After validation, resources are represented by the ResourceConfig interface defined in packages/adapters/src/types.ts. This internal model stores cpuCores, memoryMb, and diskMb as normalized numbers, decoupling the manifest format from runtime-specific implementations. The adapter receives this structured configuration regardless of whether the target is Docker, Oblien Cloud, or bare metal.

Runtime-Specific Translation

Each runtime adapter implements custom logic to convert the generic ResourceConfig into platform-native resource controls:

  • Docker: Calculates CpuShares and converts memory to bytes
  • Cloud (Oblien): Maps resources to predefined tiers or passes explicit values via API
  • Bare Metal: Currently ignores resource constraints (no enforceable limits)

Runtime-Specific Implementations

Docker Runtime: CPU Shares and Memory Bytes

The Docker adapter in packages/adapters/src/runtime/docker.ts translates abstract cores into Docker's CPU share units and megabytes into bytes.

At line 1696, the adapter calculates CpuShares by multiplying the requested cores by 1024:

const containerSpec = {
  CpuShares: Math.round(config.resources.cpuCores * 1024),
  Memory: config.resources.memoryMb * 1024 * 1024,
  // Additional Docker configuration...
};
await docker.createContainer(containerSpec);

This means a request for 2 cpuCores results in 2048 CPU shares, while 2048 memoryMb becomes 2147483648 bytes (2 GB).

Cloud Runtime: Tiers and Explicit Allocation

For Oblien's managed cloud environment, the adapter in packages/adapters/src/runtime/cloud/compose.ts (lines 369-375) applies a more sophisticated translation using the cloudCpus helper.

The system first normalizes fractional CPUs to a minimum of 0.25, then either maps to a predefined tier or uses explicit values:

import { DEFAULT_RESOURCE_CONFIG } from "./cloud-resources";
import { cloudCpus } from "./compose";

const cpus = cloudCpus(config.resources?.cpuCores ?? DEFAULT_RESOURCE_CONFIG.cpuCores);
const memoryMb = config.resources?.memoryMb ?? DEFAULT_RESOURCE_CONFIG.memoryMb;

await cloudApi.createWorkspace({
  cpus,
  memory_mb: memoryMb,
  disk_size_mb: config.resources?.diskMb ?? DEFAULT_RESOURCE_CONFIG.diskMb,
});

The tier definitions in packages/adapters/src/cloud-resources.ts (lines 35-38) provide concrete defaults for micro, low, medium, and high configurations, ensuring workloads receive appropriate resources even when the manifest omits specific values.

Bare Metal and Other Runtimes

Adapters for bare metal or custom runtimes currently consume the ResourceConfig object without enforcing limits. The cpuCores and memoryMb values have no effect in these environments, as the underlying infrastructure lacks container-style resource isolation.

Complete Configuration Flow

The following example demonstrates the end-to-end resource configuration pipeline:

import { parseOpenshipConfig } from "@repo/core/src/openship-config/parse";

// Step 1: Parse manifest
const raw = JSON.parse(`{
  "runtime": "docker",
  "resources": { 
    "cpuCores": 2, 
    "memoryMb": 2048, 
    "diskMb": 8192 
  }
}`);

const { config, errors } = parseOpenshipConfig(raw);
if (errors.length) throw new Error(errors.join("\n"));

// Step 2: Adapter receives ResourceConfig
console.log(config.resources);
// → { cpuCores: 2, memoryMb: 2048, diskMb: 8192 }

// Step 3: Runtime-specific translation happens internally
// Docker: CpuShares = 2048, Memory = 2147483648
// Cloud: cpus = 2.0, memory_mb = 2048, disk_size_mb = 8192

Summary

Frequently Asked Questions

What are the valid ranges for cpuCores and memoryMb in Openship?

According to the source code in packages/core/src/openship-config/parse.ts, Openship enforces CPU cores between 0.25 and 4, memory between 128 and 8192 MiB, and disk between 64 and 204800 MiB. Values outside these ranges trigger validation errors during manifest parsing.

How does Openship convert CPU core requests for Docker containers?

The Docker runtime adapter in packages/adapters/src/runtime/docker.ts translates cpuCores into Docker's CpuShares by multiplying the value by 1024. For example, 0.5 cores becomes 512 shares, while 2 cores becomes 2048 shares, using the calculation Math.round(cpuCores * 1024).

What happens if I omit resource configuration in my openship.json?

When resources are unspecified, the cloud adapter falls back to DEFAULT_RESOURCE_CONFIG defined in packages/adapters/src/cloud-resources.ts, which provides baseline values for predefined tiers. The Docker adapter similarly applies defaults, though specific behavior depends on the runtime implementation.

Do resource limits work when deploying to bare metal?

No. According to the source analysis, bare metal and other non-containerized runtimes ignore cpuCores and memoryMb settings because the underlying infrastructure lacks mechanisms to enforce such constraints. These values are parsed and stored but have no runtime effect on bare metal deployments.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →