Skip to content
Projects

glennib/stakk has 33 GitHub stars and 5 forks. GitHot measured 0 stars in 24 hours. Last checked 2026-11-09 10:28 UTC. Last push 2026-11-03.

How these counts are measured

A CLI tool that bridges Jujutsu (jj) bookmarks to GitHub or Forgejo stacked pull requests

Measured star growth

in 24h
0
in 7 days
Update delayed
in 15 days
Update delayed
in 1 month
Update delayed

Net star changes over overlapping periods, not daily totals. Missing measurements are left blank. Stars measure attention, not software quality.

README.md

Original

stakk

stakk turns Jujutsu bookmarks into GitHub or Forgejo stacked pull requests. Pick a stack, name the bookmarks that still need one, and stakk pushes and maintains one PR per bookmark: correct base branches, a stack overview on every PR, no duplicates on re-runs. It works with GitHub's native stacked pull requests: opt in with --native-stacks auto and GitHub renders the stack itself and retargets PRs as the stack merges.

jj stays in charge of your commits and bookmarks; stakk acts only where that state has to exist on the forge. It never calls git — everything goes through jj, so workspaces and non-colocated repos just work.

Interactive stakk submission flow

Installation

Requires the jj CLI on your PATH, version 0.39.0 or newer.

mise use -g 'github:glennib/stakk'   # recommended
mise use -g 'cargo:stakk'            # from crates.io
cargo binstall stakk
cargo install stakk
nix run github:glennib/stakk         # nix, without installing
nix profile install github:glennib/stakk

Or download a binary from the latest release.

Quick start

stakk          # pick a stack and assign bookmarks in the TUI
stakk graph    # show your stacks and their change ids (offline)

# Without the TUI: one mark per PR boundary
stakk submit --keep feat-auth --new qzvs=feat-api --new-auto wmtk --dry-run

--dry-run prints the plan and stops: no bookmark is created, nothing is pushed, nothing is written to GitHub. stakk --help and stakk <subcommand> --help are the flag reference; stakk docs prints the same documentation as docs/, bundled into the binary.

How stacking works

Bookmarks that form a linear chain are a stack:

 ○  feat-ui    ← leaf
 ○  feat-api
 ○  feat-auth
 ◆  main       ← trunk

Submitting all three — in the TUI, or as stakk submit --keep feat-auth --keep feat-api --keep feat-ui — pushes each bookmark and creates or updates one PR per bookmark, based on the one below it: feat-auth → main, feat-api → feat-auth, feat-ui → feat-api. Each PR shows only its own diff.

Unbookmarked commits can become PRs too. In the TUI each commit cycles through [x] existing bookmark, [~] name derived from the commit (TF-IDF), [>] typed, [+] generated stakk-<change_id>, [*] from --bookmark-command, and [ ] skip. --auto-prefix brands the derived names (gb-caching-database).

GitHub native stacks

--native-stacks registers the submitted stack with GitHub's native stacked pull requests (public preview), so GitHub draws the stack on every PR and retargets the remaining PRs as the stack merges bottom-up. Modes: on (fail where the feature is unavailable), auto (register where available, skip where not — GitHub Enterprise Server, for example), none (register nothing and dissolve the server-side stacks stakk's PRs are in), and ignore (never touch the stack API). The default is ignore while the feature is a public preview and may become auto in a minor release once it leaves it — the one default the stability contract exempts.

Native stacks layer on top of the base-branch chain stakk maintains anyway; nothing else about a submission changes.

Stack info placement

Every PR in a stack also gets a stack overview from stakk, leaf at the top like stakk graph and the TUI. Each row is a bare PR link, which GitHub renders with the PR's live title and merge state:

Stack of 3 PRs merging into main

• Add the search UI #14 (top of stack)
• Add the search API #13 👈 this PR
• Add user authentication #12
• main

