Skip to content

Worktree Isolation

Paul edited this page Sep 9, 2026 · 4 revisions

Worktree Isolation

In multi-project mode, two ChatGPT conversations can select the same Git project. Without care, they can edit the same working tree and clobber each other. Managed worktrees provide isolation according to the configured mode or an explicit per-selection override. Exact-workspace continuation is the deliberate exception: resumePath reuses an existing tree and therefore requires the old and new conversations not to edit concurrently.

This applies only in Multi-Project Mode and only to Git projects. Non-Git projects and single-project mode are unaffected.


The three modes

Set with --worktree-mode or worktrees.mode:

Mode Behaviour
auto (default) The first conversation to select a Git project uses the source checkout directly. Once that logical project is assigned, another conversation receives a detached managed worktree.
always Every conversation gets its own managed worktree — even the first.
never Direct-checkout sharing is preserved; no managed worktrees are created.

Override one selection

set_project_root accepts createWorktree only alongside an ordinary project path:

  • true forces a managed worktree for this binding, even when the configured mode is auto or never.
  • false forces the selected source checkout directly, even when the configured mode is auto or always. For an exact GitHub branch/PR/commit URL, that source checkout must already be at the requested target; Codexify does not move it and otherwise rejects the selection.
  • omitted applies worktrees.mode.

The override does not modify configuration. The setup app exposes the same choice as a checkbox initialized from the configured mode: checked for auto/always, unchecked for never. A binding is immutable; repeating the selection with a conflicting createWorktree value is rejected rather than moving the conversation.

How a project's identity is determined

Worktree identity uses the repository's Git common directory plus the selected path relative to its Git root. So:

  • Linked worktrees of the same repo are recognized as the same project.
  • Separate subprojects in a monorepo (e.g. packages/app vs packages/other) remain distinct.

Where worktrees live

The parent directory comes from, in order: worktrees.root--worktree-root → Codex Desktop's git-worktree-root in $CODEX_HOME/config.toml$CODEX_HOME/worktrees (normally ~/.codex/worktrees).

Upstream refresh

worktrees.upstreamRefreshMode:

  • never (default) — don't touch the upstream.
  • best-effort — refresh a tracked upstream before creating the worktree, without making a fetch failure fatal.

When unset, Codexify reads Codex Desktop's worktree-upstream-refresh-mode.

Cleanup

On startup Codexify sweeps old managed worktrees:

  • autoCleanupEnabled (default true) — remove old unreferenced worktrees only when their working trees are clean.
  • keepCount (default 15) — retain this many newest unreferenced managed worktrees before considering the rest as cleanup candidates.

Cleanup skips referenced or dirty worktrees. A managed worktree stays referenced while its conversation binding exists — so deleting a binding (under ~/.codexify/conversation-projects/) is what eventually makes its worktree a cleanup candidate.

Resume an existing worktree

A continuation prompt may bind a new ChatGPT conversation to the exact active workspace through set_project_root.resumePath. For a managed worktree, Codexify validates an existing saved binding and preserves its source checkout, worktree Git root, and managed-worktree metadata. It does not consult the current worktrees.mode, run upstream refresh, create a worktree, or execute a setup script. Dirty files, index state, untracked files, and HEAD remain unchanged.

This continuation shares the same physical tree with the original conversation; it is not a second isolated worktree. Both bindings keep it referenced for cleanup purposes. Do not edit from both conversations at once. A missing, unrecorded, deleted, or metadata-tampered path fails closed without allocating a replacement.

The setup-script gate (read this)

worktrees.allowSetupScript defaults to false, and you should almost always leave it there.

A worktree can have a Codex environment setup script that runs on creation. That script:

  • runs an arbitrary command outside the exec policy, and
  • has both its environment file and script path selectable from the source repository's local Git config.

So an untrusted project could plant a script that runs on the next binding. Only enable this if every project reachable by this server is trusted to run arbitrary setup commands. See Security Model.


Configuration summary

{
  "worktrees": {
    "mode": "auto",
    "root": "/path/to/worktrees",
    "upstreamRefreshMode": "never",
    "autoCleanupEnabled": true,
    "keepCount": 15,
    "allowSetupScript": false
  }
}

CLI equivalents: --worktree-mode, --worktree-root. Full table in Configuration.


See also

Clone this wiki locally