Skip to main content
Smithers integrates with JJ (Jujutsu) and Git to record filesystem snapshots at each task completion. This enables reverting to the exact workspace state after any attempt.

VCS Detection

Smithers walks up the directory tree from rootDir looking for .jj or .git. When both exist in the same directory (a colocated repo), Smithers prefers .jj and uses JJ semantics. Pure Git repos work without JJ installed.

VCS Pointer Flow

When a supported VCS is detected:
  1. A task executes, making filesystem changes via agent tools.
  2. The task completes (success or failure).
  3. Smithers captures the current revision into _smithers_attempts.jj_pointer:
    • JJ: the change ID from jj log -r @ --template change_id
    • Git: the commit SHA from git rev-parse HEAD
  4. The next task continues from this point.
Each attempt gets its own pointer. The revision is also recorded on the run row as vcs_revision so Smithers can detect workspace drift between a run’s start and a later resume — if the revision changed, the engine warns of a potential durability mismatch.

Recorded Data

ColumnTypeDescription
jj_pointertext (nullable)JJ change/operation ID after attempt completion. null if JJ unavailable.
sqlite3 smithers.db "SELECT run_id, node_id, iteration, attempt, jj_pointer FROM _smithers_attempts WHERE run_id = '<id>';"
smth_a1b2|analyze|0|1|zqkopwvn
smth_a1b2|fix|0|1|xrlmqkts
smth_a1b2|fix|0|2|ynpwzrmv
smth_a1b2|report|0|1|kutswxqp

Revert

smithers revert workflow.tsx \
  --run-id <run-id> \
  --node-id <node-id> \
  --attempt <attempt-number> \
  --iteration <iteration-number>
smithers revert workflow.tsx --run-id smth_a1b2 --node-id fix --attempt 1 --iteration 0
Restores the filesystem to the exact post-attempt state. Emits RevertStarted and RevertFinished events.

Without VCS

  • jj_pointer is null for all attempts.
  • revert fails with an error.
  • All other Smithers functionality is unaffected.
JJ is optional. Install only if revert support is needed. Git-only repos also provide pointer tracking and worktree support without JJ.

Setup

brew install jj
# New JJ repo
cd /path/to/my-project
jj git init

# Colocate with existing Git repo
jj git init --colocate
Smithers auto-detects JJ and starts recording pointers.

Programmatic Helpers

Smithers exports helpers for running raw jj commands, checking repo status, reading/restoring pointers, and managing JJ workspaces. See VCS Helper Reference.

Worktrees

Smithers can isolate each workflow run in its own worktree (a separate checkout sharing the same object store). This lets multiple runs modify the filesystem concurrently without stepping on each other.

Git Worktrees

When rootDir points to a Git repository, Smithers calls git worktree add to create a new working tree at worktreePath. A named branch (-B) is created from the best available base ref:
  1. baseBranch (if configured)
  2. origin/<baseBranch>
  3. main / origin/main
  4. HEAD
It tries each in turn and uses the first that succeeds.

JJ Workspaces

For JJ repos, Smithers calls workspaceAdd to create a JJ workspace at worktreePath. When a branch is supplied, it runs jj bookmark set <branch> -r @ to point a bookmark at the new workspace’s working copy. You can create a workspace at a specific revision:
import { workspaceAdd } from "smithers-orchestrator/vcs";

await workspaceAdd("feature-fix", "/workspaces/feature-fix", {
  cwd: "/my-repo",
  atRev: "main",   // start the workspace at the tip of main
});
workspaceAdd tries multiple invocation styles (jj workspace add --name, positional, --wc-path) to stay compatible across JJ versions. Stale workspaces with the same name are forgotten before creating a new one.

Rebase on Resume

When Smithers resumes a workflow that already has a worktree, it syncs the worktree to the current tip of the base branch before continuing:
  • JJ: jj git fetch then jj rebase -d <base>
  • Git: git fetch origin then git rebase origin/<base>
If the rebase fails, Smithers logs a warning and continues anyway — the resume is not blocked. The base branch defaults to main when no baseBranch is configured.

Running Workflows at a Specific Revision

When a run is started, Smithers records the current VCS revision (vcs_revision on the run row). On resume, it checks the current revision against the stored one. A mismatch emits a warning but does not block the resume. This revision snapshot is available in the database:
sqlite3 smithers.db "SELECT run_id, vcs_type, vcs_root, vcs_revision FROM _smithers_runs WHERE run_id = '<id>';"

JJ Operation ID Tracking

For JJ repos, the pointer stored in jj_pointer is the JJ change ID (the stable identifier that persists across amends and rebases), not the operation ID. This means:
  • The pointer survives jj amend, jj rebase, and other history-rewriting commands.
  • jj restore --from <change_id> reliably restores the working copy to the exact post-attempt state.
The change ID is read via jj log -r @ --no-graph --template change_id.

Cache Key Integration

VCS pointers are included in the cache key when caching is enabled (<Workflow cache> or { cache: true }):
Component
Workflow name + nodeId
Prompt text or static payload
Model ID and parameters
Tool allowlist and versions
Output schema signature
VCS pointer (JJ change ID or Git SHA)
Workspace changes invalidate cached results. Returning to a previous state (same pointer) reuses the cached result.

Next Steps