--stack-placement decides where it lives: a PR comment, a fenced section in the PR body, none (write nothing and remove what is there), ignore (write nothing, touch nothing), or auto-comment (default) / auto-body, which write like comment/body except on runs where a native stack is in effect, where GitHub's rendering replaces it. So --native-stacks auto gives native rendering where available and stack comments everywhere else, never both. Switching between comment and body migrates automatically.

Mode table and minijinja templating: docs/template.md or stakk docs template.

Configuration

CLI flags override STAKK_* environment variables, which override a repository stakk.toml, which overrides the user config (~/.config/stakk/config.toml on Linux).

# stakk.toml
remote = "origin"
pr_mode = "draft"
stack_placement = "body"
auto_prefix = "gb-"

Every key and variable: docs/config.md or stakk docs config.

GitHub Enterprise Server

github.com needs nothing, and an Enterprise host is recognised on first use by how its API answers. To skip that probe, map the host once with --host ghe.example.com=github, STAKK_HOSTS, hosts in stakk.toml, or the GitHub CLI's GH_HOST. stakk talks to https://<host>/api/v3. Tokens are resolved per host like the GitHub CLI does it, so an Enterprise token is never sent to github.com. Setup and troubleshooting: docs/auth.md or stakk docs auth.

Forgejo

codeberg.org needs nothing, and any other instance is recognised on first use by how its API answers; map it once with --host git.example.com=forgejo, STAKK_HOSTS or hosts in stakk.toml to skip that probe. A host:port over plain http works: stakk talks to <scheme>://<host>/api/v1 with the remote's own scheme. --forge forgejo (STAKK_FORGE, forge = "forgejo") skips the lookup for one run. The token comes from FORGEJO_TOKEN and nothing else. --native-stacks is a GitHub feature: on Forgejo auto and none are silent, and you get stack comments. Setup and troubleshooting: docs/auth.md or stakk docs auth.

Non-interactive selection

--keep, --new, --new-auto and --new-command (-k, -n, -a, -c) replace the TUI with an explicit selection: every PR boundary is named on the command line, all marks lie on one trunk-to-tip path, unmarked commits fold into the PR above them, and anything above the topmost mark is not submitted. rev is any jj revset naming one commit: @-, a bookmark, or a change id from stakk graph --format=json.

Rules and diagnostic codes, written for coding agents: docs/agents.md or stakk docs agents (stakk docs agents >> AGENTS.md hands it to yours). Exit codes and a worked Python example: docs/scripting.md or stakk docs scripting. The JSON schema: docs/graph.md or stakk docs graph.

PR titles and bodies

The title is the first line of the change description, the body is the rest; multi-commit segments join their descriptions with ---. Hard-wrapped prose is reflowed into paragraphs; Markdown structure passes through verbatim. Both are written only on PR creation, so edits on GitHub survive — --sync-pr-content (title, body, all) opts into updating them. --trailers strip drops the trailing Key: value block (Signed-off-by, Refs, …).

Custom bookmark names

--bookmark-command runs a program (sh -c, or cmd /C on Windows) with a JSON description of the segment on stdin and takes its stdout as the bookmark name. It powers the [*] TUI state and --new-command; the JSON schema is in stakk submit --help.

Immutable commits

Commits jj considers immutable cannot get a new bookmark: the default bookmarks revset excludes immutable(), so stakk would create a PR it could never see again. The TUI locks such rows, --new <rev> fails with stakk::selection::rev_immutable, and stakk graph marks them. Move the work onto mutable commits, or create the bookmark yourself and drop ~ immutable() from --bookmarks-revset.

Stability

stakk follows semantic versioning. Stable: subcommands, aliases and flags, STAKK_ environment variables, config keys and defaults, the two schema_version-ed JSON documents (stakk graph and --bookmark-command's stdin), and exit codes. Free to change: --help and stakk docs text, error wording, the set of diagnostic codes, stakk graph's pretty output, the order of stacks[], the TUI, and the minimum jj version. The contract: docs/stability.md or stakk docs stability.

License

MIT OR Apache-2.0

Explore related projects