clish 0.1.0-beta.1

Elegant CLI framework for Rust.
Documentation

clish

Crates.io Docs.rs License Rust edition Repository

The most elegant CLI framework. Successor of vecli, my first ever Rust crate.

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

Inspired by Typer

[!WARNING] clish is a work in progress. it's not published yet to crates-io, so you'll have to use git to experiment for now.

[dependencies]
clish = { git = "https://codeberg.org/razkar/clish" }

or

cargo add --git https://codeberg.org/razkar/clish.git

How it works

Annotate a function with #[command]. The argument types tell clish how to parse the command line.

use clish::prelude::*;

#[command]
/// Deploy to an environment
fn deploy(
    target: Pos<String>,
    env: Named<String>,
    force: bool,
) {
    println!("Deploying {} to {} (force={})", target, env, force);
}

fn main() {
    app!().run();
}
myapp deploy production --env prod --force

[!IMPORTANT] Do not import clish::* directly as it exposes the framework's internals. Only use when you know what you're doing. Always prefer using clish::prelude::*


Argument types

The type of each parameter determines how clish parses it.

Type Behavior Example
Pos<T> Positional, required myapp cmd foo
Pos<Option<T>> Positional, optional myapp cmd or myapp cmd foo
Pos<Vec<T>> Positional, variadic myapp cmd a b c
Named<T> --name val, required myapp cmd --env prod
Named<Option<T>> --name val, optional
Named<Vec<T>> --name val, repeatable myapp cmd --tag a --tag b
bool --flag presence myapp cmd --force

Any T that implements FromStr works: String, i64, u32, f64, and so on. Type mismatches produce a clear error at runtime:

error: invalid value for <port>: expected u16

Option<Vec<T>> and Option<bool> are rejected at compile time with a clear error.


Command metadata

The #[command] attribute accepts metadata at the top level:

Key Type Description
help string Short description (shown everywhere)
details string Long description (shown only in --help)
name string Override the CLI command name
aliases array Alternative names for command lookup
hidden bool Omit from app-level help listing (still invocable)
deprecated bool Print a warning when invoked
deprecation_note string Extra message for deprecation
#[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 appear dimmed in the command listing and show a warning on use. Aliased commands can be invoked by any alias.


Parameter metadata

Individual parameters are documented via param(ident, ...) (or parameter(ident, ...) if you're feeling fancy) blocks inside #[command]:

Display

Key Type Description
help string Short description
details string Long description (shown only in --help)
name string Override the CLI flag name (e.g. name = "dry-run")
short char Single-character alias (short = 'd' becomes -d)
placeholder string Custom help token (placeholder = "HOST" shows <HOST>)
hide bool Omit this parameter from help listings

Value resolution

Key Type Description
env string Environment variable to fall back to
default string Default value when nothing is provided

Resolution order: CLI arg > $ENV_VAR > default > error (if 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 Allowed values (choices = ["debug", "info"])
conflicts_with array Mutual exclusion (conflicts_with = ["quiet"])
requires array Prerequisites (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

value_hint is reserved for future use, shell completion generation is not yet implemented.


Help text

clish generates --help automatically from all metadata, showing short aliases, placeholders, choices, env vars, and defaults:

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

app!() reads CARGO_PKG_NAME, CARGO_PKG_VERSION, and CARGO_PKG_DESCRIPTION automatically from your crate. Override any of them with the builder:

app!()
    .name("myapp")
    .version("1.2.0")
    .description("Does things.")
    .run();

Styling

Help output uses farben markup by default. Override the styles:

use clish::prelude::*;
use clish::help::{HelpStyles, HelpStyle};

app!()
    .styles(HelpStyles {
        header: HelpStyle::Markup("[bold cyan underline]"),
        command: HelpStyle::Markup("[bold]"),
    })
    .run();

Or pass an anstyle::Style directly if you're already in the anstyle ecosystem:

use anstyle::{Style, AnsiColor};

app!()
    .styles(HelpStyles {
        header: HelpStyle::Anstyle(Style::new().fg_color(Some(AnsiColor::Cyan.into()))),
        command: HelpStyle::Anstyle(Style::new().bold()),
    })
    .run();

Crate structure

Crate Purpose
clish Public API, the one you add
clish-core Runtime: App, CommandEntry, parse helpers
clish-macros Proc macro: #[command]

You never need to depend on clish-core or clish-macros directly.


Status

Beta :tada:

Early development. The API is not 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.