Skip to content

API Reference

The compute service exposes a single gRPC service: compute.v1.ComputeService. All messages are defined in paper-board/proto/compute/v1/compute.proto. The service listens on port 50051 (ClusterIP — internal only, no public ingress).

service ComputeService {
rpc CreateSandbox (CreateSandboxRequest) returns (CreateSandboxResponse);
rpc DestroySandbox (DestroySandboxRequest) returns (DestroySandboxResponse);
rpc DescribeSandbox (DescribeSandboxRequest) returns (DescribeSandboxResponse);
rpc ExecCommand (ExecCommandRequest) returns (stream ExecEvent);
rpc ReadFile (ReadFileRequest) returns (ReadFileResponse);
rpc WriteFile (WriteFileRequest) returns (WriteFileResponse);
rpc ListFiles (ListFilesRequest) returns (ListFilesResponse);
}

A bidirectional ExecSession RPC for interactive REPL use cases is planned for Phase 5. It is not part of the v1 surface — message types, lifecycle, and cancellation semantics will be designed in the Phase 5 brainstorm.


Provisions a gVisor pod and a workspace PVC for a session. Returns immediately with status: STARTING; the pod becomes READY asynchronously. ExecCommand blocks internally until the pod is running — callers do not need to poll DescribeSandbox before calling ExecCommand.

Lazy provisioning. The agents service calls CreateSandbox only on the first tool_use block in a session. Sessions that complete without any tool call never create a sandbox and incur no compute cost.

FieldTypeRequiredDescription
tenant_idstringyesTenant UUID. Stored as pod annotation.
session_idstringyesAgent session UUID. One sandbox per session.
imagestringnoContainer image. Defaults to SANDBOX_IMAGE env var.
workspaceWorkspaceSpecnoPVC size, storage class, mount path. Server defaults apply if omitted.
limitsResourceLimitsnoCPU/memory/timeout. Server defaults apply if omitted.
FieldTypeDescription
sandbox_idstringUUID assigned to this sandbox.
statusSandboxStatusAlways STARTING on success.
created_atgoogle.protobuf.TimestampServer-side creation timestamp.
gRPC codeCondition
INVALID_ARGUMENTtenant_id or session_id is empty.
INTERNALK8s pod or PVC creation failed.

Returns the current status and accumulated resource usage of a sandbox.

FieldTypeRequiredDescription
sandbox_idstringyesUUID returned by CreateSandbox.
FieldTypeDescription
sandbox_idstringEcho of the request sandbox_id.
statusSandboxStatusCurrent lifecycle state.
created_atgoogle.protobuf.TimestampWhen the pod was created.
current_uptimegoogle.protobuf.DurationElapsed time since creation.
current_usageUsageMetricsCumulative resource usage since creation.
gRPC codeCondition
INVALID_ARGUMENTsandbox_id is not a valid UUID.
INTERNALK8s describe call failed.

Deletes the sandbox pod and marks the workspace PVC for soft-delete. The PVC is annotated with compute.paper-board.io/delete-after = now + 24h and physically deleted by the GC CronJob after the grace window expires.

FieldTypeRequiredDescription
sandbox_idstringyesUUID returned by CreateSandbox.
FieldTypeDescription
sandbox_idstringEcho of the request sandbox_id.
total_usageUsageMetricsCumulative resource usage over the sandbox lifetime.
gRPC codeCondition
INVALID_ARGUMENTsandbox_id is not a valid UUID.
INTERNALK8s delete call failed.

Server-streaming RPC. Runs a command inside the sandbox pod and streams stdout / stderr lines as they arrive. The final event is ExecCompleted, which carries the exit code, wall time, and UsageMetrics.

If the sandbox is still in STARTING state when ExecCommand is called, the server blocks on WaitForRunning before starting the exec. This means callers can call ExecCommand immediately after CreateSandbox without polling.

Cancellation. Cancelling the gRPC stream context sends SIGTERM to the in-pod process. If the process is still running after 10 seconds, SIGKILL is sent. A final ExecCompleted{ cancelled: true, exit_code: -1 } event is emitted before the stream closes.

Timeout. Maximum per-call timeout is 600 seconds (10 minutes). Requests with timeout unset or exceeding 600 s are capped at 600 s server-side.

FieldTypeRequiredDescription
sandbox_idstringyesUUID returned by CreateSandbox.
commandstringyesExecutable path (e.g. python3, /usr/bin/env).
argsrepeated stringnoCommand arguments.
envmap<string, string>noAdditional environment variables injected into the process.
working_dirstringnoWorking directory. Defaults to /workspace.
timeoutgoogle.protobuf.DurationnoPer-call timeout. Capped at 600 s.

Each event carries exactly one of:

VariantTypeDescription
stdoutStdoutLineA chunk of stdout bytes (base64 in JSON transport).
stderrStderrLineA chunk of stderr bytes (base64 in JSON transport).
completedExecCompletedTerminal event; always the last event in the stream.

