| name | jujutsu |
| description | REQUIRED for every version-control task in a Jujutsu workspace (`jj root` succeeds): status, diff, log, commit/describe, bookmark, push/fetch, PR, rebase, split, squash, conflict, operation recovery, or workspace work. Use jj exclusively; this skill provides a non-interactive inspect-act-verify protocol and prevents agents from mutating the wrong working-copy commit. |
Jujutsu Agent Protocol
Use this protocol whenever jj root succeeds from the current directory. Do not translate a Git workflow command-for-command; reason from jj's working-copy commit and graph.
Non-negotiable rules
- Use
jj exclusively for VCS operations. Do not run raw git commands in a jj repo, including a colocated .jj/ + .git/ repo.
- Never run
jj git push unless the user explicitly said push. Preparing, committing, shipping, or opening a PR does not imply permission to push.
- Never use interactive/editor forms (
-i, --interactive, bare commands that open an editor, jj resolve, or jj diffedit). Supply messages with -m.
- Before editing or mutating history, inspect the full status, graph position, and relevant diff. Do not assume
@ is where a previous agent left it.
- Prefer stable change IDs (letters such as
nmwwolux) over changing hexadecimal commit IDs.
- After every history mutation, verify with
jj status, jj log, and the relevant jj diff/jj show.
- If syntax or behavior is uncertain, use
jj help instead of guessing; the integrated help matches the active jj version.
- If a mutation has an unexpected result, stop and inspect
jj op log. Prefer an explicit jj op revert <op-id> or jj op restore <op-id> over the implicit target selected by jj undo.
Built-in documentation
Prefer jj's integrated, version-correct help over remembered syntax or web examples:
jj help
jj help <command>
jj help <command> <subcommand>
jj help -k <keyword>
Use command help before running an unfamiliar command or when flags may have changed. jj <command> --help is equivalent, but jj help ... composes naturally for nested subcommands.
Keyword topics:
| Keyword | Covers |
|---|
bookmarks | Bookmark semantics, remotes, tracking, and Git branch mapping |
config | Configuration files, scopes, precedence, values, and settings |
filesets | Selecting files with patterns, operators, functions, and quoting |
glossary | Canonical jj terminology |
revsets | Selecting revisions with symbols, operators, functions, and patterns |
templates | Customizing command output with -T/--template |
For example, run jj help -k revsets. Run jj help --help to list all supported keyword values.
Mental model
- The working copy is a mutable commit named
@. jj snapshots file edits at the start of most jj commands; there is no staging area.
jj new creates a new empty child commit. After completing and reviewing a described change, use it as a boundary so the completed content is in @- and future edits land in a clean @.
jj commit -m ... is equivalent to describing the current commit and then running jj new; completed content is then in @-.
- Bookmarks are named pointers, not current branches. They follow rewrites of the change they point to but do not advance to newly created child changes.
- Conflicts are stored in commits. A rebase may finish successfully while leaving conflicted commits.
- Rewrites preserve the change ID and replace the commit ID. The operation log makes repo-level recovery possible.
Required preflight
Run from the repository, before making edits:
jj root
jj status
jj show
Classify @ before touching files:
State of @ | Action |
|---|
| Empty and undescribed | Safe starting point; describe it for this task. |
| Empty but described | It may reserve another task. Continue only if its description matches; otherwise jj new. |
| Non-empty | Inspect the full diff and description. Continue only when it belongs to this task; otherwise preserve it and jj new. |
| Conflicted | Resolve or deliberately work above it; never silently treat it as clean. |
When existing work is ambiguous or unrelated, preserve it in place and start a fresh @ with jj new. Never squash, abandon, restore, or redescribe existing work merely to obtain a clean state.
Blessed coding workflow: describe first, close with new
Use one workflow consistently:
jj describe -m "<description>"
jj status
jj show
jj describe -m "<description>\n<more description>"
jj new
jj status
jj show @-
- Keep one logical change in
@.
- Review the complete diff before closing the change; do not use
jj new to hide unfinished or unchecked work.
- End the task with the completed, described change at
@- and a new empty, undescribed @ for future edits.
- If the user explicitly requests
jj commit, use jj commit -m ... instead of the separate jj describe and final jj new. Do not move bookmarks without inspecting them.
Stack cleanup recommendations
Before the final response, inspect the nearby mutable history. If adjacent commits would be clearer as one logical review unit, suggest a cleanup plan; do not perform it without approval.
Good squash candidates include fixups, tests or documentation inseparable from an implementation, and successive commits editing the same behavior. Keep commits separate when they are independently reviewable or revertible, even if they are small.
A recommendation must include:
- The shortened, unambiguous source and destination change IDs (as rendered by
change_id.short()) with their current descriptions.
- Why they belong together.
- The proposed combined description.
- An explicit statement that no rewrite has happened yet.
Treat direct approval such as “do it” as authorization for exactly the proposed cleanup. Then re-run preflight, inspect every affected commit's full diff and graph relationship, confirm they are mutable, and apply the plan with explicit change IDs and non-interactive messages. For example:
jj squash --from '<source1> | <source2>' --into <destination> \
-m "<combined description>"
jj describe -r <change-id> -m "<new description>"
Afterward, verify status, graph, destination diff, descriptions, bookmarks, and conflicts. If the result differs from the approved plan, stop and inspect jj op log.
Safe mutation pattern
For any rewrite or destructive-looking operation:
- Inspect
jj status, jj log, and jj show <change-id>/jj diff.
- State exactly which change(s) will move and where.
- Use explicit revisions and non-interactive flags.
- Verify graph, status, diff, bookmarks, and conflicts afterward.
Examples:
jj split path/to/file -m "<first description>"
jj squash --from <source> --into <destination> \
-m "<resulting description>"
jj rebase -s <source> -d <destination>
jj restore --from <revision> path/to/file
jj abandon <change-id>
Do not use a bare jj squash when both descriptions may be non-empty; it can request message editing or produce the wrong description. Do not use a destination bookmark as shorthand until jj log proves which commit it resolves to.
Push gate
Only after the user explicitly says push:
jj status
jj bookmark list --all
jj log -r '<bookmark> | present(<bookmark>@origin)' --no-graph
jj show <bookmark>
jj git push -b <bookmark>
Push one named bookmark; never use bare jj git push or --all. Never move or push main/the default branch unless the user explicitly names that exact target.
Conflicts and recovery
- Resolve conflicts by editing markers directly, then verify with
jj status and jj log -r 'conflicts()'.
- For an unexpected mutation, inspect
jj op log and the relevant historical state with jj --at-op=<op-id> log before recovering.
- Use
jj op revert <op-id> to invert one specific operation while preserving later operations. Revert additional explicitly selected operations separately if needed.
- Use
jj op restore <op-id> to return the repository to that operation's state, intentionally discarding the effects of all later operations.
- Avoid
jj undo: its implicit “last operation” target is less precise than either explicit recovery command.
- For a stale workspace, run
jj workspace update-stale, then inspect for divergence.
- Never use raw Git as a recovery fallback.