Claude Code plugins for jj (Jujutsu) workflows — project setup, workspace isolation, commit management, peer review, and a hard wall against raw git.
These plugins are for people who have chosen jj (Jujutsu) and want their coding agents to stay on it. They are opinionated and jj-only by design: the jj plugins install hard walls, not gentle reminders. If you're git-first, or want something neutral between the two, this isn't it.
LLM agents have a strong reflex toward git. It dominates their training data, so git add / git commit / git status are what they reach for automatically — often mid-task, even when the project explicitly specifies jj, and even when the agent agrees jj is the better choice. A written rule like "use jj, not git" is a suggestion the model can rationalize past a moment later.
So enforcement sits below the level the model can argue with. A PreToolUse hook (block-raw-git.sh) registered by project-setup-jj and peer-review-jj intercepts every Bash call, blocks raw git, and hands back the jj equivalent — turning a reflexive git commit into a redirect the agent recovers from. The two deliberate exceptions are jj git subcommands (e.g. jj git push) and the gh CLI, the legitimate git-interop seams.
All jj output commands (jj log, jj diff, jj bookmark list, jj op log, jj workspace list, jj show, jj evolog, jj op show, jj config list, jj tag list) use JSON templates (-T 'json(self)') by default, giving Claude Code structured, machine-parseable output instead of human-readable text. Requires jj >= 0.31.0.
| Plugin | Description | Commands | Agents |
|---|---|---|---|
| project-setup-jj | Bootstrap jj workflow enforcement with /project-setup |
1 | — |
| workspace-jj | Worktree isolation for jj repos via jj workspace hooks |
2 | — |
| commit-commands-jj | jj commit workflows — commit, push, PR creation, and more | 16 | — |
| peer-review-jj | Unified change review — generalist-first with emergent specialists | 1 | 1 |
Bootstrap jj workflow enforcement for any project with a single command. Sets up a SessionStart hook (shows jj context each session), a PreToolUse guard hook (prompts jj new before editing non-empty changes), permissions (allow jj/gh, deny git), and a CLAUDE.md policy directive.
Setup:
# 1. Install from plugin manager
/plugin install project-setup-jj@muloka-claude-plugins
# 2. Run setup in your jj project
/project-setup
# 3. Restart Claude Code for SessionStart hookEnables Claude Code's --worktree flag and subagent isolation: "worktree" in jj repositories. Claude Code uses git worktrees by default for isolated parallel sessions — this plugin replaces that with jj workspaces via WorktreeCreate and WorktreeRemove hooks, so --worktree works natively in jj repos.
Setup:
# 1. Install from plugin manager
/plugin install workspace-jj@muloka-claude-plugins
# 2. Run setup in your jj project (copies hook scripts, configures settings)
/project-setup
# 3. Restart Claude Code, then use worktrees
claude --worktree feature-authClaude Code doesn't pick up WorktreeCreate/WorktreeRemove hooks from plugins — they must be in project settings. /project-setup (from project-setup-jj) handles this: its installer copies the hook handlers to .claude/hooks/ and registers them in .claude/settings.local.json. There is no separate /workspace-setup command — it was folded into /project-setup so one command installs every jj hook.
Streamline your jj commit workflow with simple slash commands.
Commands: /commit, /commit-push-pr, /new, /edit, /describe, /squash, /abandon, /sync, /undo, /finish, /clean_stale, /show, /evolog, /op-show, /tag-list
Unified change review for jj repos. Two-phase pipeline (requesting → receiving) with generalist-first architecture and emergent specialists.
Command: /peer-review
/peer-review # review current change (@)
/peer-review <revision> # review specific change
/peer-review --deep errors types # generalist + specialist dispatch
/peer-review --track # enable progress tracking (duplicate+squash)
/peer-review --post # post findings to GitHub PR
/peer-review --json # raw structured output
Agent: change-reviewer — generalist reviewer that scales with change size (1 per ~300 lines). Returns structured JSON findings with severity tiers and confidence scoring (>= 80 threshold). Recommends specialists for deeper analysis when needed.
Specialist emergence: After 3+ reviews flag distinct patterns for a concern type, the plugin prompts to create a project-specific specialist at .claude/peer-review/specialists/.
Replaces the deprecated code-review-jj, pr-review-toolkit-jj, and feature-dev-jj plugins. See design doc for full details.
Add the marketplace and install plugins via the plugin manager:
/plugin marketplace add muloka/claude-plugins
/plugin install peer-review-jj@muloka-claude-plugins
Or browse available plugins:
/plugin
Note: After installing workspace-jj, run /project-setup in your jj project and restart Claude Code — that is what installs the WorktreeCreate/WorktreeRemove hooks into project settings.
Two verification layers cover this repo, doing different jobs:
| Layer | Question it answers | Where | Gating |
|---|---|---|---|
| 1 — evals | Does a plugin change what the model does? | plugins/<name>/evals/<case>/ |
none — run by hand |
| 2 — shell tests | Do the scripts behave, and does the prose still describe reality? | plugins/<name>/tests/test-*.sh, .github/tests/ |
CI, every push |
Layer 2 is the gate. It covers two distinct questions, and the second one is easy to overlook: besides asserting that scripts behave, it asserts that the command prose has not rotted. Prose fails silently — a command file still reads authoritatively while naming a flag jj removed, or describing behaviour jj no longer has, and nothing surfaces it until a user is misled. Two suites in plugins/commit-commands-jj/tests/ do that job: test-command-invocations.sh runs or --help-checks every jj invocation the 16 commands contain, and test-command-prose-claims.sh asserts the jj behaviours the prose claims by exercising them in throwaway repos.
The eval suite gates nothing — it is a measurement instrument, run deliberately, to answer what a deterministic test cannot: whether the prose and hooks a plugin ships actually move model behaviour. Each case runs under --ablation with-without (plugin loaded vs. not), and the delta between the two arms is the result. A case whose arms score the same measured nothing, however green it looks. For hooks that works and is demonstrated below; for command prose it does not — see the limit in Measured results before writing a command case.
# free — list the cases that would run, and print the CLI invocation
/bin/bash .github/scripts/run-evals.sh --discover-only
/bin/bash .github/scripts/run-evals.sh --plugin commit-commands-jj --dry-run
# paid — actually run them (spends model tokens; see below)
/bin/bash .github/scripts/run-evals.sh --plugin commit-commands-jj --runs 2Run from the repo root — running elsewhere exits 3 rather than dying on a stray find error. Useful flags: --case <glob> scopes to one case, matched against the case's name: field exactly as the CLI matches it (a case that declares no name defaults to its directory basename); --gate report downgrades NO_GAP/PARTIAL from failures to findings; --max-cost-usd caps spend (default 5); --keep-temp keeps the sandboxes. --allow-tools accepts a comma- or space-separated list and forwards each tool separately. A --plugin/--case combination that selects no case exits 3: scoped-to-nothing is not a clean run. Verdict rows go to stdout as TSV; everything else, including the result-JSON path, goes to stderr.
Three independent reasons, any one of which is sufficient:
- Early access.
claude plugin evalsits behindCLAUDE_CODE_WALNUT_SPIRE=1, which the runner sets on every invocation. That requirement was measured on CLI 2.1.216; by 2.1.220,plugin eval --helpexits 0 with the variable unset. Setting it stays harmless either way, so the runner keeps doing so — but no logic may treat "exits 1 without the variable" as gate detection. That signal has already drifted once. - Model spend. Every run costs real money — per case, per arm, per run. Tranche 1 cost $3.77 in total. A per-push CI job would bill this repo for every typo fix.
- No entitlement guarantee on runners. Nothing guarantees a CI runner can obtain the same early-access entitlement the local operator has, and the suites are macOS/bash 3.2 to begin with.
The runner emits one TSV row per case — name / score / score_without / delta / verdict:
| Verdict | Condition | Means |
|---|---|---|
DISCRIMINATING |
Δ ≥ 0.5 | the plugin measurably changes behaviour; the case earns its keep |
PARTIAL |
0 < Δ < 0.5 | some effect — check attribution grader-by-grader before believing it |
NO_GAP |
Δ = 0 | both arms did equally well: the case cannot discriminate. Move the assertion to layer 2 |
REGRESSION |
Δ < 0 | the plugin made things worse. Fails in both gate modes |
BROKEN |
both arms scored 0.00 | the harness failed, not the plugin |
Δ comparisons carry a 1e-9 tolerance. The CLI computes the delta by subtraction, so a case scoring 7/10 with and 2/10 without arrives as 0.49999999999999994; without the tolerance a textbook shipping case at exactly the threshold is filed PARTIAL and fails CI.
BROKENnever means "no gap". Both arms scoring zero is the signature of a case that could not run at all — nearly always a gated tool the case declares that--allow-toolsdoes not grant, leaving the agent unable to call it in either arm. Misread as "no difference between the arms", it deletes the best case in the suite. The runner also checks this before spending and exits 7 — for both case layouts, both YAML forms, and whatever--caseactually selects. Other non-zero exits: 3 nothing measured (no cases discovered, none selected, or none returned), 4 gate failure, 5 result-schema drift, 6 budget-truncated run, 64 bad argument or bad--gate(rejected before spending), 65 missing or malformed result file.
Tranche 1 (issue #79) is written up in docs/eval-triage-2026-07.md — what shipped, what was cut and why, and three runner gaps found but left unfixed. Two cases ship today, both under plugins/commit-commands-jj/evals/, both at Δ +1.00, and they now exercise different branches of block-raw-git.sh. hook-blocks-git-internals did not: its name promised the internals branch while its git rev-parse HEAD prompt was answered by the raw-git branch, which returns first (§1.1). Issue #103 repointed it at a dot-git path, narrowed its grader to wording the raw-git branch cannot produce, and re-measured at Δ +1.00 — so the triage document's §1.1 finding is resolved, not still open. A third case measured Δ 0.00 and was cut; its assertions now live in plugins/project-setup-jj/tests/test-block-raw-git.sh, where they are deterministic and free.
Tranche 2 is written up in docs/eval-command-triage-2026-07.md, and its headline is a negative result worth knowing before spending anything.
Both shipped cases exercise a hook. No eval case can measure a commit-commands-jj command. Under this harness the plugin's commands register as slash_commands contributing zero skills, and SlashCommand is not grantable — so the command's prose never enters the model's context and every case reads NO_GAP by construction, whatever the prose says. The obvious unblocking (ship the commands as skills) was refuted by measurement, not merely untried: they are already Skill-invocable in a real session, and fresh agents given a natural-language task ignored them anyway. Issues #104 and #133 are closed on that basis.
What works instead is cheaper and needs no harness: dispatch agents at throwaway repos, grade from repo state rather than from what the agent narrates, and pin each finding as a mutation-tested assertion in layer 2. That route found and fixed real defects in finish.md (#137) and abandon.md (#139).
One further measurement shapes how much any command-prose fix is worth: a command auto-invokes roughly 1 request in 6, and the rate tracks how closely the request's wording matches the command's description: field. A command whose prose is perfect but which never fires contributes nothing.
Where coverage actually stands — which plugins are prose-linted and which are not, why prose is a ~1-in-6 mechanism, the three staleness layers and the ordering trap that reinstalls a fixed bug — is mapped in docs/plugin-coverage-map-2026-08.md. Start there when deciding where to spend testing effort.
Read both triage documents before authoring a case. Tranche 1's §3 is the prompting-and-grading recipe that was measured to work; its §2 is three separate mechanisms that make a case report green while measuring nothing. Tranche 2's §2 and §7 carry the command-prose limit above and the instrument constraints behind it.
Failure taxonomy informed by netresearch/jujutsu-workflow-skill (MIT AND CC-BY-SA-4.0); cases independently authored.
This repo started as a fork of Anthropic's claude-plugins-official and has evolved through two phases:
Phase 1: jj translations — Replaced Anthropic's git-based plugins (commit-commands, code-review, feature-dev, pr-review-toolkit) with jj-native equivalents. Same capabilities, different VCS.
Phase 2: jj-native capabilities — Built features that leverage jj's model in ways git can't easily support. Lightweight workspaces for parallel subagent isolation (fan-flames), first-class conflicts for multi-workspace merging, automatic working-copy snapshots eliminating the commit/stage ceremony, and operation-log-based undo for safe experimentation. These aren't ports of git workflows — they're new patterns that emerge from jj's architecture.
| Category | This repo | Anthropic original |
|---|---|---|
| VCS | jj (Jujutsu) — all plugins enforce jj-only | git |
| Commits | commit-commands-jj — jj-native with revsets, bookmarks, operation log |
commit-commands — git add/commit/push |
| Code review | peer-review-jj — generalist-first, emergent specialists, structured findings |
code-review — single-pass review |
| Workspace isolation | workspace-jj — jj workspaces via WorktreeCreate/Remove hooks |
Not provided (git worktrees are built-in) |
| Raw-git enforcement | block-raw-git.sh — PreToolUse wall denying git at any shell command position |
Not provided |
| Project setup | project-setup-jj — jj workflow enforcement, statusline, SessionStart hooks |
Not provided |
Removed from original: code-review, commit-commands, feature-dev, pr-review-toolkit — replaced by jj-native equivalents above.
Net new (no upstream equivalent): workspace-jj, project-setup-jj, the raw-git wall, kaisen skill.
See each plugin directory for the relevant LICENSE file.