| name | jj |
| description | Jujutsu VCS operations with opt-in activation. Git-compatible VCS featuring automatic snapshotting, first-class conflicts, and powerful undo. **Use for**: explicit jj requests, change-based workflows, conflict-safe rebasing, operation log inspection. |
| license | Proprietary |
| compatibility | opencode |
| metadata | {"category":"version-control","risk":"medium","owner":"Foundation department at DHL eCommerce BNL, IT & Digital","audience":"developers","workflow":"git","tags":["jj","jujutsu","version-control","git","vcs"],"version":"1.0.0"} |
LLM Summary (Read First)
Jujutsu (jj) is a Git-compatible VCS with automatic change snapshotting and first-class conflict support. This skill is OPT-IN ONLY - agents must receive explicit user instruction to use jj (e.g., "use jj for this", "commit with jj").
Core safety features you should emphasize:
jj undo - reverses the last operation completely
jj op log - shows full operation history for recovery
- Conflicts don't block operations - can be committed and resolved later
Trigger this skill when user explicitly:
- Mentions "jj" or "jujutsu" in their request
- Is working in a repo with
.jj/ directory AND asks to use jj
- Asks questions about jj workflow or concepts
Do NOT trigger for:
- Generic git requests (use git unless user specifies jj)
- Repos without
.jj/ directory (unless user asks to initialize)
- Automated workflows (stick with git until jj requested)
Core Concepts (Teach These First)
1. Changes vs Commits
Change ID: Stable identifier that survives rewrites (e.g., kntqzsqt)
Commit ID: Git-style hash that changes with each rewrite (e.g., 5d39e19d)
jj evolog
jj evolog -p
jj show <change-id>/1
Why this matters: Track work through rebases, amendments, and squashes. Change IDs enable true change-based development vs commit-based.
2. Working Copy is Always a Commit (@)
jj log
echo "new" > file.txt
jj commit -m "snapshot current work"
Key difference from Git: No staging area. Working copy (@) is a commit that gets auto-snapshotted before every operation.
3. Bookmarks (Not Branches)
Bookmarks are named pointers to commits but do NOT move automatically like Git branches:
jj bookmark create feature-x
jj commit -m "new work"
jj bookmark move feature-x --to @-
jj bookmark track feature-x --remote=origin
jj bookmark list
jj bookmark list --all
Critical difference: Git branches move automatically; jj bookmarks stay put until you move them explicitly.
4. Operation Log (Your Safety Net)
Every operation is recorded and reversible:
jj op log
jj op log -p
jj undo
jj op restore <operation-id>
jj --at-op=<operation-id> log
Agent behavior: Lead with this safety feature early. Users can experiment fearlessly knowing jj undo exists.
5. First-Class Conflicts
Conflicts DON'T block operations:
jj rebase -s <commit> -d <dest>
jj log
jj new <conflicted-commit>
jj squash
Agent behavior: Explain conflicts can be committed and rebased like any change. Resolution can be deferred.
Activation Criteria
✅ TRIGGER this skill when:
- User explicitly says "use jj", "with jujutsu", "jj commit", etc.
- User asks "how do I X in jj?" or "what's the jj equivalent of Y?"
- User is in a
.jj/ repo AND says "commit this" after previously using jj
- User asks to initialize jj: "set up jj here", "jj git init"
❌ DO NOT trigger for:
- Generic version control requests without mentioning jj
- "git commit" (even in a colocated repo - honor explicit tool choice)
- Automated scripts/CI unless explicitly configured for jj
- First-time repo operations (default to git until user opts in)
🔍 Detection Patterns
# Positive triggers (explicit jj mentions)
\bjj\s+(commit|new|describe|squash|rebase|bookmark|evolog|undo|op\s+log)\b
\buse\s+jj\b
\bjujutsu\b
\bwith\s+jj\b
# Questions about jj
\bhow\s+(do|to|can).+(in|with|using)\s+jj\b
\bjj\s+equivalent\b
\bchange\s+id\b.*jj
\bevolog\b
# Context: already using jj (check .jj/ exists + user said "commit")
# Only trigger if previous messages in session used jj
Guardrails (Hard Rules)
A. Never Auto-Switch to JJ
- ❌ NEVER: "I see this is a colocated repo, let me use jj..."
- ✅ INSTEAD: "This repo supports both git and jj. Which would you like to use?"
Rationale: Explicit opt-in prevents surprising users unfamiliar with jj.
B. Respect Tool Choice
- If user says "git commit", use git (even if
.jj/ exists)
- If user says "jj commit", use jj (even if they used git before)
- Don't switch tools mid-workflow without explicit request
C. No Destructive Remote Operations Without Confirmation
jj git push --force
jj git push --bookmark main
"This will force-push to remote. Confirm to proceed."
D. Bookmark Protection (Adapted from safe-push-review)
Protected bookmarks (never push directly):
main
master
production
release/*
jj bookmark list
jj git push --bookmark main
"Cannot push directly to 'main' bookmark.
Should I create a feature bookmark?
jj bookmark create feature/<name> -r @-
"
E. Story Reference Validation (Adapted for Changes)
Per dhl-story-tracking, but adapted for jj's change model:
jj describe -m "feat: Add validation [PLAT-123]"
jj show @
Why change-based: Git commit-ids change on rewrite; jj change-ids persist. Track story per change, not commit.
F. Colocated Repository Detection
When both .jj/ and .git/ exist:
"This is a colocated repo (both jj and git).
Git commands work normally.
To use jj instead, say 'use jj for X'.
Note: Git will show detached HEAD (normal for colocated repos).
"
Primary Workflows
Workflow 1: Squash Workflow (Default)
Use this for most operations. Replaces Git's staging area:
jj new main
jj st
jj diff
jj commit -m "feat: Add validation [PLAT-123]"
jj squash
jj squash file1.txt file2.txt
jj bookmark create feature/validation -r @-
jj bookmark track feature/validation
jj git push --bookmark feature/validation
Agent template for squash workflow:
- Verify
.jj/ exists or ask to initialize
jj st to show current state
- If working copy has changes: suggest
jj commit to freeze
- For amendments: suggest
jj squash to update parent
- For partial amendments:
jj squash <files>
- Before push: create/move bookmark, then
jj git push
Workflow 2: Edit Workflow (Advanced)
Use when user needs to modify specific historical commit:
jj edit <commit-id or change-id>
jj new
When to teach edit workflow:
- User asks "how do I modify commit X?"
- User needs to split old commit:
jj edit <commit>, then jj split
- User wants to insert changes in middle of stack
Agent behavior: Warn that edit modifies history, descendants will be rebased. Suggest jj evolog to see before/after.
Workflow 3: Split Changes
Split working copy or commit into multiple commits:
jj split -i
jj squash file1
jj split file2
jj edit <commit>
jj split -i
jj new
Common Operations
Initialize JJ
jj git init --colocate
jj git clone --colocate <url>
jj git init
Agent behavior: Always use --colocate for existing git repos. Explain git still works normally.
Daily Operations
jj st
jj diff
jj diff -r <commit>
jj show <commit>
jj commit -m "message"
jj describe -m "new message"
jj squash
jj squash -i
jj split -i
jj log
jj log -r 'mine()'
jj evolog
jj evolog -r <change-id>
jj rebase -s <commit> -d <dest>
jj rebase -r <commit> -d <dest>
jj abandon <commit>
jj undo
jj redo
jj op log
jj op restore <op-id>
Bookmark Operations
jj bookmark create <name>
jj bookmark create <name> -r <commit>
jj bookmark move <name> --to <commit>
jj bookmark delete <name>
jj bookmark track <name>
jj bookmark untrack <name>
jj bookmark list
jj bookmark list --all
Remote Operations (Colocated Repos)
jj git fetch
jj git push
jj git push --bookmark <name>
jj git push --change @-
jj git push --force
jj git export
jj git import
Conflict Resolution
jj log
jj st
jj new <conflicted-commit>
jj squash
jj resolve
Integration with Other Skills
With dhl-story-tracking (Adapted for Changes)
Story reference in change description (persists through rewrites):
jj describe -m "feat: Add validation [PLAT-123]"
jj show @
Agent checklist:
Caching strategy:
With safe-push-review (Adapted for Bookmarks)
Sensitive file detection (same as git):
jj st
Bookmark protection (replaces branch protection):
jj bookmark list | grep "^$BOOKMARK"
echo "❌ Cannot push directly to '$BOOKMARK' bookmark."
echo "Create a feature bookmark:"
echo " jj bookmark create feature/<name> -r @-"
echo " jj git push --bookmark feature/<name>"
exit 1
Push confirmation gate:
echo "Sensitive file check: ✓"
echo "Bookmark protection check: ✓"
echo ""
echo "Please confirm the feature/bugfix works end-to-end."
echo "Reply 'Confirmed to push' to proceed."
With git-release
When creating releases in colocated repos:
git tag v1.2.0
gh release create v1.2.0
jj git export
cd .git && git tag v1.2.0 && cd ..
jj git import
Agent behavior: For releases, suggest using git commands even in colocated repos (releases are git/GitHub concepts).
Git Mental Model Transitions
Help users/agents trained on git understand jj equivalents:
| Git Command | JJ Equivalent | Notes |
|---|
git add <file> | No equivalent | Changes auto-tracked |
git add -p | jj split -i | Interactive change selection |
git commit | jj commit | Also creates new empty @ |
git commit --amend | jj squash | Works from any commit |
git rebase -i | jj rebase + jj squash/split | Descendants auto-rebase |
git checkout <branch> | jj new <bookmark> | Creates new commit on top |
git switch <branch> | jj edit <commit> | Direct edit (less common) |
git stash | jj new | Just create commits |
git cherry-pick | jj rebase -r <commit> -d <dest> | Rebase single commit |
git reset --hard HEAD~ | jj abandon @ | Hide current commit |
git reflog | jj op log | Atomic operation log |
git reset --hard <commit> | jj undo or jj op restore | Undo operations |
git branch -d <branch> | jj bookmark delete <name> | Delete bookmark |
git push | jj git push | Same in colocated repos |
git pull | jj git fetch + jj rebase | Separate fetch/integrate |
Common Pattern Translations
Git: Stage partial changes and commit
git add -p file.txt
git commit -m "partial changes"
JJ equivalent:
jj split -i
jj describe -m "partial changes"
Git: Amend last commit
git commit --amend
JJ equivalent:
jj squash
Git: Interactive rebase to fixup
git rebase -i HEAD~3
JJ equivalent:
jj squash --into <target-commit>
Git: Stash work, switch branch
git stash
git checkout other-branch
git checkout -
git stash pop
JJ equivalent:
jj commit -m "WIP"
jj new other-bookmark
jj new wip-change
jj squash
Agent Action Template
When user requests jj operation, follow this checklist:
1. Verify JJ Available
jj --version
"JJ (Jujutsu) is not installed.
Install: https://github.com/martinvonz/jj#installation
Or use git for this operation?"
2. Detect Repository Type
ls -la .jj/
ls -la .jj/ .git/
if .jj/ and .git/ exist:
"This is a colocated repo (jj + git).
Both tools work. Using jj as requested."
elif only .jj/ exists:
"Pure jj repo. Using jj."
elif only .git/ exists:
"This is a git-only repo.
Would you like to initialize jj?
jj git init --colocate"
else:
"No version control. Initialize?
jj git init --colocate (jj + git)
jj git init (jj only)
git init (git only)"
3. Safety Feature Reminder (First Use)
On first jj command in session:
💡 JJ Safety Features:
- jj undo Reverse last operation
- jj op log View all operations
- jj evolog See change evolution
You can experiment safely - operations are reversible!
4. Execute Requested Operation
Follow workflow patterns (squash, edit, split, etc.)
5. Show Result
jj log -n 5
jj st
"Created change kntqzsqt: feat: Add validation [PLAT-123]
Working copy (@) is now empty and ready for new work.
Next steps:
- Continue editing: changes auto-tracked
- Amend: jj squash
- Push: jj bookmark create feature/validation -r @- && jj git push
"
6. Integration Checks
Story tracking:
jj show @ | grep -E '[A-Z]{2,10}-[0-9]+'
"No story reference found.
Per dhl-story-tracking skill, add story key:
jj describe -m 'feat: Add validation [PLAT-123]'
"
Sensitive files:
jj st
Bookmark protection:
jj bookmark list
Error Handling
Error: "No JJ repo found"
"No .jj repository found here.
Initialize jj:
- In existing git repo: jj git init --colocate
- New jj repo: jj git init
- Clone with jj: jj git clone --colocate <url>
"
Error: Conflict markers in files
jj st
"Conflict markers detected.
Resolve conflicts:
1. Edit files to resolve conflicts
2. jj squash (move resolution into parent)
Or use external tool:
jj resolve
Conflicts in jj are normal and can be committed.
Resolve now or later (jj new <conflicted> when ready).
"
Error: Bookmark doesn't exist
jj bookmark list
"Bookmark 'feature/x' not found.
Create it:
jj bookmark create feature/x -r @-
Or did you mean one of these?
[list similar bookmarks]
"
Error: Push rejected (non-fast-forward)
"Push rejected (non-fast-forward).
Someone else pushed to this bookmark.
Options:
1. Fetch and rebase:
jj git fetch
jj rebase -s <your-change> -d <remote-bookmark>
jj git push --bookmark feature/x
2. Force push (dangerous):
jj git push --force --bookmark feature/x
⚠ Only if you're sure no one else has this work.
3. Create new bookmark:
jj bookmark create feature/x-v2 -r @-
jj git push --bookmark feature/x-v2
"
Error: Descendant commits exist
"This commit has descendants that will be rebased:
[show affected commits with jj log]
Proceed? This will rewrite history.
- Yes: Operation continues (descendants rebased)
- No: Cancel operation
- View first: jj log -r '<commit>::@'
"
Recovery: "I messed up, undo everything"
jj op log -n 10
"You can undo operations:
Undo last operation:
jj undo
Undo last N operations:
jj undo (repeat N times)
Restore to specific point:
jj op log # Find operation ID
jj op restore <op-id>
View repo at past state (read-only):
jj --at-op=<op-id> log
"
GitHub/GitLab Workflow
Pattern 1: Auto-Generated Bookmark (Quick)
jj new main
jj commit -m "feat: Add validation [PLAT-123]"
jj git push --change @-
gh pr create --head push-kntqzsqt --base main
Agent template:
1. jj commit to freeze work
2. jj git push --change @- (auto-bookmark)
3. Note bookmark name from output
4. gh pr create --head <bookmark> --base main
Pattern 2: Named Bookmark (Explicit)
jj new main
jj commit -m "feat: Add validation"
jj bookmark create feature/validation -r @-
jj bookmark track feature/validation
jj git push --bookmark feature/validation
gh pr create --head feature/validation --base main
Agent template:
1. jj commit to freeze work
2. jj bookmark create feature/<name> -r @-
3. jj bookmark track feature/<name>
4. jj git push --bookmark feature/<name>
5. gh pr create --head feature/<name> --base main
Pattern 3: Update PR (Address Review Comments)
jj squash
jj git push --bookmark feature/validation
Agent behavior: Explain that jj force-pushes automatically when bookmark is rewritten (safe for feature branches).
Pattern 4: Stacked PRs
jj new main -m "base: Add validation framework"
jj bookmark create base-validation -r @-
jj new -m "feat: Add specific validator"
jj bookmark create feature-validator -r @-
jj git push --bookmark base-validation
jj git push --bookmark feature-validator
gh pr create --head base-validation --base main
gh pr create --head feature-validator --base base-validation
Colocated Repository Patterns
Understanding Colocated Setup
.jj/
.git/
git status
git log
jj log
Agent explanation:
In colocated repos:
- Git shows "detached HEAD" (normal for jj)
- Both tools work on same commits
- jj uses git as storage backend
- Changes sync automatically
Use jj for workflow, git for compatibility.
Sync Behavior
jj git fetch
jj git push
jj git import
jj git export
Mixing Git and JJ Commands
git pull origin main
jj git import
jj git push --bookmark feature/x
Agent guidance:
Safe to mix tools:
- Use jj for your work (better workflow)
- Use git when required (releases, hooks, team conventions)
- jj git fetch/push syncs automatically
Warning: Interleaving rapidly can cause bookmark divergence.
Pick primary tool per task.
Caching Strategy
Change-Story Mapping
Cache file: .opencode/.cache/jj/change-stories.json
Format:
{
"kntqzsqt": "PLAT-123",
"vruxwmqv": "PLAT-456"
}
TTL: Session lifetime (stories shouldn't change after assignment)
Usage:
CHANGE_ID=$(jj log -r @ --no-graph -T 'change_id' | head -1)
STORY=$(jj show @ | grep -oE '[A-Z]{2,10}-[0-9]+' | head -1)
Repository Metadata
Cache file: .opencode/.cache/jj/repo-info.json
Format:
{
"repo_root": "/path/to/repo",
"is_colocated": true,
"protected_bookmarks": ["main", "master", "production"],
"last_check": "2026-03-07T21:00:00Z"
}
TTL: 1 hour
Usage: Cache expensive checks (colocated detection, bookmark enumeration)
Configuration
User Config Location
Recommended Settings
[user]
name = "Your Name"
email = "your.email@dhl.com"
[ui]
pager = "less -FRX"
diff-tool = "vimdiff"
merge-tool = "vimdiff"
[git]
[revsets]
log = "@ | ancestors(remote_bookmarks()..@, 2) | heads(remote_bookmarks())"
[aliases]
Team-Level Config
Per-repo config: .jj/repo/config.toml
[git]
[revsets]
mine = "author('me@dhl.com')"
team = "author_regex('.*@dhl.com')"
Monitoring & Debugging
Check Repository State
jj git root
jj root
jj st
jj log -n 10
jj bookmark list --all
jj op log -n 20
Verify Sync in Colocated Repo
jj log -r main
git log main --oneline
jj git export
git status
Debug Change Evolution
jj evolog -r <change-id>
jj evolog -p
jj op log | grep <change-id>
Performance Issues
jj op log | wc -l
du -sh .jj/
Setup Instructions
First-Time Setup (New User)
-
Install JJ: https://github.com/martinvonz/jj#installation
-
Configure user:
jj config set --user user.name "Your Name"
jj config set --user user.email "your.email@dhl.com"
-
Initialize in existing repo:
cd /path/to/repo
jj git init --colocate
-
Verify setup:
jj log
jj st
-
Create cache directory:
mkdir -p .opencode/.cache/jj
Team Onboarding
For teams adopting jj:
-
Read-only exploration (safe):
jj git clone --colocate <url>
jj log
jj show <commit>
-
First workflow (squash pattern):
jj new main
jj st
jj diff
jj commit -m "your message"
-
First push (feature branch):
jj bookmark create feature/my-first
jj git push --bookmark feature/my-first
-
Learn safety features:
jj undo
jj op log
jj evolog
Quick Reference
| Task | Command | Notes |
|---|
| Setup | | |
| Init colocated | jj git init --colocate | In existing git repo |
| Clone | jj git clone --colocate <url> | Git-compatible |
| Daily Work | | |
| Status | jj st | Like git status |
| Diff | jj diff | Working copy changes |
| Commit | jj commit -m "msg" | Freezes work, new @ |
| Amend | jj squash | Update parent commit |
| Split | jj split -i | Interactive split |
| History | jj log | Change graph |
| Bookmarks | | |
| Create | jj bookmark create <name> | At current @ |
| Move | jj bookmark move <name> --to @- | Manual move |
| List | jj bookmark list --all | All bookmarks |
| Remote | | |
| Fetch | jj git fetch | Get remote changes |
| Push | jj git push --bookmark <name> | Push bookmark |
| Quick push | jj git push --change @- | Auto-bookmark |
| Safety | | |
| Undo | jj undo | Reverse last operation |
| Op log | jj op log | View all operations |
| Restore | jj op restore <op-id> | Jump to operation |
| Evolog | jj evolog | Change evolution |
| Advanced | | |
| Edit | jj edit <commit> | Modify commit directly |
| Rebase | jj rebase -s <src> -d <dst> | Move commits |
| Abandon | jj abandon <commit> | Hide commit |
| Resolve | jj resolve | External merge tool |
Example User Interactions
Scenario 1: User Asks to Commit
User: "Commit these changes"
Agent (checks context):
ls .jj/ 2>/dev/null
"I can use jj or git. Which would you prefer?
- jj commit (recommended if you've been using jj)
- git commit (standard workflow)
"
jj st
"Working copy has changes:
- modified: src/validator.ts
- added: tests/validator.test.ts
Commit these changes?
jj commit -m 'feat: Add validator [PLAT-123]'
This will freeze the changes and create a new empty working copy.
"
Scenario 2: User Asks About JJ Concepts
User: "What's a change ID in jj?"
Agent:
Change IDs are stable identifiers in jj that survive rewrites.
Example:
- Change ID: kntqzsqt (stays same through amends, rebases)
- Commit ID: 5d39e19d (changes each rewrite)
Why it matters:
- Track work through history rewrites
- Reference same logical change: jj show kntqzsqt
- View evolution: jj evolog -r kntqzsqt
Git only has commit IDs (which change on rebase).
JJ has both for powerful change tracking.
Scenario 3: User Makes Mistake
User: "Oh no, I just abandoned the wrong commit!"
Agent:
jj undo
"Undone! The abandoned commit is restored.
JJ safety feature: every operation is reversible.
- jj undo: reverse last operation
- jj op log: see full operation history
- jj op restore <op-id>: jump to any point
You can experiment fearlessly - operations are atomic and reversible.
Scenario 4: First-Time JJ User
User: "Can I try jj in this repo?"
Agent:
git status
"This is a git repo. You can add jj support:
Initialize jj (colocated setup):
jj git init --colocate
This will:
✓ Work alongside git (both tools available)
✓ Use git as storage (no duplication)
✓ Git shows 'detached HEAD' (normal for colocated repos)
✓ All changes reversible (jj undo)
Your git workflow remains unchanged.
Want to proceed?
"
jj git init --colocate
jj log
"JJ initialized! Your git history is now visible to jj.
Try these safe commands:
- jj log (view history)
- jj st (working copy status)
- jj new main (start new change)
Remember: jj undo reverses any operation.
"
Scenario 5: Conflict During Rebase
User: "Rebase feature onto main"
Agent:
jj git fetch
jj rebase -s feature-bookmark -d main
"Rebase completed with conflicts in:
- src/validator.ts
In jj, conflicts are first-class:
✓ Rebase succeeded (didn't abort like git)
✓ Conflicted commit is visible: jj log (shows 'conflict' label)
✓ You can continue other work
✓ Resolve when ready:
jj new <conflicted-commit>
# Edit conflict markers
jj squash
Or resolve now:
jj resolve
# Opens merge tool
Conflicts don't block you - resolve now or later.
"
Future Enhancements
Potential additions as team matures with jj:
- Pre-push hooks for jj (story validation, sensitive files)
- Change-based CI (trigger CI per change-id, not commit-id)
- Stacked PR workflow templates
- Team revset aliases (for consistent queries)
- Custom conflict marker styles per team preference
- Operation log auditing for compliance
- jj absorb integration (auto-distribute changes to recent commits)
If you need:
- Custom workflow templates
- Team training materials
- Migration guide from git
- Pre-push hook for story validation
- CI integration patterns
Just ask!