Managed Worktrees: Isolated Git Checkouts for Agent Tasks
Learn how OpenClaw runs agent tasks in dedicated git worktrees with automatic snapshots and cleanup. Ideal for developers integrating agents into their repositories.
Read this when
- You want an isolated branch and checkout for an agent task
- You are configuring Workboard cards with worktree workspaces
- You want to store managed worktrees on another disk or in a custom folder
- You need to restore or clean up an OpenClaw-managed worktree
Managed worktrees let an agent task operate on its own dedicated git branch and checkout, with no temporary folders dropped inside the source repository. OpenClaw places these under its state directory, logs them in the shared state database, and captures both tracked and non-ignored untracked content as snapshots before cleanup.
Layout and names
Each worktree is located at:
<openclaw-state-dir>/worktrees/<repo-fingerprint>/<name>
The repository fingerprint derives from the first 16 hexadecimal characters of a SHA-256 hash computed over the canonical git common directory combined with the origin URL. Any provided name must align with [a-z0-9][a-z0-9-]{0,63}. When no name is given, OpenClaw invents a readable crustacean-themed identifier such as brisk-lobster. If an inferred name collides with any registered worktree (including the caller's own deleted checkout), a local branch, or an unmanaged path, a numeric suffix like brisk-lobster-2 gets appended; only an explicitly supplied name can reuse or recover the caller's prior record.
At the requested base ref, OpenClaw creates branch openclaw/<name>. In the absence of a base ref, it pulls origin, adopts the remote default branch when one exists, and otherwise defaults to local HEAD if the repository is offline or lacks a usable remote.
Provision ignored files
Place .worktreeinclude at the source repository root to bring selected ignored, untracked files into a fresh worktree. The file follows gitignore-pattern syntax, with one pattern per line and # for comments:
.env.local
fixtures/generated/**
Only files git marks as both ignored and untracked qualify. Tracked files arrive through git itself and never get copied at this stage. OpenClaw avoids overwriting or altering any destination file that already exists, skips symlinked directories, and keeps the file modes of what it copies. It logs only the paths it genuinely creates, so later manifest edits cannot strip those files from cleanup protection.
Run repository setup
If .openclaw/worktree-setup.sh exists in the source repository and carries executable permissions, OpenClaw executes it with the new worktree as the working directory. The script gets:
OPENCLAW_SOURCE_TREE_PATH=<source checkout>
OPENCLAW_WORKTREE_PATH=<managed worktree>
A nonzero exit halts creation and deletes both the new worktree and branch. This arrangement is a repository-local agreement; no OpenClaw configuration key governs it.
Session worktrees
To launch an isolated chat from a Git-backed folder as a worktree session, open the Control UI's New session page, pick a Gateway source folder via the Place picker, and then choose Worktree (optionally specifying a base branch and worktree name). Selecting a paired device or cloud profile forces this managed-worktree route from the chosen Gateway source; remote placement never browses or binds a node working directory. With the name omitted, OpenClaw takes it from the explicit session label or the short title generated from the first message, falling back to a crustacean-themed name. The option appears only once the Gateway verifies the selected folder is a Git checkout; ordinary folders run directly on the Gateway alone and expose no Git isolation control. iOS surfaces the same choice through Chat actions, and Android places it next to New Chat, whenever the active agent workspace is Git-backed.
The Place picker's Projects section can trigger the same worktree flow from a registered project ID. The Gateway resolves the recorded checkout path, keeping this route available at operator.write; selecting an arbitrary host folder still demands operator.admin.
Coding agents can also invoke suggest_task when they spot confirmed follow-up work outside the current task. The Control UI displays a suggestion chip without executing anything, while a Gateway-backed TUI shows an interactive prompt offering the same actions. Picking Start in worktree spins up a fresh session-owned worktree from the suggested project and delivers the self-contained prompt as its opening turn; dismissing the suggestion leaves the repository untouched. Suggestions and their IDs are transient and vanish on a Gateway restart.
OpenClaw restricts these tools to operator sessions backed by an actionable Gateway UI. Channel sessions and local/embedded TUI sessions do not get them until those surfaces gain 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 sits in a repository subdirectory, the worktree anchors at the repository root and the session runs from the matching subdirectory inside it. Session worktree creation applies 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 attempts to snapshot and remove its managed worktree, covering dirty worktrees and branches holding unpushed commits. Hourly cleanup also snapshots session worktrees after 7 idle days, counting recent session activity as worktree activity. Removed worktrees stay restorable from their snapshots as detailed below.
sessions.create may carry an absolute cwd to run directly in another Gateway folder or to select the source checkout together with worktree: true. Connections with operator.write may use a Gateway cwd contained in any configured agent workspace; realpath containment stops symlinks from escaping that boundary. Gateway paths outside those workspaces require operator.admin. Ordinary worktree chat creation remains operator.write and stays anchored to the configured workspace. New Session dispatches a completed worktree session to paired devices or cloud profiles instead of handing a paired-node working directory to creation.
sessions.create also takes worktreeBaseRef and worktreeName alongside worktree: true to set the base ref and worktree name (the branch becomes openclaw/<name>); both remain at operator.write. If worktreeName is absent, the session label or generated first-message title provides the readable branch name, with a crustacean-themed fallback. The created worktree appears in the create result and persists on the session row as worktree: { id, branch, repoRoot }, letting session lists display the checkout and branch. When session deletion cannot finish that cleanup, worktreePreserved flags the active worktree record needing attention and reports one bounded reason: owner mismatch, active use or competing cleanup, a foreign Git lock, snapshot failure, or another cleanup failure. These reasons address cleanup and ownership, not whether the checkout is dirty or holds unpushed commits.
Snapshots, cleanup, and restore
Removal starts by creating a synthetic commit containing tracked and non-ignored untracked files, then pins it at refs/openclaw/snapshots/<id>. Ignored files never reach the repository object database. OpenClaw stores only the ignored files it actually provisioned in chunked shared-state database rows; the recorded path set stays 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 halts. An explicit force delete can proceed without a snapshot.
OpenClaw enforces these cleanup rules:
- At run end, it removes a worktree only when
git status --porcelainis empty andgit log HEAD --not --remotes --onelinefinds no unpushed commits. Otherwise it merely 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.
Run-end cleanup logs its outcome on the worktree record: lossless removal, retention because the checkout is busy, dirty, unpushed, or has provisioned-file drift, or failure with an error reason. Inspect the recorded outcome with openclaw worktrees list --json or worktrees.list.
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 Worktrees page in the Control UI, located under Settings, mirrors those same capabilities while adding a base-branch selector for creation. It also displays each worktree's owner, whether manual, Workboard, or the owning session with a chat link, and includes a forced retry option when a snapshot failure occurs during removal.
Gateway methods
| Method | Purpose |
|---|---|
worktrees.list | Lists both active and restorable worktree records. |
worktrees.branches | Enumerates local and remote branches for base-ref selection. |
worktrees.create | Creates or reuses a named managed worktree. |
worktrees.remove | Snapshots and deletes a worktree; forced deletions return snapshotError. |
worktrees.restore | Recovers a removed worktree from its snapshot. |
worktrees.gc | Triggers idle, orphan, and retention cleanup immediately. |
worktrees.list depends on operator.read. For configured agent workspaces and registered projects, worktrees.create and worktrees.branches need operator.write; arbitrary host paths still demand operator.admin. Creation with write scope bypasses repository checkout hooks and .openclaw/worktree-setup.sh. Only admins can remove, restore, or garbage-collect worktrees. Branch listing reads only existing refs, never fetches, and remote-only branches appear remote-qualified (origin/feature-a) so every 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 rather than making the UI infer Git capability from an error string.
Workboard workspaces
The bundled Workboard plugin can turn a card workspace into a managed worktree:
{
"kind": "worktree",
"path": "/absolute/path/to/source-checkout",
"branch": "main"
}
path points to the source git checkout. branch, optional, serves as the base ref. For a full-host caller, Workboard creates or reuses wb-<card-id>, runs the subagent with the managed checkout as its working directory, and writes the resolved path and branch back to the card. Gateway clients require operator.admin for full-host materialization. On run end, Workboard deletes the checkout only when it is provably lossless; dirty work or unpushed commits stay available.
For a workspace-bound caller, path and the repository root must precisely match the target agent workspace. Workboard then executes directly in that directory and logs a directory workspace instead of host-materializing a managed worktree. The target must use a writable, non-shared Docker sandbox for the same workspace, its live container hash must match 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 broader, dispatch leaves the card unclaimed and reports the incompatible state.