ExecEvent also carries emitted_at: google.protobuf.Timestamp on every event.

FieldTypeDescription
exit_codeint32Process exit code; -1 if cancelled.
wall_timegoogle.protobuf.DurationElapsed wall time from exec start to process exit.
cancelledbooltrue if the exec was terminated by stream cancel.
usageUsageMetricsResource consumption for this exec call.
gRPC codeCondition
INVALID_ARGUMENTsandbox_id is not a valid UUID, or command is empty.
FAILED_PRECONDITIONSandbox status is FAILED or DESTROYED.
DEADLINE_EXCEEDEDWaitForRunning timed out (sandbox still not ready).
INTERNALK8s exec transport failure.

All workspace I/O paths are validated against WorkspaceSpec.mount_path (default /workspace):

  • Paths are cleaned (filepath.Clean) before use; .. segments after cleaning are rejected with INVALID_ARGUMENT.
  • Symlinks inside the workspace are followed only if the resolved target is also inside mount_path; otherwise the operation is rejected with PERMISSION_DENIED.
  • Per-call data cap: 16 MiB. Clients must chunk larger payloads across multiple calls.
FieldTypeRequiredDescription
sandbox_idstringyesUUID returned by CreateSandbox.
pathstringyesPath relative to mount_path. Must not escape the workspace root.
offsetint64noByte offset to start reading. 0 = start of file.
max_bytesint64noMaximum bytes to return. 0 = read to EOF (capped at 16 MiB).
FieldTypeDescription
databytesFile contents (base64 in JSON transport).
total_sizeint64Total file size in bytes (before offset/cap).
eofbooltrue if data extends to the end of the file.

FieldTypeRequiredDescription
sandbox_idstringyesUUID returned by CreateSandbox.
pathstringyesPath relative to mount_path. Must not escape the workspace root.
databytesyesContent to write. Capped at 16 MiB per call.
appendboolnotrue = append; false = truncate then write (default).
modeuint32noFile mode bits when creating. Ignored if file already exists.
FieldTypeDescription
bytes_writtenint64Number of bytes written.

FieldTypeRequiredDescription
sandbox_idstringyesUUID returned by CreateSandbox.
pathstringyesDirectory path relative to mount_path.
recursiveboolnotrue = traverse subdirectories.
max_entriesuint32noResult cap. 0 = default 1000. Hard cap: 10000.
FieldTypeDescription
entriesrepeated FileEntryFile and directory entries.
truncatedbooltrue if the result was capped by max_entries.
FieldTypeDescription
pathstringRelative to the ListFilesRequest.path.
sizeuint64File size in bytes. 0 for directories.
is_dirbooltrue for directories.
modeuint32Unix permission bits.
modified_atgoogle.protobuf.TimestampLast modification time.
gRPC codeCondition
INVALID_ARGUMENTsandbox_id not a valid UUID, or path escapes mount_path after clean.
PERMISSION_DENIEDSymlink target resolves outside mount_path.
INTERNALK8s exec I/O transport failure.

SandboxSpec (embedded in CreateSandboxRequest)

Section titled “SandboxSpec (embedded in CreateSandboxRequest)”

WorkspaceSpec and ResourceLimits are the two sub-messages:

FieldTypeDescription
storage_classstringK8s StorageClass name. Defaults to PVC_STORAGE_CLASS env var.
sizestringPVC capacity string (e.g. "5Gi"). Defaults to PVC_WORKSPACE_SIZE.
mount_pathstringContainer path where the PVC is mounted. Defaults to /workspace.
FieldTypeDescription
cpu_millisuint32CPU limit in millicores. Default: 1000 m.
memory_bytesuint64Memory limit in bytes. Default: 1 GiB.
max_runtimegoogle.protobuf.DurationHard wall-time limit for the sandbox pod. Default: 15 minutes.

Returned in ExecCompleted, DescribeSandboxResponse, and DestroySandboxResponse.

FieldTypeDescription
cpu_msuint64CPU time consumed (milliseconds).
memory_peak_bytesuint64Peak RSS during the measurement window.
memory_avg_bytesuint64Average RSS during the measurement window.
disk_read_bytesuint64Bytes read from the workspace PVC.
disk_write_bytesuint64Bytes written to the workspace PVC.
network_egress_bytesuint64Bytes sent to external destinations.
network_ingress_bytesuint64Bytes received from external destinations.
ValueMeaning
SANDBOX_STATUS_UNSPECIFIEDUnknown or not yet set.
SANDBOX_STATUS_STARTINGPod is being scheduled; not yet accepting exec requests.
SANDBOX_STATUS_READYPod is running; ExecCommand calls proceed immediately.
SANDBOX_STATUS_FAILEDPod exited non-zero or exceeded its deadline.
SANDBOX_STATUS_DESTROYEDPod deleted; workspace PVC in soft-delete grace window.