Majjit: a Magit-style TUI for the Jujutsu DAG
Majjit: a Magit-style TUI for the Jujutsu DAG
jj log is powerful; a scrolling terminal transcript is still a poor place to point at a revision, fold a diff, squash into a parent, and push—without retyping change ids. Majjit is a Rust TUI that treats the Jujutsu commit DAG like Magit treats a Git repo: browse the log tree, run multi-key command sequences, see jj output in a pane, fuzzy-pick bookmarks and changes.
This chapter sits next to the working-copy-as-commit mental model: once @ is a real commit, a DAG browser becomes the everyday control surface. It does not re-teach jj new / jj squash / colocated Git—those stay in the earlier jj chapter. Focus here is the TUI workflow and how it maps onto jj operations.
Primary source: anthrofract/majjit README (retrieved 2026-10-16). Majjit was not installed on this box (no cargo install / Nix run in scout); commands and key sequences are from upstream docs.
Learning goals
By the end of this chapter you can:
- Explain what Majjit adds on top of raw
jjCLI for DAG surgery - Install or
nix runMajjit from the upstream flake / cargo git source - Use
?help, folding, fuzzy pickers, and multi-key sequences (ss,gpa, …) - Map common Magit habits (stage/fold/push) onto jj verbs Majjit shells out to
- Know the escape hatch: custom command
Cfor arbitraryjj
Thesis
jj already made the working copy a commit. Majjit makes the operation graph browsable: select a node, chord a verb, read the pane—without losing the precision of change ids.
Mental model
jj CLI Majjit TUI
───── ────────
jj log | less foldable log + diffs
remember change id click / fuzzy select
jj squash -r X --into Y select + `ss` (example chord)
scrollback for output bottom output panel
| Habit | In Majjit (per upstream README) |
|---|---|
| Discover bindings | Press ? |
| Fold / unfold | Mouse right-click or UI fold controls |
| Select | Mouse left-click or keyboard navigation |
| Squash into parent | Example chord ss → jj squash on selection |
| Push all / tracked | Example chords gpa / gpt → jj git push … |
| Anything missing | C → custom jj … |
| Live refresh | Watchman on PATH refreshes on file changes |
Case 1 — Install options
Upstream documents three paths:
# Cargo (git)
cargo install --git https://github.com/anthrofract/majjit
# One-shot Nix
nix run github:anthrofract/majjitFlake overlay sketch (from the README):
# flake inputs / modules fragment
{
inputs.majjit.url = "github:anthrofract/majjit";
# ...
nixpkgs.overlays = [ majjit.overlays.default ];
environment.systemPackages = [ pkgs.majjit ];
}Run Majjit from a colocated jj/Git repo (or any jj workspace). If you are still learning @ vs change id, finish that mental model first—then the TUI stops feeling like magic.
Case 2 — Browse, fold, act
Typical session shape:
- Open Majjit in the repo root.
- Press
?and skim the transient help (Magit-style chord menus). - Navigate the log tree; unfold a revision to inspect the file diff.
- Select a change; run a chord (
sssquash, bookmark ops,jj rebasefamily, etc.). - Read stdout/stderr of the underlying
jjinvocation in the bottom panel—the TUI is a frontend, not a second implementation of the DAG.
Supported surface area (README list, abbreviated): abandon, absorb, bookmark create/move/track/…, commit, describe, diff, duplicate, edit, evolog, file track/untrack, git fetch/push/remote list, new/next/prev, parallelize, rebase, redo/undo, resolve, restore, revert, split, squash, status, sign/unsign, workspace add/forget/list/rename/update-stale, plus custom C.
That coverage matters: Majjit aims at most of jj help, not a toy subset. When a brand-new jj subcommand appears, C keeps you unblocked until bindings catch up.
Case 3 — Multi-key sequences as muscle memory
Majjit borrows Magit’s transient menus: short chords compose modifiers + verb.
| Example chord (README) | Underlying idea |
|---|---|
ss |
Squash selected revision into its parent |
gpa |
jj git push --all |
gpt |
jj git push --tracked |
Fuzzy matching appears when an operation needs you to pick a change or bookmark—cheaper than pasting opaque ids from jj log.
Mouse support (left select, right fold, scroll wheel) makes review sessions friendlier on laptops; keyboard chords stay for speed.
Case 4 — Where Majjit fits among “future of VCS” tools
- vs raw jj: same semantics, better spatial UX for DAG edits.
- vs Magit: same UX genre, different object model (change ids, operation log, no index).
- vs agent-scale Git infrastructure essays: orthogonal. Majjit is a human TUI on a local jj repo, not a forge-side merge farm. Keep those concerns in separate chapters.
The trap
- Treating the TUI as authoritative state separate from jj—always verify with
jj status/jj op logif something looks wrong. - Learning Magit keybindings by rote and assuming identical chords—read
?inside Majjit. - Installing from a random fork; pin
github:anthrofract/majjit(or a commit) in flakes.
The boring rule
Use Majjit to select and fire jj operations you already understand. If you cannot explain what ss will do to @ and the parent, drop to the CLI until you can—then bind the habit in the TUI.
Try this
nix run github:anthrofract/majjitinside a throwaway colocated repo.- Press
?; runjj statusvia the UI; squash a WIP change with the documented chord. - Use
Cto runjj op log -n 5and confirm the operation log matches what the TUI just did. - Optionally enable Watchman and edit a file in another pane; confirm the log refreshes.
Sources
- anthrofract/majjit — README: features, command list, install
- Jujutsu documentation — semantics of the operations Majjit fronts
- Magit — UX inspiration (conceptual only)
Inspiration
- Majjit (“Magit for jj”) TUI announcements / Rust community posts. Chapter cites the upstream README.
Verification
Docs-based from the majjit README (HTTP 200 from master, 2026-10-16). No local majjit or jj binary on this box; install-dependent screenshots and live key chords were not re-run. Cross-check command names against jj help on your machine before relying on a chord in muscle memory.