These configuration files accompany Juju-chu!, a practical Jujutsu guide.
You can use them on their own. No purchase required.
Last updated: August 30, 2026
This page provides project-level configuration files that get Claude Code and Codex CLI to use Jujutsu instead of Git.
Place the files in the appropriate locations in your project, and the agent can refer to Jujutsu’s mental model and core workflows while using Jujutsu for version control. You won’t need to ask it to “commit this.” Based on the task you give it, the agent will organize its work into sensible changes.
The same configuration files are also available in the book’s companion repository.
Why Telling the Agent Isn’t Enough
I asked the latest models available in Claude Code and Codex CLI about this
directly, and both already know Jujutsu’s basic concepts and commands. In fact,
a short instruction in CLAUDE.md or AGENTS.md telling the agent to use
Jujutsu for version control is often enough to get reasonably good behavior.
However, most of the coding workflows represented in their training data are still based on Git, so they haven’t internalized a Jujutsu-native workflow. With only that short instruction, things like this can happen:
- Just swapping each
gitcommand for whicheverjjcommand looks closest - Starting a task without checking the state of the working-copy commit, so unrelated work ends up mixed into the same change
- Treating a bookmark like a Git branch that always follows the latest commit
- Stopping work as soon as a conflict appears
- Getting stuck when a problem specific to Jujutsu occurs
Knowing individual commands is one thing; having worked through a series of tasks and developed practical judgment is another. Ask an agent to perform a specific repository operation, and it will run the corresponding Jujutsu command. But if you want it to manage version control as part of a feature or fix, organizing the work into sensible changes without being prompted, you need to teach it a workflow based on Jujutsu’s mental model.
That is what the configurations on this page cover:
- Constraints on which commands the agent may run
- Passing
--gitto commands that display diffs, making the output easier for the agent to read - Passing
--ignore-working-copyto read-only commands where appropriate, preventing unnecessary revision fragmentation and stale working-copy errors - How to handle the current change at the start of a task
- How to split changes and resolve conflicts
- How to work with bookmarks when pushing
- What to do when the working copy goes stale
Claude Code Config
The Claude Code configuration is built around rules that apply throughout every session.
CLAUDE.md contains only the highest-priority instruction: use Jujutsu instead of
Git. More detailed explanations of Jujutsu’s mental model and task-specific
procedures are kept separately in .claude/rules/jujutsu-rules.md.
The package also includes a settings.json file that blocks the agent from
running Git commands while allowing routine Jujutsu commands to run without asking
for permission each time.
.
├─ .claude/
│ ├─ rules/
│ │ └─ jujutsu-rules.md
│ └─ settings.json
└─ CLAUDE.mdCLAUDE.md## Version Control — Required Procedure
This project uses **Jujutsu (jj)** for version control. For the detailed rules, see `.claude/rules/jujutsu-rules.md`.
**Before you begin editing code**, always settle which change the work belongs to: inspect working-copy commit (`@`), reuse it if it is empty, otherwise open a new one. The decision procedure is in the rules file under "1. Starting Work" of "Basic Workflow" — do not start editing and sort the changes out afterwards.
**Prohibited:** Direct use of `git` commands (the `jj git` subcommands and the `gh` CLI are allowed)..claude/rules/jujutsu-rules.md# Jujutsu (jj) Rules for AI Agents
Standard jj semantics are assumed knowledge. What follows is only what an agent cannot infer from the tool itself: this repository's permissions, its aliases, and the conventions the team has settled on.
---
## Important Notes for AI Agents
### Command Constraints
`.claude/settings.json` denies these outright. Never plan a workflow around them; if one is genuinely needed, describe the command and let the user run it.
| Denied | Why |
| ------------- | ----------------------------------------------------------------------------------- |
| `git` (all) | Risks corrupting jj state. `jj git ...` and `gh` remain allowed. |
| `jj resolve` | Opens the interactive merge editor. Resolve conflicts by editing the files instead. |
| `jj diffedit` | Opens the interactive diff editor. |
| `jj arrange` | Interactive TUI. |
`jj split` is allowed, but **always pass filesets and `-m`. Never run it bare, and never pass `-i` or `--tool`** because these actions trigger an interactive diff editor.
These prompt for confirmation every time, so save them for the end of a task rather than firing them mid-flow: `jj git push`, `jj bookmark delete`, `jj bookmark forget`, `jj bookmark track`, `jj bookmark untrack`.
### What jj Changes About the Workflow
- **No staging, no stash, no "unsaved change".** Saving a file puts it in the working-copy commit (`@`) that instant. Never ask the user whether a change should be included — it already is.
- **Bookmarks are not branches and do not follow `@`** — and they do not need to. Leave them where they are while you work; there is nothing to keep in sync. Position one only when it is about to be used (see "Positioning a Bookmark").
- **Automatic formatting (`jj fix`)**: This project has `jj fix` set up. Because it is registered as a Stop hook, it runs when a task finishes and retroactively reformats the code across the mutable changes. Even if `jj diff` shows unintended formatting changes, accept them as long as they conform to the project's rules.
### Rules for diff Output
Always pass `--git` to `jj diff`, `jj show`, and `jj log -p`. Without it the output cannot express file additions, deletions, renames, and permission changes accurately, and an agent's reading of the diff degrades accordingly.
### Suppressing Snapshots in Read-Only Operations
Every jj command snapshots the working copy, which risks an operation-log conflict when another process is working in the same repo. Add `--ignore-working-copy` to purely read-only inspection — `jj log`, `jj diff`, `jj bookmark list`, `jj evolog`, `jj op log`.
**Never add it right after creating, editing, or deleting a file**: that is exactly when the snapshot has to be recorded. Use `jj util snapshot` if you want one without running anything else.
### Choosing the Right Log Output
Read `jj log`'s graph as-is for ordinary state checks. To extract values programmatically, add `--no-graph` and `-T`:
```bash
jj log --ignore-working-copy --no-graph -T 'change_id.short() ++ " " ++ description.first_line() ++ "\n"'
```
---
## Basic Workflow
### 1. Starting Work
Adjust your actions according to the state of the working-copy commit (`@`):
1. Run `jj status` — **without** `--ignore-working-copy`, the one exception to the rule above. The user may have edited files since the last jj command, and skipping the snapshot would report those edits as absent.
2. **If `@` is empty** (NO description AND NO diff) → **reuse it.** Set its description with `jj describe -m "<description>"` and work there. **Do not create a new change.** A change created by `jj new` is itself empty, so it falls under this rule too.
3. Otherwise (`@` already has a description or a diff) → `jj new -m "<description>"`.
4. Write the description in English, in Conventional Commits format.
### 2. Splitting a Change
```bash
jj split -m "<description for the extracted change>" <path>...
```
Filesets are what keep it out of the diff editor, `-m` out of the description editor. Hunk-level splits need that editor, so hand those to the user.
### 3. Resolving Conflicts
Edit the marked-up files directly, then confirm with `jj status` that the conflict is gone. Saving the file _is_ the resolution; there is no `git add` equivalent to run afterwards.
jj's conflict markers differ from Git's: the `%%%%%%%` block is a diff against the base, expressed with `-`/`+` lines, while the `+++++++` block is the other side's content verbatim.
### 4. Positioning a Bookmark
Move a bookmark only when asked to push, or asked to open a PR with the push step left implicit. Otherwise leave bookmarks alone — a change does not need one to exist.
Never point one at `@` unexamined: after `jj new` it is empty and undescribed, and `jj git push` refuses a commit whose description is empty. Target the newest ancestor of `@` that has both a diff and a description, and read it back before moving:
```bash
jj log --ignore-working-copy --no-graph \
-r 'heads(::@ & ~empty() & ~description(exact:""))' \
-T 'change_id.short() ++ " " ++ description.first_line() ++ "\n"'
jj bookmark create <name> -r 'heads(::@ & ~empty() & ~description(exact:""))' # the first time
jj bookmark move <name> --to 'heads(::@ & ~empty() & ~description(exact:""))' # afterwards
```
**Do not use `jj bookmark advance`.** It takes its target from `revsets.bookmark-advance-to`, so the landing point is decided by repository configuration rather than by the command you wrote. Spell the target out at the call site.
### 5. Syncing with the Remote
```bash
jj git fetch # fetch the latest state
jj git push -b <bookmark-name> # publish the bookmark
```
---
## PR Creation Workflow
- The base is always `main` unless instructed otherwise. No confirmation needed.
- **Never squash.** Keep each change as-is so the history stays traceable.
- Pass the title explicitly with `--title` in Conventional Commits format, derived from the description of the bookmark's lead change. Do not rely on the title `gh` derives.
```bash
jj git fetch
jj log --ignore-working-copy
jj bookmark list --all --ignore-working-copy # then position it — see above
jj bookmark track <bookmark-name>@origin # only if untracked
jj git push -b <bookmark-name> # skip if local and remote already match
gh pr create --base main --head <bookmark-name> --title "<type>: <summary>" --body "<body>"
```
---
## Troubleshooting
**"The working copy is stale"** — a human and an agent worked in the repo in parallel, or an external tool changed files. Run `jj workspace update-stale`, then confirm with `jj status`..claude/settings.json{
"permissions": {
"allow": [
"Bash(jj status:*)",
"Bash(jj log:*)",
"Bash(jj diff:*)",
"Bash(jj show:*)",
"Bash(jj file list:*)",
"Bash(jj root:*)",
"Bash(jj describe:*)",
"Bash(jj new:*)",
"Bash(jj edit:*)",
"Bash(jj restore:*)",
"Bash(jj squash:*)",
"Bash(jj rebase:*)",
"Bash(jj abandon:*)",
"Bash(jj evolog:*)",
"Bash(jj op log:*)",
"Bash(jj operation log:*)",
"Bash(jj undo:*)",
"Bash(jj bookmark list:*)",
"Bash(jj bookmark create:*)",
"Bash(jj bookmark move:*)",
"Bash(jj bookmark advance:*)",
"Bash(jj bookmark set:*)",
"Bash(jj bookmark rename:*)",
"Bash(jj git fetch:*)",
"Bash(jj config get:*)",
"Bash(jj config list:*)"
],
"deny": [
"Bash(git:*)",
"Bash(jj resolve:*)",
"Bash(jj diffedit:*)",
"Bash(jj arrange:*)"
],
"ask": [
"Bash(jj bookmark delete:*)",
"Bash(jj bookmark forget:*)",
"Bash(jj bookmark track:*)",
"Bash(jj bookmark untrack:*)",
"Bash(jj git push:*)"
]
}
}Codex CLI Config
Codex CLI does not have a direct equivalent to Claude Code’s behavioral rules.
The AGENTS.md file therefore contains the instructions Codex must always follow
and directs it to consult a skill for detailed guidance on using Jujutsu.
Codex also has a feature called rules, but these rules serve a different purpose:
they control whether commands may be executed outside the sandbox. The package
includes a rules file adapted from the permissions defined in Claude Code’s
settings.json.
.
├─ .agents/
│ └─ skills/
│ └─ jujutsu/
│ └─ SKILL.md
├─ .codex/
│ └─ rules/
│ └─ jujutsu.rules
└─ AGENTS.mdAGENTS.md## Version Control — Required Procedure
This repository uses Jujutsu (`jj`). Use `jj` terminology and commands; do not run raw `git` commands. `jj git ...` and `gh` are allowed.
Before editing, run `jj status` to snapshot and inspect working-copy commit (`@`). Reuse `@` only when it has neither a description nor a diff; otherwise create a new change. Write change descriptions in English using Conventional Commits.
Always use `--git` with `jj diff`, `jj show`, and `jj log -p`. Use `--ignore-working-copy` for purely read-only inspection only after the working copy is known to be snapshotted.
Do not run `jj resolve`, `jj diffedit`, or `jj arrange`. Run `jj split` only with filesets and `-m` (never bare, never with `-i` or `--tool`), which is what keeps it out of the diff editor. After history-changing operations, run `jj status` and resolve any conflicts before continuing.
Do not move bookmarks unless publishing changes. PRs target `main` unless instructed otherwise, and stacked changes must not be squashed.
For non-trivial revsets, conflicts, bookmark operations, history rewriting or recovery, fetch, push, and PR creation, consult the `jujutsu` Skill at `.agents/skills/jujutsu/SKILL.md`..agents/skills/jujutsu/SKILL.md---
name: jujutsu
description: Repository-specific procedures for non-trivial Jujutsu operations, including revsets, conflicts, bookmarks, history rewriting or recovery, remote synchronization, and PR creation.
---
# Jujutsu Operations
The standing policy lives in `AGENTS.md`. This skill covers only repository-specific decisions and procedures that are not implied by standard Jujutsu behavior.
## When to Use This Skill
- Writing or evaluating a non-trivial revset
- Resolving conflicts
- Creating, moving, tracking, forgetting, or deleting bookmarks
- Rebasing, squashing, restoring, abandoning, undoing, or restoring an operation
- Splitting a change without a diff editor
- Handling stale or immutable working-copy errors
- Fetching, pushing, or creating a PR
Routine state inspection and starting ordinary work do not require this skill; follow `AGENTS.md` directly.
## Repository Constraints
- Do not run raw `git` commands. `jj git ...` and `gh` are allowed.
- Do not run `jj resolve`, `jj diffedit`, or `jj arrange`; they require interactive interfaces. `jj split` is allowed only with filesets and `-m` — never bare, never `-i`/`--tool`. If a task cannot be completed safely with non-interactive commands, ask the user to perform that part.
- Always add `--git` to `jj diff`, `jj show`, and `jj log -p`.
- After a history-changing operation such as `jj new`, `jj rebase`, `jj squash`, `jj restore`, or `jj abandon`, run `jj status` before continuing.
- Do not squash stacked changes when preparing a PR.
## Snapshot Discipline
Add `--ignore-working-copy` to read-only inspection — `jj log`, `jj diff`, `jj bookmark list`, `jj evolog`, `jj op log` — only when the working copy is already known to be snapshotted, since it suppresses a new snapshot and can report stale state.
Omit it at the start of work and after creating, editing, or deleting a file: those are exactly the moments the latest filesystem state has to be captured.
## Splitting a Change by File
```bash
jj split -m "<description for the extracted change>" <path>...
```
Filesets are what keep it out of the diff editor, `-m` out of the text editor. Hunk-level splits need that editor, so hand those to the user.
## Resolving Conflicts
Edit the conflict markers directly into the intended final content, then confirm with `jj status` that no conflict remains. Saving the file is the resolution: do not run `jj resolve`, and do not look for a `git add` equivalent afterwards.
## Positioning a Bookmark for Publication
Do not move bookmarks during ordinary implementation. Position one only when the user asks to push or create a PR, including when the push is implicit in the PR request.
Never assume `@` is the revision to publish — after `jj new` it may be empty. Target the newest ancestor of `@` that has both content and a description, and read the result back before moving the bookmark:
```bash
jj log --ignore-working-copy --no-graph \
-r 'heads(::@ & ~empty() & ~description(exact:""))' \
-T 'change_id.short() ++ " " ++ description.first_line() ++ "\n"'
jj bookmark create <name> -r 'heads(::@ & ~empty() & ~description(exact:""))' # new bookmark
jj bookmark move <name> --to 'heads(::@ & ~empty() & ~description(exact:""))' # existing one
jj status
```
Do not use `jj bookmark advance`; spell out the target revision at the call site.
## Remote and PR Workflow
Unless instructed otherwise, use `main` as the PR base and preserve each change in a stack. Track an untracked remote bookmark with `jj bookmark track <name>@origin`, and skip the push when local and remote already match. The PR title is Conventional Commits, passed explicitly; the body is Japanese.
```bash
jj git fetch
jj log --ignore-working-copy
jj bookmark list --all --ignore-working-copy # then position it — see above
jj git push -b <name>
gh pr create --base main --head <name> --title "<type>: <summary>" --body "<body>"
```
## Recovery and Troubleshooting
Before `jj undo`, `jj op restore`, `jj restore`, or `jj abandon`, inspect the affected operation or revision and confirm that it is exactly the intended target. Do not discard or rewrite user work based on an assumed target.
**Stale working copy** — run `jj workspace update-stale`, then `jj status`.
**Immutable revision** — do not bypass immutability. Check the target, choose the intended mutable change, and retry there..codex/rules/jujutsu.rules# .codex/rules/jujutsu.rules
# --- allow ---
prefix_rule(pattern = ["jj", "status"], decision = "allow")
prefix_rule(pattern = ["jj", "log"], decision = "allow")
prefix_rule(pattern = ["jj", "diff"], decision = "allow")
prefix_rule(pattern = ["jj", "show"], decision = "allow")
prefix_rule(pattern = ["jj", "file", "list"], decision = "allow")
prefix_rule(pattern = ["jj", "root"], decision = "allow")
prefix_rule(pattern = ["jj", "describe"], decision = "allow")
prefix_rule(pattern = ["jj", "new"], decision = "allow")
prefix_rule(pattern = ["jj", "edit"], decision = "allow")
prefix_rule(pattern = ["jj", "restore"], decision = "allow")
prefix_rule(pattern = ["jj", "squash"], decision = "allow")
prefix_rule(pattern = ["jj", "rebase"], decision = "allow")
prefix_rule(pattern = ["jj", "abandon"], decision = "allow")
prefix_rule(pattern = ["jj", "evolog"], decision = "allow")
prefix_rule(pattern = ["jj", "op", "log"], decision = "allow")
prefix_rule(pattern = ["jj", "operation", "log"], decision = "allow")
prefix_rule(pattern = ["jj", "undo"], decision = "allow")
prefix_rule(pattern = ["jj", "bookmark", "list"], decision = "allow")
prefix_rule(pattern = ["jj", "bookmark", "create"], decision = "allow")
prefix_rule(pattern = ["jj", "bookmark", "move"], decision = "allow")
prefix_rule(pattern = ["jj", "bookmark", "advance"], decision = "allow")
prefix_rule(pattern = ["jj", "bookmark", "set"], decision = "allow")
prefix_rule(pattern = ["jj", "bookmark", "rename"], decision = "allow")
prefix_rule(pattern = ["jj", "config", "get"], decision = "allow")
prefix_rule(pattern = ["jj", "config", "list"], decision = "allow")
prefix_rule(
pattern = ["jj", "git", "fetch"],
decision = "allow",
justification = "Jujutsu's fetch is allowed"
)
# --- deny / forbidden ---
prefix_rule(
pattern = ["git"],
decision = "forbidden",
justification = "Do not use raw git; use jj commands instead"
)
prefix_rule(
pattern = ["jj", "resolve"],
decision = "forbidden",
justification = "Conflicts should be resolved manually"
)
prefix_rule(
pattern = ["jj", "diffedit"],
decision = "forbidden",
justification = "jj diffedit should be done manually"
)
prefix_rule(
pattern = ["jj", "arrange"],
decision = "forbidden",
justification = "jj arrange should be done manually"
)
# --- ask / prompt ---
prefix_rule(
pattern = ["jj", "bookmark", "delete"],
decision = "prompt",
justification = "Deleting a bookmark requires confirmation"
)
prefix_rule(
pattern = ["jj", "bookmark", "forget"],
decision = "prompt",
justification = "bookmark forget requires confirmation"
)
prefix_rule(
pattern = ["jj", "bookmark", "track"],
decision = "prompt",
justification = "Starting to track a remote bookmark requires confirmation"
)
prefix_rule(
pattern = ["jj", "bookmark", "untrack"],
decision = "prompt",
justification = "Untracking a remote bookmark requires confirmation"
)
prefix_rule(
pattern = ["jj", "git", "push"],
decision = "prompt",
justification = "Pushing to the remote requires confirmation",
match = ["jj git push -b feature-x"],
)Using These Configs
Setup
- Extract the downloaded ZIP file.
- Copy the contents of the extracted folder—including the dotted directories—into your project root, preserving the directory structure.
- Start a new session in Claude Code or Codex CLI.
If your project already contains files with the same names, copying the configuration as-is will overwrite them. Back up the existing files first, or merge the contents manually.
Requirements
- Jujutsu must be installed and the
jjcommand must be available. - The target project must be initialized as a Jujutsu repository.
- Claude Code or Codex CLI must be installed.
Tested Versions
- Jujutsu: 0.44.0
- Claude Code: 2.1.226
- Codex CLI: 0.147.0
License
These configuration files are provided under the Apache License 2.0. Commercial use, modification, and redistribution are permitted.
See the LICENSE file included in each download for the full terms.
Go Beyond the Starter Configs
These starter configs are enough to get Claude Code and Codex to use Jujutsu for everyday version control. As your workflow grows, however, you may also need automated checks, change cleanup, and coordination between multiple agents.
Juju-chu! explains how to build those workflows step by step, including:
- Running formatters and linters with
jj fixwhenever an agent completes a task - Running tests, builds, and security checks before pushing
- Cleaning up and consolidating large sets of agent-generated changes
- Running multiple agents in parallel and integrating their changes cleanly

