clish 0.1.0-beta.2

Elegant CLI framework for Rust.
Documentation

clish

Crates.io Docs.rs License Rust edition Repository

A Rust CLI framework that derives command-line interfaces from annotated function signatures.

#[command]
fn install(package: Pos<String>, version: Named<Option<String>>, force: bool) { ... }

[!WARNING] clish is in beta. The API is not yet stable.

[dependencies]
clish = "0.1.0-beta.2"
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.

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();
}
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.

Type Behavior Example
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:

Key Type Description
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
#[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

Key Type Description
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

Key Type Description
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).

#[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

Key Type Description
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"])
#[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

Key Type Description
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:

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().

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:

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

Field Default Context affected
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

Crate Purpose
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.

  • Positional arguments
  • Named arguments
  • Boolean flags
  • Optional arguments
  • Typed arguments via FromStr
  • Short flag/option aliases (-v, -o)
  • Environment variable fallback (env)
  • Default values (default)
  • Enum-like value constraints (choices)
  • Mutual exclusion / prerequisites (conflicts_with, requires)
  • Command aliases
  • Hidden commands / deprecated commands
  • Custom help placeholders
  • Hide individual params from help
  • Auto-generated help
  • farben + anstyle styling
  • Variadic Vec<T> in macro
  • Subcommand groups
  • Shell completions

License

Licensed under either of

at your option.

Cheers, RazkarStudio.

Copyright © 2026 RazkarStudio. All rights reserved.