# CapnWeb RPC Wire Contract: How Cloudflare Computer Connects Durable Objects to `computerd`

> Explore the capnWeb RPC wire contract for Cloudflare Durable Objects and computerd. Learn how this Cap'n Proto protocol enables secure, efficient communication for filesystem, sync, and lifecycle operations.

- Repository: [Cloudflare/computer](https://github.com/cloudflare/computer)
- Tags: internals
- Published: 2026-08-07

---

**The capnWeb RPC wire contract is a Cap'n Proto-based protocol that defines filesystem, sync, and lifecycle operations between a Cloudflare Durable Object (control plane) and the `computerd` process (data plane), using capability-based security and zero-copy serialization.**

This article explains the complete wire contract implemented in the [cloudflare/computer](https://github.com/cloudflare/computer) repository. You'll learn how the protocol is structured, what methods are available, and how capabilities enable secure, low-latency communication between distributed components.

## What Is capnWeb and Why Cap'n Proto?

Cloudflare Computer uses **capnWeb** as its core RPC layer. Cap'n Proto provides three critical advantages for this architecture:

- **Zero-copy serialization** — Large file payloads skip unnecessary memory copies
- **Capability-based security** — Fine-grained access control without authentication overhead
- **Streaming-friendly framing** — Efficient over WebSocket and HTTP connections

The protocol separates concerns: Durable Objects maintain authority and state, while `computerd` instances perform I/O operations using delegated capabilities.

## Core Concepts of the Wire Contract

### Capabilities as Security Primitives

Every resource exposed over RPC is a **capability**. The Durable Object creates capabilities (file handles, directory watchers, sync endpoints) and passes them to `computerd`. The recipient can invoke methods on a capability but cannot forge or escalate privileges.

Capabilities are reference-counted. When `computerd` drops a reference, the Durable Object automatically revokes access.

### Message Structure

Each RPC call follows Cap'n Proto framing:

| Field | Purpose |
|-------|---------|
| Method ID | 16-bit identifier from the schema |
| Request payload | Cap'n Proto struct with parameters |
| Response payload | Return value or exception |
| Capability table | References to exported/imported capabilities |

### Schema-Driven Code Generation

The contract in `packages/rpc/src/schema.capnp` generates TypeScript bindings. Method signatures are thin wrappers around binary messages, ensuring type safety across version changes.

## Top-Level `ComputerRpc` Interface

The root capability exposed by every Durable Object implements these methods:

| Method | Parameters | Returns | Description |
|--------|------------|---------|-------------|
| `open` | `path: Text`, `flags: UInt32` | `FileCapability` | Open file or directory for I/O operations |
| `read` | `file: FileCapability`, `offset: UInt64`, `length: UInt32` | `Data` | Read bytes from an open file |
| `write` | `file: FileCapability`, `offset: UInt64`, `data: Data` | `void` | Write bytes to an open file |
| `stat` | `path: Text` | `StatResult` | Retrieve metadata (size, mtime, mode) |
| `readdir` | `dir: FileCapability` | `DirectoryListing` | List entries with basic metadata |
| `mkdir` | `path: Text`, `mode: UInt32` | `void` | Create new directory |
| `unlink` | `path: Text` | `void` | Remove file or empty directory |
| `close` | `file: FileCapability` | `void` | Release capability, free resources |
| `sync` | — | `SyncResult` | Trigger VFS synchronization |
| `watch` | `path: Text` | `WatchCapability` | Subscribe to change notifications |

All paths are absolute within the Computer instance namespace. Flags follow POSIX conventions (`O_RDONLY`, `O_WRONLY`, `O_CREAT`, etc.).

## Connection Lifecycle

### 1. Handshake and Capability Exchange

When `computerd` starts, it establishes a WebSocket to its host Durable Object. Per the protocol in [`docs/08_capnweb_interface.md`](https://github.com/cloudflare/computer/blob/main/docs/08_capnweb_interface.md):

```typescript
// Simplified handshake from packages/rpc/src/client.ts
import { createRpcClient } from '@cloudflare/computer-rpc';

const rpc = await createRpcClient(DURABLE_OBJECT_URL);

// First message negotiates protocol version
// Durable Object returns root ComputerRpc capability

```

The handshake verifies version compatibility and exchanges the initial capability set.

### 2. Operation Phase

`computerd` requests capabilities as needed. Each operation validates that the caller holds the required capability:

```typescript
// Example: Read operations require explicit file capability
const fileCap = await rpc.open('/etc/config.json', 0x0000); // O_RDONLY

const data = await rpc.read(fileCap, 0n, 4096);
const text = new TextDecoder().decode(data);

await rpc.close(fileCap); // Revokes capability

```

### 3. Error Handling

Errors encode as Cap'n Proto exceptions with structured codes:

| Exception Type | `code` value | Trigger |
|--------------|------------|---------|
| `FileNotFound` | `ENOENT` | Path does not exist |
| `PermissionDenied` | `EACCES` | Missing capability for operation |
| `IsDirectory` | `EISDIR` | File operation on directory |
| `NotDirectory` | `ENOTDIR` | Directory operation on file |
| `Timeout` | `ETIMEDOUT` | Sync operation deadline exceeded |

The client library in [`packages/rpc/src/client.ts`](https://github.com/cloudflare/computer/blob/main/packages/rpc/src/client.ts) translates these to JavaScript `Error` objects:

```typescript
try {
  await rpc.open('/restricted/file', 0x0000);
} catch (err) {
  if (err.code === 'EACCES') {
    // Handle permission denial
  }
}

```

## Directory Watching and Events

The `watch` method returns a long-lived capability for reactive filesystem monitoring:

```typescript
const watchCap = await rpc.watch('/var/log');

// Stream of change events
for await (const event of watchCap.events()) {
  console.log(`${event.path}: ${event.type}`); // 'create', 'modify', 'delete'
}

// Explicit cleanup or drop reference
await rpc.close(watchCap);

```

Watch capabilities are reference-counted like file handles. The Durable Object batches events and pushes them over the existing WebSocket connection.

## Synchronization Protocol

The `sync` method triggers a three-way merge between local `computerd` state and the Durable Object's authoritative view:

```typescript
const result = await rpc.sync();

if (!result.success) {
  console.error('Conflict in:', result.conflictPaths);
  // Application logic resolves conflicts
}

```

Per [`packages/computer/src/computerd.ts`](https://github.com/cloudflare/computer/blob/main/packages/computer/src/computerd.ts), sync operations:

1. Compute content-addressed hashes of modified files
2. Exchange hash sets with the Durable Object
3. Transfer missing chunks using `read`/`write` operations
4. Update capability references to reflect new inode mappings

## Server-Side Implementation

The `computerd` process implements the `ComputerRpc` interface in [`packages/computer/src/computerd.ts`](https://github.com/cloudflare/computer/blob/main/packages/computer/src/computerd.ts). Key responsibilities:

- **Capability lifecycle** — Track reference counts, validate method invocations
- **Local VFS cache** — Maintain consistent view between sync operations
- **Event routing** — Forward watch notifications from kernel `inotify`/`kqueue` to RPC events

The implementation uses a capability table indexed by 32-bit handles. Each handle maps to a kernel file descriptor or synthetic resource.

## Client Library Architecture

[`packages/rpc/src/client.ts`](https://github.com/cloudflare/computer/blob/main/packages/rpc/src/client.ts) provides the ergonomic JavaScript API. It handles:

- **Capability proxying** — Transparent method dispatch on remote objects
- **Message pipelining** — Parallel requests over single WebSocket
- **Promise integration** — Async/await for RPC round-trips

Generated types from `schema.capnp` ensure compile-time safety:

```typescript
// Generated interface (simplified)
interface FileCapability {
  read(offset: bigint, length: number): Promise<Uint8Array>;
  write(offset: bigint, data: Uint8Array): Promise<void>;
  stat(): Promise<StatResult>;
  close(): Promise<void>;
}

```

## Security Model: Capability-Based Access Control

The capnWeb contract eliminates ambient authority. `computerd` cannot access any resource without an explicit capability. This design:

- **Prevents lateral movement** — Compromised `computerd` instances remain confined to delegated capabilities
- **Enables audit logging** — All operations trace to specific capability grants
- **Supports revocation** — Durable Objects invalidate capabilities instantly without network round-trips

Capabilities are cryptographically unforgeable. The wire format includes integrity checks on capability references.

## Testing and Verification

The contract includes comprehensive tests in [`packages/rpc/tests/wire.test.ts`](https://github.com/cloudflare/computer/blob/main/packages/rpc/tests/wire.test.ts):

| Test Category | Coverage |
|-------------|----------|
| Serialization round-trips | All request/response types |
| Capability transit | Import/export, reference counting |
| Error propagation | Exception encoding, stack preservation |
| Concurrent operations | Message ordering, pipelining correctness |

Tests use in-memory transports to verify behavior without network dependencies.

## Key Files in the Repository

| Path | Purpose |
|------|---------|
| [`docs/08_capnweb_interface.md`](https://github.com/cloudflare/computer/blob/main/docs/08_capnweb_interface.md) | Human-readable protocol specification |
| `packages/rpc/src/schema.capnp` | Canonical Cap'n Proto schema |
| [`packages/rpc/src/client.ts`](https://github.com/cloudflare/computer/blob/main/packages/rpc/src/client.ts) | Client-side RPC implementation |
| [`packages/computer/src/computerd.ts`](https://github.com/cloudflare/computer/blob/main/packages/computer/src/computerd.ts) | Server-side capability implementation |
| [`packages/rpc/tests/wire.test.ts`](https://github.com/cloudflare/computer/blob/main/packages/rpc/tests/wire.test.ts) | Wire format and behavior verification |

## Summary

- **capnWeb** is the Cap'n Proto RPC contract connecting Cloudflare Durable Objects to `computerd` processes
- **Capabilities** provide fine-grained, revocable access to files, directories, and sync endpoints
- **Zero-copy serialization** enables efficient large-file I/O over WebSocket connections
- **Schema-defined methods** (`open`, `read`, `write`, `stat`, `sync`, `watch`) implement a complete POSIX-like filesystem API
- **Security model** eliminates ambient authority—every operation requires an explicit, unforgeable capability

## Frequently Asked Questions

### What transport does capnWeb use under the hood?

capnWeb runs over WebSocket connections between the Durable Object and `computerd`. The Cap'n Proto messages are framed as binary WebSocket frames. This provides NAT traversal through Cloudflare's edge network and enables long-lived capability references without connection re-establishment.

### How does capability revocation work if `computerd` crashes?

The Durable Object maintains a reference count for each issued capability. When the WebSocket disconnects, all capabilities held by that `computerd` instance are automatically released. The next connection from a new `computerd` process receives fresh capabilities through a new handshake.

### Can I extend the capnWeb protocol with custom methods?

Yes. The schema in `packages/rpc/src/schema.capnp` can be extended with new interfaces and methods. Backward compatibility is preserved by Cap'n Proto's field numbering and interface versioning. New `computerd` implementations can ignore unknown methods, while old clients receive `unimplemented` exceptions for new operations.