Argc: a Bash CLI framework where the interface is written in comments
A Bash CLI framework, also a Bash command runner.
At a glance
- What is it?
- Argc lets a Bash script describe its options, flags, arguments and subcommands in comment tags, and a Rust binary does the parsing, the validation and the help text, so the script keeps only its core logic. It suits a shell-first team that wants a real CLI without leaving Bash, and the same tool doubles as a task runner with an Argcfile.sh.
- Who is it for?
- Argc fits a team whose tooling is already Bash and who wants a proper command line interface without a language change, because the interface is declared in comments and the runtime does the parsing, the validation and the help text. Skip it if you need the generated script to run somewhere without the binary, unless you use the build mode, which produces a standalone script with the dependency removed.
- Can I use it commercially?
- Yes. Apache-2.0 is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Yes. The repository last received commits 3 days ago.
- What is it written in?
- Mainly Rust, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 23, 2026, and from our analysis. They are not legal advice.
Editorial analysis
Two steps, and one surprising line of shell
Argc is a powerful Bash framework that simplifies building full-featured CLIs. It lets you define your CLI through comments, focusing on your core logic without dealing with argument parsing, usage text, error messages, and other boilerplate code.
The whole model fits in two steps. First, design the CLI interface by describing options, flags, positional parameters and subcommands using comment tags. Second, activate argument handling by adding one line to your script:
eval "$(argc --argc-eval "$0" "$@")"That line is the whole integration. The `argc` binary parses the arguments according to the comment tags, validates them, and emits shell code that assigns the parsed values into variables. The script then reads those variables as ordinary shell variables.
The example shows the shape of the declaration and the shape of the result:
# @flag -F --foo Flag param
# @option --bar Option param
# @option --baz* Option param (multi-occurs)
# @arg val* Positional param
eval "$(argc --argc-eval "$0" "$@")"
echo foo: $argc_foo
echo bar: $argc_bar
echo baz: ${argc_baz[@]}
echo val: ${argc_val[@]}Run with `./example.sh -F --bar=xyz --baz a --baz b v1 v2` and the values arrive as `foo: 1`, `bar: xyz`, `baz: a b` and `val: v1 v2`, with every variable prefixed `argc_`.
The `*` suffix is the multi-occurrence marker, and it changes the shape of the variable from a scalar to an array, which is why the echo uses `${argc_baz[@]}` rather than `$argc_baz`.
And the help text comes for free. Running `./example.sh --help` produces the usage block with the arguments section, the options section including the help and version flags, and the argument names in the conventional upper case form:
USAGE: example [OPTIONS] [VAL]...
ARGS:
[VAL]... Positional param
OPTIONS:
-F, --foo Flag param
--bar <BAR> Option param
--baz [BAZ]... Option param (multi-occurs)
-h, --help Print help
-V, --version Print versionSo the value proposition is not that the parsing is clever. It is that the description of the interface lives next to the code that implements it, in the file itself, in comments, and everything else is derived from it.
The comment tag vocabulary
Comment tags are standard Bash comments prefixed with `@` and a specific tag, and they provide instructions to Argc for configuring the script's functionalities.
The tag set is small and each one does one thing. `@describe` sets the description for the command. `@cmd` defines a subcommand and `@alias` sets aliases for it. `@arg` defines a positional argument, `@option` defines an option argument and `@flag` defines a flag argument. `@env` defines an environment variable and `@meta` adds metadata.
The grammar and usage of all the comment tags are in a specification document, and the tag list in the documentation links each one to its section there.
The design decision worth noticing is that the tags are ordinary comments. A `#` comment in Bash is ignored by the interpreter, so the declarations are inert as far as the shell is concerned, and Argc reads the source file to find them. That means the declaration costs nothing at runtime for a reader who does not know Argc, and the file stays a valid Bash script that runs even if the binary is absent, though it will then do no argument handling at all.
The distinction between the three argument kinds is the same one every CLI library makes. A flag is a boolean presence, an option takes a value, and a positional argument is identified by position rather than by name. Argc adds a fourth dimension that a lot of Bash tools lack, and that is subcommands, with `@cmd` and `@alias` handling the tree of commands and their alternate names.
The `@env` tag is the one that makes the tool more than a parser. Defining, validating and binding environment variables to options and positional arguments means the same declaration can source a value from the environment, which is how you get a CLI where a value can come from a flag, from an environment variable, or from a default, and the resolution order is part of the interface rather than a pile of `if` statements in the script.
The features list also credits the tool with generating information-rich usage text, mapping arguments to corresponding variables, and validating user input for robust error handling, and those three are the parts that a hand-rolled Bash parser usually does badly.
Building a script that no longer needs argc
The single most interesting feature of Argc is that the runtime is optional at deployment time.
Argc can build a bash script that incorporates all functionalities without depending on Argc itself. The generated script removes the `argc` dependency, enhances compatibility, and enables deployment in a wider range of environments.
The command is:
argc --argc-build <SCRIPT> [OUTPATH]And the usage is:
argc --argc-build ./example.sh build/
./build/example.sh -h # The script's functionality does not require the `argc` dependencySo the build step reads the source, and produces a new script that contains the parsing logic, the help text and the validation inline. The result is a single file you can copy to a machine, put in a container, or run on a host where installing the Rust binary is not an option.
That is a genuinely different deployment model from a framework with a runtime dependency. The development workflow can use the binary for its conveniences, and the shipped artefact does not need it.
The same philosophy appears in the other outputs. Cross-shell autocompletion is generated for various shells, bash, zsh, fish and powershell among them, and the command is `argc --argc-completions <SHELL> [CMDS]...`. The examples show sourcing the result:
# bash (~/.bashrc)
source <(argc --argc-completions bash cmd1 cmd2)
# fish (~/.config/fish/config.fish)
argc --argc-completions fish cmd1 cmd2 | source
# nushell (~/.config/nushell/config.nu)
argc --argc-completions nushell cmd1 cmd2 # updAnd man pages are generated automatically for the script, through the mangen feature in the manifest.
The manifest shows how these are assembled. The default feature set is `application`, which pulls in native-runtime, eval-bash, build, mangen, completions, compgen, export and wrap-help, along with the dependencies for them. Each of those is a separate Cargo feature, which means the same crate can be built without the parts you do not want, and the comment in the manifest says the application feature should be disabled when depending on argc as a library.
So there are two ways to use it. As a library in Rust, with the parts you need. As a tool that a Bash script calls, with everything.
The examples directory is the reference manual
The `examples/` directory at the top of the repository is the most useful part of the project for someone learning the tag syntax, because each subdirectory isolates one behaviour and is named after it.
The names read as a feature list. There is `args` for the argument kinds, `options` for option handling, `envs` and `bind-envs` for the environment variable binding, `hooks` for the extension points, `inherit-flag-options` for how a subcommand inherits from its parent, `nested-commands` for the subcommand tree, `default-subcommand` for the case where the command is optional, `combine-shorts` for short flag grouping, `multiline` for commands that span lines, `parallel` for running work concurrently, `strict` for the mode where unknown arguments are an error rather than a warning, and `require-tools` for checking that the tools a script needs are present before running it.
That last two are worth a look if you are choosing between Argc and a hand written parser. A strict mode is a real difference in behaviour, because most shell scripts accept a typo silently and pass it on, and a tool that turns an unknown flag into an error before your logic runs saves a class of confusing bug. And requiring tools up front is a check you would otherwise write once per script and get wrong in one of them.
The `external`, `external-foo` and `external-bar` directories are about a different kind of case, the one where a command is partly implemented in another language and the Bash side needs to know about it. And `symbol` and `demo` are the small illustrative cases.
The test setup is worth noting too. The manifest disables autotests with `autotests = false` and the dev dependencies are `insta`, `assert_cmd`, `assert_fs`, `rstest` and `predicates`, with a Unix-specific dev dependency block for the platform-specific code. `insta` is a snapshot testing library, which is the right tool for a framework whose output is help text and completions, because a snapshot of the generated help is both a test and a piece of documentation. `assert_fs` gives a temporary filesystem for the build and export modes to write into.
The Rust implementation is small in terms of top level files. There is `main.rs`, `Cargo.toml`, `src/`, `docs/` and `tests/`, and the crate is licensed MIT OR Apache-2.0, with the repository carrying both a LICENSE-APACHE and a LICENSE-MIT file. The dual licence is the standard Rust convention, and it means an organisation with a policy against one of them can usually take the other.
Argcscript, the command runner side of the tool
The second product in the same repository is a task runner, and it exists for a different reason than the CLI framework.
Argc is also a command runner built for those who love the efficiency and flexibility of Bash scripting. Similar to how a Makefile defines commands for the `make` tool, Argcscript uses an `Argcfile.sh` to store your commands, referred to as recipes.
The reasons given for choosing it are a list of what you do not have to give up. Use Bash skills you already have, with no need to learn a new language. GNU toolset integration, using familiar tools like awk, sed, grep and find. Environment variables management, loading dotenv, documenting and validating environment variables effortlessly. Powerful shell autocompletion. And cross-platform compatibility, working seamlessly across Linux, macOS, Windows and BSD systems.
The repository has an `Argcfile.sh` at the top level, which is the project's own task file.
The comparison with make is the useful frame, because make's weakness is well known. A Makefile is tab-indented, which is easy to get wrong and hard to see in a diff, and the syntax is its own small language with the target, the prerequisites and the recipe. An `Argcfile.sh` is a Bash script, so the recipes are shell, the indentation is not significant, and anything you can do in Bash you can do in a recipe.
The cost of that choice is that a Makefile is declarative and a Bash script is not, so a task runner built on a script has to impose its own conventions for what a recipe returns and how dependencies are expressed. The documentation for the command runner is a separate document, and the feature list for it is much shorter than the one for the CLI framework, which is a sign of which half of the project is more mature.
The cross-platform claim is backed by the manifest and the repository layout. The build target uses `either` and `which`, and the `native-runtime` feature pulls in `which`, which is how the tool locates the system Bash on Windows, where there is no Bash to assume. The `unicode-width` dependency is unconditional, which is a table-rendering concern, and `nom` at 8.0.0 is the parser combinator library doing the argument parsing.
Editorial conclusion
Argc fits a team whose tooling is already Bash and who wants a proper command line interface without a language change, because the interface is declared in comments and the runtime does the parsing, the validation and the help text. Skip it if you need the generated script to run somewhere without the binary, unless you use the build mode, which produces a standalone script with the dependency removed. Before you adopt it, read the comment tag specification, since the tag set is the API and the differences between the evaluation mode and the build mode are where the surprises live. The last push was on 2026-10-15 and the current release is v1.24.0 from 2026-05-20.
Frequently asked questions
What is Argc and how does a script use it?
It is a Bash CLI framework where the interface is declared in comment tags such as @flag, @option, @arg and @cmd. The script activates it with `eval "$(argc --argc-eval "$0" "$@")"`, and the parsed values arrive as variables prefixed with `argc_`.
Can Argc produce a script that does not need argc installed?
Yes. `argc --argc-build <SCRIPT> [OUTPATH]` generates an independent bash script that incorporates the functionality without depending on Argc, which is what you would ship to a host where the binary is not available.
What can Argc generate besides a script?
Shell autocompletion scripts for bash, zsh, fish, powershell and others through `argc --argc-completions <SHELL>`, and man page documentation for the script.
What is Argcscript?
It is the command runner side of the tool, using an `Argcfile.sh` to hold recipes in the way a Makefile holds commands for make, with the recipes written as Bash rather than in a new task language.
How do I install Argc?
With `cargo install argc` for Rust developers, `brew install argc` for Homebrew users or `yay -S argc` for Pacman users, or by downloading a pre-built binary for macOS, Linux and Windows from GitHub Releases and putting it on your PATH. The last push was on 2026-10-15 and the release is v1.24.0.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/sigoden-argc)Was this useful?