<div align="center">
# clish
[](https://crates.io/crates/clish)
[](https://docs.rs/clish)
[](LICENSE-MIT)
[](https://rust-lang.org)
[](https://codeberg.org/razkar/clish)
A Rust CLI framework that derives command-line interfaces from annotated function signatures.
```rust
#[command]
fn install(package: Pos<String>, version: Named<Option<String>>, force: bool) { ... }
```
</div>
> [!WARNING]
> clish is in beta. The API is not yet stable.
> ```toml
> [dependencies]
> clish = "0.1.0-beta.2"
> ```
> ```sh
> cargo add clish
> ```
---
## How it works
The `#[command]` attribute macro transforms a Rust function into a registered CLI command. Each function parameter type determines the corresponding argument's parsing strategy. The `app!()` macro collects all registered commands, reads `CARGO_PKG_*` environment variables from the Cargo.toml at compile time, and dispatches invocation at runtime.
```rust
use clish::prelude::*;
#[command]
/// Deploy to an environment
fn deploy(
target: Pos<String>,
env: Named<String>,
force: bool,
) {
println!("Deploying {target} to {env} (force={force})");
}
fn main() {
app!().run();
}
```
```sh
myapp deploy production --env prod --force
```
> [!IMPORTANT]
> Importing `clish::*` directly exposes internal framework types. Use `clish::prelude::*` instead for correct name resolution.
---
## Argument types
The parameter type determines how clish parses the corresponding command-line token.
| `Pos<T>` | Required positional | `myapp cmd foo` |
| `Pos<Option<T>>` | Optional positional | `myapp cmd` or `myapp cmd foo` |
| `Pos<Vec<T>>` | Variadic positional | `myapp cmd a b c` |
| `Named<T>` | Required `--name val` | `myapp cmd --env prod` |
| `Named<Option<T>>` | Optional `--name val` | |
| `Named<Vec<T>>` | Repeatable `--name val` | `myapp cmd --tag a --tag b` |
| `bool` | Flag presence | `myapp cmd --force` |
Any type `T` that implements `FromStr` is accepted: `String`, `i64`, `u32`, `f64`, and others. A parse failure at runtime produces a styled error message indicating the expected type:
```
error: invalid value for <port>: expected u16
```
The types `Option<Vec<T>>` and `Option<bool>` produce a compile-time error: `Vec<T>` is already zero-or-more (making the outer `Option` redundant), and `bool` is parsed as a flag that is either present or absent.
---
## Command metadata
The `#[command]` attribute accepts metadata keys at the top level:
| `help` | string | Short description displayed in listing and command help |
| `details` | string | Long description displayed only in `--help` output |
| `name` | string | Override the CLI command name (defaults to the function name) |
| `aliases` | array | Alternative names that resolve to this command |
| `hidden` | bool | Omit from app-level help listing; command remains invocable |
| `deprecated` | bool | Emit a deprecation warning on invocation |
| `deprecation_note` | string | Supplementary message appended to the deprecation warning |
```rust
#[command(
help = "Deploy the application",
details = "Runs pre-flight checks, builds the release artifact, then pushes it.",
aliases = ["ship", "release"],
deprecated = true,
deprecation_note = "use 'ship' instead",
)]
fn deploy(...) { ... }
```
Deprecated commands render with the `deprecated` style (dim by default) in the command listing and emit a warning when invoked. Aliased commands are invocable by any of their registered aliases.
---
## Parameter metadata
Individual parameters are configured via `param(ident, key = value, ...)` blocks inside the `#[command]` attribute. The `parameter` keyword is also accepted as a synonym.
### Display
| `help` | string | Short description shown in argument listings |
| `details` | string | Long description shown only in `--help` output |
| `name` | string | Override the CLI flag name (for example, `name = "dry-run"` changes `--dry_run` to `--dry-run`) |
| `short` | char | Single-character alias (`short = 'd'` registers `-d` alongside the long form) |
| `placeholder` | string | Custom help token (`placeholder = "HOST"` renders `<HOST>` instead of the default) |
| `hide` | bool | Omit this parameter from all help listings |
### Value resolution
| `env` | string | Environment variable consulted when the argument is not provided on the command line |
| `default` | string | Default value used when neither the CLI argument nor the environment variable is present |
Resolution order: CLI argument > `$ENV_VAR` > `default` > error (if the parameter is required).
```rust
#[command(
param(host, help = "Target host", short = 't', placeholder = "HOST", env = "DEPLOY_HOST"),
param(port, help = "Port number", short = 'p', default = "8080"),
)]
fn deploy(host: Pos<String>, port: Named<Option<u16>>) { ... }
```
### Validation
| `choices` | array | Set of permitted string values (`choices = ["debug", "info"]`) |
| `conflicts_with` | array | Names of parameters that cannot appear alongside this one (`conflicts_with = ["quiet"]`) |
| `requires` | array | Names of parameters that must also be present (`requires = ["output"]`) |
```rust
#[command(
param(level, short = 'l', choices = ["debug", "info", "error"]),
param(verbose, short = 'v', conflicts_with = ["quiet"]),
param(quiet, short = 'q'),
)]
fn log(level: Named<String>, verbose: bool, quiet: bool) { ... }
```
### Completion
| `value_hint` | string | Hint for shell completion engines (reserved for future use) |
Shell completion generation is not yet implemented.
---
## Help text
Help output is generated automatically from all registered metadata. Two forms are available:
- `myapp -h` (short): displays name, version, one-line description, and the command listing.
- `myapp --help` (long): additionally shows the `details` field when set on the application.
- `myapp <command> --help` (per-command): shows usage, arguments, options, and any param-level metadata.
```
myapp deploy --help
myapp --help deploy
```
Example output:
```
myapp deploy
Deploy the application
Usage: myapp deploy <HOST> [--port <PORT>] [-l <LEVEL>] [-v]
Arguments:
<HOST> Target host [env: DEPLOY_HOST]
Options:
-p, --port <PORT> Port number [default: 8080]
-l, --level <LEVEL> Log level [choices: debug, info, error]
-v, --verbose Verbose output
-q, --quiet Suppress output
```
---
## App metadata
The `app!()` macro reads `CARGO_PKG_NAME`, `CARGO_PKG_VERSION`, and `CARGO_PKG_DESCRIPTION` from the crate's `Cargo.toml` at compile time. Each value is overridable via builder methods:
```rust
app!()
.name("myapp")
.version("1.2.0")
.description("Does things.")
.run();
```
---
## Styling
Help text styling is controlled by the `HelpStyles` struct. Each field accepts either a `farben` markup string or an `anstyle::Style` value. Unspecified fields fall back to defaults via `..Default::default()`.
```rust
use clish::prelude::*;
use clish::help::{HelpStyles, HelpStyle};
app!()
.styles(HelpStyles {
header: HelpStyle::Markup("[bold cyan underline]"),
command: HelpStyle::Markup("[bold]"),
..Default::default()
})
.run();
```
For projects already using `anstyle`:
```rust
use anstyle::{Style, AnsiColor};
app!()
.styles(HelpStyles {
header: HelpStyle::Anstyle(Style::new().fg_color(Some(AnsiColor::Cyan.into()))),
command: HelpStyle::Anstyle(Style::new().bold()),
..Default::default()
})
.run();
```
### Available fields
| `header` | `[bold underline]` | Section headings ("Commands:", "Arguments:", "Options:") |
| `command` | `[bold]` | Command and parameter names in listings |
| `dim` | `[dim]` | Ancillary information (defaults, env vars, choices) |
| `deprecated` | `[dim]` | Deprecated command names in listings and deprecation banners |
| `warning` | `[yellow]` | Error label prefix |
| `error_label` | `[bold red]` | Error label line |
| `error_kind` | `[red]` | Error kind identifier ("unknown argument", "missing value") |
| `error_token` | `[yellow]` | Flagged tokens in error messages |
| `error_hint` | `[cyan]` | Hints and suggestions in error output |
---
## Crate structure
| `clish` | Public API crate; the only direct dependency needed |
| `clish-core` | Runtime types and logic: `App`, `CommandEntry`, argument parsing, help rendering |
| `clish-macros`| Proc-macro crate: `#[command]` attribute macro |
The `clish-core` and `clish-macros` crates are re-exported through `clish` and should not be depended on directly.
---
## Status
Beta. The API is not yet stable.
- [x] Positional arguments
- [x] Named arguments
- [x] Boolean flags
- [x] Optional arguments
- [x] Typed arguments via `FromStr`
- [x] Short flag/option aliases (`-v`, `-o`)
- [x] Environment variable fallback (`env`)
- [x] Default values (`default`)
- [x] Enum-like value constraints (`choices`)
- [x] Mutual exclusion / prerequisites (`conflicts_with`, `requires`)
- [x] Command aliases
- [x] Hidden commands / deprecated commands
- [x] Custom help placeholders
- [x] Hide individual params from help
- [x] Auto-generated help
- [x] `farben` + `anstyle` styling
- [x] Variadic `Vec<T>` in macro
- [ ] Subcommand groups
- [ ] Shell completions
---
## License
Licensed under either of
* Apache License, Version 2.0 ([LICENSE-APACHE](LICENSE-APACHE) or <http://www.apache.org/licenses/LICENSE-2.0>)
* MIT license ([LICENSE-MIT](LICENSE-MIT) or <http://opensource.org/licenses/MIT>)
at your option.
Cheers, RazkarStudio.
Copyright © 2026 RazkarStudio. All rights reserved.