Managed Worktrees: Isolated Git Checkouts for Agent Tasks

This page explains how OpenClaw uses managed worktrees to run agent tasks in isolated git branches and checkouts. It covers layout, naming conventions, and provisioning of ignored files for developers and system administrators.

Read this when

  • You want an isolated branch and checkout for an agent task
  • You are configuring Workboard cards with worktree workspaces
  • You need to restore or clean up an OpenClaw-managed worktree

Managed worktrees provide each agent task with its own dedicated git branch and checkout, eliminating the need to place temporary directories within the source repository. OpenClaw stores these worktrees under its state directory, logs them in the shared state database, and captures a snapshot of both tracked and non-ignored untracked content before cleanup.

Layout and names

Each worktree is located at:

<openclaw-state-dir>/worktrees/<repo-fingerprint>/<name>

The repository fingerprint consists of the first 16 hexadecimal characters from a SHA-256 hash computed over the canonical git common directory combined with the origin URL. Any supplied name must conform to [a-z0-9][a-z0-9-]{0,63}. When no name is given, OpenClaw generates wt- followed by eight random hexadecimal characters.

OpenClaw creates the branch openclaw/<name> at the specified base ref. If no base ref is provided, it fetches origin, uses the remote default branch when present, and falls back to local HEAD when the repository is offline or lacks a usable remote.

Provision ignored files

Add .worktreeinclude at the root of the source repository to include selected ignored or untracked files when creating a new worktree. This file follows gitignore-pattern syntax, with one pattern per line and # for comments:

