Releases: AS-FOSS/mandible
Release list
v0.2.2
Install
cargo install mandible
Or download a pre-compiled binary from the assets below. Verify with the accompanying .sha256.
This release introduces two general parser fixes that significantly improve documentation extraction. Together, they increase described coverage across the PATH sweep from 89.23% to 94.18% on 2,266 tools, with zero regressions.
Fixed
- Tab-Aligned Entry Tables: The parser now recognizes tabs as valid description gaps. Previously,
find_description_gaponly looked for runs of two or more spaces, causing tab-separated columns to appear undocumented (e.g.,mokutil --helpreported 38 flags with 0 described). Because a tab inherently advances to the next 8-column stop, it now correctly separates columns. This fix recovers 100% description coverage formokutiland restores 11 real commands formysqladmin/mariadb-admin. - Option Synonym Handling: As a necessary companion to the tab-alignment fix, a second column of option spellings is no longer mistakenly read as a description. For example,
awk --helppairs POSIX short options with GNU long equivalents separated by a tab. Treating that tab as a description gap previously gave-f progfilethe false description--file=progfile. Single tokens beginning with-in the description column are now recognized as synonyms and dropped, preserving the tool's accurate "no description" state. - Positional Headers in Option Tables: An options table is no longer discarded if it opens with a positional argument. The parser's flags-vs-bare-words decision previously only evaluated the section's first content line. Because
kill --helpopens itsOptions:block with<pid> [...], every subsequent flag was discarded, resulting in 0 parsed flags. The parser now evaluates up to three leading non-flag rows at the block's indent level, provided it still finds a real--leading row. This boundary deliberately prevents fabrication while successfully recovering all 6 flags forkill.
v0.2.1
Install
cargo install mandible
Or download a pre-compiled binary from the assets below. Verify with the accompanying .sha256.
This release addresses the root causes behind the execution safety lockouts introduced in previous versions. By fixing a severe underlying argument-parsing bug and refining fallback behaviors, Mandible is now globally safer and has restored documentation support for essential system-state tools.
Critical Safety & Execution Hardening
- Fixed the Empty Positional Hazard (
<tool> -- ""): The primary cause of the catastrophic system freezes reported in earlier versions has been identified and fixed. Aclapcompletion probe was passing an empty string as a first positional argument (<tool> -- ""). For pattern-matching tools likepkill, an empty string means "match everything." Measured in a private PID namespace,pkill -- ""killed every reachable process. This specific argument shape is now globally refused at the execution chokepoint (Spec §6 rule 2a) for all tools. - Blocked Dangerous Fallbacks (
-h): Mandible normally falls back to-hif--helpfails. However, for machine-state tools (halt,poweroff,reboot,shutdown),-his an action flag meaning "halt". Unprivileged execution was the only thing preventing Mandible from rebooting the host machine during a background sweep. The-hfallback is now strictly refused for these specific system tools. - Specification Correction: Corrected the safety rationale in
spec.md. The previous assumption thatkillall foo --helpwas dangerous was factually incorrect (on glibc, GNU getopt permutes arguments and safely processes--helpfirst). The true hazard was the empty positional bug mentioned above.
Restored Tool Support
- Process Killers & System Tools Browsable: With the root execution bugs fixed, tools previously locked behind a blanket ban (
pkill,killall,fuser,reboot,shutdown, etc.) are now safely probed using a strict<tool> --helpshape. - Coverage Boost: Twelve of the thirteen previously locked tools now parse successfully.
pkillnow yields 27 fully described flags, andkillall/fuseryield 16 each. This bumps overall described coverage from 89.20% to 89.23%.
Parser Accuracy Improvements
- Removed Inaccurate
clap CompleteEnvProbe: This probe was the source of the dangerous empty positional argument. Beyond being unsafe, it was highly inaccurate—lacking a strict protocol signature, it relied on shape heuristics that falsely matched unrelated tools (likeecho,bzless, andupdate-alternatives). Removing it deleted eight bogus parses and actually improved described accuracy without losing valid data for any tool.
Project Metadata
- Canonical Repository Move: The project's official repository is now
[https://github.com/AS-FOSS/mandible](https://github.com/AS-FOSS/mandible). This update is reflected in the crates.io metadata and themandible mandibleeaster egg.
v0.2.0
Install
cargo install mandibleOr download a binary below. Verify with the accompanying .sha256.
Six fixes, three of them found by rendering a deliberately awkward CLI through a
real pseudo-terminal rather than by any test.
Fixed
-
The USAGE line no longer repeats the command name.
docker import
rendered asimport docker import [OPTIONS] file|URL|- [REPOSITORY[:TAG]].
The check asked whether the usage's first word was the node's name, but
cobra and argparse both print the full command path, so the name was stapled
on the front of nearly every subcommand of every such tool. It now scans the
whole leading run of command words. Tools that print no name at all
(Usage: [OPTIONS] FILE) still get one added, which is what the prepending
was for. -
A token wider than the pane is broken across lines instead of discarded.
It was ellipsis-truncated, so a 150-character URL rendered as
https://registry.example.com/v2/org…with everything after it unrecoverable
from the parsed view. Splits are placed by display width, so a double-width
character cannot straddle the boundary and overflow the pane. -
A relative tool path works.
mandible ./scripts/tool.pyfailed with
"No such file or directory" for a file plainly present: the path was checked
against the caller's working directory, then the probe ran with its own
directory redirected into a scratch dir (§6 rule 8). Resolution now yields an
absolute path — viastd::path::absolute, deliberately not
fs::canonicalize; see below. -
argparse subcommands survive a styled section heading.
add_subparsers(title="commands")is the ordinary way to name that block,
and the dedicated scan was gated on the heading readingpositional arguments, so a styled heading collapsed the entire command tree to a single
node. The scan's structural evidence — a{a,b,c}pseudo-entry with deeper
lines beneath it — is stronger than the heading text ever was, and still
refuses a plain positional carryingchoices=[...]. -
A command list at the same indent as its heading is recognized.
dnf4
prints its whole command list flush at column 0 under a flush-left heading;
the engine required content indented more than its heading, somandible dnfshowed one node and no subcommands. Now 30. -
A pending row's spinner no longer touches the name.
dnf's longest
command renderedcheck-update⋯ loading, one mangled word rather than a name
and its status — the same defect fixed for summaries in an earlier release
(apt-get'sdselect-upgradeFollow) and missed in the sibling branch,
because no tool in the suite had a pending row at the column untildnf
gained subcommands.
Notes on two near-misses
Both were caught by the PATH-wide coverage sweep and by nothing else; the unit
suite was green through both.
- Making resolved paths absolute with
fs::canonicalizedefeated §6 rule 0.
is_never_probematches on the file name, andreboot,poweroff,
shutdownandtelinitare symlinks tosystemctl— resolving renamed them
before the refusal ran. It also broke teniptables*tools, which dispatch on
argv[0]. Fixed by usingstd::path::absolute, which does not follow links. - The same-indent command rule initially fabricated 28 subcommands out of
mysqlslap's config-variable table (port 3306,no-drop FALSE), because at
a shared indent every row is a candidate heading for the rows beneath it and
init-commandcontains the word "command". A heading must now not itself look
like a row.
Final sweep is identical to baseline on every aggregate — 89.19% described
across 2266 tools, 1 suspicious, 320 verbatim — with zero status changes, zero
nodes lost, and dnf the only gain.
Internal
scripts/smoke_cli.py: a deliberately awkward argparse CLI for exercising
layout by hand — a twelve-level command chain, four flag-table shapes, tokens
with no whitespace to wrap at, and sixty flags. It found three of the bugs
above within minutes of existing.
v0.1.7
Install
cargo install mandible
Or download a pre-compiled binary from the assets below. Verify with the accompanying .sha256.
This release introduces responsive table layouts for narrow terminals and completely eliminates sandbox path leakage in tool documentation, ensuring extracted defaults reflect expected environment variables rather than ephemeral test directories.
Sandbox Path Sanitization & Environment Isolation
- Dynamic Path Masking: Tools outputting environment-derived defaults (e.g.,
docker --helpprinting its config path) will no longer leak Mandible's ephemeral sandbox paths (like/tmp/mandible-exec-L3saJ8/.docker). At the execution boundary, these scratch paths are now dynamically masked back to their source variables (e.g.,$HOME/.docker). This keeps documentation readable and captured fixtures independent of the machine that generated them. - Symlink & Resolution Awareness: Paths are masked using both logical and canonicalized spellings. This ensures correct masking even when a probed tool resolves its own working directory (e.g., macOS
$TMPDIRresolving from/varto/private/var). - Strict Variable Isolation: Each redirected variable (
HOME,TMPDIR,XDG_*) now receives its own dedicated scratch subdirectory. Previously, they shared a single directory, creating an impossible filesystem state where writing to a cache directory and reading from a home directory resolved to the same file. This isolation also serves as the foundation enabling the dynamic path masking above.
Responsive UI & Table Layouts
- Invariant Table Alignment: The flag description column is now strictly aligned across the entire list. Previously, exceptionally wide flags pushed the column boundary for themselves, creating ragged prose and causing spelling and value placeholders (e.g.,
--log-level string) to visually collapse into single tokens. Now, outlier wide flags simply hang their descriptions on the next line. - Narrow Terminal Stacking: Below a usable table width, parameter lists now automatically stack—placing the flag spelling on the first line with the description indented underneath. This mirrors standard CLI help behavior and prevents severe line-wrapping artifacts (such as a six-word description breaking across six lines).
Internal Tooling
- PTY Rendering Tests: Restored
scripts/pty_screenshot.pyto render the TUI through a genuine pseudo-terminal. This debugging tool caught both of the UI layout defects addressed in this release, proving its value over the standardTestBackendsuite which reported green throughout.
v0.1.6
Install
cargo install mandible
Or download a pre-compiled binary from the assets below. Verify with the accompanying .sha256.
This release fundamentally overhauls the re-extraction (r) workflow, addressing critical concurrency defects reported in [#6](#6) and ensuring the UI retains your exact context across refreshes.
Stateful Re-extraction
- Context Retention: Pressing
rto re-extract no longer rebuilds the application state from scratch. Your expanded nodes, selection, scroll position, search filter, and view mode are all preserved. The selection is intelligently restored by path rather than row index, accommodating changes in the underlying tree structure. - Root Fill Restoration: Fixed a bug where a refresh left the detail pane entirely empty. The root fill is now properly re-queued to start the tree walk immediately, removing the need to manually trigger an expansion to force an update.
Concurrency & Performance Fixes
A series of shared architectural defects were resolved surrounding how the event loop handles a refreshed state:
- Input Buffer Clearing: Holding
ron a slow tool no longer queues up multiple synchronous re-extractions. Because extraction runs on the UI thread, key auto-repeat previously filled the input buffer with blind events that continuously re-froze the screen. Input arriving during this blocking operation is now explicitly discarded. - Non-Blocking Cascade Abandonment: Refreshing the tree now safely orphans previous background warming cascades using generation counters via
Warmer::reset. Previously, dropping therayon::ThreadPoolforced the UI to wait for running jobs to finish, freezing the screen for the exact duration of the abandoned work. - Warming Budget Reset: The
MAX_WARMED_NODESbounding counter now correctly resets per generation. Previously, this counter was monotonic across refreshes, meaning eachrconsumed a non-replenishing budget until background warming silently stopped working for the rest of the session.
UI Discoverability
- Footer Visibility: The
r(re-extract) key binding is now explicitly displayed in the status footer. - Help Pinning: The
? helphint is now permanently pinned alongside^C quit. On narrow terminals, this guarantees the most critical discoverability hint is never pushed off-screen by other status text.
v0.1.5
Install
cargo install mandible
Or download a pre-compiled binary from the assets below. Verify with the accompanying .sha256.
This release introduces an on-demand audit toggle to expose parser inaccuracies, restructures the project documentation, and fixes a critical missing UI hint for pane navigation.
Added
- Raw Output Audit Toggle (
t): Pressington any node now displays the tool's raw--helpoutput instead of the parsed tree. - The Rationale: While low-confidence parses already carry warnings, a grammar can misread a layout and produce a plausible but fabricated tree—which looks identical to a correct one. Every fabricated subcommand regression in Mandible's history was caught by comparing the parsed tree to the real output. This toggle puts that audit capability one keystroke away for all users.
- Memory Efficiency: The raw text is re-probed on demand rather than cached. Caching raw text for every node across a warmed tree would consume megabytes of memory and risk displaying stale data.
- Transparent Refusals: If a tool cannot be probed (e.g., due to safety rules), the refusal reason is rendered in the pane rather than swallowed, preventing confusion with tools that genuinely print nothing.
Changed
- README Restructuring: The README now leads with evidence—coverage metrics and safety guarantees—rather than reference material. The exhaustive keybinding table has been replaced with prose covering only non-obvious interactions. The in-app
?overlay and status footer remain the authoritative, drift-proof sources for keybindings.
Fixed
- Missing Navigation Hint: Added
Tabto the status footer. Although bound since the first release, its absence from the footer left many users unable to focus the detail pane or scroll long flag lists unless they had explicitly opened the?help overlay.
v0.1.4
Install
cargo install mandible
Or download a pre-compiled binary from the assets below. Verify with the accompanying .sha256.
This release introduces a critical execution safety update to prevent Mandible from accidentally triggering destructive system commands during background probing, alongside a UX fix for tools that output full man pages.
Critical Safety Fix
- Blocked Destructive Commands: Mandible will no longer execute programs designed to kill processes or alter system states. (Previously, running
mandible pkillcould trigger a system freeze requiring a hard reset). - The Root Cause: Mandible's specification permits probing tools using argument shapes like
<tool> <word> --help. For process killers, the first positional argument is treated as a target, not a subcommand. Therefore, an automated probe ofkillall foo --helpattempts to kill everything namedfoo. Any parser change that emitted subcommands for these tools risked turning the background tree-warmer into a process massacre. - Chokepoint Defense: Execution of
kill,pkill,killall,killall5,skill,xkill,fuser,halt,poweroff,reboot,shutdown,telinit, andinitis now explicitly refused before any process is spawned. This check sits at the single execution chokepoint, protecting all tiers, including the backgroundPATHsweeper. - Architectural Distinction: This blocklist is explicitly a safety rule based on what a program does, preserving Mandible's strict architectural ban on hardcoding per-tool parsing logic.
Fixed
- Accurate Confidence Reporting: Fixed an issue where tools falling back to raw man pages (like
mandible git) displayed a misleading "low confidence: 0% parsed" warning on every node. For tools likegit clone --help(which renders 405 lines ofroffprose), degrading to verbatim text with 0.0 confidence is the intentional, correct behavior. The low-confidence caveat now appropriately skips verbatim nodes while still flagging genuinely poor structural parses (e.g.,findat 11%,ipat 9%).
v0.1.3
Install
cargo install mandible
Or download a pre-compiled binary from the assets below. Verify with the accompanying .sha256.
This release restores critical functionality for developers using version managers and formalizes Mandible's architectural specifications based on real-world edge cases.
Toolchain Resolution & Shim Support
- Version Manager Compatibility: Restored parsing for developer tools managed by
rustup,pyenv,nvm,asdf,sdkman, andvolta. Previously, Mandible's strict execution sandboxing—which redirects$HOMEto a scratch directory—prevented these tool shims from resolving their underlying binaries. - Targeted Sandbox Exemptions: Safely bypassed this limitation by explicitly passing through specific toolchain variables (such as
RUSTUP_HOME,PYENV_ROOT, andNVM_DIR) while keeping the core$HOMEredirect intact. - Restored Coverage: Essential developer tools are fully readable again. For example,
cargonow correctly parses 12 nodes and 13 flags instead of throwing a resolution error.
Architecture & Specification Updates
- Framework Detection Constraints (Spec §7): Documented the rationale behind the ~17% implemented detection rate versus the theoretical 71% recall rate. Mandible strictly optimizes for high-precision markers over broad recall; guessing the wrong framework silently applies the wrong grammar and corrupts output, while unidentified tools safely fall back to the general engine.
- Process Containment Limits (Spec §6): Detailed the root cause of hanging coverage-sweep shards. Background processes that call
setsid(likechromedriverorvimtutor) escape their process group and avoid timeout termination. Full containment requires OS-level sandboxing, as cheaper mitigations likePR_SET_PDEATHSIGrequirepre_exec, violating the project's strict#![forbid(unsafe_code)]guarantee.
General Updates
- Crate Metadata: The
authorsfield in the manifest now explicitly names the maintainer rather than using a placeholder.
v0.1.2
Install
cargo install mandible
Or download a binary below. Verify with the accompanying .sha256.
This release focuses on transforming the detail pane from flat output into structured documentation, alongside major universality improvements ensuring Mandible remains fully functional in constrained environments—like minimal containers lacking Unicode or color support.
Detail Pane Redesign
- Aligned Columns: Flag descriptions now share a single aligned column, converting ragged prose into a readable parameter table.
- Value Placeholders: Arguments receive their own dedicated column (preventing
--envandlistfrom running together as a single token). This column collapses entirely if no flags in the group take a value. - Original Tool Ordering: Flag groups now preserve the tool's original editorial ordering rather than sorting alphabetically (e.g.,
tarnow opens with "Archive format selection" instead of "Main operation mode"). - Permitted Values Displayed: A flag's accepted values are now explicitly surfaced in the UI (e.g., showing that
--formataccepts exactlygnu, oldgnu, pax, posix, ustar, v7). - Cleaner Typography: Section headings now feature a visual rule (e.g.,
FLAGS ─────) for better anchoring. The usage signature block no longer redundantly repeats the tool's name, and padding has been added to prevent text from sitting flush against terminal borders.
Universality & Environment Support
- Robust ASCII Fallback: Every UI glyph now has an ASCII fallback, automatically chosen from the locale or forced via
MANDIBLE_ASCII=1. This prevents broken rendering (tofu blocks) in non-UTF-8 environments. This is enforced by a test that asserts no cell contains a non-ASCII symbol during fallback. - Environment-Aware Styling: Setting
TERM=dumbor piping output to a non-terminal stdout now correctly strips color escapes. - Formalized Rendering Policy: Added spec §9.2, which dictates that rendering capabilities must be detectable (permanently ruling out requirements like Nerd Fonts) and must degrade gracefully.
- Wordmark: Running
mandible mandiblenow renders an animated wordmark, redrawn in place so it stays in scrollback (skipped if piped or if the terminal lacks block element support).
Controls & Provenance UI
- Status Row Overhaul: UI controls are now anchored to the left of the status row, with provenance information on the right.
- Dynamic Status Messages: Status messages now expire. Previously, copying a flag with
yleftcopied: <command>in the footer indefinitely, masking keybinding hints for the rest of the session. - Help Overlay: Reorganized into logical categories (MOVE / SEARCH / ACTIONS), padded for readability, and purged of stale keybinding entries.
- Streamlined Provenance: The repetitive per-command footer has been removed. Framework metadata has moved to the tree pane title, and low-confidence parse scores (e.g.,
findscoring 0.11) are now explicitly surfaced.
Fixed
- Search Modes Clarified: Name-mode search now strictly matches command names. Flag spellings have been moved to the alternative mode, now explicitly labeled
everything. This fixes confusing behaviors where a command surfaced in search only because a hidden flag contained the search string. - Scroll Boundaries: Fixed a bug where holding the down arrow on a short description would scroll the text completely off the top of the pane.
- Formatting Artifacts: Value placeholders are no longer italicized, avoiding rendering artifacts on terminals that ignore or mishandle italic modifiers.
CI & Infrastructure
- Sharded PATH Sweeps: The executable sweep now runs in 16 shards and logs tools immediately before and after probing. If a runner hangs, the exact blocking tool is clearly identified.
- Stable Asset URLs: Release assets now include version-less copies (e.g.,
mandible-<target>.tar.gz) to ensure automated download links remain unbroken across releases. - Auditing: Added
cargo-denychecks for advisories, licenses, bans, and sources.
v0.1.1
This release addresses parser edge cases and UI issues discovered while running version 0.1.0 against real-world CLI tools. Three major tools that previously returned incomplete structures now correctly parse their subcommand trees.
Installation
cargo install mandible
Or download a pre-compiled binary from the assets below. Verify with the accompanying .sha256.
Key Improvements
apt-get: Recovered 17 subcommands with descriptions (1 node → 18 nodes).busybox: Added support for wrapped, comma-separated applet lists (1 node → 271 nodes).openssl: Cleared false-positivesuspiciousflags across 151 bare commands.
Fixed
- Literal Name-Mode Search:
namesmode now strictly performs literal substring matching on names and flag spellings. Fuzzy search across descriptions is isolated tonames+textmode. - Search Match Indicators: Rows surfaced because of a flag match now explicitly display
via <flag>(e.g.,via --no-trunc) in place of their summary during search. - Accurate Search Status Bar: Fixed footer guidance while searching. The status bar now displays
type to filter ↑↓ move Enter/Esc leave search / names↔text ^C quitinstead of indicatingqto quit. - Layout Overflow: Fixed zero-padding layout collapses where long node names overflowed directly into summary text.
opensslFalse-Positive Verification: AddedCommandNode::heading_attestedto prevent legitimate bare subcommands (nodes with no flags, children, or summaries) under verified headings from being flagged as fabricated structure.apt-getSubcommand Extraction: Added support for-(space-dash-space) entry separators under recognized command headings, allowingapt-getsubcommand descriptions to be parsed correctly.busyboxApplet List Extraction: Implemented a dedicatedFrameworkProfile::comma_separated_command_listscanner to handle tab-indented, comma-separated applet blocks under"Currently defined functions:".
Added
- Supply-Chain & License Auditing: Integrated
cargo-denyinto CI (deny.toml) with policy configurations for direct vs. indirect unmaintained dependencies and explicit MPL-2.0 license handling. - Coverage Scoreboard Queue: The
cargo xtask coveragescoreboard footer now lists the top ~25 unidentified tools ranked by flag count to prioritize future framework fingerprinting.