Releases: jdx/usage
Release list
v6.6.1: Cleaner plain help and smarter flag completion
A small bugfix release focused on help rendering and shell completion. Plain help output no longer leaks embedded ANSI escapes, root-only help metadata stays on the root page, and completion now handles attached --flag=value syntax.
Fixed
- (complete) Complete attached long flag values (#1349, @nfvelten). Completions now work for inline long-option syntax like
--flag=value: the fragment after=is used to narrow suggested values, the full--flag=prefix is reattached to each candidate (since shells replace the whole word), and file-path fallback still applies when a flag has no explicit choices. Fixes #999. - (docs) Strip authored ANSI from plain help (#1357, @jdx).
Style::PLAINnow removes ANSI CSI/SGR sequences that were already baked into command metadata (common when migrating from clap'scolor_print::cstr!help), keeping plain terminal help and generated Markdown escape-free while colored output is unchanged. - (help) Keep root help on the root page (#1358, @jdx). Before/after help, examples, author, and license are now command-local instead of falling back to the root spec. Root-specific material no longer appears on unrelated leaf commands (e.g.
mise self-update --help), aligning with clap's command-local help behavior. Applied consistently across the Rust renderer, documentation templates, and the Go renderer.
New Contributors
Full Changelog: v6.6.0...v6.6.1
💚 Sponsor usage
usage is built and maintained by @jdx, an open source developer at entire.io, the title sponsor of his open source work.
If usage powers CLI specs, docs, or completions for a tool you maintain or use, please consider becoming an individual or company sponsor. Your support funds ongoing development and helps keep usage fast, free, and independent.
v6.6.0: Scoped flags and implicit clauses
This small release extends the repeatable clause groups introduced in v6.5.0 with per-instance scoped flags and separator-free (implicit) clauses, and completes their integration across the compiled parser, portable KDL, help, completions, and generated documentation.
Added
-
Scoped flags and implicit clauses. Clauses can now carry
flagnodes that are scoped to a single repeatable instance and reset at each boundary. Theseparatoris now optional: when omitted, a clause with exactly one required, non-variadic positional ends each instance implicitly as soon as that terminal positional is consumed. Scoped flags precede and apply to the next terminal positional, and the parser rejects ambiguous implicit layouts, conflicting flag spellings, duplicate scalar flags within an instance, and trailing scoped flags that never complete an instance. Threaded through the interpreted parser, the compiled argv parser, Rust derive, portable KDL emission, help/completion,usage diff, and the generated Go bindings (#1343, @jdx). Requiresmin_usage_version "6.6".clause "tools" { flag "--postinstall <COMMAND>" arg "<tool>" }
use --postinstall A a --postinstall B bproduces twotoolsinstances:postinstall="A",tool="a"andpostinstall="B",tool="b". In Rust derive, omitseparatorand place the scoped fields on the nestedArgstype.
Fixed
- Complete implicit clause integration (#1345, @jdx):
- Command-level relationships (
requires,conflicts, etc.) can now target arguments inside typed clauses in the compiled parser, so e.g.--forcecan require a clause's terminal positional. - Portable KDL now emits spec-facing argument names (e.g.
TOOL,--postinstall) for clause relationship fields instead of Rust field selectors, keeping reference-parser round-trips valid. - Repeated clauses are now rendered as optional groups (wrapped in
[…]) in compiled help, manpage synopsis, and Markdown, and clause-scoped flags and arguments now appear in generated documentation. Empty clauses no longer fail to render.
- Command-level relationships (
Full Changelog: v6.5.0...v6.6.0
💚 Sponsor usage
usage is maintained by @jdx, an open source developer for entire.io, the title sponsor of the jdx.dev open source tools including mise, aube, hk, and more. Work on usage is funded by sponsorships.
If usage powers CLI specs, docs, or completions for a tool you maintain or use, please consider sponsoring at jdx.dev. Every sponsorship helps the project stay independent and moving.
v6.5.0: Sigils, clauses, and Cobra examples
This release introduces two new positional-argument primitives — sigil-classified arguments and repeatable clause groups — plus support for Cobra's Example field when generating specs, and a zsh completion fix for aliases.
Added
-
Sigil-classified positional arguments. Positionals can now be declared with a leading
sigilprefix so they are matched by that prefix rather than by slot order. The prefix is treated as syntax and stripped before the value is stored, validated, or completed, and a sigil argument never advances the ordinary positional cursor — so classified values can interleave with flags and normal positionals. Completion, canonical KDL, argv tables, derive metadata, the Python/TypeScript SDKs, and the conformance corpus all carry sigils through the same contract, and tab completion strips/restores the prefix on every candidate (#1322, #1319, @jdx). Requiresmin_usage_version "6.5".arg "[tool]..." sigil="+" { choices "node@22" "node@24" "python@3.14" } arg "<command>" arg "[args]..."
With that spec,
ex +node@24 node -vbindstool=["node@24"],command="node", andargs=["-v"]. In Rust derive, annotate the field with#[usage(sigil = "+")]. -
Repeatable clause groups. A command can declare one separator-delimited group of positionals that repeats: each separator ends the current instance and starts a new one instead of overwriting it, and every instance is stored independently in parse output. Flag and positional state reset at each boundary, an explicit
--protects a literal separator, and completion treats the separator like a restart. Clauses are wired through the interpreted parser, the zero-allocation compiled argv parser, Rust derive (#[usage(clause, separator = "…")]onVec<T>), the Go parser, andusage diff(which reports clause add/remove/separator changes as breaking) (#1321, #1320, @jdx). Requiresmin_usage_version "6.6".clause "tasks" separator=":::" { arg "<task>" arg "[args]..." var=#true double_dash="automatic" }
run lint --fix ::: test --allproduces twotasksinstances:task="lint",args=["--fix"]andtask="test",args=["--all"]. -
Cobra
Examplefield support. Specs generated with--usage-specnow include Cobra'sExampletext asexamplenodes — a root command's example becomes a top-level node, and a subcommand's becomes a child of itscmdblock. The conventional two-space indent is stripped while multiline formatting and comment lines are preserved (#1333, @thecodesmith).
Fixed
- (zsh) Command-position aliases are now expanded before the line is sent to the completion binary, so completions work for aliases that add arguments (e.g.
gfin="mise run git:finish-branch"). Recursive and cyclic aliases are handled safely (#1330, @halms).
Changed
- The Rust framework (
usage-rs) documentation and site no longer carry the experimental label;usage-cliitself is built with it. The separateusage-dynamiccrate remains marked experimental, and Go remains a work in progress (#1334, @jdx).
New Contributors
- @halms made their first contribution in #1330
- @thecodesmith made their first contribution in #1333
Full Changelog: v6.4.1...v6.5.0
💚 Sponsor usage
usage is maintained by @jdx, an open source developer for entire.io, the title sponsor of the jdx.dev open source tools including mise, aube, hk, and more. Work on usage is funded by sponsorships.
If usage powers CLI specs, docs, or completions for a tool you maintain or use, please consider sponsoring at jdx.dev. Every sponsorship helps the project stay independent and moving.
v6.4.1: Colorful Help and Sharper Negative-Value Parsing
A focused patch release that adds terminal-aware color to interpreted help output, tightens how negative numbers are parsed as flag values, and lowers the published crates' minimum supported Rust version.
Added
- Colorized help output. The
usageCLI,usage bash, andusage execnow render interpreted help with terminal-aware semantic styling (headings, options, metavars, inline markdown, andhelp_template{$…}tags). Coloring is auto-detected from the terminal and honorsNO_COLORandCLICOLOR_FORCE; plain rendering remains available for snapshots and generated artifacts (#1309, @jdx).
Fixed
- More predictable negative-value parsing. Tokens like
-1are only consumed as a detached flag value whenallow_negative_numbersis set or when the flag's value is truly required (nodefault_missing, not optional). This keeps optional anddefault_missingflags from swallowing negative numbers during subcommand andexternal_subcommanddiscovery, while required flags and explicit opt-ins still bind them correctly. Missing-value errors are also now reported for the awaiting flag even when another recognized option follows (#1317, #1318, @jdx). - Hidden commands excluded from Markdown docs. Single-file Markdown reference generation no longer emits sections for commands marked
hide=#true, matching the existing index and flag/arg filtering (#1315, @jdx). - Simplified the
required_unlesspredicate logic for arguments and flags with no change in behavior (#1326, @jdx).
Changed
- Lowered MSRV to Rust 1.91. The published
usage-lib,usage-dynamic,clap_usage, andusage-clicrates now build on Rust 1.91 (down from 1.95), lettingusage-cliinstall on runner images that ship Rust 1.94 (#1314, @jdx).
Dependency Updates
Full Changelog: v6.4.0...v6.4.1
💚 Sponsor usage
usage is maintained by @jdx, an open source developer for entire.io, the title sponsor of the jdx.dev open source tools including mise, aube, hk, and more. Work on usage is funded by sponsorships.
If usage powers CLI specs, docs, or completions for a tool you maintain or use, please consider sponsoring at jdx.dev. Every sponsorship helps the project stay independent and moving.
v6.4.0: XDG config layers and terminal-aware help wrapping
This release adds XDG-based config file resolution, teaches --help to wrap to the terminal width with a smarter column layout, fixes zsh completions at mid-line cursor positions, and slims down the library's dependency tree with an independent Markdown feature.
Added
-
XDG file layers for config resolution.
FileLayer::xdg(XdgBase, path)resolves a relative path under the standard XDG config, data, state, cache, or runtime bases, honoring each base's defaults, absolute-path rules, and precedence with no new dependencies. Config and data bases include system search directories (with the user file winning), while state, cache, and runtime stay user-scoped. TheConfigderive gains matching#[usage(file(path = "…", xdg = "config"))]metadata that expands into the standard precedence chain in the emitted spec (#1303, @jdx).use usage::config::{FileLayer, XdgBase}; // Reads $XDG_CONFIG_HOME then $XDG_CONFIG_DIRS in precedence order, // falling back to $HOME/.config and /etc/xdg when unset. let layer = FileLayer::xdg(XdgBase::Config, "ex/config.toml");
Fixed
- Terminal help now wraps to the terminal width. Help output uses a hybrid column layout: long option spellings keep their description inline when at least 30 columns remain, otherwise the prose stacks under the shared description column. Paragraphs, section intros, annotations, bullet and numbered lists (with hanging indents), and labelled notes/warnings all wrap, while blank lines and preformatted (4-space/tab-indented) lines are preserved. The Rust reference renderer, the dependency-free usage-argv renderer, and the generated Go renderer stay in parity (#1304, @jdx).
- zsh completions respect the cursor position. Generated zsh scripts now forward zsh's one-based
CURRENTtocomplete-wordas a zero-based--cword, so completing a word in the middle of a command line (for example--fbefore a trailing argument) resolves against the correct word instead of the last one (#1300, @jdx, fixes #1298).
Changed
-
Independent
markdownandmanpagedoc features. Markdown and manpage rendering are now separate features so consumers who only generate Markdown can drop theroffdependency. The existingdocsandrofffeature names remain as aliases. Internally,heck,shell-words, andstrumwere replaced with focused in-tree implementations andunicode-widthwas bumped to 0.2, shrinking the dependency footprint while keeping the public API and error variants stable (#1301, @jdx).usage-lib = { version = "6", default-features = false, features = ["markdown"] }
Full Changelog: v6.3.0...v6.4.0
💚 Sponsor usage
usage is maintained by @jdx, an open source developer for entire.io, the title sponsor of the jdx.dev open source tools including mise, aube, hk, and more. Work on usage is funded by sponsorships.
If usage powers CLI specs, docs, or completions for a tool you maintain or use, please consider sponsoring at jdx.dev. Every sponsorship helps the project stay independent and moving.
v6.3.0: Colorful help by default and a slimmer dependency tree
This release brings semantic colors to --help output by default, adds a runtime style vocabulary for help_template, tightens help-column layout, and removes the kdl and default miette dependencies from the library.
Added
-
Semantic colors in help output by default. Coloured
--helpnow renders headings, option literals, and metavariables with distinct semantic colors so pages are easier to scan, while plain and piped output stays untouched (#1297, @jdx). -
Runtime style tags in
help_template. Templates can now colour and emphasize their own prose with a dependency-free tag vocabulary of 23 named styles (heading,option,metavar, the 8 standard and 8 bright ANSI colors, plusbold,dim,italic,underline). Styles nest and combine,{$$…}/{/$$}escape a literal tag, and substituted section text stays opaque so prose containing{$red}is left alone. Malformed markup falls back safely instead of panicking, and the vocabulary is validated in both Rust derives and KDL specs (#1297, @jdx).help_template = "{$heading}MY TOOL{/$}\n\n{{usage}}\n\n{$cyan}{{flags}}{/$}" -
Optional
miettefeature. With the library's own error rendering now built in, an opt-inmiettefeature makesUsageErrand KDL parse diagnostics implementmiette::Diagnosticagain, preserving source spans, labels, severity, and help text for callers that already use a miette reporter (#1296, @jdx).
Fixed
- Long entries no longer widen the whole help table. The aligned usage column is now capped at 40% of the remaining width, so a single long flag, argument, or command name (for example
--report-unused-disable-directives-severity <SEVERITY>) no longer forces every entry on the page into block layout. Oversized entries drop into a wrapped block under their own spelling while shorter neighbors keep a readable two-column layout. Applied consistently across the reference, zero-allocation, and Go renderers (#1293, @jdx). - Repeatability ellipses removed from output. The
…marker is no longer appended to repeatable flags in help tables,Usage:synopses, Markdown, or generated SDK docs, so options render with ordinary spellings like--env <ENV>. Value-side ellipses (<arg>…) are unchanged, and repeatability is still preserved structurally in the spec viavar(#1295, @jdx). - Go renderer now prints section prose. The Go help renderer honours the
headingsprose field introduced in v6.2.0, so a generated Go CLI renders the same declared section text as the Rust renderer instead of printing the heading alone (#1290, @jdx).
Changed
kdland defaultmiettedependencies removed.usage-libnow vendors a trimmed KDL v2 parser and renders diagnostics (source labels, help, and codes) with a small in-process renderer, dropping two dependencies from the default build without changing spec parsing behaviour. Apache-2.0 notices for the vendored code are recorded inNOTICE.md(#1296, @jdx).
Breaking Changes
UsageErrno longer derivesmiette::Diagnosticby default. Callers who relied on miette integration should enable the newmiettefeature to restore it (#1296).SpecFlag::usage()no longer round-trips the repeatability marker: parsing--flag…still setsvar, but reprinting yields--flag. Keepvar=#trueas the source of truth in specs rather than relying on the…suffix surviving a reparse (#1295).
Full Changelog: v6.2.0...v6.3.0
💚 Sponsor usage
usage is maintained by @jdx, an open source developer for entire.io, the title sponsor of the jdx.dev open source tools including mise, aube, hk, and more. Work on usage is funded by sponsorships.
If usage powers CLI specs, docs, or completions for a tool you maintain or use, please consider sponsoring at jdx.dev. Every sponsorship helps the project stay independent and moving.
v6.2.0: Embedded parsing, richer specs, and a redesigned help page
Added
- Embedded parse outcomes.
embedded::outcomeand the derive-generatedCli::embedded_outcome/embedded_outcome_intolet N-API, WASM, editor, and test-runner hosts parse without terminating the process, returning a renderedOutcome::Exitwith stream and clap-compatible status (#1250, #1270, #1281). - Structured diagnostic reports.
diagnostic::reportreturns a stableCode, subject, and optionalArgvSpan(index plus byte offsets intoOsStr) so hosts can label parse failures without scraping terminal text (#1255). - Opt-in response files.
usage::response::expandpre-parses@filearguments with shell-style quoting, nested includes,@@escaping, and cycle detection — kept off the zero-allocation parse path (#1259). - Ordered argument groups.
#[usage(multiple)]on anArgGroupenum collects related flags like-A/-W/-DintoVec<T>in argv order (#1271). - Value-carrying argument groups.
ArgGrouptuple variants now declare one value-taking flag (Migrate(Source),StdinFilepath(PathBuf)), bound throughFromStr, lossless path conversion, orValueEnum(#1253). - Typed command finalization.
#[usage(validate_with = …)]runs command-wide invariants after field conversion, and#[usage(try_into = DomainType)]addsparse_into*entry points that finalize throughTryFrom(#1254). - Runtime-computed defaults.
default_fnevaluates a typed default at parse time, withdefault_notefor help prose that describes it honestly (#1256). - Dynamic command catalogs. New
usage-dynamiccrate merges runtime-discovered plugin specs into a derived host's help, completion, and parsing viaCatalog::builder, attaching to a staticexternal_subcommandcatch-all (#1275). - Addressable help topics.
help::topicsandhelp::render_topicrender a single standard orhelp_headingsection without inventing fake subcommands (#1257). - Inline formatting in help text. Coloured
--helprenders Markdown-style bold, italic, inline-code, and strikethrough spans in prose, leaving plain and piped output unchanged (#1245). - Elvish shell completions. Elvish joins bash, zsh, fish, PowerShell, and Nushell as a first-class completion target (#1243).
- Semantic completion candidates. Candidates carry a
kind(Command,Flag,File,Directory,Value) so PowerShell can use nativeCompletionResulttypes, plus adisplaylabel so zsh and PowerShell can show a richer name while insertingvalue(#1239, #1242). - Path extension filters. Specs declare
type="path:toml,yaml"(or use.extensions("toml", "yaml")onFilePath/AnyPath) and every generated completion script filters accordingly; directories still traverse (#1240). - Completion traces. Public
CompletionTracerecords words, prefix, command path, cursor owner, separator state, candidates, and shell path fallback for a Tab answer (#1241). - Grouped help template sections.
{{grouped_args}},{{ungrouped_args}},{{grouped_flags}}, and{{ungrouped_flags}}let templates interleave namedhelp_headinggroups with default lists (#1251). - Section prose on headings.
heading("Ignore Files", help = "…")(andheading "Title" help="…"in KDL) puts a sentence under a named section, next to the entries it explains (#1282). - Command outputs, exit codes, and media types. Specs declare
outputblocks with text/JSON/JSONL framing, selectors, defaults, JSON Schemas (includingschema file="…"), an optionalmedia_type, and documentedexitcodes — surfaced through derives, MCP, generated Python/TypeScript SDKs, Markdown, and manpages (#1249, #1274). - Semantic note and warning blocks.
#[usage(note = "…", warning = "…")](or KDLnote/warningchildren) render as labeled admonitions in long help and portable Markdown blockquotes (#1273). - Surface availability metadata.
#[usage(surface = "…", available_if(…))]carries descriptive audience labels through KDL, JSON, docs, and conformance tables without changing parse behavior (#1258). - Overridable Markdown templates.
MarkdownRenderer::with_templateand theusage generate markdown --template NAME=PATHflag replace individual bundled Tera templates while unchanged ones remain available via{% include %}(#1267).
Changed
- Compact Markdown references by default. Generated Markdown now uses
MarkdownTheme::Compact— dense grouped lists instead of one heading per argument or flag, with title-cased metadata labels, "Output Formats" instead of "Output", and long output catalogs collapsed behind<details>. The previous layout isMarkdownTheme::Detailed(#1272, #1280). - Redesigned command lists on
-hand--help. Rows now show one aligned column of leaf names plus a short summary; usage syntax and children's fulllong_helpstay on their own pages. mise's root--helpdrops from hundreds of lines to 136 (#1284). - Short help wraps. Descriptions and annotations like
[env: …]no longer run off the terminal on-h; they join first and wrap into the description column together, matching what--helphas always done (#1287). - Long-help annotations align to the description column.
[possible values: …],(default: …), and env notes now sit under the description they qualify instead of at a fixed four-space indent (#1291).
Fixed
- Attached completion values.
--format=jnow completes as--format=json— static choices, named completers, and runtime overlays route through the attached-value context. Generated specs also materialize the parser-supplied help/version spellings asbuiltin=#trueflags so listings and completions see them (#1277). - Flattened command metadata. Outputs,
select, and exit codes declared on flattenedArgstypes survive spec emission (including nested flatten) (#1268). - Typed defaults with restricted choices. Choice validation now runs only on values from argv or environment variables, so a
default_fnmay return an empty or non-advertised typed value (#1269). - Override does not erase an invalid choice.
mise --log-level=v --traceused to be accepted by usage-argv (and usage-go) because the post-binding choice check sat inside thegivenguard thatoverridesclears. Both parsers now judge a displaced flag's leftover choice like usage-lib and clap do; Go exports a matchingCheckDisplaced(#1286). - KDL writers agree on three more nodes.
write_groupquotes dashed members ("--allow"not--allow),cmdwriteshelp_headingbeforehelp, and rootbefore_help/after_helpmove earlier and into before-then-after order. A maximal fixture now covers every node both writers emit (#1289). - Generated partial fields no longer trip Clippy.
#[expect(clippy::pub_underscore_fields)]onPartialstructs keeps internal fields public for cross-module flattening without noisy adopter lints (#1278). - Nushell completion. Replaces deprecated
str downcaseusage on Windows so case-insensitive command matching keeps working (#1262 by @TheBearodactyl).
Performance
- Skip empty admonition contexts in Markdown rendering, clawing back most of the cost added by note/warning blocks (#1279).
- Reduce sort code size in the argv hot path (#1264).
New Contributors
- @TheBearodactyl made their first contribution in #1262
💚 Sponsor usage
usage is maintained by @jdx, an open source developer for entire.io, the title sponsor of the jdx.dev open source tools including mise, aube, hk, and more. Work on usage is funded by sponsorships.
If usage powers CLI specs, docs, or completions for a tool you maintain or use, please consider sponsoring at jdx.dev. Every sponsorship helps the project stay independent and moving.
v6.1.1: Windows path fixes and slimmer derived binaries
A patch release focused on making usage a good citizen on Windows and shrinking the code the derive macro generates. Five separator- and prefix-aware fixes across complete, config and argv land alongside two derive perf passes that trim ~16.5% off a mise-scale stripped binary.
Fixed
- Path completion keeps the separator you typed.
complete_pathalready accepted/or\on Windows on the way in, but wrote back the platform separator for the middle of the path and a hard-coded/for the trailing directory marker, so typingtarget/de/inccame back astarget\debug\incremental/— a spelling no shell will match. Output now uses the same separator the token already contains (#1230 by @JamBalaya56562). - Config paths lose the verbatim prefix.
normalizestill canonicalizes for boundary checks, but strips the Windows\\?\/ UNC extended-length prefix before returning, soFileLayer::paths— whichconfig explainreports as provenance — matches what a caller built withcurrent_dir().join(…)(#1232 by @JamBalaya56562). - Install plans respect the target platform.
plantakes aPlatformfor a reason: an install plan is made for a machine, not on one. Three places had regressed to using the host's separator (andPath::is_absolute/Path::ends_within tests) — a Linux plan made on Windows was emittingfpath+=('/home/u\.local\share\zsh\site-functions'). All fixed to route throughPlatform::separatorand the crate's own platform-aware helpers (#1233 by @JamBalaya56562). - Simpler completion-script headers. Rust and Go generators now emit a single
@generated by …marker line instead of the extra "do not edit / no cached spec" preamble (#1226 by @jdx). - Cleaner flag reference docs. Generated Markdown headings show only the canonical short and long form; additional visible spellings move to a dedicated
Aliasesline. Hidden-alias filtering and interactive help are unchanged (#1228 by @jdx).
Performance
Two stacked derive-macro passes shrink the code every generated build() carries, without changing behavior or error messages:
- Cold error construction moves out of line into four
#[cold] #[inline(never)]builders inusage-argv(invalid_utf8_value,invalid_parsed_value,invalid_choice_value,invalid_os_value). On a mise-sized shadow binary this drops the stripped size from 1,579 KB to 1,369 KB (−210 KB, −13.3%) and roughly halves generatedbuild()code. Cold parse instructions dip 0.9%; wall time is unchanged within noise (#1235 by @jdx). - Repeated-value collection loops are shared through four monomorphized helpers (
utf8_values,parsed_values,os_values,spec::choice_values) with an inlinedis_empty()fast path that avoids paying for a call when aVec-shaped field received nothing. Another −51 KB on top, for a cumulative −261 KB (−16.5%) across the stack; instruction counts end up below the pre-stack baseline (#1236 by @jdx).
Tests
- Joined Windows test paths component-by-component so a self-comparison stops disagreeing with itself, and scoped the "refuse to skip under CI" guard for zsh/fish/bash-completion to Unix — Git for Windows does not ship bash-completion, and the workflow does not install POSIX shells on Windows either (#1229 by @JamBalaya56562).
- Silenced two Windows-only warnings (
unused import: WarningKind,enum_variant_namesonShell::PowerShell) socargo clippy --all-targets -- -D warningspasses there (#1234 by @JamBalaya56562).
Between them, these three test PRs take a windows-latest cargo test --all --all-features run from 2,383 pass / 5 fail to 2,393 pass / 0 fail, clearing the way for a real Windows CI job.
Full Changelog: v6.1.0...v6.1.1
💚 Sponsor usage
usage is maintained by @jdx, an open source developer for entire.io, the title sponsor of the jdx.dev open source tools including mise, aube, hk, and more. Work on usage is funded by sponsorships.
If usage powers CLI specs, docs, or completions for a tool you maintain or use, please consider sponsoring at jdx.dev. Every sponsorship helps the project stay independent and moving.
v6.1.0: Sharper derives, richer dispatch
This release sharpens the Rust derive framework introduced in 6.0: #[usage(run)] now handles the enum shapes real clap CLIs actually have, help and diagnostics respect the runtime identity of parse_from callers, and flatten-site help headings work. On the CLI itself, settings move to a prefix mise cannot strip, and generated KDL now round-trips multiline help.
Added
Broader #[usage(run)] dispatch (#1221)
The derived dispatch previously required every variant to wrap a named Args type, the whole enum to be sync or async, and the root to hold nothing but its subcommand field. That is now covered:
- Unit and inline variants get a generated
{Enum}{Variant}struct you canimpl Runon. - Mixed sync/async: put
#[usage(run_async)]on the enum and#[usage(run)]on the variant that should not.await. - Catch-alls:
#[usage(run, external = fallback)]forwards the unmatched argv (and context, ifrun_with). - Roots with flags:
#[usage(run)]on a struct with--verboseand a required subcommand generatesrun_commandinstead ofimpl Run, so top-level flags are not dropped. - Skip context:
#[usage(no_ctx)]plusrun_with_lazy/run_async_with_lazy(FnOnce() -> Ctx) lets commands likeversionavoid loading a config file. output = Typeexplicitly names the match'sOutputinstead of borrowing it from the first command.
Runtime identity in help, and flatten-site headings (#1220)
parse() already overlays the embedder's computed name / bin. parse_from callers that rendered help through Cli::spec() did not. Cli::render_help and Cli::render_failure now apply the same identity, so vendored parsers stop leaking the portable aube name into help and diagnostics.
#[usage(flatten, next_help_heading = "…")] at the flatten site now groups the unheaded flags of a flattened Args struct — matching clap's behavior — and reaches into subcommand help and generated KDL too.
USAGECLI_* settings prefix (#1213 by @JamBalaya56562)
Because Windows env-var names are case-insensitive, USAGE_DEBUG (a usage-cli setting) collides with usage_debug (a spec's own flag), and mise clears everything starting with usage_ before running a task — including usage-cli's settings. Settings can now be read under USAGECLI_*:
| New | Legacy (still read) |
|---|---|
USAGECLI_SHELL_{BASH,ZSH,FISH,PWSH} |
USAGE_SHELL_* |
USAGECLI_DEBUG |
USAGE_DEBUG |
USAGECLI_TRACE |
USAGE_TRACE |
USAGECLI_LOG |
USAGE_LOG |
First name set wins. As a side benefit, USAGE_LOG is no longer written back into the environment with set_var, so a spawned script's own log argument survives.
Fixed
- Long help flows like short help. Non-verbatim doc comments wrap the same way for
long_helpas forhelp: source-wrapped lines become spaces, indented examples and fenced code blocks keep their breaks, andverbatim_doc_commentis untouched (#1215). - KDL keeps newlines.
Spec::to_kdlemits#"""…"""#raw multiline strings for values that contain newlines, so generated.usage.kdlno longer collapses multi-paragraph help into one giant escaped line (#1215).
Changed
- Removed clap-compatible attribute spellings (a989d26b). Derives now accept only
#[usage(...)].#[command(...)],#[arg(...)],#[value(...)],#[group(...)], and inner synonyms (id,default_value,conflicts_with,value_parser,last, …) still parse, but fail at the source span with a diagnostic telling you the native replacement. Implicit clap-style#[group(...)]generation for one-member groups is gone — requiredness comes from the field type orrequired. - Stricter variant validation (#1224): redundant
#[usage(run_async)]on an enum variant is now rejected while parsing the attribute.
Documentation
- Complete KDL reference for the spec (#1214).
- Rust framework docs refreshed: sharper framework page (#1222), summarized parser performance page (#1219), combined clap migration guide (#1217), refreshed clap binary-size comparison (#1212), dropped a restated intro line (#1211).
- Benchmark charts added to the Rust and Go pages and comparison methodology clarified (#1209, #1210).
Breaking Changes
- Derive attributes must use
#[usage(...)]. Any remaining clap-shaped attributes (#[command],#[arg],#[value],#[group], or their inner synonyms) will now fail to compile with a diagnostic pointing at the replacement. See the clap migration guide for before/after rewrites. - Implicit single-member
#[group(...)]generation is gone. If you relied on it for requiredness, mark the fieldrequiredor use its type (e.g. non-Option) instead.
Full Changelog: v6.0.0...v6.1.0
💚 Sponsor usage
usage is maintained by @jdx, an open source developer for entire.io, the title sponsor of the jdx.dev open source tools including mise, aube, hk, and more. Work on usage is funded by sponsorships.
If usage powers CLI specs, docs, or completions for a tool you maintain or use, please consider sponsoring at jdx.dev. Every sponsorship helps the project stay independent and moving.
v6.0.0
Usage 6.0
Usage 6 is a much larger release than its version number can comfortably summarize. Since 5.1, the project has grown from a spec parser and artifact generator into a complete CLI platform: the new usage-rs reference framework for Rust, the beginnings of the usage-go reference framework, layered configuration, portable validation, richer completions, compatibility tooling, and a substantially more expressive Usage spec.
The idea is still the same: a CLI should have one machine-readable contract. In 6.0, that contract can now drive the program itself as well as its help, completions, docs, manpages, config schema, and compatibility checks.
Introducing usage-rs
usage-rs is the new reference framework for building Rust CLIs with Usage. Declare typed commands, arguments, subcommands, value enums, argument groups, and settings with ordinary structs and enums; usage-rs compiles the declaration into static data instead of constructing a command tree at startup.
That gives applications:
- Typed parsing with no runtime parser construction
- Built-in
-h,--help,help,--version, clap-shaped diagnostics, and suggestions - Generated sync/async command dispatch and
update_fromsupport - Shell completion scripts and in-process dynamic completers
- A built-in
__usage_spec__endpoint, so the running binary can describe itself - First-party assertions for parsing, help, execution, and completion behavior
On the checked-in mise-scale benchmark—211 commands, 711 flags, and 128 positionals—the parse-only path takes about 7,377 instructions / 0.7 µs, with no allocations when no owned values are bound. See the methodology and current numbers.
usage-rs is experimental: it is complete enough that usage-cli now uses it itself, but 6.x point releases may still change APIs.
Configuration becomes part of the contract
usage-rs can resolve settings across command-line, environment, and file layers while retaining provenance for every value. Its Config derive generates the registry, typed reader, and portable spec metadata from the same settings struct.
The resolver supports typed values, merge policies, aliases and renames, deprecation milestones, TOML/JSON/YAML readers, lossy reads, and explanations of where a value came from. Because config declarations live in the spec, the CLI can also generate JSON Schema and complete config keys and values.
See the configuration guide.
A substantially richer spec and CLI
The spec now covers much more of a real CLI's behavior: conflicts, requirements, overrides, groups, reusable flag sets, value-conditional rules, fixed and variadic arity, external and default subcommands, token-boundary controls, deprecations, portable expression validation, config metadata, help layout, and command effects.
Two new commands make that contract easier to operate:
usage explainshows how argv was interpreted, including token roles, fallbacks, provenance, warnings, and accumulated errors.usage diffcompares two specs and classifies changes as breaking, compatible, or metadata-only. It has machine-readable output and CI-friendly exit behavior.
Completion generation gained richer value hints, config completion, shell-safe quoting, partial-path expansion, aliases, async overlays, and --install for placing scripts where each shell expects them. JSON Schema generation for CLI config is new as well.
Introducing usage-go
usage-go is the new Go reference framework. It follows the same static-data design, generates typed command structs from a Usage spec, and keeps parsing, validation metadata, and help text linker-separable.
This work is not ready for adoption or testing yet. Its APIs and generated output are still in flux, and the published documentation is a preview of the direction rather than a stability promise.
Breaking changes and migration notes
usage-rsandusage-goshould be treated as brand-new in 6.0. Some implementation crates were accidentally published with 5.x versions, but those releases did not constitute supported public frameworks or an API lineage to migrate from. Start with the 6.0 framework documentation.UsageErris now#[non_exhaustive], and file/shell failures have dedicated variants. Downstream exhaustive matches need a fallback arm.subcommand_requiredis now enforced by the reference parser. An invocation that previously slipped through without a required child command now fails as declared.- Rust
flattendeclarations are emitted as reusableflagset/usenodes instead of duplicating flags under every command. The accepted command line is unchanged, but tools comparing serialized generated specs will see a structural change. - Usage no longer vendors or embeds bash-completion.
--include-bash-completion-liband the corresponding Rust option were removed. Generated Bash scripts require bash-completion 2.11 or newer to be installed and sourced; the scripts now diagnose a missing library clearly. - Dependency and feature cleanup removed unused transitive crates and stopped implicitly enabling capabilities for consumers. Direct
usage-libusers should declare the features they actually use.
For clap adopters, the usage-rs migration guide documents the mechanical derive mapping, known compatibility gaps, and intentional boundaries around runtime builders and ArgMatches.
Everything else
This release spans 347 commits and 500 changed files. The curated notes above are the practical overview; the full changelog retains every feature, fix, performance change, and pull request, and the complete comparison is available on GitHub.