How to Contribute to Cloudflare Computer Runtime Types: A Developer's Guide

To contribute to Cloudflare Computer's runtime types, modify the TypeScript interfaces in packages/computer/src/runtime/types.ts, update the router logic in runtime.ts, and add tests covering serialization and edge cases.

The Cloudflare Computer repository provides a programmable execution environment through its Workspace Runtime API. The runtime types define the contract between callers (such as Workers) and the backends that execute commands or modules. This guide walks through the architecture, key files, and step-by-step process for contributing to these runtime types based on the actual source code in cloudflare/computer.

Understanding the Runtime Type Architecture

The Workspace Runtime is built around a layered type system that separates the public API from backend implementations. Before making changes, you need to understand how these interfaces interact.

Core Type Definitions

All public type definitions live in packages/computer/src/runtime/types.ts. The primary interfaces include:

Interface Purpose Location
WorkspaceRuntime Entry point that routes exec, getExec, killExec, and disposeExec calls runtime.ts (implementation), types.ts (interface)
WorkspaceRuntimeExecHandle A ReadableStream of events with result(), kill(), and [Symbol.dispose] methods types.ts
WorkspaceRuntimeEvent Low-level event shape for stdout, stderr, or exit with generic encoding support types.ts
WorkspaceRuntimeResult Final aggregate containing status, exit code, captured output, and sync statistics types.ts
WorkspaceModuleBackend Backend protocol interface that backends implement for module execution types.ts

The generic E parameter on WorkspaceRuntimeEvent allows the same interface to represent either UTF-8 strings or raw Uint8Array buffers depending on the encoding option passed to exec().

Runtime Implementation Layer

The packages/computer/src/runtime/runtime.ts file contains the concrete WorkspaceRuntime class. This class performs three critical functions:

  1. Validates options passed to each operation
  2. Selects the correct backend based on the backend option (e.g., 'container', 'worker-javascript')
  3. Wraps returned handles in a streaming-or-result API that guarantees exclusive use

Two helper functions in this file handle the complex stream transformations:

  • transformModuleEvents — converts raw byte streams into UTF-8 strings when encoding: 'utf8' is specified
  • drainModuleResult — aggregates streams into a complete WorkspaceRuntimeResult

Step-by-Step: Contributing New Runtime Types

Follow this five-step process when adding new capabilities or fixing bugs in Cloudflare Computer's runtime types.

Step 1: Add or Modify Types in types.ts

Begin by editing packages/computer/src/runtime/types.ts. Follow the established naming convention: prefix all public types with WorkspaceRuntime.

// Example: Adding a new exec option for signal handling
export interface WorkspaceRuntimeExecOptions {
  backend: string;
  encoding?: 'utf8' | 'bytes';
  cwd?: string;
  env?: Record<string, string>;
  stdin?: ReadableStream<Uint8Array> | string;
  timeout?: number;
  signal?: AbortSignal; // New field
}

Maintain backward compatibility where possible. New fields should be optional with sensible defaults.

Step 2: Update the Runtime Router

If your change introduces a new operation or requires different validation, modify the WorkspaceRuntime class in runtime.ts:

// In packages/computer/src/runtime/runtime.ts
async exec(
  command: string,
  options: WorkspaceRuntimeExecOptions
): Promise<WorkspaceRuntimeExecHandle> {
  // Validate new signal option
  if (options.signal?.aborted) {
    throw new Error('Exec aborted before start');
  }
  
  const backend = this.selectBackend(options.backend);
  const handle = await backend.exec(command, options);
  
  return new WorkspaceRuntimeExecHandleImpl(handle, options.encoding);
}

Step 3: Adjust Streaming Logic

New event kinds require updates to transformModuleEvents or drainModuleResult. For example, adding a resize event for terminal emulation:

// In runtime.ts - extending event transformation
function transformModuleEvents(
  stream: ReadableStream<WorkspaceModuleEvent>,
  encoding: 'utf8' | 'bytes'
): ReadableStream<WorkspaceRuntimeEvent> {
  return new TransformStream({
    transform(event, controller) {
      switch (event.name) {
        case 'stdout':
        case 'stderr':
        case 'exit':
          // Existing handling
          break;
        case 'resize': // New event type
          controller.enqueue({ name: 'resize', value: event.value });
          break;
      }
    }
  });
}

Step 4: Write Comprehensive Tests

Add tests in packages/computer/src/runtime/runtime.test.ts or create new test files in the same directory. Cover:

  • Serialization — round-trip of options through backend boundaries
  • Error handling — invalid IDs, timeout scenarios, backend failures
  • Edge cases — empty IDs, oversized IDs, malformed UTF-8 sequences
