mandible 0.9.0

mandible: a universal, interactive TUI reference for CLI tools. `mandible git` opens an explorable tree of every command, subcommand, and flag git has, with descriptions.
mandible-0.9.0 is not a library.

mandible

A TUI manual for every command-line tool you have

CI framework support crates.io License Platform

Install • How it works • Coverage • Keys

man tells you about one command. --help tells you about one invocation. Neither explores a tool you don't already know.

$ mandible docker

[!TIP] Try running mandible mandible

Install

Linux and macOS, on x86_64 and arm64. Windows is not supported: the containment above relies on POSIX process groups, and Windows tools use conventions (/?, PowerShell's own help system) this project does not speak.

Cargo

# fetch prebuilt binary
cargo binstall mandible
# build from source
cargo install mandible

Fedora / EPEL (COPR repo)

sudo dnf copr enable as-foss/mandible
sudo dnf install mandible

Nix

nix run github:AS-FOSS/mandible

Homebrew (macOS or Linux)

brew install as-foss/mandible/mandible

Debian / Ubuntu (signed apt repo)

sudo curl -fsSL https://as-foss.github.io/mandible-apt/mandible-archive-keyring.gpg \
  -o /usr/share/keyrings/mandible-archive-keyring.gpg
sudo tee /etc/apt/sources.list.d/mandible.sources >/dev/null <<'EOF'
Types: deb
URIs: https://as-foss.github.io/mandible-apt
Suites: stable
Components: main
Architectures: amd64 arm64
Signed-By: /usr/share/keyrings/mandible-archive-keyring.gpg
EOF
sudo apt-get update && sudo apt-get install mandible

Standalone binaries, .deb and .rpm packages, each with a .sha256, are attached to every release.

How it works

There is no per-tool logic anywhere in this project. No if tool == "docker", no vendored catalogue of hand-written definitions. That approach is convenient for a week and unmaintainable ever after. It is always slightly out of date, and it is wrong in ways you cannot see from the outside.

The insight it runs on instead: help text isn't written by hand, it's generated, and only a small closed set of generators exists. mandible works out which framework produced a tool's output, then applies that framework's grammar. For example:

[!TIP] Open straight at a subcommand: mandible cargo clippy. Subcommands that live as separate <tool>-<sub> binaries (cargo-clippy, git-lfs) show up too, marked unverified: they were found on PATH, not in the parent's own help.

Is it actually universal?

That claim is measured, not asserted. cargo xtask coverage runs the pipeline against every executable on your PATH and scores each one: sources used, framework detected, nodes, flags, percentage described.

It also carries a structure-sanity column, which exists because a coverage number alone can be gamed by the very failure it should catch. %described once reported a tool as fine at 100% while 39 of its 40 subcommands had been fabricated out of wrapped prose. A metric that improves when the tool gets worse is worse than no metric.

CI gates every change against a fixed tool list, and sweeps the whole PATH separately for the broad picture.

Coverage is not accuracy, though, and the honest number is lower than a green badge suggests. Accuracy comes from a human-reviewed audit, where a person checks a randomly drawn sample of real tools against each tool's own --help text. The sample is committed to the repo before any verdict is recorded, so it cannot be quietly redrawn once the results look bad. In the most recent audit, 25 of 43 tools parsed fully correctly, about 58%. A sample that small leaves real statistical slack, so the true rate across all tools could sit anywhere between about 43% and 72%. Tools that mandible itself marks ok do better, at 80% correct with a plausible range of 61% to 91%.

mandible is useful today and wrong often enough that you should check anything surprising against the tool's own --help.

[!TIP] Something parses wrong? Run mandible --report <tool> and paste the output into an issue. That takes two minutes and is a complete contribution on its own.

Settings live in ~/.config/mandible/config.toml. mandible never creates the file; the settings tab of the ? pop-up writes it, one key at a time, and leaves your comments and other keys alone. A key that is unknown or has a bad value is ignored and the footer says which line until you press a key.

# ~/.config/mandible/config.toml

[ui]
raw_view = false
horizontal_scroll = false
description_preview = true
ascii = false

[sort]
flags = "tool"
commands = "tool"

[colors]
theme = "default"

theme is default, light, high-contrast, gruvbox-style, nord-style, dracula-style, catppuccin-style, custom or none. With custom, seven more keys give the colours, each a name (black to bright-white) or a number from 16 to 255:

[colors]
theme = "custom"
accent = "bright-cyan"   # flag spellings, focused border
warning = 220            # low confidence, notices
muted = "bright-black"   # secondary text
section = 246            # section headings
group = 240              # group headings
selection = 237          # the selection bar
selection_text = 252     # text on the bar
Key Values What it does
raw_view true, false Start in the tool's own --help view, as if t were pressed
horizontal_scroll true, false false folds long lines to the pane. true keeps one row per line and scrolls sideways, in the parsed and the raw view. w flips it for the view on screen
description_preview true, false false draws a long description in full, in place
ascii true, false Force the ASCII glyph set
flags "tool", "az-sections", "az" Where s starts in the detail pane
commands "tool", "az" Where s starts in the commands list
theme a theme name, "custom" or "none" none draws no colour. custom uses the seven colour keys; a missing one keeps the default theme's value

An environment variable beats the file, and the file beats the default.

Getting a tool's documentation right is mandible's job, not yours. If something parses wrong, mandible --report <tool> plus an issue fixes it for everyone. (Local per-tool corrections do exist for the impatient: ~/.config/mandible/overrides/<tool>.toml.)

Environment variables

Variable Effect
NO_COLOR Same as theme = "none", and beats the file. TERM=dumb and piped output do the same
MANDIBLE_ASCII=1 Force the ASCII glyph set, for terminals that mangle Unicode. Beats ascii
MANDIBLE_CONFIG_DIR Read config and overrides from a different directory
MANDIBLE_LOG Tracing filter, written to stderr

Keys

? inside mandible lists every binding, and its second tab, reached with Tab, changes the settings above. The footer keeps the important keys on screen: arrows or hjkl to move, / to search, Tab between panes, ←/→ to scroll wide lines sideways, t for the tool's own --help, s to sort the focused pane A–Z, y to copy the selected flag, q to quit.

Search has two modes. names matches a command name or any spelling of a flag, positional, modifier or environment variable; everything also searches descriptions. In both, a row matches when it contains every word you type, in any case, and a dash counts like any other character: size finds --blocksize, no verify finds --no-verify. The best match is where the cursor jumps; every other match stays in the tree. While you type, a dim suggestion shows where Enter will land, or the closest name when nothing matches, and Tab takes it. / opens the first mode, pressing it again switches to the second.

Completions

The packages install shell completions for you. For a hand-built binary, mandible --completions <shell> prints the script (bash, zsh, fish, and more); drop it wherever your shell looks for completions. For zsh:

$ mkdir -p ~/.zfunc && mandible --completions zsh > ~/.zfunc/_mandible

then add fpath=(~/.zfunc $fpath) to ~/.zshrc, above its compinit line. zsh silently skips completion directories it considers insecure (anything under /tmp), so keep the file under your home.

The tool argument completes too, to the command names on your PATH: mandible gi<TAB> suggests git rather than whatever files sit in the current directory. zsh and fish do this today; bash's script format can't express it yet.

Onto the prompt

y gets a spelling as far as the clipboard. To land it on the command line instead, add the shell integration:

$ eval "$(mandible --shell-init bash)"   # or: zsh — in your ~/.bashrc, ~/.zshrc

Now type a tool name, press Ctrl-X m, browse, and press Enter: the command you selected (git commit --amend, say) replaces the line, ready to edit. Quit with q and the line stays exactly as it was.

The binding is a few lines of shell around mandible --print-selection <tool>, which browses as usual but makes Enter print the selection instead of expanding the row (the UI draws on stderr, so stdout carries just that one line). Bind it to a different key, or wrap it in your own widget, by reading what --shell-init prints.

Diagnostics

$ mandible --doctor gh
framework: cobra (from artifact)
nodes: 29
flags: 2 (100.0% described)

--doctor reports which framework mandible identified, which sources contributed, and how much of the tool it understood. It turns "mandible is wrong about tool X" into "the cobra grammar mishandles Y", which is a bug someone can actually fix.

A probe is stopped after 30 seconds and reported as a failure. --no-timeout with --doctor or --report lets every probe run as long as it needs.

Running as root

mandible refuses to start as root, printing the flag that lifts the refusal. A probe like fail2ban-client start --help reaches a daemon socket, and under root that is an action, not a question. Pass --allow-root to proceed anyway; mandible never asks for or gains privileges on its own.

Documentation

docs/design.md Design authority: the source model, the safety policy, and the measurement behind every non-obvious decision
AGENTS.md The invariants table. Every entry names the failure it prevents

Contributing

If a tool renders wrong, an issue is the fastest way to tell us. Run mandible --report <tool> and paste the output into the issue form; it asks for the rest (your OS, what you expected, a screenshot if you have one). Your tool's version and its exact help text vanish when you upgrade, and nobody else can recover them, so the report is a complete contribution on its own.

If you want to go further, audit mandible against the tools on your own machine. Every accuracy figure here comes from one Ubuntu machine on ARM, so whatever you have installed is probably software this project has never seen.

$ git clone https://github.com/AS-FOSS/mandible && cd mandible
$ cargo xtask audit contribute

The command asks for your GitHub login, scans your PATH, draws twenty tools and opens each one in the normal interface next to its real help text. Press t to see the raw text, then c, i, w or s for correct, incomplete, wrong or skip. It saves after every verdict, so you can Ctrl-C and come back later. When you finish, it writes your verdicts under audit/submissions/<your-login>/ and prints the commands to commit them and open the pull request. Merged audits sit under your name in the tree and are credited in the release notes.

[!NOTE] When auditing, verify by hand and by eye only, in the interface itself: cargo xtask audit contribute opens it for you, and mandible --review <seed> reopens an unfinished draw. mandible does have automated checks (pty renders of the TUI, and cargo xtask audit emit and review, which print a tool's raw help text beside the tree as plain text for machines with no terminal), however none of them can tell you what was missed or which flags are wrong. That judgement is the whole point of an audit. So: no AI, no CI, nothing non-manual, and no verdicts formed from the text dump.

CONTRIBUTING.md has the details, plus writing tests and changing the parser.