From jj-concurrent
Orchestrate one (or several concurrent) jj-workspace-worker subagents, each in its own Jujutsu (jj) workspace, to carry out a workload and integrate the result. The workload is either a skill invocation the worker runs via its Skill tool (e.g. "/opsx:apply my-change") or a plain slice spec. Triggers: /jj-delegate, "delegate this to a jj worker", "run <skill> in a jj workspace", "fan out agents on jj workspaces". Requires a jj repo (a .jj directory), ideally colocated with git for PRs. Workflow-agnostic: this skill owns the jj/workspace choreography only — what the worker does is the workload's business.
How this skill is triggered — by the user, by Claude, or both
Slash command
/jj-concurrent:jj-delegateThe summary Claude sees in its skill listing — used to decide when to auto-load this skill
You are the **orchestrator**, working in the **primary (default) jj workspace**.
You are the orchestrator, working in the primary (default) jj workspace.
You own workspace lifecycle, all bookmark/ref operations, jj git push, and
integration. Workers own exactly their own workspace's commits. This skill is
the single- and multi-worker driver for that model.
Substrate knowledge (jj command surface, non-interactive rules, output
formats) comes from the installed jj-vcs skill — defer to it for command
detail; this skill owns only the orchestration.
| Role | Where | Owns |
|---|---|---|
| Orchestrator | primary/default workspace | workspace add/forget, all jj bookmark + jj git push + ref ops, integration, the agent-plan manifest, issue tracker |
| Worker | one jj workspace each | edits + shaping its own commits (jj new/jj describe -m). Never bookmarks, never pushes, never raw mutating git. |
/name or name:subname token (e.g.
/opsx:apply my-change) — the worker invokes it via its Skill tool.feat/<short-slug>
from the workload, matching the repo's branch naming. Surface it in the
confirmation step; do not ask separately.../wt-<short-slug>, derived from the bookmark.Bring the base up to date (jj git fetch if there is a remote), then present
one compact plan — workload, bookmark, workspace, base revision — and wait for
confirmation, exactly as single-agent planning requires.
Choose a clean base revision. jj auto-snapshots EVERYTHING not gitignored
into the current change @, so @ may carry incidental working-tree churn
(local settings, other in-flight work). Do NOT blindly base a worker on a
polluted @. Either base on trunk, or on a curated change that contains
exactly the inputs the workload needs (e.g. a freshly-authored OpenSpec change
folder — see the jj-openspec binding). There is no seed-commit ceremony
(jj has no untracked-file limbo), but you MUST point the workspace at the
revision that contains the inputs:
jj workspace add -r <base-rev> ../wt-<slug> # -r is required; default would
# base on @'s PARENT and miss inputs
jj bookmark create <bookmark> -r @- # create the worker's bookmark
# (orchestrator owns all bookmarks)
Per-workspace environment is real: each workspace is its own directory, so
install dependencies / copy gitignored env files the workload needs
(cp .env.local ../wt-<slug>/ etc.). If the workload runs the app, assign it
a distinct port and put that in the dispatch brief.
Write the manifest .jj-agent-plan.json at the repo root (gitignored) with
the slice(s): bookmark, workspace, base-rev, status, workload.
Spawn jj-workspace-worker subagent(s) (NOT the harness isolation: worktree
option — the jj workspace IS the isolation). Each prompt MUST include:
<name>
and args <args>."; for spec form: the slice spec verbatim;Dispatch in the background by default (run_in_background: true): control
returns to the user immediately and you reconvene on the completion
notification. While a background worker runs, the user may dispatch MORE
workers — concurrent workspaces are the whole point. Provisioning always
serializes through you (the orchestrator); the workers run in parallel.
Foreground only when the user asks to wait or for a deliberate validation run — warn that it blocks the session and that the worker's inline tool activity is not the orchestrator doing the work.
jj makes this the easy part — integration never halts.
jj log --ignore-working-copy --no-pager)./opsx:verify — over ad-hoc review).jj resolve), then push: jj git push -b <bookmark> (or open a
PR with gh).jj workspace forget <workspace-name>
rm -rf ../wt-<slug> # the directory only — NEVER the repo .jj
Update then delete the manifest entry.Invoking jj-delegate again while a background worker runs is fine for
INDEPENDENT slices: provision the new workspace + bookmark off trunk, add it to
the manifest, dispatch. Each worker reconciles as it reports. Because jj
integration never halts and ops are lock-free, there is no prune-before-
restack barrier to wait on (unlike git worktrees) — but mind staleness:
do not move a revision that another live workspace builds on. If a workspace
goes stale, the fix is jj workspace update-stale in that workspace, not a
failure.
blocked_on → leave its workspace intact for inspection,
relay the blocker. Never resolve cross-workspace conflicts in its name.jj log -R ../wt-<slug> --ignore-working-copy --no-pager and
jj evolog..jj; jj op log/jj op restore is the
recovery surface, orchestrator-only.jj log does not auto-snapshot sibling workspaces, so a plain log can show
stale state. Before reasoning about cross-workspace status, snapshot each live
workspace first (e.g. loop jj -R <ws> util snapshot over the manifest's
workspaces), THEN jj log. Keep the operation log short; abandon dead
experiments.
Creates, edits, and optimizes skills for Claude Code, including drafting, evaluating with test prompts, iterating on performance, and improving skill descriptions for better triggering accuracy.
npx claudepluginhub dannygoodall/claude-code-jj --plugin jj-concurrent