.env.local
fixtures/generated/**

Only files identified by git as both ignored and untracked qualify for copying. Tracked files are already available through git and are never duplicated during this step. OpenClaw will not overwrite or modify existing destination files, does not follow symlinked directories, and retains the file modes of copied items. It logs only the paths it actually creates, so later manifest edits cannot remove those files from cleanup protection.

Run repository setup

If .openclaw/worktree-setup.sh exists in the source repository and is executable, OpenClaw runs it with the new worktree as the current working directory. The script receives:

OPENCLAW_SOURCE_TREE_PATH=<source checkout>
OPENCLAW_WORKTREE_PATH=<managed worktree>

A nonzero exit code aborts creation and removes both the new worktree and its branch. This operates as a repository-local agreement; no OpenClaw configuration key exists for it.

Session worktrees

To start an isolated chat from a Git-backed folder using a worktree session, go to the Control UI's New session page, use the Place picker to select a Gateway source folder, then choose Worktree (optionally specifying a base branch and worktree name). This option appears only after the Gateway confirms the selected folder is a Git checkout; regular folders run directly and do not show Git isolation controls. On iOS, the same choice is available from Chat actions, and on Android it appears beside New Chat, provided the active agent workspace is Git-backed.

Coding agents can also invoke spawn_task when they identify follow-up work outside the current task. The Control UI displays a suggestion chip without initiating anything, while a Gateway-backed TUI shows an interactive prompt with identical actions. Selecting Start in worktree creates a fresh session-owned worktree from the suggested project and sends the self-contained prompt as its first turn; dismissing the suggestion leaves the repository unchanged. Suggestions and their IDs are temporary and do not persist after a Gateway restart.

OpenClaw exposes these tools exclusively to operator sessions that have an actionable Gateway UI. Channel sessions and local or embedded TUI sessions do not receive them until those surfaces adopt a portable typed task-action contract.

The resulting managed worktree belongs to the session, and every agent run within that session uses its checkout. When the workspace is a repository subdirectory, the worktree is anchored at the repository root and the session runs from the matching subdirectory inside it. Session worktree creation uses the method's operator.write scope, but repository checkout hooks and the .openclaw/worktree-setup.sh step run only for operator.admin callers because they execute repository code; .worktreeinclude provisioning still applies to all callers. Deleting the session removes the worktree only when doing so causes no data loss. Dirty worktrees or branches with unpushed commits remain available; hourly cleanup snapshots session worktrees after 7 days of inactivity, treating recent session activity as worktree activity. Removed worktrees can be restored from their snapshots as described below.

sessions.create may include an absolute cwd to run directly in another Gateway folder, to select the source checkout together with worktree: true, or to set a paired node's working directory. Every explicit host path requires operator.admin; ordinary worktree chat creation remains operator.write and stays anchored to the configured workspace.

sessions.create also accepts worktreeBaseRef and worktreeName alongside worktree: true to choose the base ref and the worktree name (the branch becomes openclaw/<name>); both remain at operator.write. The created worktree is returned in the create result and persisted on the session row as worktree: { id, branch, repoRoot }, so session lists can display the checkout and branch. Deleting a session reports a preserved dirty checkout as worktreePreserved instead of silently leaving it behind.

Snapshots, cleanup, and restore

Removal first generates a synthetic commit containing tracked and non-ignored untracked files, then pins it at refs/openclaw/snapshots/<id>. Ignored files never enter the repository object database. OpenClaw stores only the ignored files it actually provisioned in chunked shared-state database rows; the recorded path set remains authoritative even if .worktreeinclude later changes or disappears. Restore reads those bytes from the immutable snapshot and reapplies their complete modes. Automatic cleanup preserves a live worktree when a recorded path can no longer be snapshotted safely. If snapshot creation fails, removal stops. An explicit force delete can continue without a snapshot.

OpenClaw applies these cleanup rules:

  • At run end, it removes a worktree only when git status --porcelain is empty and git log HEAD --not --remotes --oneline finds no unpushed commits. Otherwise it only releases the activity lock.
  • Hourly cleanup snapshots and removes unlocked Workboard- and session-owned worktrees idle for more than 7 days, even when dirty. Manual worktrees are never automatically removed.
  • Snapshot records remain restorable for 30 days. Cleanup then deletes the snapshot ref and registry row.
  • A live OpenClaw process lock and any foreign or unrecognized git worktree lock protect a worktree from garbage collection.

Restore recreates openclaw/<name> at the original pre-snapshot commit, then rebuilds the snapshot differences as unstaged modifications and untracked files. This keeps the synthetic snapshot commit out of branch history. The snapshot ref remains recorded as provenance.

CLI

openclaw worktrees list [--json]
openclaw worktrees create <repo-root> [--name <name>] [--base-ref <ref>] [--json]
openclaw worktrees remove <id> [--force] [--json]
openclaw worktrees restore <id> [--json]
openclaw worktrees gc [--json]

The Control UI Worktrees page under Settings provides the same actions plus creation with a base-branch picker, shows each worktree's owner (manual, Workboard, or the owning session with a link into its chat), and offers a force retry when a removal reports a failed snapshot.

Gateway methods

MethodPurpose
worktrees.listList active and restorable worktree records.
worktrees.branchesList local and remote branches of a repository for base-ref pickers.
worktrees.createCreate or reuse a named managed worktree.
worktrees.removeSnapshot and remove a worktree. Forced removals report snapshotError.
worktrees.restoreRestore a removed worktree from its snapshot.
worktrees.gcRun idle, orphan, and retention cleanup now.

worktrees.list requires operator.read, and the mutating methods require operator.admin. worktrees.branches needs operator.write for configured agent workspaces, while any other host path requires operator.admin (matching the sessions.create cwd bar). It reads existing refs only and never fetches, and remote-only branches come back remote-qualified (origin/feature-a) so every returned name resolves as a base ref. New Session can also request a typed repository status from this method; a plain directory or unavailable checkout returns no branches instead of forcing the UI to infer Git capability from an error string.

Workboard workspaces

The bundled Workboard plugin can materialize a card workspace as a managed worktree:

{
  "kind": "worktree",
  "path": "/absolute/path/to/source-checkout",
  "branch": "main"
}

path points to the originating git checkout. branch is not required and serves as the base ref. When a full-host caller is involved, Workboard either creates or reuses wb-<card-id>, launches the subagent with the managed checkout as its working directory, then records the resolved path and branch onto the card. Gateway clients depend on operator.admin to perform full-host materialization. At the conclusion of a run, Workboard removes the checkout only when doing so is provably lossless; dirty state or unpushed commits remain intact.

For a workspace-bound caller, path together with the repository root must match the target agent workspace exactly. In this case Workboard runs directly within that directory and logs a directory workspace rather than host-materializing a managed worktree. The target must use a writable, non-shared Docker sandbox for the same workspace, its live container hash must align with the requested mounts and policy, and it must not expose elevated execution, host control, host-wide sessions, persisted host/node execution, or unclassified plugin and MCP tools. If the target policy or live container is more permissive, dispatch leaves the card unclaimed and logs the mismatch.