Skip to content

Releases: jdx/usage

v3.5.0: Type-Safe SDKs and Zsh Colon Fixes

11 Jun 00:34
Immutable release. Only release title and notes can be modified.
5a96383

Choose a tag to compare

This release introduces usage generate sdk — type-safe subprocess-wrapper SDKs for TypeScript and Python derived from a usage spec — and fixes two zsh completion bugs around colons in subcommand and value names that were biting mise users.

Added

  • usage generate sdk for TypeScript and Python (#623 by @gaojunran). A new generator emits a type-safe SDK client for any usage-described CLI. The SDK is a subprocess wrapper — not a native binding — so it works for any binary on $PATH, with typed args, flags, and choice-constrained values instead of stringly-typed subprocess.run/spawn calls.

    usage generate sdk -l typescript -o ./sdk -f ./mycli.usage.kdl
    usage generate sdk -l python     -o ./sdk -f ./mycli.usage.kdl
    import { Mycli } from "./sdk";
    const cli = new Mycli();
    const result = await cli.build.exec(
      { target: "release", output: "./dist" },
      { release: true },
    );

    Each generated SDK has three pieces: a types module (dataclasses / interfaces, with Literal / union types for choices and global flags propagated to every subcommand), a client module mirroring the subcommand tree with exec() methods that build the argv list, and a small runtime module wrapping subprocess.run / child_process.spawn. See the SDK generation guide for the full walkthrough. Rust support is planned.

  • usage sponsors command and docs sponsor block (#662, #608, #656). The new top-level usage sponsors command and a sponsor strip on the docs site acknowledge 37signals and link to the canonical en.dev sponsor pages. A dedicated /sponsors docs page lists tiers fetched live from en.dev/sponsors.json.

  • More CLI-framework integration guides (#655, #667 by @gaojunran). The docs now cover using usage alongside JCommander, picocli, and Clikt (Java/Kotlin) and urfave/cli and Kong (Go), joining the earlier Commander.js / oclif / yargs / Typer / Click guides.

Fixed

  • zsh: all subcommands with a shared colon prefix now show up in completion (#666 by @zeitlinger). _describe groups matches that share a \:-escaped prefix and surfaces only one entry per group, so a spec with release:create, release:docs-sync, release:pr, and release:update would only ever show release:create in the menu. The completion now builds its own display column and calls compadd directly so every match is offered, with descriptions padded for column alignment. Regenerate zsh completions to pick up the fix. Surfaced via jdx/mise tasks.

  • zsh: completion no longer truncates values at the first colon (#670 by @davidolrik). Completing a mise task named chezmoi:brew:dump was inserting chezmoi and then destroying the user's typed :brew: on the next <Tab>, because _describe parses candidate:description in both the display and insert arrays it receives. The fix escapes colons in the insert column the same way the display column was already escaped. Regenerate zsh completions to pick up the fix.

  • parse: orphan short/long aliases on a re-declared global flag are preserved (#659 by @JamBalaya56562). Follow-up to #649. When a subcommand re-declared an inherited global flag as non-global and added a new alias (e.g. mise's run/tasks run re-declaring long-only --raw/--silent as -r --raw / -S --silent), the merge kept the global flag but discarded the re-declaration wholesale, throwing away the new short. The parser now unions the re-declaration's extra short/long aliases (matched on a shared long name) onto the surviving global flag, so completions like mycli run -r sample:run -- <TAB> work and usage_raw=true reaches as_env() and mount scripts. This makes mise's promote_orphan_shorts workaround unnecessary.

Changed

  • Docs examples use KDLv2 raw multiline strings throughout (#657 by @salim-b). The remaining KDLv1 r#"…"# raw strings in the documentation and examples/mise.usage.kdl were converted to KDLv2 #"""…"""#, matching the rest of the docs that already use KDLv2 syntax (#true, etc.).

New Contributors

Full Changelog: v3.4.0...v3.5.0

💚 Sponsor usage

usage is built by @jdx at en.dev — an independent developer-tooling studio behind 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 en.dev. Every sponsorship helps the project stay independent and moving.

v3.4.0: Readable KDL specs and tighter shell completions

31 May 15:26
Immutable release. Only release title and notes can be modified.
6e000ca

Choose a tag to compare

A small but pleasant release: spec files round-trip with human-readable multiline strings instead of \n-laden one-liners, and three completion-side bugs are fixed across zsh, nushell, and the parser.

Added

  • Multiline KDL strings for descriptions (#639 by @gaojunran). When the spec serializer encounters a string value containing newlines — typically long_help, help_md, multi-line complete run scripts, etc. — it now emits a KDL raw multiline string literal instead of a single-line string with embedded \n escapes:

    cmd bash help="Execute a shell script using bash" {
        long_help #"""
    Execute a shell script with the specified shell
    
    Typically, this will be called by a script's shebang.
    
    If using `var=#true` on args/flags, they will be joined with spaces using `shell_words::join()`
    to properly escape and quote values with spaces in them.
    """#
        ...
    }

    The number of # delimiters is computed automatically so values containing embedded """ sequences are always escaped safely.

Fixed

  • zsh: consistent single-quoting for choice values with spaces (#635). usage complete-word --shell zsh now emits two tab-separated columns per match — a display string for _describe's menu rendering and a pre-shell-quoted insert string — and the generated completion script wires them through _describe ... -U -Q -S ''. Choice values like Alice Alice or A B & C are inserted verbatim as 'Alice Alice' instead of zsh's default mix of backslash and single-quote styles, and values starting with ' correctly switch to menu-insert mode so the leading quote isn't truncated as a longest-common-prefix. If you have existing generated zsh completion scripts, regenerate them to pick up the fix.

  • nushell: invoke commands as externals with ^ (#638 by @silvanshade). Generated nushell completion scripts now prefix the user's CLI and the usage callback with ^, e.g. ^mybin usage | collect | save $spec_file and (^usage complete-word ...). Without the caret, nushell parsed bare mybin as an internal function and errored with Extra positional argument when loading the completion file.

  • parser: keep inherited global flags when a subcommand re-declares them as non-global (#649 by @JamBalaya56562). A value-taking global flag (e.g. -C/--cd) placed before a mounted subcommand whose definition re-declares the same flag without global=#true was being dropped from the recognized-flag set on descent. The leftover token was then mis-parsed as a positional — producing errors like Invalid choice for arg profile: -C, expected one of alpha, beta, gamma — and the flag's value was silently omitted from as_env() and from the environment passed to mount scripts. This was the parser-side root cause referenced by jdx/mise#10069.

New Contributors

Full Changelog: v3.3.0...v3.4.0

💚 Sponsor usage

usage is built by @jdx at en.dev — an independent developer-tooling studio behind 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 en.dev. Every sponsorship helps the project stay independent and moving.

v3.3.0: Auto-completion for usage shebang scripts

03 May 18:16
Immutable release. Only release title and notes can be modified.
f8fa60b

Choose a tag to compare

The headline feature in this release is one-line auto-completion for usage-shebang scripts: source a single init script from your shell rc and every usage-powered script on your $PATH gets <Tab> completion automatically. This release also brings new third-party integration guides and a handful of docs site polish fixes.

Added

  • Auto-completion for usage shebang scripts (#620 by @jdx). A new usage generate completion-init <shell> subcommand (alias ci) emits a one-time init script for bash, zsh, and fish. Source it once and any executable on $PATH whose first line is a usage shebang gains tab-completion — no per-script usage g completion <shell> <bin> -f <script> generation step.

    # bash — add to ~/.bashrc (source after bash-completion)
    source <(usage g completion-init bash)
    
    # zsh — add to ~/.zshrc
    source <(usage g completion-init zsh)
    
    # fish — add to ~/.config/fish/conf.d/usage.fish
    usage g completion-init fish | source

    Mechanism per shell:

    • bash registers a complete -D default handler that peeks the candidate command's first line for a usage shebang and dispatches to usage complete-word. Non-usage commands chain to bash-completion's _completion_loader, so existing completions keep working.
    • zsh registers a compdef -default- fallback with the same shebang detection, falling back to _files for non-usage commands.
    • fish has no default-completer fallback, so the init scans $PATH once at shell startup and registers complete -c <name> for each shebang script it finds.

    Pass --usage-bin (or set JDX_USAGE_BIN) if your usage binary is installed under a different name.

  • Third-party integration guides. Documentation now covers using usage alongside Commander.js, oclif, and yargs (#616 by @gaojunran) as well as Typer and Click (#619 by @gaojunran), based on the usage-integrations monorepo.

Fixed

  • Docs site banner now stacks vertically on viewports <=640px with the close button pinned to the top-right corner, fixing cramped two-line wrapping on mobile (#603 by @jdx).

Full Changelog: v3.2.1...v3.3.0

💚 Sponsor usage

usage is built by @jdx at en.dev — an independent developer-tooling studio behind 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 en.dev. Every sponsorship helps the project stay independent and moving.

v3.2.1: Zsh completion fix for values without descriptions

22 Apr 01:37
Immutable release. Only release title and notes can be modified.
06510f4

Choose a tag to compare

A small patch release that fixes a zsh completion regression introduced in v3.1.0. If you use zsh completions with values that contain colons (such as nested task names) and those values don't have descriptions, you should upgrade and regenerate your completions.

Fixed

  • Zsh completions now correctly escape colons in completion values even when no descriptions are present. In v3.1.0, the switch from _arguments to _describe introduced a bug where the escape logic only ran when at least one completion had a description. Without escaping, a value like test:git was misinterpreted by zsh -- it treated git as a description for the item test rather than as part of the value. If you have existing generated zsh completions, regenerate them to pick up this fix. (#597 by @david-hamilton-glean)

  • Test suite now respects the CARGO_BIN_EXE_usage environment variable when set, fixing test failures in environments with non-standard build directories such as Nixpkgs cross-compilation builds. (#568 by @kybe236)

New Contributors

Full Changelog: v3.2.0...v3.2.1

v3.2.0: Environment-backed choices and zsh escaping fix

23 Mar 18:37
Immutable release. Only release title and notes can be modified.
1b428b7

Choose a tag to compare

This release adds the ability to source argument/flag choices from environment variables at runtime and fixes a zsh completion regression where parentheses and brackets in task descriptions caused shell errors.

Added

  • Arguments and flags can now pull their allowed values from an environment variable using choices env=.... The env var value is split on commas and/or whitespace, deduplicated against any literal choices, and resolved at parse/completion time rather than baked into generated output. (#548 by @mustafa0x)

    arg "<env>" {
      choices env="DEPLOY_ENVS"
    }

    With DEPLOY_ENVS="foo,bar baz", valid values become foo, bar, and baz. You can also combine literal choices with env-backed ones:

    flag "--env <env>" {
      choices "local" env="DEPLOY_ENVS"
    }

    When the env var is unset or empty and no literal choices are provided, validation rejects all values with a clear error message. Help output and generated markdown surface the controlling env var name rather than snapshotting its current value.

    This feature is currently behind the unstable_choices_env feature flag in the library crate.

Fixed

  • Zsh completions now properly escape parentheses ((, )) and brackets ([, ]) in completion descriptions. Previously, these characters were passed through to zsh's _describe function unescaped, causing it to interpret them as glob qualifiers or character classes -- resulting in cryptic errors like unknown file attribute and unknown sort specifier. This was a regression from v2.x. If you have existing generated zsh completions, regenerate them to pick up this fix. (#559 by @jdx, fixes #558)

New Contributors

Full Changelog: v3.1.0...v3.2.0

v3.1.0: Richer help output, stdin support, and zsh completion fixes

22 Mar 16:54
Immutable release. Only release title and notes can be modified.
1e81f1b

Choose a tag to compare

This release improves the CLI's --help output to render all the documentation-related fields that were previously only used in manpage and markdown generation, adds stdin support for piping specs into usage commands, and fixes a long-standing zsh completion annoyance with trailing spaces.

Highlights

  • The --help / -h output is now much richer, rendering examples, before/after help text, version headers, author/license info, and deprecation markers -- fields that were previously only surfaced in generated manpages and markdown.
  • You can now pipe a usage spec from another tool directly into usage via --file -, enabling workflows like jbang usage | usage generate markdown --file -.
  • Zsh tab completions no longer insert unwanted trailing spaces after partial completions, fixing a bug reported nearly a year ago.

Added

  • The built-in --help / -h rendering now includes before_help, after_help (and their _long variants), examples, a name+version header, author/license in the long help footer, and [deprecated: reason] markers on subcommands. Short help (-h) uses the base variants; long help (--help) prefers the _long variants with a fallback to the base ones. (#554 by @jdx, closes #549)

    For example, a spec like:

    before_help "Welcome to my CLI"
    after_help "See the project website for docs"
    example "mycli --verbose" header="Run with verbose output"

    will now render those sections in mycli --help output, not just in generated docs.

  • All --file flags across generate, lint, and complete-word subcommands now accept - to read the usage spec from stdin. This enables piping specs from other tools without writing a temporary file. (#555 by @jdx, closes #546)

    jbang usage | usage generate markdown --file -
    cat myspec.kdl | usage lint --file -

    Not supported for exec / shell subcommands, which pass stdin through to the child process.

Fixed

  • Zsh completions no longer append an unwanted trailing space after partial completions. Previously, completing node@ would produce node@ (with a space), and path completions like /opt/homebrew would not include a trailing slash. The generated zsh completion scripts now use _describe with -S '' instead of _arguments with command substitution, and directory completions include a trailing /. If you have existing generated zsh completions, regenerate them to pick up this fix. (#556 by @jdx, closes #67)

Full Changelog: v3.0.0...v3.1.0

v3.0.0: Spec metadata expansion and Cobra escaping fix

13 Mar 16:58
Immutable release. Only release title and notes can be modified.
743efec

Choose a tag to compare

This release adds several new metadata fields to the usage spec and includes a breaking API change to the Spec struct. The spec parser now supports license, before_help, after_help, before_long_help, and after_long_help -- fields that were documented in the spec reference but silently ignored until now. The Spec struct has been marked #[non_exhaustive] to allow future field additions without further breaking changes.

Breaking Changes

The Spec struct now has the #[non_exhaustive] attribute. If you construct Spec values using struct literal syntax, your code will need to be updated:

// Before (no longer compiles)
let spec = Spec { name: "my-cli".into(), bin: "mycli".into(), /* ... */ };

// After (option 1)
let mut spec = Spec::default();
spec.name = "my-cli".into();
spec.bin = "mycli".into();

// After (option 2)
let spec = Spec { name: "my-cli".into(), bin: "mycli".into(), ..Default::default() };

This change was made so that new fields can be added to Spec in future minor releases without breaking downstream code. (#542 by @jdx, fixes #537)

Added

  • Support for license, before_help, after_help, before_long_help, and after_long_help top-level metadata fields in the usage spec. These fields are now parsed, serialized, and included in spec merges and generated docs. For example:

    license "MIT"
    before_help "Welcome to my CLI"
    after_help "See the docs for more info"
    before_long_help "Detailed welcome text"
    after_long_help "Detailed footer text"

    (#542 by @jdx)

  • New community integration: Ruby's OptionParser via option_parser_usage. (#533 by @packrat386)

Fixed

  • The Cobra integration now correctly escapes newlines (\n), tabs (\t), and carriage returns (\r) in KDL output. Previously, Cobra commands with multi-line help text would produce invalid KDL specs that failed to parse. (#539 by @thecodesmith)

Changed

  • Updated the roff dependency from 0.2 to 1.0 for man page generation. (#529)

New Contributors

Full Changelog: v2.18.2...v3.0.0

v2.18.2: Fix noclobber compatibility in shell completions

01 Mar 22:59
Immutable release. Only release title and notes can be modified.
8dc9747

Choose a tag to compare

A small patch release that fixes a compatibility issue with the noclobber shell option. If you had set -o noclobber (or set -C) enabled in bash or zsh, tab completions generated by usage would fail with a "cannot overwrite existing file" error every time the spec cache file already existed. This is now fixed.

Fixed

  • Generated bash and zsh completion scripts now use >| (force-overwrite redirection) instead of > when writing the spec cache file, preventing failures when the shell's noclobber option is enabled. Previously, users with noclobber set would see errors like bash: /tmp/usage__usage_spec_mycli.spec: cannot overwrite existing file on every tab completion. (#524 by @nkakouros)

New Contributors

Full Changelog: v2.18.1...v2.18.2

v2.18.1: Fix choice validation for variadic args and flags

24 Feb 23:42
Immutable release. Only release title and notes can be modified.
a7e0b75

Choose a tag to compare

A small patch release that fixes a parsing bug where variadic arguments and flags with declared choices were not being validated. Previously, any value was silently accepted for variadic (var=#true) args and flags, even when a choices constraint was specified. Non-variadic args and flags were unaffected and already validated correctly.

Fixed

  • Variadic args and flags with choices now correctly reject invalid values at parse time, matching the existing behavior for non-variadic args and flags. For example, given a spec like arg "<level>" var=#true { choices "debug" "info" "warn" "error" }, passing an invalid value such as "invalid" now produces a clear error message instead of being silently accepted. (#520 by @jdx, fixes jdx/mise#8334)

Full Changelog: v2.18.0...v2.18.1

v2.18.0 (Internal CI improvements)

18 Feb 14:52
Immutable release. Only release title and notes can be modified.
8b35fc3

Choose a tag to compare

This is a maintenance release with no user-facing changes. The only modification is an internal CI/CD improvement that extracts the AI-powered release-note enhancement step into a separate GitHub Actions job, making it independently re-runnable if it fails due to transient errors.

There are no changes to the library, CLI, shell completions, spec format, or documentation.

Full Changelog: v2.17.4...v2.18.0