bunx smithers-orchestrator graph):
cwd unset so <Worktree> supplies the isolated working directory (see Notes).
Path Access
Workflow code can read the same resolved absolute worktree path Smithers uses for task execution:ctx.worktreePath(taskOrWorktreeId) once a task descriptor or explicit <Worktree id>
has rendered; use ctx.resolveWorktreePath(pathProp) for the same string passed to
<Worktree path={...}>, including on the first render before descriptor lookups exist.
Both use the graph resolver, so they match the path Smithers gives worker tasks.
Notes
- Descendants inherit
worktreeIdand absoluteworktreePathascwd. - Do not pin a
cwdon an agent used inside a<Worktree>. A worker agent’s working directory resolves asagent.cwd ?? worktreePath ?? repoRoot, so an explicitcwd(e.g.new ClaudeCodeAgent({ cwd: process.cwd() })) overrides the worktree: the agent then reads and writes the repo root instead of the isolated worktree, its branch stays empty, and a downstream merge/land step has nothing to merge. Leave agentcwdunset and let<Worktree>supply it. Likewise, helpers touching a worktree’s files must usectx.worktreePath(...)orctx.resolveWorktreePath(...), never reconstructing paths withprocess.cwd(),import.meta.dir,../.., or fallback candidate lists. - jj-backed worktrees include colocated git metadata, so git-native CLI agents such as Codex
already resolve the worktree directory as their repository root. Don’t set
cwdto compensate: that’s the isolation break described above. - Dependencies are not installed in a fresh worktree. Agent tasks inside a
<Worktree>get a[smithers worktree isolation]prompt preamble: do all work inside the worktree, install dependencies fresh there (e.g.pnpm installat the worktree root), and never symlink node_modules from, or write into, the parent checkout. An install through a shared node_modules link rewrites the parent checkout’s workspace links to point into the worktree, all of which dangle once the worktree is removed. - jj continuously snapshots a worktree’s working copy onto its bookmark. A compute
<Task>(or helper) that checks for changes withgit status --porcelaincan see a clean tree and skip its work, because jj has already committed the working-copy edits to the bookmark, andgit checkout/git restorewon’t stick either, for the same reason (jj re-materializes it). Detect changes by diffing against the base branch (jj diff --from <baseBranch> --to @, orgit diff <baseBranch>...HEAD) instead of relying on git’s dirty-state, and let the merge/land step operate on the committed bookmark rather than re-runninggit add/git commit. - Innermost
<Worktree>wins when nested; duplicate ids are rejected. - Empty/whitespace
pathis rejected at render time. - A relative
pathresolves against the launch root, never the workflow file’s directory (workflowPathis threaded through render separately and isn’t used as the path base). The launch root is--rootif given, else the nearest ancestor of the operator working directory containing a.smithers/package, else the operator working directory. A relativepathlikewt-alands beside wherever you ranbunx smithers-orchestrator up <path>from, which can differ from where the workflow source lives; Smithers emits a one-time warning for relative worktree paths showing the base and resolved absolute path. Pass an absolutepath(e.g./tmp/smithers/wt-a) for a deterministic location, and read back the resolved location withctx.worktreePath(...)orctx.resolveWorktreePath(...)rather than reconstructing it.