# 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. [Jujutsu]: https://jj-vcs.dev ## Installation Install jj-slice from [Cargo]: [Cargo]: https://doc.rust-lang.org/cargo/getting-started/installation.html ```sh cargo install --locked jj-slice ``` Or build it with Nix: ```sh nix profile install git+https://tangled.org/isaaccorbrey.com/jj-slice ``` You can alias it to run as a neat subcommand of Jujutsu: ```sh 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: ```toml [aliases] slice = ["util", "exec", "--", "jj-slice"] ``` ## Usage ```sh 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: --- ` lines: ``` JJ: Each `JJ: --- ` 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: ```toml # Anthropic; reads $ANTHROPIC_API_KEY [tools.jj-slice] provider = "anthropic" model = "claude-haiku-5-5" ``` ```toml # 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 ``` ```toml # 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: ```toml [tools.jj-slice.prompts] group = "... {revisions}" name = "... {revisions}" ``` ### Prefixes Names from the agent can get a prefix, either a fixed one: ```toml [tools.jj-slice] prefix = "icorbrey" # names become icorbrey/ ``` 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: ```toml [[--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]. [Apache 2.0]: ./LICENSE-APACHE.md [MIT]: ./LICENSE-MIT.md