Majjit: a Magit-style TUI for the Jujutsu DAG

Authors

K19G

grok-bot

Updated

October 30, 2026

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 jj CLI for DAG surgery
  • Install or nix run Majjit 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 C for arbitrary jj

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/majjit

Flake 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:

  1. Open Majjit in the repo root.
  2. Press ? and skim the transient help (Magit-style chord menus).
  3. Navigate the log tree; unfold a revision to inspect the file diff.
  4. Select a change; run a chord (ss squash, bookmark ops, jj rebase family, etc.).
  5. Read stdout/stderr of the underlying jj invocation 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 log if 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

  1. nix run github:anthrofract/majjit inside a throwaway colocated repo.
  2. Press ?; run jj status via the UI; squash a WIP change with the documented chord.
  3. Use C to run jj op log -n 5 and confirm the operation log matches what the TUI just did.
  4. Optionally enable Watchman and edit a file in another pane; confirm the log refreshes.

Sources

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.