// Example test structure
describe('WorkspaceRuntimeExecOptions', () => {
  it('validates signal option', async () => {
    const controller = new AbortController();
    controller.abort();
    
    await expect(ws.runtime.exec('echo', {
      backend: 'container',
      signal: controller.signal
    })).rejects.toThrow('Exec aborted before start');
  });
  
  it('handles empty exec ID', async () => {
    await expect(ws.runtime.getExec('')).rejects.toThrow(/invalid.*id/i);
  });
});

Step 5: Document the Public API

Update two documentation locations:

Include method signatures, parameter descriptions, and version information when relevant.

Working with Backend Protocols

The runtime abstracts over multiple backend implementations through the WorkspaceModuleBackend interface. When contributing types that affect backend communication, coordinate changes across:

Component File Responsibility
Backend handle factory types.ts backendHandle type definition
Concrete backend Backend-specific files Implements WorkspaceModuleBackend and returns WorkspaceModuleBackendHandle
Runtime router runtime.ts Calls exec, getExec, killExec, disposeExec on the backend handle

Practical Code Examples

Running a Command with UTF-8 Output

import { Workspace } from '@cloudflare/computer';

const ws = new Workspace(/* configuration */);
const handle = await ws.runtime.exec('echo "hello world"', {
  backend: 'container',
  encoding: 'utf8',
});
const result = await handle.result();
console.log(result.stdout); // → hello world

Streaming Real-Time Output

const handle = await ws.runtime.exec('yes', { 
  backend: 'container',
  encoding: 'bytes' // Receive raw Uint8Array
});

for await (const event of handle) {
  if (event.name === 'stdout') {
    console.log(new TextDecoder().decode(event.value));
  }
  if (event.name === 'exit') break;
}
// Clean up resources
handle[Symbol.dispose]();

Resuming a Previous Execution

const execId = 'my-long-running-task';
const handle = await ws.runtime.getExec(execId, {
  backend: 'worker-javascript',
  resume: 'tail' // Start from most recent output
});

Cleaning Up Remote Resources

await ws.runtime.disposeExec(execId, { 
  backend: 'container' 
});

Key Files Reference

File Purpose Lines to Watch
packages/computer/src/runtime/types.ts All public type definitions Interface declarations, generics with E parameter
packages/computer/src/runtime/runtime.ts Runtime router and stream wrappers WorkspaceRuntime class, transformModuleEvents, drainModuleResult
packages/computer/src/runtime/runtime.test.ts Test suite for runtime API Serialization, error, and edge case coverage
packages/computer/README.md Package documentation Usage examples, API overview
docs/README.md Design specification Architectural rationale, evolution roadmap

Summary

  • Cloudflare Computer runtime types are defined in packages/computer/src/runtime/types.ts with the WorkspaceRuntime* naming convention
  • The runtime router in runtime.ts validates options, selects backends, and wraps handles with streaming-or-result semantics
  • Stream transformation helpers (transformModuleEvents, drainModuleResult) handle encoding conversions and result aggregation
  • Contributions require type changes, router updates, streaming logic adjustments, comprehensive tests, and documentation updates
  • Backend protocols implement WorkspaceModuleBackend and are selected by the backend option string

Frequently Asked Questions

What encoding options does WorkspaceRuntimeExecHandle support?

The encoding option accepts either 'utf8' for string output or 'bytes' (default) for raw Uint8Array. This is controlled by the generic E parameter on WorkspaceRuntimeEvent<E>. When 'utf8' is specified, transformModuleEvents automatically decodes byte streams using TextDecoder.

How do I add a new backend to the runtime?

Define your backend's options interface in types.ts, implement the WorkspaceModuleBackend interface, then register it in the runtime's backend selection logic. The backend must return a WorkspaceModuleBackendHandle with exec, getExec, killExec, and disposeExec methods that match the runtime's expected signatures.

Why does WorkspaceRuntimeExecHandle guarantee exclusive use of streaming or result()?

This design prevents race conditions between consuming the ReadableStream and awaiting the result() promise. Once you call result(), the stream is drained and consumed. Attempting to iterate the stream after calling result() will yield no events. This invariant is enforced by the implementation in runtime.ts.

Where should I add tests for new runtime types?

Add tests in packages/computer/src/runtime/runtime.test.ts or create additional *.test.ts files in the same directory. Test coverage should include: valid and invalid option serialization, backend error propagation, timeout behavior, and edge cases like empty or oversized IDs.

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 →