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

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.

Step 1: Pinning the Worktree at Creation

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

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 ("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.

Step 3: Lazy Reads and Pull-on-Fault

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

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 and minimizes upfront data transfer.

Step 4: Committing the Overlay

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

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

Per 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 ("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 Design specification for pinning, OT overlay, and commit handling
packages/workshop-shared/src/worktree.d.ts Agent RPC interface (listFiles, readFile, writeFile, deleteFile, grep, commit)
packages/workshop-backend/src/overseer.ts Orchestrates workpiece creation, OT row writing, and epoch resets
packages/workshop-backend/src/git-store.ts Low-level Git object storage for lazy walker
packages/workshop-backend/src/git-cache.ts GitCache implementation for pull-on-fault and pack building
packages/workshop-backend/src/approval-queue.ts Gatekeeper integration and push authorization
packages/workshop-backend/src/ot-client.ts Client-side OT fetching; contains code stripping logic

Complete Agent Workflow Example

// 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

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. 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.

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 →