BashTab
BashTab is a Bash scripting framework that makes shell development feel like a modern CLI platform. Command scripts, argument parsing, autocompletion, module loading, and interactive fzf previews β all in pure Bash.

π Try it in your browser
No install needed β the live demo boots Alpine Linux with BashTab pre-installed, running entirely in your browser via v86 (x86 emulation in WebAssembly). Demo source: evagreendev/BashTabDemo.
Quick start
./setup # one-time: initialise submodules, build Fig specs
source ./activate # load BashTab into your shell
bu # list commands
bu new-module --name myapp # scaffold a module
Add this to your ~/.bashrc to load BashTab automatically:
source /path/to/BashTab/activate
Demos
Each clip starts in an activated shell. Expand a topic to watch a focused walkthrough; setup and activation are cut from every recording.
Query a data file β inferred fields, numeric filters, and team summaries
Query TSV directly with --from, complete fields from its header, or pipe bu import-tsv into a query. Use numeric JSON records for grouped averages. CSV and JSONL are supported too (CSV requires jc).

Build an object pipeline β tables, JSONL, grouping, and table styles
The same records become a table on a terminal or JSONL in a pipe. Complete comma-separated fields, group and filter records, then render double-border or Markdown tables.

Write a query with Tab β clauses, fields, operators, values, and connectors
Build a where expression interactively, then project a few columns with a readable select name, verb, module list.

Inspect a pipeline β compatible commands, field diagnostics, and record types
Completion uses declared stream formats and required fields. bu validate-pipeline checks known field references without executing the pipeline; bu get-shape runs a producer to inspect its observed field types.

Compose modules β a host and library under one CLI
The included devbox host loads gitshelf as a library. Inspect module precedence and Git state, discover commands with their owning modules, and open the libraryβs help. Try it with source ./activate --example devbox in a fresh shell.

Rewrite a command line β preview, wrap, and undo
An opt-in Alt+T selector previews a registered timeout wrapper and its automatically derived inverse. Unwrapping restores the original command before it runs. See the recording setup for the registration and binding.

Complete external commands β Docker and Git options with descriptions

Discover help β topic pages, paging, and generated command help

Demo coverage and recording guide documents the feature audit, commit history, and regeneration commands.
Highlights
β¨οΈ IDE-style autocompletion
- fzf dropdown aligned under the cursor with syntax-highlighted preview line
- Color-coded metadata: file types, sizes, symlink targets, option type tags
- Tree-sitter parser for accurate CST-based tokenization of pipes, substitutions, and variables
- Lazy completion generation β no compilation step, modify scripts and see suggestions instantly
π Structured output (PowerShell-inspired)
- JSONL is the object pipeline β commands emit records, jq is the engine
- Cmdlet suite:
bu where,bu select,bu sort,bu distinct-object,bu format-table,bu out-default, β¦ bu query-objectβ SQL in one command:where,group-by,agg,having,select,distinct,order-by,firstin any order- Out-Default: tables on a terminal, JSONL when piped β automatically
- File queries:
--fromandimport-csv/import-tsv/import-json/import-jsonl, with inferred field completion - Pipeline contracts: compatible command suggestions,
bu validate-pipeline, andbu get-shape - Table styles: Unicode borders by default, plus Markdown, ASCII, double, and more; long tables open in a pager
- Pipeline-aware completion:
bu get-command | bu select <TAB>suggests the producerβs fields - See Structured Output
bu query-object is a fully interactive DSL β it completes clause keywords, field names (from pipeline analysis), binary operators, distinct field values (via tab-execute), and and/or connectors as you type.
π¦ Module system
BU_MODULE_LISTβ semicolon-separated list ofname:version:preinit_pathentriesbu new-module --name myappβ scaffold a module with activate / module script / preinit callback / commands directorybu get-moduleβ inspect module precedence, version, Git branch, and dirty statebu get-commandβ attribute commands to modules and inspect shadowed definitions- Module preinit callbacks register commands, keybindings, aliases, and completion specs
π Argument parsing that writes your completions
bu_parse_multiselectβ named flags with-h|--help)# _FLAGsyntaxbu_parse_positionalβ positional args with--enum,--hint,--as-ifcompletion- Single definition drives both runtime parsing AND autocomplete generation β no duplication
π Safety
- RAII-style scope stack (
bu_scope_push_function/bu_scope_pop_function) ensures cleanups run - Custom
sourcewith--__bu-onceprevents redundant re-sourcing bu_exit_handler_setupcatches unexpected exits
π Fig spec integration
BashTab can use Fig completion specs as a fallback when no native bash completion exists (715+ CLIs).
Setup (handled automatically by ./setup):
git submodule update --init fig_specs
cd fig_specs && pnpm install --ignore-workspace && pnpm build && node ../fig_convert_to_json.mjs
What you get:
bu get-fig-statusβ see which commands on your PATH are coveredbu get-fig-status --usefulβ commands on PATH that lack bash completions- Automatic fallback: pressing
<TAB>on an unknown command checks the Fig specs
π Help topics
bu get-helpβ list help topics with module provenancebu get-help <topic>β rendered topic pages with SEE ALSO back-references--helpon any command is generated from its parser definition (options, enums, examples)
π Datetime releases
- Calendar-based tags (
v2026.08.15,v2026.08.15.1for same-day) β never a hand-picked semver ./release.shcuts + pushes the tag and opens a GitHub Releasebu get-versionreports the active release (v2026.08.15-3-g1f4ae9c)- See Releasing
π― Everything is a script
Every built-in command β bu new-command, bu import-environment, bu get-command β is a Bash script generated from the same template you use. The framework eats its own dogfood.
Not in scope
BashTab is not:
- A package manager (no
import/loadβ usesourceandBU_MODULE_LIST) - A YAML/TOML-to-Bash compiler (we stay in Bash)
- A POSIX-sh framework (requires Bash 4+, uses associative arrays,
coproc,mapfile)