Interactive TUI for mask — browse and run maskfile commands with fuzzy search.
- Fuzzy search — quickly find commands by typing
- Hierarchical navigation — browse subcommands with arrow keys (
→enter,←back,Escquit) - Rich preview — see full markdown documentation with ANSI rendering powered by md4x
- Comark/MDC support — renders block components, alerts, and inline components
- Interactive prompts — fill in arguments and flags before execution
- Zero config — just run
maskiin a directory with amaskfile.md
maski drives mask, which must be installed too (mask --introspect reads the maskfile structure). mask publishes binaries for Linux x86_64 and macOS on its releases page; elsewhere, cargo install mask.
Each release ships a standalone binary per platform:
| Asset | Platform |
|---|---|
maski-x86_64-linux |
Linux x86_64, any distribution |
maski-aarch64-linux |
Linux ARM 64-bit, any distribution |
maski-arm64-darwin |
macOS on Apple Silicon (11 Big Sur or later) |
maski-x86_64-darwin |
macOS on Intel (11 Big Sur or later) |
The Linux binaries are statically linked: they depend on nothing, so they run the same on Debian, Ubuntu, Fedora, Arch, Alpine or NixOS. The asset names follow uname, so one command picks the right one:
mkdir -p ~/.local/bin
curl -fsSL -o ~/.local/bin/maski \
"https://github.com/ManUtopiK/maski/releases/latest/download/maski-$(uname -m)-$(uname -s | tr '[:upper:]' '[:lower:]')"
chmod +x ~/.local/bin/maski~/.local/bin must be in your PATH; for a system-wide install, write to /usr/local/bin with sudo instead. To check the download, compare it with the release's SHA256SUMS (sha256sum ~/.local/bin/maski, or shasum -a 256 on macOS).
On macOS the binaries are not signed by Apple. Downloaded with curl as above they run directly; downloaded with a browser, macOS blocks them until you clear the quarantine flag: xattr -d com.apple.quarantine ~/.local/bin/maski.
# Try it
nix run github:ManUtopiK/maski
# Install in your profile
nix profile install github:ManUtopiK/maskiOr add it as a flake input. Two things matter to get binary-cache hits from maski.cachix.org — otherwise maski recompiles from source:
- Don't make maski follow your
nixpkgs. maski is cached against its own pinned nixpkgs;inputs.maski.inputs.nixpkgs.follows = "nixpkgs"changes the derivation hash and misses the cache. - Declare the cache yourself. A flake's
nixConfigis only honored for the top-level flake, not for inputs, so consumers must add it:
# flake.nix
inputs.maski.url = "github:ManUtopiK/maski"; # no `follows` on nixpkgs
# NixOS configuration (or nix.conf)
nix.settings = {
extra-substituters = [ "https://maski.cachix.org" ];
extra-trusted-public-keys = [
"maski.cachix.org-1:D5Ok9Mln7WxD7vm5ADYL92kTlrN6tB1y1V5Yq2UGmUw="
];
};maski # launch TUI in current directory
maski --maskfile ./ops.md # use a specific maskfile
maski --preview right # preview panel on the right (default: down)With arguments, maski is a drop-in replacement for mask — everything is forwarded as-is:
maski build --release # runs `mask build --release`
maski help # runs `mask help`
maski --maskfile ./ops.md deployOne exception: naming a command that only groups subcommands (no script of its own) opens the TUI at that level instead of printing mask's help. Navigation still works from there — ← / Esc walk back up to the root.
Given a maskfile.md with a ## db section holding ### migrate and ### seed:
maski db # browse db > migrate, seed
maski db migrate # runs `mask db migrate` directlyexamples/maskfile.md is a sample maskfile covering subcommands, prompted arguments, flags, and the markdown the preview panel renders (tables, alerts, MDC components, task lists). Every task only echoes, so nothing can go wrong:
maski --maskfile examples/maskfile.md # browse everything
maski --maskfile examples/maskfile.md db # open the TUI on the db groupexamples/langs.md has one task per language mask can run, to see how the preview highlights each code block. Its tasks only print too, but each needs its interpreter (node, python, ruby...) to run:
maski --maskfile examples/langs.md| Key | Action |
|---|---|
↑ ↓ |
Navigate commands |
→ Enter |
Enter subcommands / execute command |
← |
Go back to parent |
Esc |
Go back, or quit at root |
| Type | Fuzzy filter commands |
The preview panel shows the full markdown content of each command section, rendered with syntax highlighting and formatting:
- Bold, italic,
inline code - Fenced code blocks, framed with their language and syntax highlighted (bash, sh, zsh, js, python, lua, ruby, php, batch; other languages stay uncolored)
- MDC/Comark components (alerts, tips, warnings, details)
- Lists, blockquotes
maski mask --introspect
│ │
│ 1. get command tree ────────▶ │
│ │
│ 2. receive JSON ◀──────────── { commands: [...] }
│
│ 3. read maskfile.md for full markdown sections
│
│ 4. TUI: skim fuzzy search + md4x ANSI preview
│
│ 5. dialoguer prompts for args/flags
│
│ 6. execute ─────────────────▶ mask <cmd> --flag val arg1
maski uses mask --introspect to get the command structure (names, args, flags, scripts) and reads the maskfile.md directly to extract the full markdown content for the preview panel.
The markdown is rendered to ANSI using md4x compiled as a C library (via FFI), so there are no external runtime dependencies.
This project started as PR #145 to add an interactive mode directly to mask. The maintainer preferred to keep mask minimal, suggesting an external wrapper instead. maski is that wrapper — it uses mask's --introspect flag and subprocess execution, with zero coupling to mask's internals.
MIT
