Skip to main content
JSX API — This page documents the JSX-based API. For alternative approaches, see TOON (declarative) or the Effect builder (TypeScript).

Import

import { Worktree, Task, Parallel, MergeQueue } from "smithers";

Props

PropTypeDefaultDescription
idstringauto-generatedOptional stable id for tracking and deduping.
pathstringFilesystem path for the JJ workspace root. Required; non-empty.
branchstringundefinedGit/JJ branch name to check out in the worktree. When omitted, the worktree uses the current branch.
skipIfbooleanfalseSkip the subtree when true.
childrenReactNodeNested tasks and control-flow nodes.

Basics

<Worktree path="/tmp/smithers/wt-a">
  <Task id="build" output={outputs.outputC}>{{ value: 1 }}</Task>
  <Task id="test" output={outputs.outputC}>{{ value: 2 }}</Task>
  <MergeQueue>
    <Task id="apply" output={outputs.outputC}>{{ value: 3 }}</Task>
  </MergeQueue>
  <Parallel maxConcurrency={2}>
    <Task id="lint" output={outputs.outputC}>{{ value: 4 }}</Task>
  </Parallel>
  <Task id="package" output={outputs.outputC}>{{ value: 5 }}</Task>
  <Task id="release" output={outputs.outputC}>{{ value: 6 }}</Task>
</Worktree>
All descendant tasks within the <Worktree> receive worktreeId and a normalized absolute worktreePath in their task descriptors. The engine uses this worktreePath as the cwd for JJ operations and as the task root when executing tools.

Path Resolution

  • Relative path values resolve against the workflow’s base directory (engine baseRootDir when provided, otherwise process.cwd()).
  • Absolute paths are preserved and normalized.
  • Empty or whitespace-only path is rejected: <Worktree> requires a non-empty path prop.

Nesting

Nested <Worktree> components are supported. The innermost worktree in scope for a task determines its effective worktreeId/worktreePath.
<Worktree id="outer" path="/tmp/wt-outer">
  <Task id="a" output={outputs.outputC}>{{ value: "outer" }}</Task>
  <Worktree id="inner" path="./nested">
    <Task id="b" output={outputs.outputC}>{{ value: "inner" }}</Task>
  </Worktree>
</Worktree>

With Parallel and MergeQueue

Worktrees compose with concurrency primitives. For example, queue serialized patch application inside a dedicated workspace:
<Worktree path="/tmp/wt-queue">
  <MergeQueue>
    {prs.map((pr) => (
      <Task key={pr.id} id={`apply-${pr.id}`} output={outputs.outputC}>
        {{ value: pr.id }}
      </Task>
    ))}
  </MergeQueue>
</Worktree>

Rendering Internals

  • Renders to a <smithers:worktree> host node.
  • Extraction assigns worktreeId and worktreePath to every descendant task descriptor.
  • The scheduler remains unaware of worktrees; the engine consumes these fields to scope JJ operations and reverts.

Notes

  • Duplicate id values are rejected.
  • Prefer absolute, ephemeral paths for isolation when running CI.
  • Relative paths aid portability for local development.