A semantic stack slicer for Jujutsu. crates.io/crates/jj-slice
cli jujutsu stacked-prs
jj-slice README.md
4.1 kB
Markdown
at main

jj-slice #

A semantic stack slicer for Jujutsu. Lets you easily break up a range of commits into logical chunks, name them, and track them in one fell swoop. Integrates with your favorite (or least favorite) AI provider to enable split suggestions and branch names.

Installation #

Install jj-slice from Cargo:

cargo install --locked jj-slice

Or build it with Nix:

nix profile install git+https://tangled.org/isaaccorbrey.com/jj-slice

You can alias it to run as a neat subcommand of Jujutsu:

jj config set --user aliases.slice '["util", "exec", "--", "jj-slice"]'

Or, if your config is generated and thus readonly, make sure you output in your config:

[aliases]
slice = ["util", "exec", "--", "jj-slice"]

Usage #

jj-slice -r 'trunk()..@-'    # or `jj slice` with the alias above

The range must be a single linear run of commits with no merges. jj-slice opens your editor (ui.editor, same as jj) with the commits newest first, split into PRs by JJ: --- <bookmark> lines:

JJ: Each `JJ: --- <bookmark>` line starts one PR in the stack. Move the existing
JJ: separators or add new ones to change the split, and edit the names after
JJ: them; separators left without a name are named automatically. Don't reorder
JJ: or remove commits. Clear the buffer to abort.

JJ: --- abc-123/add-dry-run-flag
kvmrsnxl  cli: Add a --dry-run flag
ytuqzwop  cli: Parse config overrides from the command line
JJ: --- abc-122/handle-quoted-strings
wlpqrxmz  parser: Handle quoted strings

Move the existing separators or add new ones to change where it splits, and write or edit a bookmark name after any separator. Don't reorder or remove commits. Clear the buffer to abort.

When you save, jj-slice creates a bookmark on the newest commit of each PR and tracks it on your remotes. Separators left without a name are named by the agent if one is configured, or else with your templates.git_push_bookmark, the same names jj git push -c would make.

Configuration #

With no configuration, the whole range starts as one PR with no name.

To have an agent suggest where to split and what to name each bookmark, configure one of these providers:

# Anthropic; reads $ANTHROPIC_API_KEY
[tools.jj-slice]
provider = "anthropic"
model = "claude-haiku-5-5"
# Any OpenAI-compatible API; sends $OPENAI_API_KEY when set
[tools.jj-slice]
provider = "openai"
model = "gpt-6-luna"
base-url = "http://localhost:11434/v1"   # optional, e.g. for Ollama
# Any command that reads a prompt on stdin and answers on stdout
[tools.jj-slice]
provider = "noninteractive"
command = "claude -p"                    # or an argv list: ["claude", "-p"]

The built-in prompts can be replaced. {revisions} is replaced with each commit's full description and changed files, and custom prompts must include it:

[tools.jj-slice.prompts]
group = "... {revisions}"
name = "... {revisions}"

Prefixes #

Names from the agent can get a prefix, either a fixed one:

[tools.jj-slice]
prefix = "icorbrey"              # names become icorbrey/<name>

or one captured from the commits' descriptions. ^ and $ match at line boundaries. The first capture group (or the whole match, if there's no group) from the oldest matching commit in each PR is used. PRs with no match get no prefix. Combined with jj's conditional config, this can put a Jira ticket from a Jira: trailer at the front of every name at work:

[[--scope]]
--when.repositories = ["~/work"]

[--scope.tools.jj-slice.prefix]
capture = '^Jira: ([A-Z]+-\d+)$'
transform = "lowercase"          # optional

transform takes the same case names as serde: lowercase, UPPERCASE, kebab-case, snake_case, camelCase, PascalCase, SCREAMING_SNAKE_CASE, and SCREAMING-KEBAB-CASE.

License #

jj-slice is distributed under one of MIT or Apache 2.0.