Files
printserver/.opencode/skills/jujutsu/SKILL.md
T

334 lines
14 KiB
Markdown

---
name: jujutsu
description: Use this skill for any version control operations (commit, log, diff, push, fetch, bookmark, workspace, rebase, undo, etc.). If a `.jj` directory exists, the repo is jujutsu and git mutations will corrupt it — use `jj` for all mutations; read-only `git log/diff/show/blame/grep` are allowed. Covers co-located repos, multi-agent parallel workspaces, and operation-log recovery. **DO NOT IGNORE**
allowed-tools: Bash(jj *)
license: Apache-2.0
metadata:
author: johnstegeman
version: "1.3"
---
# Jujutsu (jj) Version Control System
This skill helps you work with Jujutsu, a Git-compatible VCS with mutable commits and automatic rebasing.
**Tested with jj v0.41.0** - Commands may differ in other versions.
For token-sensitive inspection commands, prefer the compact commands in `references/TEMPLATES.md` over jj's default output.
The compact commands in `references/TEMPLATES.md` intentionally use `jj --no-pager ...`.
For revsets, filesets, and template syntax, see `references/QUERY_LANGUAGES.md`.
For sibling or unrelated work that should start from `trunk()`, see `references/NONLINEAR.md`.
For common surprises and easy mistakes, see `references/GOTCHAS.md`.
<!--
Attribution and inspiration sources:
- Forked from danverbraganza/jujutsu-skill (https://skills.sh/danverbraganza/jujutsu-skill/jujutsu).
The original scaffolding, references/ structure, and core mental-model wording are from there.
- Enforcement language in "Critical: never use git for mutations" was tightened using the
read-only-git allowlist pattern from knoopx/pi@jujutsu
(https://skills.sh/knoopx/pi/jujutsu).
- "Parallel Workspaces" framing as a tool for multi-agent isolation draws on
onevcat/skills@onevcat-jj (https://skills.sh/onevcat/skills/onevcat-jj),
which is explicitly subtitled "Version Control for Agent Workflows".
- The .workspaces/ project-local directory convention, the .gitignore safety check,
and the directory-selection priority documented in references/WORKSPACES.md
come from edmundmiller/dotfiles using-jj-workspaces
(https://lobehub.com/skills/edmundmiller-dotfiles-using-jj-workspaces).
- The "op log records every mutation; nothing is ever truly lost" framing in the
Recovery section is adapted from trevors/dot-claude@jj-workflow
(https://skills.sh/trevors/dot-claude/jj-workflow).
- Query-language guidance, nonlinear-work patterns, and workspace handoff /
monitoring ideas were adapted from joshuadavidthomas/agent-skills `jj`
(https://github.com/joshuadavidthomas/agent-skills/tree/main/jj) and its
`workspaces.md`
(https://raw.githubusercontent.com/joshuadavidthomas/agent-skills/main/jj/workspaces.md),
while intentionally preserving this skill's local describe-first workflow and
`.workspaces/` / `workspaces/` directory priority.
-->
## Detecting a jj repo
Check whether a directory is part of a jj repo:
```bash
jj root
```
If it returns a path, the repo is jj-managed. If it returns `Error: There is no jj repo in <directory>`, it isn't. The presence of a `.jj/` folder is another giveaway. If the repo is not a jj one, do not further use this skill.
<!-- Enforcement wording (allowed/forbidden split with read-only git allowlist) adapted from knoopx/pi@jujutsu. -->
## Critical: never use git for mutations in a jj repo
In a jj repo (including co-located repos that also have `.git/`):
- **Forbidden** (corrupts jj state): `git commit`, `git add`, `git stash`, `git reset`, `git checkout <branch>`, `git switch`, `git rebase`, `git merge`, `git cherry-pick`, `git push`, `git pull`.
- **Allowed** (read-only): `git log`, `git show`, `git diff`, `git blame`, `git grep`, `git status`. Prefer the `jj` equivalents (`jj log`, `jj show`, `jj diff`, etc.) but read-only git commands won't break anything.
- **Use jj instead**: `jj git push`, `jj git fetch`, `jj edit <change>` (not `git checkout`), `jj rebase`, `jj new <a> <b>` (for merges).
See `references/COLOCATED.md` for the full co-located repo workflow.
## Important: Automated/Agent Environment
When running as an agent or running on behalf of the user:
1. **Always use `-m` flags** to provide commit messages inline rather than relying on editor prompts:
```bash
# Always use -m to avoid editor prompts
jj desc -m "message" # NOT: jj desc
jj squash --into @- -m "message" # NOT: jj squash (which opens editor or prompts for hunks)
```
Editor-based commands will fail in non-interactive environments.
2. **Verify operations with `jj st`** after mutations (`squash`, `abandon`, `rebase`, `restore`) to confirm the operation succeeded.
## Important Principles
1. Each commit should represent one logical change. See [commit messages](references/COMMIT_MSG.md) for details on good commit messages. Before starting work on a new change, make sure the working copy is clean (no changes)
```bash
jj st
```
## Core Concepts
### The Working Copy is a Commit
In jj, your working directory is always a commit (referenced as `@`). Changes are automatically snapshotted when you run any jj command. There is no staging area.
There is no need to run `jj commit`.
### Commits Are Mutable
**CRITICAL**: Unlike git, jj commits can be freely modified. This enables a high-quality commit workflow:
1. Before starting work, run `jj st`. If `@` already has changes, run `jj new` first. If `@` is empty, use it as-is.
2. Describe your intended changes with `jj desc -m "Message"`
3. Make your changes.
4. Do NOT run `jj new` when finished — leave that to the next task's step 1.
You may refine the commit using `jj squash` or `jj absorb` as needed
### Change IDs vs Commit IDs
- **Change ID**: A stable identifier (like `tqpwlqmp`) that persists when a commit is rewritten
- **Commit ID**: A content hash (like `3ccf7581`) that changes when commit content changes
Prefer using Change IDs when referencing commits in commands.
## Essential Workflow
### Starting Work: Describe First, Then Code
**Always create your commit message before writing code:**
```bash
# First, describe what you intend to do
jj desc -m "feat: Add user authentication to login endpoint"
# Then make your changes - they automatically become part of this commit
# ... edit files ...
# Check status
jj st
```
For the full starting-a-change workflow (when to reuse `@` vs `jj new`, anti-patterns, decision logic), see `references/NEW_CHANGE.md`.
For unrelated or sibling work that should branch from `trunk()`, see `references/NONLINEAR.md`.
### Creating Atomic Commits
Each commit should represent ONE logical change.
### Viewing History
```bash
# View recent commits
jj log
# View with patches
jj log -p
# View specific commit
jj show <change-id>
# View diff of working copy
jj diff
```
If you need to run `jj log`, `jj show`, or `jj diff` as an agent, use the matching compact command from `references/TEMPLATES.md` unless the full default output is explicitly needed.
For the revsets, filesets, and template syntax behind those compact commands, see `references/QUERY_LANGUAGES.md`.
### Moving Between Commits
```bash
# Create a new empty commit on top of current
jj new
# Create new commit with message
jj new && jj desc -m "Commit message"
# Edit an existing commit (working copy becomes that commit)
jj edit <change-id>
# Edit the previous commit
jj prev -e
# Edit the next commit
jj next -e
```
## Refining Commits
If you need to refine a commit (squash, abandon, undo, split, etc), see (Refining commits)[references/REFINE_COMMIT.md]
## Working with Bookmarks (Branches)
Bookmarks are jj's equivalent to git branches:
```bash
# Create a bookmark at current commit
jj bookmark create my-feature -r@
# Move bookmark to a different commit
jj bookmark move my-feature --to <change-id>
# List bookmarks
jj bookmark list
# Delete a bookmark
jj bookmark delete my-feature
```
If you need to run `jj bookmark list`, use the matching compact command from `references/TEMPLATES.md`.
<!--
Multi-agent workspace framing inspired by onevcat/skills@onevcat-jj.
The .workspaces/ project-local convention codified in references/WORKSPACES.md
is adapted from edmundmiller/dotfiles using-jj-workspaces.
-->
## Parallel Workspaces
For running multiple agents in parallel against the same repo without working-copy collisions, use `jj workspace`. Each workspace gets its own `@` while sharing the underlying repo store.
```bash
# Quick reference (full convention in references/WORKSPACES.md)
jj workspace add .workspaces/<repo>-<purpose> # Create
jj workspace list # List
jj workspace forget <name> # Untrack (files stay on disk)
```
If you need to run `jj workspace list`, use the matching compact command from `references/TEMPLATES.md`.
See `references/WORKSPACES.md` for the full convention: the `.workspaces/` directory layout, `.gitignore` safety check, naming, environment bootstrapping, agent handoff, monitoring, stale-workspace recovery, and merging results from multiple workspaces back together.
## Working with tags
jujutsu does not yet support tags and pushing them to a remote. If you need to tag (such as for a release), you will need to use git to create and push the tags.
## Git Integration (Co-located Repos)
Always use co-located repos when working with existing git projects. They give you jj locally while keeping the repo remote-compatible with git tooling.
```bash
jj git clone <url> --colocate # Clone a git repo
jj git init --colocate # Adopt an existing git repo
```
See `references/COLOCATED.md` for the complete workflow: the mutation rule (`git` is forbidden for mutations, allowed read-only), the git-command allowlist, common gotchas, and switching modes when absolutely necessary.
See `references/GOTCHAS.md` when the behavior feels surprising and you want the short list of jj-specific footguns before trying a git-style workaround.
### Pushing Changes
For pushing bookmarks to a remote, see `references/PUSH.md`. For named remotes, fork+upstream setups, and other multi-remote workflows, see `references/REMOTES.md`.
## Handling Conflicts
jj treats conflicts as first-class objects — a commit can contain a conflict, and that conflict persists through rebases until resolved. `jj` refuses to push conflicted commits, so they must be resolved before `jj git push`.
```bash
jj st # Reports if @ has unresolved conflicts
jj resolve --list # Lists conflicted paths
jj resolve --tool :ours # Take side #1 non-interactively (agent-safe)
jj resolve --tool :theirs # Take side #2 non-interactively (agent-safe)
```
**Never run bare `jj resolve` (no `--tool`)** — it's interactive and will hang in non-interactive agent environments. Either pass `--tool :ours` / `--tool :theirs`, or edit conflict markers directly in the file and let `jj st` snapshot the resolution.
See `references/CONFLICTS.md` for the full resolution playbook: marker formats (diff vs snapshot), five resolution paths, ancestor-level resolution to avoid re-resolving across descendants, verification (beyond `jj st`), and anti-patterns.
<!-- Recovery framing ("op log records every mutation; nothing is ever lost") adapted from trevors/dot-claude@jj-workflow. -->
## Recovery and the Operation Log
The op log records every mutation. Nothing is ever lost.
```bash
jj undo # Reverse the last operation (primary recovery tool)
jj op log # See all operations
jj op restore <op-id> # Jump back to any past state
jj evolog -r <change> # See how a specific change evolved
```
If you need to run `jj op log` or `jj evolog`, use the matching compact commands from `references/TEMPLATES.md` first. Add `-p` only after you have narrowed the scope.
**Always reach for `jj undo` first** when something looks wrong — it's always correct and safe. See `references/RECOVERY.md` for recovery patterns by scenario (bad squash, accidental abandon, lost work, etc.).
## Preserving Commit Quality
**IMPORTANT**: Because commits are mutable, always refine them:
1. **Review your commit**: `jj show @` or `jj diff`
2. **Is it atomic?** One logical change per commit
3. **Is the message clear?** Use imperative verb phrase in sentence case format with no full stop: "Verb object"
4. **Are there unrelated changes?** Use `jj restore` to move changes out, then create separate commits
5. **Should changes be elsewhere?** Use `jj squash` or `jj absorb`
## Quick Reference
| Action | Command |
|--------|---------|
| Describe commit | `jj desc -m "message"` |
| View status | `jj st` |
| View log | `jj log` |
| View diff | `jj diff` |
| New commit | `jj st` then `jj new` only if `@` has changes, then `jj desc -m "message"` |
| Edit commit | `jj edit <id>` |
| Squash to parent | `jj squash --into @- -m "message"` |
| Auto-distribute | `jj absorb` |
| Abandon commit | `jj abandon <id>` |
| Undo last operation | `jj undo` |
| Restore files | `jj restore [paths]` |
| Create bookmark | `jj bookmark create <name>` |
| Push bookmark | `jj git push -b <name>` |
| Add workspace | `jj workspace add .workspaces/<repo>-<purpose>` |
| List workspaces | `jj workspace list` |
| Forget workspace | `jj workspace forget <name>` |
| See operation log | `jj op log` |
| Jump to past state | `jj op restore <op-id>` |
| See change evolution | `jj evolog -r <id>` |
## Best Practices Summary
1. **Describe first**: Set the commit message before coding
2. **One change per commit**: Keep commits atomic and focused
3. **Use change IDs**: They're stable across rewrites
4. **Refine commits**: Leverage mutability for clean history
5. **Embrace the workflow**: No staging area, no stashing — the op log replaces both
6. **Workspaces for parallel agents**: Isolate concurrent agent work in `.workspaces/<repo>-<purpose>` (see `references/WORKSPACES.md`)
7. **`jj undo` first**: When something looks wrong, undo before fixing manually (see `references/RECOVERY.md`)