On this page
On this page
Agent workspace
Managed worktrees
Managed worktrees give an agent task its own git branch and checkout without placing temporary directories inside the source repository. OpenClaw records them in the shared state database and snapshots their tracked and non-ignored untracked contents before ordinary removal. Capacity eviction can purge unsaved data when a snapshot cannot be made.
Projects cloned by OpenClaw always start new sessions in managed worktrees,
including requests that omit worktree or set it to false. The shared clone is
the maintenance-owned source for refreshes, Git objects, and templates. The
project picker offers New worktree for these clones; explicitly registered
folders and agent workspaces can still use Current checkout. Opening a
repository URL also allocates a managed worktree.
Keep disposable builds and temporary clones in the session's .openclaw/tmp/,
which follows the scratch cleanup policy. Save durable
outputs outside that directory. Do not create task worktrees inside a shared
project clone. Existing sessions retain their accepted working directories;
start a new project session to leave a previously selected shared checkout.
Unregistered nested Git worktrees are preserved because OpenClaw cannot prove
their ownership or lossless removal from their path names alone.
Branch pickers display the last recorded local refs while discovery refreshes in background. A refreshing indicator stays visible until the Gateway sends the updated options; slow Git keeps cached choices available. Discovery never fetches from a remote or scans checkout contents. Ref changes invalidate the suggestions, and session creation validates the selected base before changing a checkout. Failed or non-Git discovery becomes eligible for another user-requested read after five seconds of elapsed time, even if the system wall clock moves backward.
When the selected source is a folder inside a Git repository, Recents keeps that folder rather than replacing it with the repository root or the managed checkout. Choosing the recent source again starts the next session in the same selected folder.
When a new chat starts a managed worktree, OpenClaw can begin the first model turn while the checkout finishes. It first prepares the project instructions, workspace skills, and other prompt files from the selected Git commit in the final worktree directory. The initial prompt therefore uses the same paths and contents as a completed checkout. Workspace tools, including PDF analysis, local message attachments, and generation tools reading local references, wait for checkout and the session's initial diff baseline. Tools that do not use the workspace can run immediately, including generation with inline or remote references. Completion also waits for preparation, and a preparation failure ends the turn with a retryable error. If workspace ownership expires or is lost, retry the operation. Caller access revocation is separate: restore access before retrying. Preparation diagnostics retain the failing phase when a lease error wraps the original failure. Accelerated clones can start prompt preparation once their files are complete, while Git index preparation finishes behind the same workspace-tool gate.
Repositories with setup scripts, included files, unsupported checkout transforms,
or project configuration whose required files are not yet available finish preparation before
the first turn starts. Active bootstrap hooks, including bootstrap-extra-files,
also retain complete preparation so configured instructions remain available.
Sandboxed projections require a fully published worktree before startup, as do
required remote-worker placements. Codex configurations without native tool-hook
admission and plugins that read workspace files while constructing tools wait for
preparation before starting their model turn. An explicitly
requested worktree name or existing session title can name the checkout.
Otherwise, allocation chooses a short generated name while display-title
generation runs in the background.
Worktree registration waits at most 30 seconds for a shared repository Git operation, including object repair. After one second it logs the wait; if the operation remains busy, creation reports a retryable error naming the repository wait. A timed-out registration cannot create a checkout later. Git operations that have already started retain their normal execution and cleanup budgets.
Pull-request statistics may refresh Git's cached file timestamps in a managed checkout; they do not stage content or change commits. Statistics for user-managed checkouts keep their index unchanged.
Existing folders on devices
An existing folder on a device is separate from a managed worktree. A compatible paired session host can run a session directly in an absolute folder on that specific device. OpenClaw does not clone, snapshot, transfer, reconcile, or remove that folder as a managed worktree. Choose New workspace or a repository source when you want an isolated, OpenClaw-managed workspace instead. See session hosting.
Sandboxed sessions
Sandboxed project sessions use a private Git checkout for execution, while the managed worktree remains the source of truth for accepted changes. Docker and Podman support this local projection. The host repository's shared Git metadata and ignored-file provisioning are not mounted or copied into it.
Changed local checkpoints report Local workspace checkpoint capture in the
agents/worktrees log, with the worktree ID and selected path=snapshot or path=paused.
The rendered reason distinguishes adaptive direct capture, a non-subvolume root,
an unavailable Btrfs clone backend, clone failure, and a nested-subvolume fallback.
attemptedSnapshot=true also identifies a snapshot attempt that fell back to
paused capture; cloneError names an expected clone failure code.
preCopyMs measures from completed pause preparation to the copy attempt,
including settlement of an earlier checkpoint. copyMs covers the complete
native copy helper, and postCopyBeforeResumeMs covers the interval from its
completion to the resume call. resumeMs sums resume calls, including container
inspection, unpause, and receipt persistence. Missing measurements appear as -.
These are owner-operation timings, not syscall or writeback timings, and their
sum is not the container's frozen duration. The record follows finalization
attempts, including failures that retain a pause. accepted=true means
synchronization returned successfully; it does not certify that resume succeeded.
On Btrfs, APFS, and ReFS, new private checkouts with a committed pnpm-lock.yaml
can reuse installed dependencies. OpenClaw prepares the dependencies once in a
disposable sandbox, then clones the prepared checkout for each session. After the
Gateway is ready, it prepares the default session base for agent repositories
with sandbox mode all or non-main in the background. Agents with sandbox mode
off skip background dependency preparation; creator-role-required sandboxes
still prepare dependencies on first use. A session arriving during preparation
waits for the same build; later checkouts arrive with node_modules. Other selected commits
still run dependency installation on first use. When the frozen lockfile and Git
attributes are unchanged, OpenClaw clones a prepared template into a separate generation,
imports only the new Git objects, and checks out the source delta before reinstalling
into its retained dependencies.
Repeat installation still runs repository lifecycle scripts when manifests and
lockfiles are unchanged.
Concurrent requests for that commit share the refresh. Lockfile or attribute changes
build a fresh template. Refresh never changes the source generation, including while
another session is cloning it. Each
clone still receives only the selected source snapshot in its private Git object
store. Shutdown cancels preparation and
drains accepted installer cleanup. Validation leaves the last-good generation published;
refreshes and replacement builds publish atomically after preparation succeeds. An
interrupted build leaves that previous generation available for requests with matching
inputs. Before publishing a template, OpenClaw fences
the disposable installer against restart and verifies that it has stopped. Container
removal runs serially in the background, so a slow Docker or Podman removal does
not delay the prepared workspace. Failed removals remain registered, log a warning,
and retry during housekeeping, including after a Gateway restart. This cleanup
also runs when ordinary sandbox idle and age pruning are disabled.
The private checkout storage must support filesystem acceleration, and
worktreeAcceleration: false disables this preparation too.
Sandbox preparation retains up to four recently used generations per repository and private template root, across runtime identities. Returning to a retained commit reuses its prepared dependencies instead of refreshing the shared template back and forth. Every build still passes disk admission. Live clone and installer readers can temporarily retain additional generations; cleanup never removes their files before those readers settle.
The template registry keeps compressed content manifests in a process-local LRU bounded to 64 MiB, keyed by generation, selected commit and build-cache path policy. A matching preparation uses that manifest instead of hashing the cloned source again. Commit refreshes reuse unchanged file hashes from the previous generation using Git's source delta; metadata discovery still records empty directories and changed input markers. Missing manifests or changed checkout attributes use a full capture. Canonical workspace edits are reconciled separately, so cached template contents never replace authored changes. Retirement deletes the cached manifest. After a Gateway restart or cache eviction, the first preparation rebuilds it; the template registry does not persist manifests.
Older runtime identities become eligible for cleanup after six unused hours. The most recently used identity keeps the ordinary idle retention window, subject to the four-generation limit. Hourly maintenance shares the existing deletion spacing and IO-pressure limits without holding the template publication lock while waiting. Completed projections have independent Git metadata and COW file references, so retiring their original template does not remove their files or dependencies.
Dependency preparation uses the selected sandbox image, network restrictions,
and guest working directory, without configured credentials, custom bind mounts,
or setup commands. Git metadata stays read-only during installation. Only
node_modules directories are retained as additional output, regardless of Git
ignore spelling; generated native protocol files and other setup artifacts are
not shared. Repository code never
runs on the host as part of this preparation. Existing permission requirements
for unsandboxed repository setup are unchanged.
With network: "none", pnpm uses offline mode so a missing package or metadata
cache falls back promptly instead of waiting through network retries.
The reusable generation binds the source commit, frozen lockfile, immutable image
(including its Node and pnpm versions), guest path, and sandbox policy. A changed
generation uses a distinct builder identity, including incremental refreshes.
Exact commit identity remains necessary because repository lifecycle scripts and
local packages can consume source files outside the lockfile and manifests.
Background housekeeping recovers interrupted builders independently of template expiration. Installation failure or changed tracked source
records a warning with a bounded, redacted tail of the installer output and keeps
a source-only template for that generation. Repeated preparations with the same
inputs reuse that source-only template without rerunning the failed install. Missing
lockfiles, unsupported filesystems, and unavailable images use source-only
checkout. The agent can install normally in that private checkout. Dependency
preparation does not update an already-used session when its lockfile changes.
Layouts whose pnpm virtual store is outside node_modules also use the
source-only fallback, preserving their ordinary installation contract.
See Workspace access
for write policy, reconciliation, and conflict recovery. To update an existing
local sandbox workspace from its selected repository base, use github_publish
action refresh_base before tests and Auto Review.
For an open PR originally published from this conversation, refresh uses that
PR's current destination, including an externally changed base branch. It keeps
the original PR selected for subsequent publication; the earlier publication
receipt remains unchanged.
Publication and base refresh reuse exact commits already stored locally instead
of fetching them again. Partial clones still fetch missing contents when the
operation needs those files. Missing publication commits use the cached target
and default base tips for fetch negotiation when available, avoiding unrelated
session histories while retaining commit ancestry and trees. When a cached base
and an existing promisor registration for the publication URL are available,
acquisition uses temporary Git metadata and writes directly to the existing
object store. This avoids scanning every session ref before negotiation; local
refs and shallow boundaries stay unchanged. The first filtered fetch for a URL
uses the original repository so Git can register it for later content hydration.
Managed worktree default-branch refresh uses the same isolated object-store
transport regardless of origin's configured fetch mappings. It fetches only the
default branch and publishes its tracking ref; additional PR refspecs and custom
destinations do not broaden that operation. The shared repository's ref-mutation
queue is held only for ref publication, so other worktrees can register while
transport runs. Origin's effective transport settings, other branches, and the
source FETCH_HEAD remain unchanged. An unavailable cached base is fetched through
the same isolated transport; ordinary explicit fetches still own broader ref
refresh and repository repair.
Only sessions with a writable managed sandbox are offered this action; direct
host sessions merge the base with git in their workspace before publishing.
Resolve reported conflicts and repeat it with conflictsResolved: true and the
returned baseCommit. Completion stages current source inside the sandbox while
retaining its HEAD and commit
history; use the returned local/base Auto Review target before publishing. The host retains the integrated base ancestry; guest Git metadata,
host credentials, and unrelated ignored host files remain separate.
Local sandbox baselines share immutable directory packs and compressed source path sets in the existing shared-state database. Sessions on the same source tree reuse those records. Compact file fingerprints let a restarted Gateway reuse unchanged hashes while detecting same-size edits and files moved by directory renames. Filesystem discovery still checks for additions and deletions on every scan. Existing projections convert one at a time during reconciliation; database open does not rewrite their inventories.
Archive preparation compares live sandbox files with that accepted tree in the filesystem worker. If Git already preserves every accepted file and directory, cleanup needs no separate workspace overlay. Ignored files and empty directories still retain their restore receipt, and owner protection gates removal.
This storage format requires shared-state schema 35.
Let pending workspace operations settle before downgrading. Older builds refuse
the newer schema; rollback requires the verified pre-upgrade backup and its
matching build. Keep private projection files and pending recovery data intact
when returning to a supporting version.
Versions that support projections but predate refresh_base reject a retained
result from an interrupted base transfer. After both copies accept, that result is
cleaned and native merge state owns any remaining conflict resolution. Complete
refresh and conflict resolution on a supporting version before downgrading.
Choose where worktrees are stored
By default, OpenClaw stores managed checkouts under <openclaw-state-dir>/worktrees. Set the global worktreeRoot option in openclaw.json to use another folder or disk:
Use an absolute path on the Gateway host, ~ for the Gateway user's home directory, or a path beginning with ~/ for a folder inside it. Relative paths are rejected. The Gateway user must be able to create and write to the directory.
This setting applies to all managed worktrees, including session, manual, and Workboard worktrees; there is no per-agent override. It changes checkout storage only. The shared state database, snapshots of provisioned ignored files, allocation limits, and cleanup lifecycle remain associated with the same OpenClaw state directory.
Changing worktreeRoot affects new allocations. Existing registered worktrees keep their recorded paths for reuse and cleanup, and removed worktrees restore to their original paths. OpenClaw does not move existing checkouts or snapshots when this setting changes. Keep their original storage available until those worktrees are no longer needed.
Outside the default state-owned worktree directory, cleanup acts only on registered worktrees and acceleration templates. It leaves unrelated, unregistered folders in your custom location alone.
See Configuration reference for the option's default and scope.
Capacity and eviction
worktreeMaxCount sets one limit for live managed worktrees and pending creations across all agents, repositories, and owners sharing the state directory. The default is 4096. There is no separate per-agent or per-repository count cap. To allow more checkouts on a larger disk, increase it in openclaw.json:
The policy is: squashed/merged first, then by age including unsaved data. Cleanup prefers branches merged into the repository's default branch, then branches detected as squash-landed, then idle checkouts ordered from oldest to newest by last use. Manual worktrees, moved branches, nested repositories, and unreadable contents do not exempt a managed checkout from the cap. When possible, OpenClaw snapshots dirty contents before purging the checkout, but snapshot failure does not block cap eviction. Commit or otherwise back up work you need to retain.
Creation reserves a persisted slot before preparing files. Name and owner checks happen at that reservation; materialization, ignored-file provisioning, and setup then run independently of other creates. Publication atomically replaces the pending slot with a live record. Concurrent requests for the same owner wait and reuse its completed checkout. Capacity admission waits for an in-progress creation when its slot prevents admission; pending checkouts are never eviction candidates.
Sandbox projection preparation uses its existing worktree's mutation lease, so a cold dependency build does not hold global creation capacity. Preparations of the same template still share one build. Disk reservations account for concurrent writes; a preparation waiting for disk capacity releases its worktree and projection leases before retrying.
Full Git checkout materialization can continue beyond five minutes while Git reports progress. Five minutes without output stops the checkout with a retryable error; cancellation still stops it immediately. A single large file or a silent object lookup can still reach the idle timeout. Registration and other Git operations retain their existing execution deadlines.
The managed worktree preparation log reports errorClass and errorPhase
when preparation throws, including the innermost failed timed phase. Failures
outside a timed phase use unattributed. The receipt omits error messages and
command output.
Lease acquisition appears separately as allocationWait for global slot admission,
mutationWait for checkout custody, and capacityWait for disk reservations.
These durations also appear in slow-chat diagnostics under worktree.<kind>.
reservation measures the protected allocation work after acquisition. Phases
can overlap, so their sum is not the total preparation duration.
provisionEstimate measures included-file discovery and byte estimation before checkout;
provisionInspect measures fresh selection before copying, after source custody is reacquired.
Repository-backed creation discovers unmanaged Git branches and checkout paths before waiting for capacity admission. Reservation still checks current managed names, owners, and pending slots under the allocation lease. Git enforces branch and path conflicts when creating the checkout, including external changes after discovery. Each admission retry refreshes its Git inventory.
If a registered project's checkout is busy, creation releases allocation before waiting for that project. Other repositories can continue reserving and creating workspaces. Once project access is available, creation releases it and retries the reservation with current source, owner, name, and capacity checks. Registered-source waits share the existing 30-minute creation contention budget, including source checks before checkout and before final session binding. The accepted request stays pending and cancellable while waiting; it continues when access becomes available without another request. Source contention after checkout or setup waits at that stage without repeating completed work.
Source custody inspects managed checkout and Git storage ownership once per operation. Destination protection reuses that inventory while reserving a slot, so ordinary repository creation does not rescan every managed repository under the allocation lease. Unchanged inspected paths reuse the database owner's prepared ancestry index; changed paths update it while in-flight operations retain their original snapshot. Filesystem aliases and external Git metadata are still inspected for each operation, and cleanup checks live dependencies before deleting a checkout.
A failed creation releases its slot after confirmed cleanup. If the caller crashes or a native operation has an uncertain outcome, the next allocation or openclaw worktrees gc reclaims count capacity after proving the caller is dead. It retains the unfinished checkout and its name in recovery custody and reports its path. Inspect the Git registration and any surviving native processes before manually recovering those files; cleanup does not assume parent-process death stopped a native write. Recovery custody does not publish an incomplete checkout as ready or block a new checkout with an unused name. Creation shares one 30-minute contention budget across admission retries and lease waits. Successful checkout, provisioning, setup, and publication do not consume that budget; an available lease can still be acquired after the wait budget is exhausted. Further contention reports the inspection and cleanup commands instead of starting another wait. Existing records need no schema migration. Let pending operations settle before downgrading to a version that does not understand these reservations.
Live owner leases protect active runs. If creation would require evicting an active run, OpenClaw refuses it and names the cap and live owners. Let those runs finish or raise worktreeMaxCount, then retry. Background cleanup and create admission share the same capacity owner, including concurrent creates and snapshot restoration. Removed checkouts and their retained snapshots no longer consume a live-worktree slot.
Eviction preserves source repositories and Git storage needed by other managed checkouts, including objects borrowed through git clone --shared. Creation and snapshot restoration also hold source custody, so freeing their slot cannot purge the object donor they need.
Lowering the setting applies the eviction policy to existing checkouts. Disk-space checks still apply independently: raising the count does not bypass the measured allocation and snapshot reserves. See worktreeMaxCount.
Creation hydrates only the selected commit's missing contents. Its object census returns only missing IDs, keeping preparation responses small for large checkouts. The batch fetch uses that commit as its only negotiation tip, avoiding reads of unrelated session branch tips even though object negotiation is disabled. It does not scan every promisor pack to classify missing objects; that proof belongs to snapshot removal, where lost locally authored data must preserve the checkout. Successful default-base hydration is already shared by commit while the Git worker remains active. Hydration failures are not cached.
Filesystem acceleration
OpenClaw automatically uses filesystem acceleration for new managed worktrees when supported. Linux uses native Btrfs snapshots without requiring the btrfs command, or per-file reflinks on XFS. macOS uses a native APFS directory clone, preserving independent file contents, executable modes, and symbolic links. Windows uses ReFS block clones, including on Dev Drive volumes. OpenClaw keeps the template on the same writable filesystem as the new checkout; the source repository can be on another filesystem. Effective checkout filters, sparse checkout, or external attributes in the target or template use normal Git checkout. Enabling Git's extensions.worktreeConfig or configuring sparse checkout in another worktree does not disable acceleration for full checkouts. Template reuse includes the effective per-worktree configuration, so changing a template's checkout settings invalidates it.
To opt out, set:
Omitting the option or setting it to true enables automatic selection. Setting it to false uses normal Git checkout and file copying for new worktrees. Existing worktrees keep their contents and lifecycle. NTFS, ext4, HFS+, and other unsupported filesystems use the normal Git path. Unavailable native bindings or failed clones also fall back to Git; APFS and ReFS file-data cloning never silently substitute ordinary file copies inside the accelerated path.
APFS and Btrfs operations use isolated native helpers without changing the Gateway process's filesystem configuration. APFS acceleration also works under Rosetta with a matching x64 native helper. ACL inspection runs in the metadata worker; unknown ACL state or inheritable parent ACLs select normal Git checkout. The Gateway and these helpers retain fs-safe's auto native default. An explicit FS_SAFE_NATIVE_MODE=off or OPENCLAW_FS_SAFE_NATIVE_MODE=off also disables these helpers. Read-only metadata workers can stop on cancellation; recovery waits for a write helper to exit before touching its destination.
On Windows, point worktreeRoot at a directory on a ReFS volume, such as D:\worktrees. ReFS provides file block cloning rather than a writable directory snapshot: OpenClaw creates the directory tree and clones each file's data. Full clusters can share storage; partial file tails and filesystem metadata still consume space. The Gateway needs ordinary file access, not administrator access, to clone worktrees on an existing volume.
OpenClaw maintains one reusable source template per repository, destination root, and checkout mode. Concurrent creates share one cold build and retain the ready template while cloning independently. While that ready generation has readers, further creates acquire reader custody atomically without waiting for the template mutation lease. An idle template is validated under that lease before reuse. Concurrent callers in the same process share the pending preparation wait, then each acquires its own reader custody instead of queuing another mutation lease. Once all readers settle, the next reuse validates the idle template again. Template retirement stops new readers before touching files and waits for accepted readers to settle. Replacing an unusable generation unpublishes it under a separate registry key; background housekeeping or openclaw worktrees gc removes its files and Git registration. New requests wait for the replacement build, but do not wait for deletion of the old tree. The old generation continues to occupy disk space until cleanup runs. A changed commit advances an unused source template through Git, writing only changed files. Checkout policy or .gitattributes changes rebuild it so transforms apply even to unchanged blobs. The template is unpublished while updating; its new commit and content identity become available together after Git finishes. While readers still hold a different generation, that request uses normal Git checkout. Cleanup retires templates unused for seven days once their readers have settled. Uncertain native operations retain template custody while their process owner is live or unknown. The next template acquisition or cleanup reclaims readers whose process owner is definitely dead, without requiring an OS reboot. Allocation and template mutation leases retain their existing expiry-based recovery. Git continues to own worktree registration, indexes, and branches; the filesystem backend supplies the shared file contents.
Sandboxed source-only sessions also reuse templates. Template creation, validation, and index refresh use the same isolated Git configuration as ordinary source-only materialization, so repository filters never run on the host. Ordinary and source-only checkouts have separate template and prepared-checkout slots per repository and destination root. Alternating between them preserves both templates while their content identities still prevent reuse across checkout policies.
The Gateway keeps one prepared checkout per active repository, destination root, and checkout mode. After a successful accelerated creation, the existing maintenance owner refills that slot asynchronously and serially, subject to normal disk admission. A matching ready slot is consumed once by moving its files and transferring its prepared index into the request's normal Git registration. The request validates only the independent slot it will consume; unused source-template validation stays with refill or a pool miss. It does not clone the template again. Empty, unfinished, modified, or stale slots use the normal checkout path; a changed commit, template generation, or checkout policy cannot reuse the old slot. Setup scripts and included files still run through normal per-request preparation. Hourly cleanup releases slots idle for an hour, and interrupted preparation uses the existing template recovery path. No additional configuration is needed.
Preparation logs include templateDetails with the backend, selection or failure reason, clone-byte estimate, and an error code when available. Reasons distinguish disabled acceleration, empty or profiled checkouts, native probing, ACL rejection, checkout policy, missing or stale templates, template creation, and disk admission.
Preparation phases are inclusive. For sandbox dependency preparation, checkout,
setup, and a concurrent caller's mutationWait are inside templatePrepare;
templateApply measures each private clone separately. A warm caller waiting
for a build therefore reports preparation time without running a second install.
For managed source checkouts, checkout includes its child phases; do not add it
to templateApply. Sub-phases separate registration metadata and inspection, commit preparation, clone admission estimates, destination preparation, marker replacement, index location/copy/refresh, prompt publication, template release, and warm-slot acquisition/application. The clone-byte estimate is a disk-admission allowance, not measured bytes written.
The workspaceWait phase records waits for private sandbox workspace reconciliation custody and for an already-running preparation. It includes waits behind another caller's dependency-template build, even when the waiting caller ultimately reuses the prepared workspace without selecting a template itself.
The provision phase includes ignored-file selection (provisionInspect), copy admission and worker preparation (provisionCopyWait), safe file copying (provisionCopy), and repository script execution (setup). Selection includes the Git worker queue. provisionCopyWait includes filesystem worker queueing, startup, and eligibility checks before the first authorized mutation; provisionCopy covers the remaining copy work and safety checks. Copying runs in a filesystem worker so other sessions remain responsive; the new worktree waits for copying to finish before becoming ready. provisionCopy starts at the first authorized copy-directory or file admission. Safe copying requests copy-on-write cloning when supported and falls back to ordinary copying otherwise; destination files remain independent of their source. On Linux with procfs and GNU cp, selected directories are admitted once and retained by descriptor; batches of up to 128 pinned files are reflinked through private staging while preserving nanosecond timestamps. One small helper runs those batches, so each batch does not fork the Gateway's resident address space. Other systems retain the portable guarded copier. copyDetails records the selected copier and fallback reason, admitted source bytes, batch and Gateway-child counts, synchronous spawn time, child wait time, and live-authority check count/time. Source bytes describe selected content, not exclusive disk usage; reflinks can share those bytes. These bounded diagnostics include no file paths. Creation records the provisioned file paths; later recovery snapshots may replace that ledger with file modes and chunk counts. Those snapshot fields describe recovery storage, not whether initial provisioning used a reflink. Source custody waits and disk admission also occur inside provision; diskAdmission accumulates space checks across the entire preparation, so it is not exclusively a provisioning sub-phase. These timings do not log paths or setup output.
Private Git index copies for template checkouts prefer native copy-on-write, including on APFS, and fall back to independent byte copies when cloning is unavailable. Safety snapshots use Git's read-only status and cached file metadata to identify changes. Clean checkouts reuse the committed tree without building a private snapshot index; changed checkouts hash only selected paths. Hidden index flags do not exclude edits from snapshots.
Supported filesystems keep using copy-on-write templates even when an isolated Git checkout is faster. Avoiding repeated file-data writes protects other work sharing the volume during concurrent creation. Unsupported filesystems and failed clone operations retain normal Git checkout; no calibration checkout is needed after restart.
New checkouts with no file data, including empty session workspaces, use normal Git checkout without preparing or cloning a template.
If template cleanup cannot acquire its template lease or read its cache, OpenClaw logs a warning and continues ordinary worktree and snapshot cleanup. A later cleanup pass retries template retirement.
Shared worktree templates contain checked-out source only. .worktreeinclude provisioning and .openclaw/worktree-setup.sh still run separately for each new worktree, under their existing permissions. Private sandbox dependency templates follow the separate preparation contract above; they never copy ignored files from the host repository. Copy-on-write snapshots share storage until files change; their actual savings depend on the repository and subsequent writes.
The first accelerated worktree includes the cost of preparing a template through Git. Later APFS worktrees clone the whole directory in one native operation. OpenClaw reads shared data-stream identities in bounded native batches before updating Git's cached file metadata, avoiding a content reread for proven unchanged files. Git metadata preparation counts toward the timestamp-safety delay, so finishing it after the clone's timestamp boundary does not add another wait. Git still validates the resulting index and detects subsequent edits; unsupported index formats and unverified files receive ordinary Git validation.
Apple discourages general directory cloning through clonefile without publishing its complete rationale. One verified limitation is that directory clones do not apply the destination's inherited ACL permissions to descendants. OpenClaw uses normal Git checkout when the destination parent has inheritable ACL entries, when the template root carries ACLs, or when ACL inspection fails. It checks again around cloning to catch policy changes during preparation. Non-inheritable ACLs on the destination parent alone do not disable acceleration. Git owns permission inheritance; OpenClaw does not rewrite ACLs after cloning.
The fast path is limited to OpenClaw's private source-only templates; do not customize ACLs inside the template cache. Cancellation waits for an already-started native clone to finish before recovery can touch its destination.
ReFS cloning can take longer than native Git checkout for repositories with many small files because each file needs independent metadata and Git refreshes its index. Use worktreeAcceleration: false if checkout latency matters more than source storage savings.
Repository source profiles
Full source remains the default. To select a repository-owned sparse source profile when creating a new worktree:
Track plain UTF-8 cone-directory lists in
.openclaw/worktree-profiles/<name>. Names use lowercase letters, digits and
hyphens (up to 64 characters, starting with a letter or digit). Each nonempty
line names a tracked repository-relative directory; do not use comments, globs,
absolute paths or parent traversal. Selected lists compose as a sorted union.
Git cone mode also retains files at the root and ancestor directories. OpenClaw
includes the definition directory so the selection remains inspectable.
Definitions are read from the immutable checkout commit, not uncommitted source files. A default-remote retry loads the definitions again from its fallback commit. Selection finishes before ignored-file provisioning and setup. It does not request a dependency install or build, and an existing repository setup script retains its independent policy. Profiles cannot reshrink reused or restored worktrees; choose a new name.
The existing --profile option still selects runtime state; --source-profile
only selects repository source:
Expand intentionally before native work or whole-repository checks:
If sparse materialization fails after registration, keep the partial checkout and Git registration for recovery. A retry with the same name does not shrink that partial state; inspect it before choosing a new worktree name.
Selected profiles currently use ordinary Git checkout. Git enables shared per-worktree configuration when setting sparse rules, so subsequent full checkouts of that repository also use Git fallback, including after a native full expansion. Existing checkouts retain their own source and indexes.
Then run the separately requested dependency/build preparation. PR whole-repository gates still require full source. Sparse checkout changes source materialization, not shared Git objects or history; it is not shallow cloning.
Layout and names
Each worktree lives at:
The repository fingerprint is the first 16 hexadecimal characters of a SHA-256 hash over the resolved Git common directory and origin URL. A supplied name must match [a-z0-9][a-z0-9-]{0,63}. Without a name, OpenClaw generates a readable crustacean-themed name such as brisk-lobster. Inferred names already occupied by any registered worktree (including the caller's own removed checkout), local branch, or unmanaged path get a numeric suffix such as brisk-lobster-2; only a supplied name reuses or restores the caller's existing record.
OpenClaw creates branch openclaw/<name> at the requested base ref. Without a base ref, repositories with an origin remote discover and fetch its default branch, reusing a successful preparation for up to 30 seconds across nearby creates. When origin still advertises the commit already tracked by the remote default ref, OpenClaw uses it without fetching. To use a freshly fetched commit immediately, fetch it and select its explicit base ref. If the fetch fails, it uses the last-fetched remote default and logs a warning with the Git failure reason. When origin is configured, OpenClaw never substitutes local HEAD; if no remote default is available, repair origin or choose an explicit base ref. When no origin remote is configured, OpenClaw instead uses the primary checkout's current HEAD commit, including a detached HEAD, without remote discovery, fetching, or local fast-forwarding. Remote options such as remote.origin.prune alone do not prevent this local-HEAD path. Concurrent creates share that local base decision, record HEAD as the base ref, and log local HEAD (no origin remote) with the chosen SHA and commit age. A local default branch is fast-forwarded when it is a strict ancestor of the selected remote commit and the clean primary checkout is on that branch. Dirty, diverged, sparse, locked, separately checked-out, and detached checkouts are preserved. An active Git rebase, am, or bisect in the primary checkout also defers local advancement. Linked-checkout operations defer advancement only when they reserve the default branch, including a rebase that names it in --update-refs; unrelated operations do not block it. Creation logs identify the worktree and session owner, chosen base SHA, commit age, and fetch outcome; commits older than seven days produce a warning. An explicitly requested base must resolve to a commit; OpenClaw never substitutes another base for it. Git first registers the branch without materializing files, preserving its normal upstream-tracking rules. OpenClaw then captures that branch's commit and uses it for the size estimate, source template, and checkout. Later changes to the source ref cannot switch the files being written or reuse a smaller commit's allowance.
When refreshing a changed default branch, OpenClaw negotiates from its previous remote-tracking commit to avoid advertising unrelated session histories. A new default branch without a tracked commit uses ordinary Git negotiation.
When a session starts from a GitHub URL and its explicit base is missing locally, OpenClaw refreshes the managed clone from its recorded remote before resolving the base again. This refresh accepts complete ref inventories up to 8 MiB, both before and after fetching. Truncated inventories are rejected instead of being used to prune tracking refs. If this limit is exceeded, choose a base already available in the checkout or ask the Gateway administrator for help; a large inventory alone does not mean branches are obsolete. Ordinary default-branch creation and bounded branch suggestions keep their separate behavior.
Concurrent creations from the same source checkout share remote-default preparation and the local-default advancement decision, including creations waiting for allocation. Existing callers retain their prepared result until their group finishes. New callers reuse a successful preparation for up to 30 seconds; callers arriving after expiry start a new refresh even while an older group is still active. If the initiating caller is canceled, loses authority, or closes preparation, still-authorized callers share a replacement after the native attempt safely settles. This also covers callers that joined before waiting for source access. Recovery uses the remaining creation waiting budget without resetting it. Retry workspace creation if that budget is exhausted. Canceling a follower does not cancel another caller's fetch. Each replacement retains its initiating caller's current authority, and a caller that only reads the base cannot authorize local branch advancement. Other failed preparation is discarded when its group finishes. Preserving a busy local default does not fail a Git ref mutation. Branch registration uses the repository's shared Git mutation queue so upstream tracking cannot race another registration; file materialization remains concurrent. A fetch that loses a ref-lock race retries once within its original timeout. Creation reports unconfirmed Git cleanup without starting another fetch.
Git worktree registration, ordinary checkout removal, and source materialization during creation or snapshot restore each have a five-minute timeout. Fetching missing objects for the size estimate uses the same five-minute budget. Remote-default discovery has a 30-second budget and its fetch has a 60-second budget. Other managed-worktree Git commands keep their two-minute timeout, except automatic Git maintenance, which gets 30 minutes. Explicit interrupted-removal recovery joins deletion without a deadline. The separate .openclaw/worktree-setup.sh step also keeps its own two-minute timeout.
Background Git maintenance and pack-index repair use only locally available objects. Removal snapshots inspect objects offline, then fetch missing promised blobs from the clone's configured promisor remote in one batch under the removal operation's authority and five-minute fetch budget. The snapshot validates those objects locally before recording the capture or removing the checkout. Missing non-promisor objects, failed fetches, or lost removal authority preserve the checkout; restore remote access or repair the repository before retrying cleanup.
Local agent shells, including worker-local execution and Codex shells in app-server processes started by OpenClaw on the Gateway host, disable Git's automatic maintenance and legacy auto-GC. Execution adapters append these settings to the effective Git parameters, preserving unrelated author and transport settings. This also covers Git child processes such as promisor fetches and applies to the next run in existing worktrees after an update. The Gateway cleanup owner remains responsible for managed-repository maintenance; explicit maintenance commands remain available. Sandboxes, node transports, and externally started app-server peers keep their own policy.
Gateway-cloned projects also persist maintenance.auto=false and gc.auto=0 in
the repository's shared local Git configuration. Linked worktrees inherit this
policy even when a command clears the agent environment. The clone owner applies
it at creation and reapplies it under the checkout lifecycle lease when reusing
or refreshing an existing managed project. This lazy adoption needs no Doctor
migration or immediate repack. Operator-registered repositories keep their own
configuration. Managed clones additionally set pack.threads=1 and
pack.windowMemory=64m; the latter limits delta-search memory per thread, not
total process RSS. The existing hourly cleanup performs bounded pack maintenance
outside agent commands, as described below.
Internal worktree and publication Git commands also disable automatic maintenance and GC for operator-registered repositories without changing their saved configuration; scheduled maintenance remains owned by src/agents/worktrees/git-maintenance.ts.
Capacity and disk space
Creation and restoration enforce the count and eviction policy before allocating files. Disk admission independently measures every affected volume.
Before allocating a checkout, OpenClaw checks its destination, Git metadata, source checkout, and state volumes. It keeps a fixed 4 GiB operational reserve on each volume, plus twice the estimated Git checkout and provisioned-file size. A validated reusable source template replaces the full Git checkout allowance with an estimate for clone metadata and Git index writes. Btrfs snapshots share directory metadata; APFS, XFS, and ReFS clones budget metadata per tracked entry, with the ReFS volume allocation size included. Cold templates and every native Git fallback require the full checkout allowance again immediately before allocation. Provisioned files retain their separate full-copy allowance. An executable setup script requires additional room equal to the larger of 4 GiB or the current source checkout footprint excluding Git metadata. Space is checked again before provisioning/setup and after setup. An unavailable capacity reading stops allocation with an actionable error.
For partial clones, OpenClaw inventories missing objects before estimating checkout size and fetches them from the clone's promisor remote in one batch. Default-base creations share that preparation by captured commit while the Git worker remains active, including across later creation groups, before advancing local main. Explicit refs without shared preparation recheck object availability. If the selected ref moves before worktree registration, the registered commit gets its own preparation. The batch requests only the missing objects without treating shared commits as proof that their contents are available locally. Neither size inventory nor checkout can trigger per-object lazy fetches. A failed prefetch logs the missing-object count and stops preparation. Allocation fetches skip Git auto-maintenance; the cleanup pass (hourly in the Gateway, or openclaw worktrees gc) repairs pack lookup and consolidates small packs before running threshold-gated commit-graph and loose-object packing tasks at most once per hour per shared repository with live managed worktrees or retained snapshots. Archive-triggered cleanup still removes eligible checkouts and orphans immediately; it does not repeat repository housekeeping within that hour. Newly registered repositories are maintained on their first cleanup pass, and --retry-deferred bypasses the hourly limit. Removing an individual checkout never rebuilds the shared pack index or consolidates packs. These tasks preserve unique objects and worktree reflogs; cleanup does not run full Git GC or expire reflog history. If pack repair fails, OpenClaw logs the Git error once and suspends maintenance for that repository for the service lifetime. A later commit-graph or loose-object task failure suspends only those tasks; bounded pack consolidation continues on subsequent hourly maintenance passes. After repairing the repository, run openclaw worktrees gc --retry-deferred or restart the Gateway to retry. Other repositories and worktree cleanup continue. Partial clones are supported, but full clones are recommended for registry-owned projects to keep checkout and restore independent of missing remote objects. If objects are missing without a promisor remote, fetch or repair the clone before retrying. A Git timeout reports its budget and suggests checking remote reachability, repository locks, and partial-clone behavior.
Empty pack directories skip pack mutation admission; threshold-gated commit-graph and loose-object maintenance still runs. Packs arriving after that inventory are handled by the next maintenance pass.
Pack consolidation keeps promisor and ordinary packs separate. Each group selects up to 1,024 of its smallest eligible packs, capped at 16 GiB of pack data and 128 MiB of index data per pass. The index budget admits multiple large fetch indexes; a budget smaller than two ordinary indexes would leave their packs permanently fragmented. Consolidation combines at least two packs only when the smaller inputs together reach the largest selected pack's size. Otherwise it leaves that largest pack untouched and considers the smaller batch. The index budget bounds object metadata even for highly compressed inputs. Git verifies each selected pack and index, then streams all their objects into a replacement without fetching missing partial-clone objects. The single-threaded writer searches for deltas across separately fetched revisions with a 10-object window and an 8 MiB window-memory budget, so historical blob reads do not permanently retain every revision at full size. This budget bounds the delta-search window, not total process RSS; unrelated objects can cost more background CPU without shrinking. Inputs retire only after Git publishes the verified replacement. Kept packs, cruft packs, and packs outside the batch remain untouched. This size-based policy lets bounded batches keep converging below 16 packs without repeatedly rewriting a large pack for tiny additions. Maintenance removes optional multi-pack-index lookup metadata, including stale indexes, so Git uses individual pack indexes without a repository-wide rebuild. Verification and rewriting each have a 30-minute subprocess budget. Backlogs drain over successive passes; consolidation does not guarantee a fixed pack count for arbitrary repository growth or impose an operating-system RSS limit. Consolidation uses low-priority Git subprocesses, one thread per pack process, and idle I/O priority where ionice is available. On delegated Linux services, maintenance runs in the resource-limited agent-exec group. Foreground Git retains its Gateway placement. A separate project Git maintenance lease serializes background passes. Verification and rewriting do not hold the project checkout lease, so foreground preparation and fetch can proceed during pack writing. Only optional pack-index invalidation and retirement take the checkout lease without waiting; a busy checkout defers maintenance without consuming its hourly slot. Retirement joins the ref-mutation queue before acquiring the checkout lease and stops starting pack deletions after 250 ms, leaving valid duplicates for a later sweep. Losing maintenance ownership defers the pass instead of suspending the repository. Lease-wait logs include the holder's operation as well as its unique identity.
A fresh clone is not a replacement for a managed project's object store: remote
history does not include its unpublished commits, local branches, snapshots, or
worktree reflogs. Replacing the store requires preserving those objects and all
linked-worktree administrative metadata, plus a quiet window for the directory
swap. Prefer the existing online, promisor-aware compactor for fragmentation.
Do not substitute native maintenance run --task=incremental-repack on partial
clones: Git versions including 2.56 can combine promisor and ordinary packs
without retaining the promisor marker, then expire the original promisor pack.
On Linux, maintenance also removes up to 256 abandoned temporary pack files (tmp_pack_*, tmp_idx_*, and other tmp_*_ files Git leaves when interrupted) per pass once they are older than 24 hours. An isolated native helper must obtain an exclusive Linux file lease, which detects open users across user IDs and blocks new opens through deletion. It rechecks each file's identity, size, and timestamps before unlinking it. A live user, unsupported filesystem lease, or changed file preserves that temporary file. Other platforms retain temporary packs. Installing an update requires no migration or immediate repack; the next ordinary maintenance pass applies these bounds.
Transient fetch failures, including an incomplete object transfer, retry once after one second within the original fetch timeout. Cancellation and expired workspace authority stop recovery; a second failure surfaces the Git error. See Retry policy.
If a fetch finds a ref tip in the commit graph but not in the object store,
OpenClaw attempts one bounded repair before retrying. It prunes only origin
tracking branches confirmed deleted upstream (unless the fetch explicitly uses
--no-prune), preserving tracking refs required by local symbolic refs or
worktree HEADs, then fetches missing ref and
worktree-HEAD objects by ID with commit-graph lookup and automatic maintenance
disabled. Repair negotiates from a physically present commit when available,
including in isolated transport metadata, to reuse local history. If requested
objects remain missing, it retries once without negotiation: a resident descendant
can otherwise hide a missing ancestor. Local branches, tags, and worktree HEADs
are never deleted. Repair is
limited to 50,000 refs, 4,096 missing tips, and five minutes; healthy fetches do
not scan repository health. Managed project refresh retains its isolated,
URL-pinned transport during recovery.
Repair may clear empty origin-tracking ref locks on supported local Linux filesystems when their unchanged inode timestamps prove they predate the current boot by at least one hour. Age alone cannot establish that a native Git lock has no live owner, so same-boot, nonempty, symlinked, and otherwise uncertain locks remain intact. Recovery logs its result and an actionable warning if missing objects or locks still prevent fetching. No configuration or state migration is required.
The Git worker reuses a bounded set of successful commit-size estimates while it remains active. Default-base object hydration is shared by immutable commit while the worker remains active; explicit refs without shared preparation recheck object availability. Free disk space is checked on every allocation. Git replacement refs disable reuse of the affected size estimates, and worker shutdown discards them.
Creation, restore, orphan cleanup, and snapshot expiry share an allocation owner across repositories and processes using the same state directory. Registered worktree removal holds custody of its own checkout, so an unrelated creation can proceed while background removal runs. Every allocation reserves its estimated pending writes on each volume. If another operation’s reservations leave insufficient space, creation waits for that operation to settle before retrying. Reserved bytes remain accounted for until native work settles, including after cancellation or lease loss. Managed sources stay protected while a creation copies them. Slot admission and orphan cleanup share allocation custody. Template preparation serializes per template while independent checkouts materialize concurrently. A dedicated heartbeat thread renews operation leases, and contention waits are bounded to 30 minutes, allowing a dependency install's 15-minute budget plus checkout and cleanup. Caller cancellation and overall request limits can stop the wait earlier. The separate Git and setup timeouts described above still apply. Costs on the same volume are added together. These checks are conservative estimates, not a disk quota: other OpenClaw state directories, shell commands, deployment tools, and arbitrary setup/build output can still consume space. Reusing an existing valid checkout does not allocate another checkout. Worktrees created directly through Git are outside the managed cleanup lifecycle.
Git inventories and directory-size calculations run on bounded background workers. Branch and checkout-context reads use a dedicated worker, separate from diff and snapshot processing. Session diffs, baseline capture, pull-request statistics, removal snapshots, checkout deletion, and Git maintenance share a limit of two Git subprocesses and run at a lower CPU priority on POSIX systems.
The Gateway keeps ownership of Git subprocesses, cancellation, operation leases, and registry writes. Canceling an operation waits for its subprocesses and temporary-index cleanup to settle before releasing that ownership. A ref mutation still waiting behind another writer can cancel without waiting for that writer; mutations already running finish their cleanup before cancellation returns. Preparation is cancellable. Once destructive checkout deletion starts, it either finishes and records the removed checkout or exhausts its five-minute budget, joins its child processes, and retains the completed snapshot for recovery. The operation lease and removal claim retain finalization authority even if maintenance stops or its configuration changes. Ref cleanup failures preserve the removed record and snapshot for recovery.
A snapshot reuses its operation's path inventories and pins the source HEAD while constructing its temporary index. Publication verifies HEAD atomically after waiting for other ref mutations. If HEAD changes during preparation, cleanup preserves the checkout and asks you to retry. Provisioned-file membership is checked again at capture time because ignore rules and the source index can change independently. Concurrent operations retain independent checkout custody and shared disk admission without weakening snapshot protection.
Snapshot removal uses a smaller reserve of 128 MiB plus estimated snapshot writes, so safe cleanup remains possible below the operational reserve. If a required snapshot cannot fit, ordinary removal preserves the checkout and asks you to free space first; cap eviction permits snapshot loss.
Provision ignored files
Add .worktreeinclude at the source repository root to copy selected ignored, untracked files into a new worktree. The file uses gitignore-pattern syntax, one pattern per line, with # comments:
The manifest is read from the actual source checkout and does not need to be committed. Without it, provisioning copies no ignored files; there are no default include patterns. Broad patterns can select build outputs and caches, so include only files the new checkout needs.
Only files reported by git as both ignored and untracked are eligible. Tracked files are already present through git and are never copied by this step. OpenClaw does not overwrite or change destination files that already exist, does not follow symlinked directories, and preserves copied file modes and access/modification times at the filesystem’s supported precision. This keeps the timestamp ordering of prepared build inputs and outputs instead of making every copied file look newly written. It records only paths it actually creates, so later manifest edits cannot make those files disappear from cleanup protection.
Ordinary removal snapshots omit provisioned files inside node_modules directories,
including nested package dependencies. Reinstall those dependencies after restoring
the worktree. Other provisioned files, including edited local configuration, remain
recoverable. Tracked files and non-ignored untracked files keep their normal snapshot
protection, including files inside node_modules. Existing snapshots still restore
their recorded dependencies; explicit exact-state retirement retains its complete
provisioned-file capture.
Run repository setup
Git source materialization leaves submodules unpopulated, matching native worktree creation even when submodule.recurse is enabled. A repository setup script can initialize the submodules it needs.
If .openclaw/worktree-setup.sh exists in the source repository and is executable, OpenClaw runs it with the new worktree as its current directory. The script receives:
A nonzero exit aborts creation and removes the new worktree and branch. This is a repository-local contract; there is no OpenClaw config key for it.
Setup failures report the exit code or termination signal, or an actual timeout after 120 seconds, with a bounded excerpt of recent output rather than the full setup log. If setup times out, inspect .openclaw/worktree-setup.sh and its dependencies for slow downloads, unavailable services, or commands waiting for interactive input.
Session worktrees
Native sessions_spawn children can use a managed worktree while remaining hidden:
Hidden children use the same session worktree preparation and persisted binding as visible sessions. Acceptance does not wait for checkout and setup; the first agent turn waits until the managed workspace is ready. The child stays a native subagent, retaining its completion routing, sandbox policy, run timeout, and cleanup choice. cleanup: "delete" uses session deletion to snapshot the checkout before removal; "keep" retains it under the normal idle and archive lifecycle. Session lists and the Worktrees page can inspect the recorded worktree without making the child a sidebar session.
For hidden children, projectId requires worktree: true. Worktree names and base refs also require worktree: true. projectId and cwd are mutually exclusive. group, projectGitUrl, and cloud placement profiles remain visible-only; ACP does not accept managed-worktree parameters. See Sub-agent tool parameters.
For a fresh isolated session without a source repository, call sessions.create with worktree: true and worktreeSource: "empty". This does not copy the agent workspace or any selected folder. It cannot be combined with cwd, project or repository selection, an external catalog, execNode, or worktreeBaseRef. The Control UI uses this mode for New workspace on paired devices and cloud destinations.
Each fresh session has its own OpenClaw-owned backing repository under <openclaw-state-dir>/worktree-sources/empty, so Git remotes and history remain isolated between sessions. The existing managed-worktree registry owns allocation, snapshots, restore, and cleanup; no database migration is needed. The backing source remains available while a live worktree or retained snapshot references it and is removed after its final expired snapshot is collected. Git is still required internally. Existing installations adopt this mode only for new explicit empty-workspace requests; existing sessions and their snapshots keep their original source.
If worktree preparation fails before the first model reply, the session records the failure reason. The Control UI shows it with the failed session and in the chat, and the transcript retains a failure notice. Command failures identify the command and its exit or timeout reason, so a Git setup timeout is distinguishable from a model-provider timeout.
Start an isolated chat from a Git-backed folder with a worktree session: on the Control UI's New session page, use the Place picker to choose a Gateway source folder, then select Worktree (with an optional base branch and worktree name). Choosing a paired device or cloud profile with a Gateway folder selected uses this managed-worktree path; remote placement never browses or binds an arbitrary node working directory. When the name is omitted, OpenClaw derives it from the explicit session label or the concise title generated from the first message, then falls back to a crustacean-themed name. iOS exposes the same choice from Chat actions, and Android exposes it beside New Chat, when the active agent workspace is Git-backed.
Remote sessions started from a Gateway folder retain a durable managed-worktree mirror for workspace reconciliation, recovery, and publication. The same disk-space checks apply to this mirror. To start without a Gateway checkout, select a GitHub repository and a remote destination instead: repository cloud sessions fetch on the node and retain accepted checkpoints on the Gateway. Their checkpoints have a separate lifecycle from managed-worktree snapshots.
The Control UI offers Worktree only after confirming a usable Git checkout with at least one commit, or when a selected remote Git repository is awaiting cloning. Plain folders and newly initialized repositories without commits can run directly on the Gateway. A failed Git check also leaves direct execution available if the folder is accessible; a .git entry or saved project alone does not enable isolation. If you already selected Worktree and a later check fails, that selection stays visible and starting is blocked. Clear Worktree to run directly, or reselect the folder to check it again.
The base-ref field suggests up to 100 local and 100 remote refs, plus the default and current branches. The current branch comes from the selected checkout, including linked worktrees; a detached checkout has no current branch. Branch discovery reads that checkout directly without inventorying sibling worktrees. Repeated lookups reuse the completed branch list, including bounded suggestions from large repositories, for up to 30 seconds without checking ref or HEAD metadata or starting another Git process. Repository changes can leave suggestions and repository status stale until that refresh; they never bypass validation of the selected ref during creation. You can enter any branch or commit even when it is not suggested. If branch suggestions cannot be loaded, the Control UI explains that you can enter a ref manually; a verified Git checkout remains available for worktrees. The selected ref must still resolve to a commit before session creation.
Group New session defaults checks the agent workspace the same way as a custom folder. If verification fails, retry before saving the group defaults. A remembered cloud destination cannot block a new local draft in a plain folder; a transient Git-check failure leaves the saved destination intact for the next visit.
The Place picker's Projects section can start the same worktree flow from a registered project ID. The Gateway resolves the recorded checkout path, so this path remains available at operator.write; selecting an arbitrary host folder still requires operator.admin.
Agents can also call suggest_task when they discover confirmed follow-up work outside the current task. The Control UI and Gateway-backed TUI offer Start in a new session. This starts the task directly in the suggested folder without creating a worktree or requiring Git. The new session is instructed to explain the need and ask the user before creating or switching to a worktree later. Dismissing a suggestion starts nothing. Suggestions and their IDs are ephemeral and do not survive a Gateway restart.
In the Control UI, the arrow beside Start in a new session offers two additional actions: Start in a new worktree creates an isolated session from the suggested Git checkout, and Start in this session sends the task to the current conversation. If the current session is running, the task follows its normal steering behavior. Worktree creation requires a usable Git checkout; a failed start displays an error and keeps the suggestion available to retry.
Closing a suggested-task card removes it immediately while the Control UI sends the dismissal to the Gateway. Other cards and the composer remain usable. If the request fails, the card returns with an error so you can retry; switching chats does not bring the old card into the new conversation.
The primary action and the Gateway-backed TUI send taskSuggestions.accept with mode: "local". The Control UI menu sends explicit worktree or session modes for those choices. RPC clients also retain cloud mode. Omitted mode still means worktree for callers that used the original worktree action; the Control UI and TUI never omit it.
OpenClaw exposes these tools only to operator sessions with an actionable Gateway UI. Channel sessions and local/embedded TUI sessions do not receive them, because those surfaces have no portable typed task-action contract.
The resulting managed worktree is owned by the session, and every agent run in 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. Repository checkout/ref hooks and filesystem monitors are always disabled. The .openclaw/worktree-setup.sh step runs only for an operator.admin caller; retries evaluate the current caller's scope rather than retaining the original caller's permission. .worktreeinclude provisioning still applies to every caller. Deleting the session attempts to snapshot and remove its managed worktree, including dirty worktrees and branches with unpushed commits. Hourly cleanup also snapshots session worktrees after 7 idle days, treating recent session activity as worktree activity. Removed worktrees remain restorable from their snapshots as described below.
Reply commands /new and /reset, and automatic idle resets, start a fresh conversation context while keeping the session's managed worktree, project, and working directory. Plain New Chat in the Control UI deliberately leaves the previous worktree through the normal cleanup flow.
If an earlier local publication adopted a conversation into a managed worktree,
create a linked ordinary conversation to continue in its original workspace.
Call sessions.create with the old conversation's key as parentSessionKey, the
absolute original workspace as cwd, worktree: false, and
emitCommandHooks: false; leave key unset. Continue using the returned key.
The new conversation starts fresh at that folder under the normal workspace-path
permissions. The old conversation keeps its history, file links, managed checkout,
and publication receipts. Recover any pending publication there using its original
request identity. This also keeps each conversation's historical file references
associated with the source that produced them.
Archiving a session returns after its archive state and publication are committed, preserving the conversation and worktree binding. After sending the response, the Gateway wakes background maintenance to snapshot and remove the checkout. The response does not wait for Git or the worktree allocation lease. A failed metadata write leaves the checkout untouched. If cleanup cannot finish safely, the session stays archived and its files remain available for a later cleanup pass. Hourly garbage collection also picks up automatically archived sessions. Cleanup holds the session lifecycle mutation only while admitting its registry claim and publishing the removed checkout. Git runs outside that mutation. Unarchiving before cleanup starts keeps the existing checkout; during cleanup, unarchive reports that removal is in progress and asks you to retry after it settles. An incomplete deletion requires recovery of its preserved snapshot before unarchive.
Slow archive requests log request-owned phase durations, including snapshot reads, projection, runtime selection, archive placement checks, commit, cron effects, and response preparation. These timings separate foreground metadata work from background Git cleanup; nested phases can overlap.
Archive preparation reads the selected session without reserving its database's writer, so unrelated queued writes do not delay stopping that session. Committed policy changes invalidate the prepared source. The archive mutation still joins the writer queue and rechecks the current session and permissions before committing.
Unarchiving, or an authorized human message that reopens the archived session, restores the original branch HEAD plus saved dirty and untracked files before admitting work. A restore failure leaves the session archived. If the original repository or its snapshot is missing, or the 30-day snapshot retention has expired, recover the original repository/snapshot or start a new task; OpenClaw does not substitute an empty checkout for the saved work.
sessions.create may include an absolute cwd to run directly in another Gateway folder or to choose the source checkout together with worktree: true. Connections with operator.write may use a Gateway cwd contained in any configured agent workspace; realpath containment prevents 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. For a Gateway source, New Session dispatches the completed worktree session to paired devices or cloud profiles instead of passing a paired-node working directory to creation. The separate repository: { url, ref? } create input starts a remote-owned repository session without a Gateway path or worktree: true.
sessions.create also accepts worktreeBaseRef and worktreeName alongside worktree: true to pick the base ref and the worktree name (the branch becomes openclaw/<name>); both stay at operator.write. If worktreeName is omitted, the session label or generated first-message title supplies the readable branch name, with a two-word, crustacean-themed fallback if naming fails or exceeds the 30-second wait. Raw first-message text is never a branch-name fallback. A title that arrives later updates the session without renaming its existing branch. For a new session with an initial message or task, creation returns the admitted session and run before worktree preparation finishes. The chat shows the submitted message and repository-update, checkout, and setup progress, including after reopening the session; failures remain visible and retryable in the same session. The agent starts only after the finalized worktree is bound. Creation without an initial turn still waits for preparation and returns the worktree in the create result. The bound checkout is persisted on the session row as worktree: { id, branch, repoRoot }, so session lists can show its checkout and branch. Ordinary session deletion waits for cleanup; if it cannot finish, worktreePreserved identifies the active worktree record that needs 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 describe cleanup and ownership, not whether the checkout is dirty or has unpushed commits.
For sessions.delete with archivedOnly: true, the response confirms durable session deletion and transcript export before worktree cleanup finishes. The Gateway retains the cleanup operation and blocks same-key successors until it settles. Inspect worktrees.list for the retained worktree and its runEndCleanup outcome; a snapshot failure preserves the checkout and records the failure there. A crash leaves the registry binding available to lossless garbage collection, which also runs hourly or through worktrees.gc. Removal still requires a completed snapshot; the early response does not authorize discarding unsaved work. Incognito deletion keeps its existing synchronous cleanup behavior.
An explicit session base must resolve to a commit. Local refs are checked before the session is saved; remote-project refs are checked after cloning. A missing remote ref is refreshed from the recorded project URL and retried only in a Gateway-managed clone, never an operator-registered checkout. Once accepted, the commit stays pinned across setup failures and retries while the original ref remains publication metadata. Invalid explicit refs never silently switch to the repository default. Managed-clone refresh uses an isolated Git repository for network transport, so checkout-local URL rewrites and hooks cannot redirect or execute during the fetch. Pinned-commit presence checks disable lazy fetching; missing commits use the explicit incremental fetch rather than downloading their ancestry again through a promisor remote. Refresh preserves an existing clone's partial-clone filter; checkout preparation fetches the selected commit's missing contents when needed.
For a same-agent sessions_spawn with worktree: true, omitting cwd uses the parent's live managed repository or its directly selected registered project. The child gets its own managed worktree. An explicit source selection takes precedence; other spawns use the target agent workspace. A parent working directory alone does not authorize inheritance outside that workspace.
The parent session and its managed-worktree or registered-project binding must remain current until the child is accepted. Accepted child sessions retain their saved repository choice across parent archive, replacement, or worktree changes. A retry must still be authorized for the current child session and uses the current caller's setup permissions.
Troubleshoot creation
If creation reports git checkout has no commits, create an initial commit in the source repository, then retry. Running git init alone does not provide a commit for the new worktree.
If New session reports git worktree add failed, read the termination reason and the final Git error lines. Preparing worktree and Updating files are progress, not the cause of failure. Error messages collapse carriage-return progress redraws and bound the diagnostic tail so it cannot flood the banner.
timed out after 300 seconds means a worktree checkout reached its five-minute limit. Other Git commands report timed out after 120 seconds at their two-minute limit. Check repository access and available disk space on the Gateway host. A signal or nonzero exit status alone does not establish a timeout; use any accompanying fatal: or error: detail to investigate. An output-limit error means the command exceeded its output capture limit.
If allocation ownership is lost during creation, cleanup is best effort. Without cleanup authority, OpenClaw preserves the checkout and branch; manual cleanup or another worktree name may be required. Before another creation attempt after a cleanup failure, inspect git -C <repo-root> worktree list and git -C <repo-root> branch --list 'openclaw/*' for partial state. A failed creation does not guarantee that its checkout and branch were removed. Do not delete a checkout or branch without checking whether it contains work you need.
If a checkout's .git link points to missing administrative files, OpenClaw preserves its files and refuses to reuse it. Restore the original repository metadata before using git worktree repair from that repository. A different clone with the same remote URL does not recover the missing index or unpushed history; do not replace the link or rebuild the index without verifying the original metadata.
Snapshots, cleanup, and restore
Registry lookups, pending-slot inspection, and template listings use read-only workers so they do not wait in the shared SQLite writer queue. Creation, activity, and removal still await their durable writes; an unchanged registry update does not rewrite the row. Inspecting an empty registry does not create its database.
Ordinary removal first creates a synthetic commit containing tracked and non-ignored untracked files, then pins it at refs/openclaw/snapshots/<id>. Host-provisioned ignored files do not enter the Git snapshot or repository object database. OpenClaw stores the ignored files it actually provisioned, except files inside node_modules directories, 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. Idle cleanup preserves a live worktree when a recorded path can no longer be snapshotted safely. If snapshot creation fails, ordinary removal stops unless --force explicitly permits snapshot loss. Cap eviction is best effort and can purge the checkout without a snapshot.
For an ordinary clean checkout, the snapshot reuses the original HEAD tree after checking working files with a private index that clears hidden status flags. It checks object availability in one batch before creating the same recovery commit and snapshot ref. Missing objects preserve the checkout with a repository-repair error, including in partial clones. Exact-state snapshots continue capturing their complete recorded state.
Sandbox-created ignored files (including symlinks) and empty directories already accepted by reconciliation remain in the existing projection owner’s custody. Before removal, OpenClaw retains their missing snapshot delta in its pending-result receipt and private recovery refs. Restore replays that receipt before another turn can synchronize the workspace. This does not force ignored paths into publication or import unrelated ignored host files. The receipt follows the same snapshot retention period, and unaccepted private edits defer cleanup. The legacy provisioned-file ledger remains regular-file-only. Older versions can restore that ledger and the Git snapshot, but do not apply the projection receipt; return to a supporting version to recover accepted guest data.
Ordinary removal is archival: after a successful snapshot it uses Git's forced checkout removal so dirty files can be restored later. The CLI's --force option permits snapshot loss; omitting it does not select non-force Git removal. Use openclaw worktrees remove <id> --if-lossless when deletion must be non-force. This uses the same owner as run-end cleanup, retains dirty or unpublished work, and never retries a Git refusal with force. It cannot be combined with --force.
Ordinary removal requires HEAD to remain on the recorded managed branch. Switching branches or detaching HEAD preserves the checkout and recorded branch during ordinary removal and idle cleanup, but does not exempt the checkout from cap eviction. Branch deletion uses native git branch -d against the completed snapshot, so a tip advanced beyond that snapshot remains intact. Without a snapshot, the branch stays retained. Removal deletes only its own Git worktree registration and never runs repository-wide git worktree prune.
Idle cleanup preserves an outer worktree containing a nested Git repository or linked worktree, even when it shares the same Git common directory. Cap eviction can purge unmanaged nested repositories. Nested OpenClaw-managed checkouts retire individually through their own claims and snapshots; a live nested checkout also protects its enclosing checkout. Capacity admission holds live custody of managed source and destination containers needed by creation or restoration.
OpenClaw applies these cleanup rules:
- The hourly maintenance pass deletes disposable entries in each managed worktree's and project checkout's
.openclaw/tmp/after 24 hours, measured from the newest file's modification time (or the entry's modification time when it contains no files). The same pass expiresnode-coverage-*directories in the runtime temp root. There is no configuration option. Live or queued runs protect their checkout; unrelated runs do not protect shared runtime coverage. Idle sessions and recorded artifact references do not protect scratch. Save durable outputs outside these roots. Missing scratch artifacts displayfile expired (scratch cleaned after 24 h)when listed or opened. - Scratch cleanup never follows symlinks. Each pass enumerates at most 4,096 top-level names and inspects at most 256 candidates, with separate limits of 2 million filesystem entries for age scanning and removal, to depth 64. Deletion streams through the tree and pauses 100 milliseconds after every 128 removals. An incomplete scan retains the entry and reports a deferral. The next pass resumes the directory iterator; an entry exceeding the full scan or depth limit is deferred so later entries remain reachable. The cleanup receipt and health log include scratch entries and bytes removed, live-run skips, and deferred inspections;
openclaw worktrees gc --job <id>shows the latest receipt. - At run end, it removes a worktree without Git force only when
git status --porcelainis empty andgit log HEAD --not --remotes --onelinefinds no unpushed commits. It also checks the captured contents for edits hidden by index flags. Otherwise it retains the checkout and records why. - Background cleanup snapshots and removes unlocked Workboard- and session-owned worktrees idle for more than 7 days, even when dirty. A stable per-worktree delay of up to one additional hour spreads age-based expiry. Session worktrees whose owner is archived or absent are eligible without waiting 7 days. Failed owner lookups defer idle cleanup. Run
openclaw worktrees gcto request cleanup and see its progress. - The same background owner enforces
worktreeMaxCount, default4096, using the capacity eviction policy. Manual worktrees and unsaved data are eligible when enforcing the cap. - Snapshot records remain restorable for 30 days. Cleanup then deletes the snapshot ref and registry row.
- Live owner leases protect active runs from eviction. Ordinary idle cleanup also preserves foreign or unrecognized Git worktree locks.
Maintenance works in small batches with a time budget, yields between batches, and resumes from its previous position until the sweep finishes; the batch size is not an hourly removal limit. Filesystem scans, lossless checks, and nested-repository inspection run in the Git worker. The Gateway request starts or observes the same background job instead of waiting for the entire fleet to be inspected; openclaw worktrees gc reports that owner's progress. Health summaries include each eviction reason and any live-owner refusal.
Gateway idle cleanup starts at most one removal attempt per minute, including across archive-triggered sweeps. On Linux, high recent IO pressure or slow btrfs commits pause admission for five minutes before checking again. Missing kernel counters retain the minute pacing. Waiting releases no snapshots and holds no checkout or session mutation custody; the existing live checks still run after the wait. Capacity eviction and explicit single-worktree removal retain their existing policies.
Cleanup progress and JSON output report eligibleCount (removal candidates that passed initial policy and checkout checks), deferredCount, and failedCount. These are running totals for the current sweep, not a prediction of the next sweep: final authority checks can still defer an eligible removal. Deferred and failed totals count dispositions across all cleanup stages, even when the 64-entry issue detail list is full. Protected checkouts contribute to deferred totals. Retiring an orphan record while preserving its files is reported separately in orphansRetired and retiredCheckoutPaths; it does not count as a successful checkout deletion.
Idle collection checks registry eligibility, remembered dispositions, owner activity, and run leases before requesting Git inventories. It classifies candidates serially and shares one preliminary lock and branch inventory per repository. Known provisioning ledgers use filesystem checks without Git setup. Ordinary removal rereads the current lock and HEAD and verifies worktree activity under its allocation lease. Cap eviction ranks branch history in the Git worker and checks live removal authority again before deletion. Preliminary inventories never authorize removal. If cleanup cannot acquire the lease, it preserves orphan candidates and expired snapshots for a later pass.
Each cleanup pass batches session-owner activity and worker-placement reads in database workers without loading saved prompts or full session entries. Owner classification yields between batches. Cleanup still rechecks the current session identity, activity, archive state, worktree binding, and worker placement immediately before mutations. Unreadable or uncertain owner state preserves the checkout.
Cleanup remembers protected checkouts' deferral reasons and fingerprints instead of repeating unchanged inspections. Managed activity, registry lifecycle changes, and observed checkout or HEAD changes invalidate those decisions. Run openclaw worktrees gc --retry-deferred to force another inspection after repairing files or Git metadata. Remembered idle-cleanup protection never exempts a checkout from cap eviction. The nullable derived-state column is added on database admission without a schema-version change; older builds ignore these dispositions and resume their previous inspection behavior. Snapshot retention remains 30 days.
A Git timeout records its removal stage, elapsed milliseconds, attempt count, and next retry time in the existing revision-bound cleanup disposition. Automatic retries wait two hours initially, then double up to 24 hours; passes inside that window skip checkout inventory work. This backoff survives Gateway restarts. An explicit --retry-deferred bypasses the wait, while owner activity or a new registry lifecycle invalidates the old disposition. Existing rows require no migration; builds that understand only the deferral reason retain their existing protection behavior. Slow-removal log lines include the checkout path, stage durations, tracked and non-ignored untracked counts when available, and the deferral decision. A timeout during deletion preserves the pending snapshot and prevents a new run from using the potentially partial checkout; use the recovery procedure below.
When cleanup recaptures a workspace created by an older build, current Git eligibility excludes ignored dist/ and .cache/openclaw-bun/ output even if an older capture accepted those paths. This retires capture membership without deleting files; tracked or explicitly admitted inputs remain eligible.
A rejected local workspace checkpoint or archive overlay is terminal for automatic application. Accepted checkpoints can accumulate more data than one archive overlay permits; that rejection also preserves the checkout and records the byte count, limit, and largest new paths. Idle cleanup preserves its result reservation, any saved Git ref, and guest files, and records a cleanup deferral instead of retrying removal on a timer. The cleanup summary (openclaw worktrees gc --json or worktrees.gc) names the reserved result and guest path. Reduce the change and checkpoint the corrected workspace, or recover the files manually, then run openclaw worktrees gc --retry-deferred. The existing result byte and path limits remain enforced; an explicit retry does not reapply the rejected result.
Missing or corrupt Git objects also use this persisted backoff. One failed idle-cleanup attempt pauses further idle snapshots for the shared repository, including sibling checkouts in the same sweep. Pack consolidation independently verifies only the bounded batch it may retire; missing snapshot objects do not force a full repository integrity scan or block healthy packs. A damaged selected pack stops that batch without deleting its sources. Checkouts remain protected until the objects needed by their snapshots are available locally. Cleanup reports the repository needing repair and preserves the checkouts. Restore missing objects or repair the clone, then run openclaw worktrees gc --retry-deferred to retry immediately. The existing cleanup revision invalidates the remembered failure when its worktree's owner or lifecycle changes; no database migration is required. Explicit removal and capacity eviction retain their existing policies.
Listing and cleanup mark a missing checkout as removed only if its recorded path, activity, and repository identity still match the earlier check. A restore or repository repair that completes during that check preserves the newer live record.
Idle cleanup retains a checkout whose HEAD has detached or switched away from its registered branch as branch-moved. If a linked checkout's Git metadata directory is gone but its source repository remains available, idle cleanup retires the orphan record while preserving checkout files and the normal snapshot retention period. These dispositions do not fail openclaw worktrees gc; genuine inspection or cleanup failures still return a nonzero exit status. The summary and JSON output include orphan retirement counts and totals for every protection reason, even when individual details are truncated. Cap eviction can purge these otherwise protected checkouts.
Permission-denied idle inspections (EACCES or EPERM) retain the checkout as unreadable, with the offending path in its cleanup detail and one protection count in the summary instead of a warning for every sweep. If a registered path cannot be resolved, orphan deletion also waits. Repair access for the Gateway user; a later pass rechecks changed checkouts. Cap eviction attempts purge regardless of an earlier unreadable disposition, but cannot bypass operating-system permissions.
A missing checkout or gitdir with a local workspace projection remains registered as local-workspace-projection. Projection-only files may still need recovery; cleanup defers retirement until the projection owner releases custody, including during later retention passes.
An orphan retired without a snapshot no longer appears in worktrees list and cannot use worktrees restore. GC verifies the recorded repository identity and reports every preserved checkout path for manual recovery in retiredCheckoutPaths, independently of the bounded issue details. These cases are deferred cleanup: the CLI exits 0, and the Gateway's existing deferred-cleanup response includes all recovery details without changing its success-response contract. The text summary preserves every recovery path too. Keep those files and the retained source branch; recover work into a separate checkout instead of deleting or overwriting the preserved files. Retirement does not reconstruct missing Git metadata or create a replacement snapshot.
Run-end cleanup records 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.
Ordinary forced checkout removal first renames the captured file tree, then lets Git remove the original registration. File deletion runs serially in the background, so cleanup can release the checkout name without waiting for every file to be unlinked. A deletion failure logs the retained directory for manual cleanup; a crash before background deletion starts can leave a sibling .openclaw-removing-* directory for inspection. Non-force lossless removal and explicit interrupted-removal recovery keep Git's final check and joined file deletion.
Orphan cleanup retries permission-denied deletion once after restoring owner write permission on directories owned by the Gateway user. It never changes file permissions or follows symlink targets. If deletion still fails, cleanup reports the orphan and warns once while continuing with other orphans. Automatic passes skip that directory until the Gateway restarts, the directory is replaced, or you run openclaw worktrees gc --retry-deferred after repairing access.
Idle artifact sweeps skip the allocation lease when all observed checkout directories are already registered and no pending creation or expired snapshot needs work. Unknown paths still take the lease and receive the full cleanup checks. A checkout that becomes unregistered during this read-only inspection is reconsidered on a later sweep.
If checkout deletion fails or is interrupted, OpenClaw preserves the completed capture at refs/openclaw/removals/<id>. A later removal refuses to replace that capture with files from a possibly partial checkout. Preserve the remaining files, recorded branch, snapshot refs, and shared-state database for recovery. Inspect the original removal error and Git worktree registration before attempting cleanup; do not repeatedly force removal or prune registrations. A normal completed removal, successful restore, or snapshot expiry clears this recovery ref. A failure after checkout removal can leave its branch retained and require operator reconciliation before restore can recreate that branch.
Snapshot expiry retires the snapshot and its associated recovery refs in one Git transaction. If Git cannot lock a ref or an observed snapshot or restore receipt has changed, the transaction preserves all of those refs and cleanup reports the failure for a later retry. Existing snapshots use this behavior after an update without a migration.
For an interrupted ordinary clean snapshot removal, use the exact pending commit:
Recovery keeps the original capture, verifies the retained index and all remaining files, repairs only that checkout's missing Git link, and recreates only missing captured files without overwriting existing paths. Native non-force Git removal then completes the checkout and branch cleanup. This can temporarily require disk space for the missing files. The snapshot remains available for restore; this command does not retire snapshots or run repository-wide repair/prune.
Stop external editors, terminals, and other unmanaged writers before recovery. Managed consumers stay excluded until finalization; a synchronous byte/mode check admits native deletion without an intervening asynchronous check.
Changed files, foreign paths, live consumers, changed refs/registry ownership, missing original metadata, and an index that differs from the capture stop recovery. Dirty captures, provisioned ignored files, projected workspaces, and exact-state retirements retain their existing recovery owners. Preserve those sources for inspection; this command does not reinterpret them as clean removals. An interrupted recovery can be repeated with the same ID and snapshot after its blocker is resolved. Once checkout deletion is admitted, it is joined without the ordinary Git command deadline so that the timeout cannot interrupt deletion again.
Restore recreates openclaw/<name> at the original pre-snapshot commit, reusing its clean source template when available. Git applies the saved differences as unstaged modifications and untracked files without replacing the template with snapshot contents. Without a reusable template, Git materializes the snapshot directly. Disk admission includes space for changed and added files alongside clone metadata, or the full snapshot for an ordinary checkout. If the snapshot changes .gitattributes or its diff exceeds the bounded inventory size, Git rematerializes all snapshot files with a full-copy space allowance. This applies the snapshot's line endings and filters even to unchanged blobs. The synthetic snapshot stays out of branch history; its ref remains recorded as provenance.
A branch at a shallow history boundary can still be snapshotted and restored. If a later depth-limited fetch makes the snapshot commit itself shallow, Git may no longer resolve its parent. Restore then preserves the snapshot and reports the repository and snapshot commit with git fetch --unshallow guidance. OpenClaw does not deepen automatically: origin may not contain the local snapshot, so even a successful fetch cannot guarantee recovery. If the snapshot remains shallow after fetching, recover its parent from the original repository before retrying.
Retire an already removed snapshot early
Use openclaw worktrees retire-snapshot only when the removed snapshot is redundant
with a retained local branch or remote-tracking commit. This CLI operation
requires the exact worktree ID, snapshot ref and commit, recorded removedAt
milliseconds, and retained source ref and commit. Read those identities from the
removed record and repository before invoking it:
The retained source must be an ordinary branch outside openclaw/* or a
remote-tracking ref. Managed branches expire with their worktrees and cannot
serve as durable source custody after the snapshot's registry row is retired.
Retirement applies only to ordinary snapshots, not exact-state recovery snapshots or their retained checkouts. It requires identical source trees and retained snapshot-parent history. It refuses a live or reappeared checkout, Git registration, changed identity, pending removal, run/removal consumer, unknown or nonempty provisioned-file inventory, or any retained local workspace projection. Git equality does not prove that accepted ignored projection data is redundant. It uses the existing allocation lease and projection owner, then atomically verifies the retained ref and deletes only the expected snapshot ref. It does not create a backup, delete the retained source or PR outcome refs, run global garbage collection, or report reclaimed disk bytes. Git object storage can remain shared after ref retirement.
A successful JSON result is { "retired": true, "id": "<id>" }; the removed
registry entry is then absent and cannot be restored. A refusal is not cleanup
success. If an interruption occurs after the ref is retired, inspect the remaining
record and projection custody before further cleanup; this command does not infer
safe retirement from a missing ref. The CLI uses worktrees.retireSnapshot on a
live same-root Gateway; the Control UI does not expose this action.
Exact-state detached retirement
Ordinary removal, forced removal, and --if-lossless still refuse a detached
HEAD. To retire a deliberately detached managed checkout without changing its
recorded branch or staging state, use an explicit owner-fenced request:
The request contains the current registry owner and lifecycle timestamps from
worktrees list --json, the detached HEAD commit, the recorded branch's commit,
and the SHA-256 of the original Git index bytes. For example:
Use actual observed values, not the example. Omit ownerId for a manual record
without an owner ID. This option cannot be combined with --force or
--if-lossless. A live run lease, foreign Git lock, changed owner/lifecycle, or
changed HEAD, branch, index, or captured files preserves the checkout. It does
not authorize removing another session's active work.
The versioned snapshot keeps the detached commit and separate recorded branch tip, the original index bytes and split-index dependency, and objects referenced only by staging, cache-tree, or resolve-undo state. It saves raw tracked and non-ignored untracked bytes, symbolic links, permission mode bits, and modification times. Ignored-file selection in this snapshot stays unchanged: only the native provisioned-file ledger and staged-input contract preserve eligible ignored files. Object-only recovery does not reproduce filesystem identities such as inode numbers or change times. The recorded branch stays at its original commit.
Exact retirement is archival, not immediate disk reclamation. It moves the
original checkout through native Git to a private recovery name and removes the
live managed-worktree binding. The original checkout and its native registration
remain under the same 30-day recovery retention as the immutable snapshot. The
result includes recoveryPath and recoveryRetainedUntil. This retains writes
from processes that already held a working directory or open file descriptor;
Git index/ref locks alone cannot make deleting those bytes safe. The recovery
path is not an active workspace. Snapshot expiration deletes this retained
checkout and retires its managed branch once no other checkout or recovery owner
needs it, so do not continue working there or treat it as permanent storage.
If branch deletion fails, cleanup records the failure and keeps the registry entry
for retry. A checkout retired because its Git metadata is missing keeps its branch
and registry recovery ownership while source files remain, even after the normal
snapshot retention period.
Exact-state retirement requires a full, non-sparse checkout with Git file refs and supported Git index extensions. It holds native Git index and ref locks while revalidating its index, refs, files, and authority before archival finalization. A validation failure moves the complete checkout back when its original path is still available. Neither move overwrites a recreated source path.
Restore normally moves the retained original checkout back, preserving its index, metadata, ignored caches, and even workfile writes made through old handles after capture. If its HEAD or index changed, restore refuses and preserves both recovery sources. If the retained checkout and its registration are both unavailable, restore instead materializes the immutable snapshot directly from Git objects, without filters, line-ending conversion, or working-tree encoding. That fallback restores only the snapshot's eligible ignored files, not unrelated caches. Both routes restore detached HEAD without replacing the recorded branch. If restore is interrupted after its native move, retry restore: it recognizes only the captured original directory incarnation at the live path and never adopts a recreated replacement directory.
Object-only restoration also keeps a versioned native Git recovery receipt for the newly allocated directory incarnation. It publishes complete files and the original index atomically while native Git locks exclude staging and HEAD writers through registry finalization. Retry the same restore command after an interruption; it resumes only that receipt-owned directory and preserves changed or replacement sources. Publishing the exact index is the restoration commit point: a retry after that point preserves subsequent workfile edits and only finishes registry cleanup. The receipt is cleared after successful finalization. A retry after interrupted snapshot expiration can finish the expired registry entry without guessing the identity of an unknown retained directory.
Snapshots use refs/openclaw/snapshots/exact-v1/<id> and the existing 30-day
retention owner. Keep repository objects, retained recovery checkout, and the
shared-state database together. Use a runtime supporting this option; older
restore implementations cannot preserve the extra index state. Ordinary
snapshots retain their existing behavior.
If the native archival move completes but registry finalization is interrupted, reconcile and restore with the original request:
Recovery requires the matching completed capture and unchanged owner and recorded branch. Recovery holds the existing removal claim while the registry still shows a live row, rejecting active runs and new run admission until it settles. A retry recognizes the captured original directory already moved back; it never adopts an unknown occupied path. An inconsistent source/registration preserves all recovery material and refuses to overwrite it. Listing and garbage collection do not infer completed retirement from the missing original path. Preserve unfinished source and recovery for inspection; do not force another removal, reset the index, reattach HEAD, or prune the registration.
CLI
Human-readable worktree reports escape control characters in displayed values. The records and paths returned by --json are unchanged.
Worktree CLI mutations use the authenticated Gateway that owns the selected local
state directory when one is running. This includes creation, ordinary, lossless
and exact-state removal, restoration, garbage collection, interrupted-removal
recovery, and snapshot retirement. The route requires operator.admin, preserves
source profiles and repository setup, and never redirects local paths to a
configured remote Gateway. Creation binds the captured repository directory;
every mutation binds the request to the current owner's incarnation.
While a Gateway owns the local state, worktrees list inspects the registry through
a read-only worker and leaves its rows unchanged. Missing checkouts appear as
retirement candidates in the table and as IDs in retirementCandidates with
--json; these observations do not authorize deletion. Offline listing retains
exclusive state ownership because it can retire missing checkouts.
Reconciliation waits for each checkout's mutation
lease and rereads its registry record and path before recording retirement, so a
checkout restored while the listing waits remains active.
Each operation requires its own supported parameter and result contract. A Gateway
that supports routed creation can still lack routed removal or recovery. A changed
owner, missing capability, authentication failure, or uncertain reply never triggers
local mutation. Upgrade an older Gateway or stop it through its service owner and
retry offline. After an uncertain reply, inspect worktrees list --json, the source
repository, and any reported recovery paths before retrying. Exact-state JSON files
are validated by the CLI and sent as request data, not as client-local filenames.
Offline mutation holds exclusive state-directory lifecycle ownership through Git work, database settlement, and cleanup, including interruption. A Gateway starting during that operation waits or reports ownership contention. SDK workspace and worktree capabilities retain their existing ownership boundaries; this does not exclude arbitrary direct writers or a different state root sharing external files. The updater and Doctor retain their existing owners and do not require this routing capability to upgrade an older installation. No schema or configuration migration is required.
The local state owner contract lists each required capability, refusal state, and retained writer boundary.
The Control UI Worktrees page under Settings provides creation with a base-branch picker, ordinary removal and restoration, and garbage collection. It 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.
Leave Base branch empty to fetch and use the remote default branch, or the primary checkout's current HEAD commit when no origin remote is configured. Branch suggestions do not select a base; choosing or entering a branch or commit uses that exact ref without fetching. Clearing the field restores automatic selection. Automatic selection also fast-forwards a clean, strictly older local default branch. For repositories with origin, failed fetches use the cached remote default with a warning; unavailable remote defaults require repairing origin or choosing an explicit ref.
--if-lossless --json returns removed plus the recorded cleanup outcome. A retained checkout returns removed: false; it is not a successful deletion. The qualified Gateway removal contract preserves this outcome.
With a running local Gateway, openclaw worktrees gc queues background cleanup and prints its receipt plus a command to inspect progress:
--json prints the receipt, including the job state and current cleanup summary. Polling observes the job without starting another pass. Enqueue requests made while a job is queued or running return that same job; only the latest job is retained, and restarting the Gateway discards its receipt. To force reinspection of unchanged deferred checkouts, start a new job with --retry-deferred after any current job finishes.
Ordinary GC also removes orphaned local openclaw/* branches in repositories
recorded by the worktree registry or pending creation. It preserves branches
attached to any Git worktree, referenced by a live or retained registry record, or
reserved by pending creation. Recovery refs without a matching registry record
preserve all branch candidates in that repository. Other local branches and
remote-tracking refs are outside this cleanup's scope.
Cleanup holds the existing allocation lease and revalidates its live authority immediately before each native Git deletion. Successful deletion counts appear in the worktree log; failures appear in the GC receipt and are retried on a later pass. No new persisted cleanup flag is required: existing recovery records protect their branches until their recovery obligations expire. Repositories with no remaining registry or pending records are not discovered by this sweep.
For partial clones, openclaw worktrees gc --retry-deferred also checks the
objects needed by all Git-registered worktree indexes and current HEAD trees
during repository maintenance.
It fetches missing objects from the existing promisor remote in bounded batches,
preserving staged and working files. Historical commits remain filtered, and
ordinary background maintenance does not fetch. Repair has a five-minute budget
and a 4,096-object limit per pass; completed fetches survive interruption.
Each checkout is inspected separately. The shared state database records the
last attempted checkout, so the next explicit retry starts with its successor
even after a Gateway restart. A slow or unreadable checkout cannot keep later
linked indexes from being repaired. This position only schedules work; it never
certifies object availability or permits checkout removal. Failed checkouts are
revisited on later sweeps, and a completed sweep clears the position.
If repair cannot finish, maintenance logs a warning. Restore remote access and
run the command again to continue. A checkout whose own inventory exceeds the
budget still needs repository repair; locally created objects unavailable from
the remote require recovery from another copy.
Gateway Git inspections also use only locally available objects. In partial clones, missing objects can leave optional checkout, branch, or diff facts unavailable instead of downloading packs during a read. Explicit fetches, checkout preparation, and requested object repair retain their transfer behavior.
UI preferences and other unrelated configuration writes do not interrupt cleanup. Changes to cleanup inputs, such as the worktree root or capacity, agent workspaces, session storage or ownership, and sandbox mode, cancel the current job before its next mutation. Start a new job to use the updated settings.
Without a running local Gateway, openclaw worktrees gc runs cleanup to completion under exclusive local state ownership and returns the completed summary. Offline mode cannot poll Gateway jobs with --job. The CLI includes partial results and recovery locations in its output and exits nonzero for partial cleanup.
An empty or offline --job selector and an unreadable exact-state request report
their specific input error and exit with code 1 before cleanup or removal.
Gateway methods
| Method | Purpose |
|---|---|
worktrees.list |
List active and restorable worktree records. |
worktrees.branches |
List local and remote branches of a repository for base-ref pickers. |
worktrees.create |
Create or reuse a named managed worktree. |
worktrees.remove |
Snapshot and remove a worktree. Forced removals report snapshotError. |
worktrees.restore |
Restore a removed worktree from its snapshot. |
worktrees.gc |
Queue cleanup and read progress. |
worktrees.recoverRemoval |
Complete an interrupted removal from the exact pending snapshot. |
worktrees.retireSnapshot |
Retire one redundant snapshot with exact retained-source guards. |
worktrees.list requires operator.write because it returns every session's worktree paths, repository roots, and branches. worktrees.create and worktrees.branches require operator.write for configured agent workspaces and registered projects; arbitrary host paths still require operator.admin. All creation disables repository Git hooks; write-scoped creation also skips .openclaw/worktree-setup.sh. Removing, restoring, and garbage-collecting worktrees remain admin-only. Branch listing reads existing refs only and never fetches. Unchanged inventories are reused after checking checkout, ref, configuration, and object-storage metadata, including repositories with large pack directories; changed metadata refreshes the inventory. 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.
Owner-routed requests require operator.admin and the corresponding
capability. Their wire
fields and results are:
| Method | Request beyond expectedOwnerId |
Result |
|---|---|---|
worktrees.create |
repoRoot; optional name, baseRef, profiles, expectedRepoIdentity |
Full worktree record, including any gcProtection. The CLI captures the physical repository identity before dispatch. |
worktrees.remove |
id; optional, mutually exclusive force, ifLossless, or exactState |
removed, optional snapshotRef, snapshotError, recoveryPath, recoveryRetainedUntil, and lossless cleanup. |
worktrees.restore |
id; optional recoverExactState |
Full restored worktree record. |
worktrees.gc |
Optional jobId to poll; retryDeferred: true when queuing |
Job receipt. |
worktrees.recoverRemoval |
id, snapshot (the expected pending snapshot OID) |
removed: true, optional snapshotRef. |
worktrees.retireSnapshot |
id, expectedSnapshotRef, expectedSnapshotOid, expectedRemovedAt, retainedSourceRef, expectedRetainedSourceOid |
retired: true, id. |
exactState and recoverExactState carry the validated JSON object, not a file
path: ownerKind (manual, session, or workboard), optional ownerId,
createdAt, lastActiveAt, head, branchHead, and indexSha256. Snapshot and
head OIDs accept 40 or 64 lowercase hexadecimal characters; indexSha256 is 64.
Snapshot retirement also requires an exact removal timestamp and a retained ref
under refs/heads/ or refs/remotes/.
worktrees.gc returns immediately with jobId, state (queued, running,
completed, or failed), startedAt and completedAt (Unix milliseconds or
null), and error (a failure message or null). The same object carries the
cleanup summary: removed, orphansDeleted, orphansRetired,
retiredCheckoutPaths, snapshotsPruned, outcome, issues, issueCount,
protectedCount, protectionReasons, evictions, and limitsSatisfied. While queued or
running, those fields describe progress so far; inspect state to determine
whether the job finished. outcome describes cleanup results (completed,
deferred, or partial), not whether background work is still running.
During repository housekeeping, gitMaintenance names the current or last
repoRoot and stage (packs, objects, maintenance, completed,
suspended, or throttled). It includes packsBefore once inventory is ready
and packsAfter when that repository's bounded pass finishes. packsRemoved
accumulates completed pack reductions across the job. These counts are separate
from checkout eligibility and removal counts. Maintenance failures appear in
issues with stage git-maintenance; a running job's initial outcome is not
proof of completion.
Poll with worktrees.gc and { jobId: "<id>" }. A missing or replaced job returns
an error; only the latest job remains available. Omitting jobId queues a new job
or returns the currently queued/running one. retryDeferred: true requests fresh
inspection when starting a new job; it does not restart an in-flight job.
Old RPC clients that omit expectedOwnerId retain the public record without
gcProtection, the original removal fields (removed, snapshotRef,
snapshotError). For those clients, a snapshot failure returns removed: false
and snapshotError. Owner-routed removal instead reports a snapshot failure as
an error. Garbage collection uses the background receipt for all clients,
including clients that omit expectedOwnerId; it no longer holds a request until
cleanup completes. Clients that relied on the completed-GC response must poll
jobId and check state. Recovery and retirement methods always require the owner
field. A partial or lost result is not permission to replay the mutation.
Workboard workspaces
The bundled Workboard plugin can materialize a card workspace as a managed worktree:
path identifies the source git checkout. branch is optional and becomes 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 need operator.admin for full-host materialization. On run end, Workboard removes the checkout only when it is provably lossless; dirty work or unpushed commits remain available.
A card reuses its retained checkout across dispatches, including its original base ref and local work. If you re-specify the card with a different explicit base ref while that checkout still exists, dispatch reports the mismatch before starting a worker and preserves the checkout. It does not reset or rebase existing work, even when the checkout is clean. Use the original base ref to continue that work, or create a new card to start from a different base. Reusing the same ref, or omitting it, does not refresh the checkout when a branch name advances.
For a workspace-bound caller, path and the repository root must exactly match the target agent workspace. Workboard then runs directly in that directory and records 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.
Shared clone history
Managed project preparation, clone reuse, and refresh warn when the base has
shallow history and continue without automatic repair. The same condition is
visible in openclaw doctor. Run openclaw doctor --fix during a maintenance
window: fetching full history retains blob:none and existing objects, but can
take minutes while holding the project checkout lifecycle lease. Ordinary
preparation never starts that repair. Operator-registered repositories keep
their own history policy.
Doctor fetches the registry's recorded repository URL through the same isolated
transport as managed refresh, ignoring checkout origin, URL rewrites, and
credential helpers. It has no admitted Control UI/Gateway credential context and
does not borrow tokens from configuration or the environment. Authentication
failure leaves history shallow and reports that the operator must use an approved
authenticated unshallow under the checkout lifecycle lease. Git cannot prompt;
the explicit maintenance fetch has a 30-minute timeout. The shallow boundary is
removed only after complete history arrives, with Git's shallow lock held for
the maintenance operation. A shallow upstream leaves the original boundary intact.
Linked worktrees share the base's shallow boundary. Do not run git fetch or
git pull with --depth, --shallow-since, or --shallow-exclude in a managed
base or its linked worktrees. Fetch the required ref without a depth limit;
Git retains the configured blob filter. Git has no repository setting that
prevents an explicit depth fetch, so an already-running agent can still make
the shared clone shallow until an operator repairs it.
Related
- Workboard plugin — cards that materialize a managed worktree
- Configuration reference — where
worktreeRootis set