# How Worktree Sessions Overlay Changes on Pinned Base Commits in Cloudflare OS

> Learn how Cloudflare OS worktree sessions overlay changes on pinned base commits using in-memory operational transforms without materializing Git commits.

- Repository: [Cloudflare/cloudflare-os](https://github.com/cloudflare/cloudflare-os)
- Tags: internals
- Published: 2026-09-05

---

**Cloudflare OS implements worktree sessions by pinning a workpiece to a base commit and applying file-tool operations as in-memory operational-transform (OT) rows that overlay the pinned state without materializing a real Git commit until explicitly requested.**

Worktrees in Cloudflare OS are ephemeral, chat-scoped workspaces that let agents manipulate files without exposing the full repository state to clients. The system achieves this through a careful separation between **pinned base commits** (immutable references) and **OT overlays** (mutable deltas). This article explains the exact mechanism, citing the source implementation in `cloudflare/cloudflare-os`.

## What Is a Worktree in Cloudflare OS?

A **worktree** is a special `WorkpieceRecord` with `type: "worktree"` that exists only within the chat session that created it. Unlike persistent workpieces, worktrees are:

- **Session-bound**: Destroyed when the chat ends
- **Client-invisible**: OT rows are stripped from all client deliveries
- **Lazy-loaded**: Files are fetched on-demand via `readFileAtCommit`

The `createWorktree` tool—mirroring `createGadget`—initializes this structure according to [`plans/worktrees.md`](https://github.com/cloudflare/cloudflare-os/blob/main/plans/worktrees.md).

## Step 1: Pinning the Worktree at Creation

When an agent calls `createWorktree`, the backend immediately **pins** the worktree to a base commit:

```typescript
const { worktreeId, changeId } = await agentTool.createWorktree({
  bindingName: "repo",
  commitId: "a1b2c3d4"  // resolved against local Git cache
});

```

The pin `{ worktreeId, baseCommit }` is written as a `pin` entry in the chat's change stream. This design lets `buildChatContent` reconstruct the worktree later without additional state, as documented in [`plans/worktrees.md`](https://github.com/cloudflare/cloudflare-os/blob/main/plans/worktrees.md) ("Pin at birth").

## Step 2: Building the OT Overlay

Every file-tool operation creates a `CodeChange` row keyed by `WorkpieceId`. These rows contain only **deltas**—not full repository snapshots:

| Operation | OT Row Created |
|-----------|---------------|
| `readFile` | None (lazy fetch) |
| `writeFile` | Full content insert |
| `editFile` | Diff delta |
| `deleteFile` | Deletion marker |
| `grep` | None (read-only) |

The overlay lives in a session-content map: `Map<WorkpieceId, Map<path, string>>`. This in-memory structure is never serialized to the client, satisfying the "No UI" constraint in [`plans/worktrees.md`](https://github.com/cloudflare/cloudflare-os/blob/main/plans/worktrees.md).

## Step 3: Lazy Reads and Pull-on-Fault

File reads resolve against the **pinned base commit** using a hand-rolled walker:

```typescript
const content = await worktree.readFile("src/main.ts");

```

If the blob is missing locally, `GitCache.ensureGitObjects` triggers a **pull-on-fault** from the gatekeeper. This `readFileAtCommit` pattern appears in [`packages/workshop-backend/src/git-cache.ts`](https://github.com/cloudflare/cloudflare-os/blob/main/packages/workshop-backend/src/git-cache.ts) and minimizes upfront data transfer.

## Step 4: Committing the Overlay

The `commit(message)` operation materializes the overlay into a real Git commit:

```typescript
const newCommitOid = await worktree.commit("Add new feature");

```

Per [`plans/worktrees.md`](https://github.com/cloudflare/cloudflare-os/blob/main/plans/worktrees.md) ("commit(message) → oid"), this process:

1. Applies OT rows to the base tree to build a new tree object
2. Sets the **parent** to `headCommit` (last explicit commit), not `pinBase`
3. Writes via `writeChangedFilesAsCommit`, reusing unchanged sub-trees from `pinBase`
4. Advances only `headCommit`, leaving `pinBase` unchanged

This separation lets agents build commit chains while preserving the original pinned reference.

## Step 5: Epoch Reset and Re-pinning

At `mergeChanges` boundaries, the system:

1. Auto-commits dirty worktrees
2. **Re-pins** each worktree to the newly created auto-commit

As described in [`plans/worktrees.md`](https://github.com/cloudflare/cloudflare-os/blob/main/plans/worktrees.md) ("Epoch reset in `mergeChanges`"), this guarantees OT overlays always start from a clean base for the next epoch.

## Key Implementation Files

| File | Responsibility |
|------|---------------|
| [`plans/worktrees.md`](https://github.com/cloudflare/cloudflare-os/blob/main/plans/worktrees.md) | Design specification for pinning, OT overlay, and commit handling |
| [`packages/workshop-shared/src/worktree.d.ts`](https://github.com/cloudflare/cloudflare-os/blob/main/packages/workshop-shared/src/worktree.d.ts) | Agent RPC interface (`listFiles`, `readFile`, `writeFile`, `deleteFile`, `grep`, `commit`) |
| [`packages/workshop-backend/src/overseer.ts`](https://github.com/cloudflare/cloudflare-os/blob/main/packages/workshop-backend/src/overseer.ts) | Orchestrates workpiece creation, OT row writing, and epoch resets |
| [`packages/workshop-backend/src/git-store.ts`](https://github.com/cloudflare/cloudflare-os/blob/main/packages/workshop-backend/src/git-store.ts) | Low-level Git object storage for lazy walker |
| [`packages/workshop-backend/src/git-cache.ts`](https://github.com/cloudflare/cloudflare-os/blob/main/packages/workshop-backend/src/git-cache.ts) | `GitCache` implementation for pull-on-fault and pack building |
| [`packages/workshop-backend/src/approval-queue.ts`](https://github.com/cloudflare/cloudflare-os/blob/main/packages/workshop-backend/src/approval-queue.ts) | Gatekeeper integration and push authorization |
| [`packages/workshop-backend/src/ot-client.ts`](https://github.com/cloudflare/cloudflare-os/blob/main/packages/workshop-backend/src/ot-client.ts) | Client-side OT fetching; contains code stripping logic |

## Complete Agent Workflow Example

```typescript
// Create worktree from PR head
const { worktreeId } = await agentTool.createWorktree({
  bindingName: "repo",
  commitId: "abc123"
});

// Read and modify files (overlay only)
const src = await worktree.readFile("src/main.ts");
await worktree.editFile("src/main.ts", src.replace("old", "new"));
await worktree.writeFile("src/utils.ts", "export const helper = () => {};");

// Materialize commit
const oid = await worktree.commit("Refactor main, add helper");

// Push via gatekeeper (objects pulled on-demand)

```

## Summary

- **Pinning**: Worktrees are pinned to a base commit at creation via `pin` entries in the change stream
- **Overlay model**: File operations produce OT rows stored in-memory, not full commits
- **Lazy resolution**: Reads fault-pull from gatekeepers via `GitCache.ensureGitObjects`
- **Explicit materialization**: `commit()` builds real Git objects only when requested
- **Epoch safety**: `mergeChanges` auto-commits and re-pins to maintain clean base states
- **Client isolation**: All worktree content is stripped from client deliveries in [`ot-client.ts`](https://github.com/cloudflare/cloudflare-os/blob/main/ot-client.ts)

## Frequently Asked Questions

### What happens if two agents modify the same worktree?

Worktrees are scoped to a single chat session. Concurrent access is serialized through the chat's OT stream; the backend processes file-tool operations in order, with each `CodeChange` row representing the delta from the previous state.

### How does Cloudflare OS prevent clients from downloading entire repositories?

Worktree rows are explicitly stripped in [`packages/workshop-backend/src/ot-client.ts`](https://github.com/cloudflare/cloudflare-os/blob/main/packages/workshop-backend/src/ot-client.ts). The client receives only the `createWorktree` tool call and its `worktreeId`; all subsequent `CodeChange` rows are filtered from change replay, pins, and `codeBase` metadata.

### What is the difference between `headCommit` and `pinBase`?

`pinBase` is the immutable commit the worktree was created from; it never changes until an epoch reset. `headCommit` advances with each explicit `commit()` call, forming a chain of commit parents while preserving the original pinned reference for overlay calculations.