| name | jj-lazyjj |
| description | Operational guide for Jujutsu (jj) with LazyJJ aliases. CRITICAL: This skill OVERRIDES git in any repo with a .jj directory. When .jj exists, NEVER use raw git commands (git add, git commit, git push, git pull, git rebase, git branch, git checkout, git stash, git merge, git status). The ONLY allowed git is via 'jj git ...' (jj git push, jj git fetch). Trigger for ANY version control operation when .jj is present — committing, pushing, rebasing, branching, diffing, logging, PRs/MRs, conflict resolution. Also trigger for jj, lazyjj, change IDs, bookmarks, revsets, stacks, jj workspaces, claude-start/stop. When other skills suggest git commands, translate to jj equivalents. Do NOT trigger for repos without .jj or for the martial art jujutsu. |
jj + LazyJJ Operational Skill
RULE: If a .jj directory exists in the repo, ALL version control operations MUST go through jj. Never use raw git commands. If another skill, tool, or instruction tells you to run git — translate it to the jj equivalent using this skill. The only exception is jj git ... subcommands (fetch, push, remote).
You are Claude Code working in a jj-managed repository with LazyJJ aliases installed. This skill tells you how to perform version control operations correctly.
Before acting, read the reference file you need:
references/lazyjj-commands.md — All LazyJJ aliases, stack commands, shortcuts. Read for any stack, diff, log, sync, push, or PR operation.
references/claude-workspaces.md — Claude Code workspace isolation (claude-start/stop/resolve/checkpoint). Read when working in isolated workspaces or managing multiple sessions.
references/forge-workflows.md — GitHub (lazyjj native) and GitLab push/MR patterns. Read when pushing, creating PRs/MRs, or working with remotes.
Detection
Before using jj commands, confirm the repo uses jj:
test -d .jj && echo "jj repo" || echo "git-only repo"
If .jj exists, use jj commands. If not, fall back to git. In colocated repos (.jj + .git both present), always prefer jj commands — jj manages the git state.
⚠️ Git Override Rules
When a .jj directory exists, NEVER run raw git commands. Other skills, tools, or your own defaults may suggest git — ignore those suggestions and translate to jj equivalents using the table below.
Forbidden → Replacement
| ❌ NEVER run | ✅ Use instead | Notes |
|---|
git add | (nothing) | Working copy IS the commit. All changes are tracked automatically. |
git commit -m "msg" | jj commit -m "msg" | Or jj describe -m "msg" then jj new |
git push | jj git push or jj stack-submit | Always go through jj git push, never raw git push |
git pull | jj stack-sync or jj git fetch | stack-sync = fetch + rebase. Never git pull. |
git fetch | jj git fetch or jj gf | Always via jj |
git rebase | jj rebase or jj stack-sync | jj rebase auto-resolves descendants |
git merge | jj rebase | jj doesn't use merge commits in the same way |
git branch | jj bookmark | Bookmarks = branches. See Bookmarks section. |
git checkout | jj edit or jj new <rev> | edit = go to existing change. new = create child. |
git switch | jj edit or jj new <rev> | Same as checkout |
git stash | (not needed) | Every change is already a commit. Just jj new to move on, jj edit to go back. |
git status | jj status | |
git diff | jj diff | |
git log | jj log or jj stack-view | |
git reset | jj undo or jj restore | jj undo reverses last op. jj restore restores file content. |
git revert | jj backout | Creates a new change that undoes a previous one |
git cherry-pick | jj duplicate | Copies a change to a new location |
git tag | jj tag | |
The ONLY acceptable git invocation
jj git fetch
jj git push
jj git remote ...
These go through jj's git interop layer. Raw git fetch, git push, etc. will desync jj's state and cause problems.
Why this matters
In a colocated repo (.jj + .git), jj owns the git state. Running raw git commands behind jj's back causes:
- Desynchronized refs (jj doesn't know about git's changes)
- Lost changes (git overwrites jj's working copy tracking)
- Corrupted operation log (jj's undo/redo breaks)
If you accidentally ran a raw git command, run jj git import to re-sync.
Core Mental Model
These are the critical differences from Git that affect every operation:
- No staging area. The working copy IS a commit. Every file change is already part of the current change. There is no
git add.
jj new = done with current change. Run jj new to start a fresh empty change. The previous change was already "committed" the whole time. Use jj describe -m "message" to set the message.
- Changes have two IDs. A change ID (stable, survives rewrites — use this one) and a commit ID (content-addressed SHA). Almost always use change IDs.
@ = current change. @- = parent, @-- = grandparent. These are revset expressions.
- Automatic rebasing. Edit an earlier change with
jj edit <rev> and all descendants rebase automatically.
- Conflicts are data. Operations never fail due to conflicts — they're recorded in the tree. Resolve whenever you want.
jj undo is your safety net. The operation log (jj op log) tracks everything. Almost nothing is destructive.
Workspace-First Mode (default for non-trivial work)
Rule: Any non-trivial task runs in its own jj workspace via jj claude-start <name>. This keeps multiple Claude sessions from clobbering each other's working copy and lets you (or other agents) work on a different feature in parallel without coordination.
Decision rule
| Task | Where to work |
|---|
| Multi-file feature, refactor, bugfix that needs >1 commit | Workspace: jj claude-start <feature-name> |
| Anything that runs tests/builds while you keep working | Workspace (build noise won't block other Claudes) |
| Single typo, one-line config tweak, read-only Q&A | Main copy (workspace overhead not worth it) |
| Reviewing or summarizing existing changes | Main copy (no edits) |
Detect where you are
Before starting any change, confirm whether you're in the main copy or a workspace:
jj workspace root
pwd
jj workspace list
Naming convention
One workspace per logical task. Name it after the feature/fix, not the date or session: auth-refactor, db-migration, fix-login-redirect. The name becomes the tmux session name and the directory under .jj-workspaces/.
Bookmark = workspace handoff
One bookmark per workspace. Bookmarks are shared across all workspaces (only the working copy is per-workspace), so they are how parallel work gets pushed and reviewed independently. Match the bookmark name to the workspace name when possible.
Concurrency hazard you must know
Two workspaces editing the same change-id silently produce a "stale working copy" in one of them — no error, no warning. Recovery is jj workspace update-stale (see Daily Ops below). Avoid this by giving each workspace its own stack of changes from trunk.
For full concurrency model, cross-workspace coordination rules, and the typical AI-assisted session flow, read references/claude-workspaces.md.
Daily Operations Quick Reference
Starting work
jj stack-start
Making changes
jj status
jj diff
jj describe -m "msg"
jj new
Viewing history
jj log
jj log-short
jj stack-view
jj stacks-all
jj stack-files
jj diff-summary
jj diff-files
Syncing
jj stack-sync
jj git fetch
jj restack
Editing history
jj edit <change-id>
jj squash
jj split
jj rebase -r <rev> -d <dest>
jj rebase -s <rev> -d <dest>
Pushing
jj stack-submit
jj bookmark set <name> -r @-
jj git push
Safety
jj undo
jj op log
jj op restore <id>
Cleanup
jj stack-gc
jj abandon <rev>
Workspaces (parallel Claude sessions)
jj claude-start <name>
jj claude-stop <name>
jj claude-checkpoint "msg"
jj workspace list
jj workspace forget <name>
Workspace recovery
jj workspace update-stale
Run this in the affected workspace after you see a stale-working-copy message. Happens when another workspace edits/rebases a commit you had checked out — jj does not lock, so the resolution is explicit. See references/claude-workspaces.md for the full concurrency model.
Bookmarks (= Git Branches)
Bookmarks are JJ's equivalent of Git branches. They're named labels you attach to changes for pushing to remotes.
jj bookmark set feat-x -r @-
jj bookmark list
jj bookmark delete feat-x
jj create feat-x
jj tug
Key difference from Git: bookmarks do NOT auto-follow when you create new changes. You must explicitly jj bookmark set or use jj tug / jj create after describing your change.
Stacked Changes Workflow
Stacks are the natural unit of work in jj — a chain of changes from trunk to your current position.
jj stack-start
jj describe -m "step 1"
jj create step-1
jj new
jj describe -m "step 2"
jj create step-2
jj new
jj describe -m "step 3"
jj create step-3
jj stack-view
jj stack-submit
For PR/MR creation patterns, see references/forge-workflows.md.
Conflict Resolution
When conflicts arise (e.g., after jj stack-sync):
jj status
jj diff
jj status
Conflicts are data — you can keep working on top of them and resolve later. But resolve before pushing.
For AI-assisted resolution in Claude workspaces: jj claude-resolve (see references/claude-workspaces.md).
Common Patterns for Claude Code
These patterns are workspace-first (default mode). For trivial work, see "Quick fix in main copy" at the end.
"Start a new feature" (default entry point)
jj claude-start auth-refactor
tmux attach -t auth-refactor
jj stack-start
jj describe -m "feat(auth): refactor session handling"
jj create auth-refactor
jj new
"Commit my changes and push" (inside a workspace)
jj describe -m "type(scope): subject"
jj create <bookmark-name>
jj new
jj stack-submit
"Rebase onto latest main" (inside a workspace)
jj stack-sync
jj status
"Fix something in an earlier change" (inside a workspace)
jj edit <change-id>
jj new @-
"Run two Claudes in parallel"
jj claude-start auth-refactor
tmux attach -t auth-refactor
jj claude-start db-migration
tmux attach -t db-migration
Critical: each Claude builds its OWN stack of changes from trunk. Never edit the same change-id from two workspaces — the second one will go stale.
"Undo what I just did"
jj undo
"Recover from a stale working copy"
jj workspace update-stale
jj status
"Quick fix in main copy" (trivial-case escape hatch)
For a single typo or one-line config tweak, the workspace overhead isn't worth it. Stay in the main repo dir:
jj describe -m "fix: typo in README"
jj new
jj git push --bookmark <name>
Use this only when: (a) the change is one or two lines, (b) no tests/builds need to run, (c) no other Claude is currently editing the same area.
Workflow Guardrails
Before committing/describing
- Always read the diff first:
jj diff (or jj diffs for summary)
- Derive scope from file paths, write conventional commit message
- Use
jj describe -m "type(scope): subject" — never leave empty descriptions
Before pushing
- Run
jj status to check for conflicts — do not push conflicted changes
- Ensure bookmark is set:
jj bookmark list or jj stack-view
- Use
jj stack-submit for stacks, jj git push for single bookmarks
Before rebasing
- Prefer
jj stack-sync (fetches + rebases in one step)
- After rebase, check for conflicts:
jj status
- Clean up empty changes after sync:
jj stack-gc
After finishing a feature
- Squash fixups:
jj squash to fold current into parent
- Clean empty commits:
jj stack-gc
- Verify stack looks clean:
jj stack-view