Minimalist toolkit for Rust command-line applications.
climate is a collection of modular crates designed to help you build fast,
small, and robust command-line tools. Every crate depends only on the Rust
standard library, making it a perfect fit for resource-constrained
environments and systems programming.
Important
Currently optimised for Unix-like systems (Linux, macOS, BSD). Windows support is not a priority.
| Crate | Description |
|---|---|
climate-arg |
Option parser with subcommands and positional arguments. |
climate-cfmt |
printf-style colour formatting with %keyword tags. |
climate-fx |
Small {}-style formatter with ANSI and time tokens. |
climate-daemon |
Lifecycle utilities for background services and signal handling. |
climate-prompter |
Interactive user prompts with support for masked secrets. |
climate-paths |
Resolves standard config paths (XDG on Linux, Library on macOS). |
climate-tab |
Clean, elastic tabbed columns for terminal tables. |
climate-human |
Byte-to-human scaling (1024/1000) for readable metrics. |
climate-env |
Environment variable fetching with default fallbacks. |
climate-ini |
INI parser with schema and env overrides. |
climate-loglines |
Simple, timestamped logging helpers. |
Add whatever crate you need to Cargo.toml:
# Single crate
climate-arg = { git = "https://github.com/grimdork/climate" }
climate-cfmt = { git = "https://github.com/grimdork/climate" }
climate-human = { git = "https://github.com/grimdork/climate" }Handle flags, subcommands, and positional arguments.
use climate_arg::{Options, VarType, GroupDefault};
let mut opt = Options::new("mytool", "Short one-line description");
opt.set_default_help(true);
// Set a boolean flag (-v, --verbose)
opt.set_option(GroupDefault, "v", "verbose", "Enable verbose output",
false, false, VarType::Bool, &[] as &[&str]);
// Create a subcommand with a positional argument
let cmd = opt.set_command("greet", "Greet a user", GroupDefault,
None, &[] as &[&str]);
cmd.set_positional("name", "The name to greet", "world", true, VarType::String);
match opt.parse(std::env::args().skip(1).collect()) {
Ok(()) => {},
Err(e) => eprintln!("Error: {e}"),
}Use ANSI colours with printf-style syntax.
use climate_cfmt as cfmt;
cfmt::print("%red Error:%reset file not found: '%s'\n", filename);
cfmt::println("%green Success!%reset Process completed.");Use simple {} placeholders plus colour and time tokens.
use climate_fx as fx;
fx::println("{green}Status:{@} {}", "ready");
fx::println("[{time}] Starting up");Cleanly handle Ctrl+C or SIGTERM.
use climate_daemon as daemon;
// Block until termination signal
daemon::break_channel().recv().unwrap();
println!("Shutting down gracefully...");use climate_prompter as prompter;
let mut pr = prompter::Prompter::new(&[
prompter::Question { question: "Username".into(), default: "admin".into(), secret: false },
prompter::Question { question: "Password".into(), default: String::new(), secret: true },
]);
pr.ask().unwrap();
println!("User: {}", pr.answers[0]);
println!("Pass: {}", pr.answers[1]);use climate_paths as paths;
let dir = paths::Paths::new("myapp").unwrap();
// Returns ~/.config/myapp (Linux) or ~/Library/Application Support/myapp (macOS)
println!("Config dir: {}", dir.user_base.display());use climate_tab as tab;
let input = "Name Role Status\nAlice Admin Active\nBob User Offline";
let output = tab::tabulate(input, false).unwrap();
print!("{output}");use climate_human as human;
println!("{}", human::uint(1572864, false)); // "1.5 MiB"
println!("{}", human::uint(1500000, true)); // "1.5 MB"use climate_env as env;
let host = env::get("DB_HOST", "localhost");
let debug = env::get_bool("DEBUG", false);
let port = env::get_int("PORT", 5432);
let timeout = env::get_float("REQUEST_TIMEOUT", 1.5);use climate_ini as ini;
let cfg = ini::unmarshal("port=8080\n[server]\nmax=1024").unwrap();
let port = cfg.get_int("", "port");use climate_loglines as ll;
ll::msg!("Service started on port {}", 8080);
ll::err!("Failed to bind: {}", err);
ll::cmsg!("Listening on {}", ":8080");- Standard library only: No third-party dependencies.
- Unix focus: Made for systems I actually use every day.
- Idiomatic Rust: Leverage
Display,From,Error, and the type system rather than fighting them.
This project is licensed under the MIT License. See the LICENSE file for details.