Thanks for considering a contribution to Bash CLI.
- Security vulnerabilities: never via issue or PR. See SECURITY.md.
- New features: open an issue first to discuss fit. The framework is deliberately small and dependency-free; anything that needs a tool beyond Bash and coreutils belongs in a plugin, and anything that needs a runtime belongs in another project. See the design philosophy.
- Bug fixes and documentation: PRs welcome directly.
git clone https://github.com/modufolio/bash-cli
cd bash-cli
./build.sh
./cli.sh doctorBash 4.3 or later is required. On macOS, brew install bash and make sure it
precedes /bin/bash in PATH. ShellCheck is optional but expected for PRs.
make test # rebuild and run the whole suite
./cli.sh test workflow:parallel # one test while iterating
shellcheck -s bash -x src/*/*.sh plugins/*.sh tests/*.shTests run against dist/cli.sh, so rebuild after editing src/. The suite
takes a few seconds; one workflow test waits out a single 5-second retry.
Drive the real command path with run_cli or run_cli_with_stderr rather
than calling functions in isolation; discovery, dispatch and argument parsing
are where regressions hide. Skip with test_warn when an optional tool such
as yq or sqlite3 is missing, so the suite passes on a minimal machine.
See Testing for the harness and conventions.
set -euo pipefailis on. Guard optional values (${var:-}), capture failing statuses (cmd || rc=$?), and avoid((i++))on a zero counter.- Quote everything. No
eval, nobash -cwith user input. - Commands
return, they do notexit. - Print user-supplied strings with
printf '%s', notecho -e. - Keep modules free of top-level side effects other than declarations; the build concatenates them.
- Follow the existing naming:
cmd_*for commands,_prefix_*for a plugin's private helpers,test_*for tests.
- One logical change per PR.
- Every behaviour change comes with a test that fails without it.
make testgreen and ShellCheck clean for the files you touched.- Update the relevant page in
docs/when behaviour, options or file formats change, and add a line underUnreleasedinCHANGELOG.md. - Commit messages follow Conventional Commits:
type(scope): lowercase imperative subject.