Skip to content

chore(deps): update dependency jdx/usage to v6 - #29

Open
renovate[bot] wants to merge 1 commit into
mainfrom
renovate/jdx-usage-6.x
Open

chore(deps): update dependency jdx/usage to v6#29
renovate[bot] wants to merge 1 commit into
mainfrom
renovate/jdx-usage-6.x

Conversation

@renovate

@renovate renovate Bot commented Aug 22, 2026

Copy link
Copy Markdown
Contributor

ℹ️ Note

This PR body was truncated due to platform limits.

This PR contains the following updates:

Package Update Change
jdx/usage major 2.18.26.1.0

Warning

Some dependencies could not be looked up. Check the Dependency Dashboard for more information.


Release Notes

jdx/usage (jdx/usage)

v6.1.0: : Sharper derives, richer dispatch

Compare Source

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 can impl Run on.
  • 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, if run_with).
  • Roots with flags: #[usage(run)] on a struct with --verbose and a required subcommand generates run_command instead of impl Run, so top-level flags are not dropped.
  • Skip context: #[usage(no_ctx)] plus run_with_lazy / run_async_with_lazy (FnOnce() -> Ctx) lets commands like version avoid loading a config file.
  • output = Type explicitly names the match's Output instead 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_help as for help: source-wrapped lines become spaces, indented examples and fenced code blocks keep their breaks, and verbatim_doc_comment is untouched (#​1215).
  • KDL keeps newlines. Spec::to_kdl emits #"""…"""# raw multiline strings for values that contain newlines, so generated .usage.kdl no 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 or required.
  • 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 field required or use its type (e.g. non-Option) instead.

Full Changelog: jdx/usage@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

Compare Source

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_from support
  • 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 explain shows how argv was interpreted, including token roles, fallbacks, provenance, warnings, and accumulated errors.
  • usage diff compares 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-rs and usage-go should 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.
  • UsageErr is now #[non_exhaustive], and file/shell failures have dedicated variants. Downstream exhaustive matches need a fallback arm.
  • subcommand_required is now enforced by the reference parser. An invocation that previously slipped through without a required child command now fails as declared.
  • Rust flatten declarations are emitted as reusable flagset / use nodes 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-lib and 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-lib users 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.

v5.1.0: : Embed specs from strings, cleaner include metadata

Compare Source

A small feature release: embedders get a string-based script parser, included specs stop clobbering their parent's inferred metadata, and the test suite finally runs cleanly on Windows.

Added

  • Parse embedded USAGE comments from a string (#​782 by @​jdx). The new Spec::parse_script_str lets embedders turn a script body into a Spec without writing to a temp file or hand-deserializing KDL:

    let spec = Spec::parse_script_str(r#"
    #!/bin/bash
    #USAGE bin "mycli"
    #USAGE flag "--foo" help="a flag"
    "#)?;

    Because there's no source path, bin/name are not inferred from a filename and relative include paths are rejected with relative includes require a source file; absolute includes still work. The file-based parse_script now shares the same internal path, so behavior stays consistent.

Fixed

  • Included specs no longer overwrite parent metadata (#​786 by @​jdx). parse_file derives a missing bin (and then name) from the filename — but include was going through the same path, so an empty included fragment would take on its own filename and overwrite the parent spec, producing a spurious missing-cmd-help. Filename-based inference is now limited to the top-level spec; explicit metadata in includes still merges as before. The unreachable missing-name lint (which fired for stdin but never for files) was also removed so file and stdin linting behave the same way. Closes #​784 and #​785.

Changed

  • Corrected USAGE comment marker documentation (#​782). The docs previously described # USAGE: and // USAGE:; the real supported markers are #USAGE, //USAGE, ::USAGE, and their [USAGE] variants.
  • Bumped rmcp to v3 (#​780 by @​renovate). Tracks the MCP 2026-07-28 protocol revision.

Tests

  • Windows test suite is fully green (#​771 by @​JamBalaya56562). Reworks the shell skip guards to probe the actual precondition instead of a proxy (WSL's bash.exe cheerfully answers --version and then fails everything else), routes fixture invocations through USAGE_SHELL_<SHELL>, normalizes paths handed to shell script bodies and $PATH, and removes the #![cfg(unix)] gate on shell_override.rs — which held back the very tests for the Windows-facing USAGE_SHELL_<SHELL> feature added in v5.0.0. Result on a windows-latest runner: 538 passed, 0 skipped. No library or CLI source is touched.

Full Changelog: jdx/usage@v5.0.0...v5.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.

v5.0.0: : Double-dash routing and Windows shell fixes

Compare Source

A parser-level fix that makes double_dash="required" actually behave as declared drives the major bump: values before -- are now rejected, and values after -- are routed past greedy variadics to the arg that was waiting for them. The release also fixes a cluster of long-standing Windows problems — usage bash losing every usage_* variable under WSL, run= scripts being handed to cmd /c, and completion guards being fooled by a shell function named usage — and lets generate markdown write to stdout like the other generators.

Added

  • Override the shell binary with USAGE_SHELL_<SHELL> (#​767 by @​JamBalaya56562). Point usage bash, usage zsh, usage fish, and usage powershell at a specific interpreter — mainly so Windows users can escape the WSL bash.exe that Win32's search order picks up ahead of $PATH:

    set USAGE_SHELL_BASH=C:\Program Files\Git\usr\bin\bash.exe
    usage bash C:/work/mycli
    

    The variable is keyed by the program (so powershell's override is USAGE_SHELL_PWSH). Unset, empty, or whitespace-only falls back to the default. Spawn failures now name the program that was tried and the variable it came from, and on Windows a bash exit 127 against a drive-letter path prints a hint pointing at this override.

  • generate markdown writes to stdout (#​766 by @​JamBalaya56562). --out-file is now optional and defaults to stdout, matching manpage, fig, json, and completion. --out-file - also means stdout on markdown, manpage, and fig, mirroring the -f - input convention. The writing to … progress line moved to stderr on markdown, manpage, fig, and sdk, so it no longer ends up inside the generated document. --out-dir now requires --multi.

Fixed

  • double_dash="required" is now enforced on both sides (#​762 by @​JamBalaya56562). The parser previously ignored SpecDoubleDashChoices::Required entirely — a word offered to such an arg without -- was accepted anyway, and a required arg sitting behind a greedy variadic was unreachable even with a separator. Now offering a value before -- is reported as ArgRequiresDoubleDash (once per variadic, not once per word), and an explicit -- routes the positional cursor onto the arg that required it, past earlier args. Completion learns about -- too: while an arg is locked behind a separator, -- itself is offered rather than values the parser would reject.

  • Windows: usage_* variables reach WSL bash (#​764 by @​JamBalaya56562). On Windows the bash picked up from the system directory is WSL's launcher, and WSL only forwards a Win32 variable when WSLENV names it — so scripts saw every usage_* value unset. Both shell and exec now append the parsed argument names to WSLENV (bare, no /p or /l flags), preserving any entries the user had already configured.

  • Windows: run= scripts use sh when available (#​765 by @​JamBalaya56562). complete run= already used sh -c everywhere, but mount run= used cmd /c on Windows, so the same POSIX one-liner behaved differently depending on which KDL node it lived in — and shebang scripts silently exited 0 with empty output. Both call sites now share one implementation: sh -c first, falling back to cmd /c only if sh is not found. Non-UTF-8 output from either shell is now reported as an error instead of panicking.

  • Bash/fish completion guard ignores shell functions (#​760 by @​JamBalaya56562). The generated completion opens with a guard that bails out when the usage CLI is not installed, but type -p returns exit 0 for a shell function, so any environment defining a usage function (e.g. oh-my-bash) passed the guard and then failed further down with an unrelated error. Switched to type -P in both bash guards and the fish equivalent; zsh's type -p already forces a $PATH search and is unchanged.

Breaking Changes

  • double_dash="required" positional args now reject values before -- (#​762). Specs where such an arg previously happened to work without a separator will now error. In examples/mise.usage.kdl, post--- values also move from the preceding greedy variadic to the arg that declared the separator (e.g. from TASK_ARGS to TASK_ARGS_LAST, from TOOL@VERSION to COMMAND under exec), which changes which usage_* variable a consumer reads. Spec authors who want the old permissiveness can drop back to double_dash="optional" (the default).
  • UsageErr and ParseOutput gained fields. UsageErr has a new ArgRequiresDoubleDash variant, and ParseOutput gained next_arg and double_dash_seen. Library consumers matching these types exhaustively will need to update.

Full Changelog: jdx/usage@v4.1.0...v5.0.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.

v4.1.0: : MCP server, repository metadata, and self-declared effects

Compare Source

Puts the effect= work from 4.0 to use: a new usage mcp server lets agents read command effects locally over stdio, the CLI declares effects for its own commands, and specs gain a repository field so consumers away from the checkout can find the source.

Added

  • usage mcp — serve a spec to an agent over stdio (#​746 by @​jdx). A local Model Context Protocol server that speaks JSON-RPC 2.0 over newline-delimited stdio, so an agent can ask what a command does before running it. Load a spec with -f or -s (stdin is the transport, so --file - is rejected):

    usage mcp -f mycli.usage.kdl
    

    Two tools:

    • list_commands — the command tree, each entry tagged with its effect
    • describe_command — one command's help, flags, arguments, and the effect of each

    Effect is reported as an attribute alongside help and aliases; an unset effect stays null rather than defaulting to something reassuring, and the server instructions tell the client that a missing effect means ask. Hidden commands are excluded from listings by default, with include_hidden to opt back in. This is the first consumer of the effect= metadata now declared across roughly 385 commands in mise, hk, pitchfork, aube, and communique.

  • repository field on the spec (#​747 by @​jdx). A plain top-level URL, mirroring what Cargo.toml, package.json, or pyproject.toml carry — declared as a repository "..." node at the top of a spec. Distinct from source_code_link_template (which is a per-command deep link with a {{path}} placeholder). Anything reading a spec away from its checkout — usage.sh, a registry, an agent handed a .usage.kdl — previously had no way back to the project it described. Round-trips through parse, merge, serialize, and template rendering.

  • usage CLI declares its own effects (#​751 by @​jdx). Every command is now classified: most generate subcommands are read, with --out-file / --out-dir raising them to write; generate sdk is write at the command level (its output flag is required). Script runners (bash, fish, zsh, powershell, exec) are deliberately unclassified — their effect is whatever the user's script does — and a test asserts every unclassified command has an entry in UNCLASSIFIED with a reason. Also emits min_usage_version "4.0" so an older usage doesn't silently drop the annotation.

  • clap_usage::spec() (#​743 by @​jdx). Returns the Spec derived from a clap::Command (with bin already set), so callers can annotate it before rendering:

    let mut spec = clap_usage::spec(&mut cmd, "mycli");
    spec.cmd.subcommands.get_mut("rm").unwrap().effect = Some(SpecCommandEffect::Destructive);
    println!("{spec}");

    generate() now delegates to spec() plus two writeln!s; a test asserts its output is byte-identical.

  • usage::available_flags is public (#​746 by @​jdx), so consumers can enumerate flags the same way the parser does — respecting global merge and re-declaration rules.

Fixed

  • Re-declared globals keep their aliases on one flag (#​752 by @​jdx). A global like flag "-y --yes" global=#true re-declared non-globally by a subcommand (optionally adding a third alias, e.g. -y --yes --assume-yes) could leave -y and --yes pointing at two different Arc<SpecFlag> objects, with the -y view missing the new alias. The collision guard now compares flag origins rather than Arc identity, and rebinds every existing alias for the global to the merged flag on first merge.

  • Completions for repeated variadic args (#​753 by @​Jai-JAP). complete-word counted parsed positional entries to pick which arg to complete next, but variadic values all collapse into one entry — so after the first value, completion fell through to files. It now checks the parsed value per positional and keeps using the variadic arg's completer until var_max is reached.

Changed

  • clap_usage republished as 4.0.0 (#​743 by @​jdx). crates.io still shipped clap_usage 2.0.3, pinned to usage-lib ^2.0.3, because its source hadn't changed since — blocking downstream crates from adopting effect=. It now tracks usage-lib's major, and the spec() addition means dependents no longer have to inline generate() and depend on usage-lib directly.

New Contributors

Full Changelog: jdx/usage@v4.0.0...v4.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.

v4.0.0: : effect= on flags and args

Compare Source

Extends the effect= annotation from commands down to individual flags and arguments, so specs can express commands whose danger depends on how they are invoked.

Added

  • effect= on flags and args (#​742 by @​jdx). A command's danger often depends on how it is invoked: pitchfork logs reads, pitchfork logs --clear deletes; mise settings foo reads, mise settings foo=bar writes. Flags and args can now carry the same effect= annotation that #​739 introduced on commands:

    cmd "logs" effect="read" help="Show daemon logs" {
      flag "--clear" effect="destructive" help="Delete stored logs"
      flag "--follow"
    }
    
    cmd "settings" effect="read" {
      arg "[setting]"
      arg "[value]" effect="write"   // `settings foo` reads, `settings foo=bar` writes
    }

    The rule: the effect of an invocation is the maximum of the command's effect and the effect of every flag and argument actually supplied. SpecCommandEffect now implements Ord (read < write < destructive) so the maximum is well defined. Two helpers:

    • SpecCommand::effect_of(flags, args) — for a consumer that parsed the command line.
    • SpecCommand::max_effect() — the pessimistic bound across every declared flag and arg, for one that didn't.

    Effects only ever raise, never lower. --dry-run is deliberately not supported: a bug in a dry-run path would otherwise produce a spec that claims a command is safe when it isn't. Because the rule is monotonic, a consumer that can't parse the invocation can safely fall back to max_effect() and degrade to today's behavior — which is what makes this additive rather than a semantics break on the wire.

    Accepted as either a prop (effect="write") or a child node (effect "write"); unknown values are a parse error with a span. Generated markdown now renders an **Effect**: line beneath each flag that declares one. Most flags should declare nothing — this is for the handful that change what a command does to the world, not an annotation for every option.

  • New builder and constructor helpers (#​742 by @​jdx). SpecFlagBuilder and SpecArgBuilder gain .effect(...), .usage(...), and .help_first_line(...). SpecExample, SpecComplete, SpecConfig, SpecConfigProp, and SpecMount all gain a public ::new and chaining setters, so they can be constructed from outside the crate.

Breaking Changes

SpecArg, SpecFlag, SpecExample, SpecComplete, SpecChoices, SpecConfig, SpecConfigProp, and SpecMount are now marked #[non_exhaustive]. Any code that built one of these types with a struct literal outside usage-lib will no longer compile. Use the builders (SpecFlag::builder(), SpecArg::builder()) or the new ::new helpers instead; existing field access is unaffected.

Full Changelog: jdx/usage@v3.6.0...v4.0.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.

v3.6.0: : effect= and four silent SpecCommand bugs

Compare Source

Adds an effect= annotation for classifying command side effects, and fixes four latent SpecCommand bugs uncovered while auditing the code paths a new field has to touch.

Added

  • effect= on commands (#​739 by @​jdx). Declare what running a command does to the world so docs, wrapper scripts, and AI agent allowlists can consume the same annotation instead of hand-maintaining their own lists:

    cmd "ls"        effect="read"        help="List installed tools"
    cmd "use"       effect="write"       help="Install a tool and add it to the config"
    cmd "uninstall" effect="destructive" help="Remove a tool"
    Effect Meaning
    read Only inspects state. Idempotent.
    write Creates or modifies state, but removes nothing the user can't recreate.
    destructive May delete or irreversibly overwrite. Deserves a confirmation prompt.

    Accepted as either a prop (effect="read") or a child node (effect "read"); unknown values are a parse error. The field is not inherited by subcommands (git remote and git remote remove do different things), and unset means unknown, not safe — consumers should treat missing values as "ask". Round-trips through KDL and renders an - **Effect**: line in generated markdown. Exported as usage::SpecCommandEffect.

Fixed

Four silent gaps in SpecCommand handling, all found by auditing every field against merge, the KDL serializer, and the docs model (#​740 by @​jdx):

  • deprecated was dropped by merge. An included spec could silently un-deprecate a command.
  • examples were never written by the KDL serializer. spec.to_string() dropped every example.
  • help_md / before_help_md / after_help_md were accepted only as props but serialized as child nodes. Any spec with markdown help failed to reparse with Error: unsupported cmd key help_md. They are now accepted as child nodes as well.
  • restart_token never reached the docs model, so no template could render it.

Changed

  • Missing SpecCommand fields are now a compile error (#​740). merge and both From impls destructure their source with no .., so adding a field produces three compile errors pointing at exactly the places that owe it a decision. Runtime-derived fields are bound with a NOTE comment. A new round-trip test parses a spec exercising every field, serializes, reparses, and compares serde representations — catching the class of bug where the serializer writes something the parser rejects (which is how the help_md regression survived).

Full Changelog: jdx/usage@v3.5.7...v3.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.

v3.5.7: : Mounted commands stop leaking mounting-CLI flags

Compare Source

A parser fix for shell completions inside mounted commands. Addresses jdx/mise#11282, where the mounting CLI's global flags leaked into mounted task completions and non-global flags before a task hid the task from the parser.

Fixed

  • Mounted commands no longer inherit the mounting CLI's flags (#​738). Three related defects in how the partial-parse's subcommand scan and re-parse interact with mount:

    1. Globals leaked into mounted commands. For a CLI like mise, where everything after a task name is forwarded to the task, mise run mytask --<TAB> used to offer --cd --env --jobs --locked --quiet --raw --silent --verbose --yes even though the mounted program rejects them (unexpected word: --silent). Worse, when a mounted task declared a flag whose name collided with a global (e.g. its own --env with choices), the global shadowed it and value completion fell back to file paths instead of the task's choices. Mounted commands are now marked internally and their own flags take precedence over inherited globals for their own names; a new ParseOutput::completion_flags() returns just the flags a completion should offer once a mount boundary has been crossed. Globals stay recognized before the mounted command, and mount scripts still receive them.

    2. A non-global flag hid the subcommand behind it. Phase 1 stopped scanning at the first non-global flag, so usage complete-word ... -- mise run --force build --bump '' failed with unexpected word: build. Known non-global flags are now consumed like globals and the scan continues; they are simply not forwarded to mounts. Unknown flags still stop the scan since their arity is unknown.

    3. Re-parsed prefix words could bind to the wrong flag. A global's value that appeared before a mounted command with a same-named flag would be re-validated against the mounted flag's choices and rejected. Phase 1 now records which flag each skipped word was read as, and Phase 2 respects that binding, so mycli --env prod run task --env <TAB> still parses --env prod as the global and offers the task's --env choices after the task name.

    Documentation for global flags and mounted commands has been added under docs/spec/reference/.

Full Changelog: jdx/usage@v3.5.6...v3.5.7

💚 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.

v3.5.6: : Private completion cache and Markdown code-block escaping

Compare Source

A security-focused patch release that moves the shell-completion spec cache out of world-writable /tmp into a private per-user cache dir, plus a Markdown renderer fix that stops mangling < inside fenced code blocks.

Fixed

  • Completion spec cache is no longer written to world-writable tmp (#​727, fixes #​722). The generated bash, zsh, fish, and nu completion scripts previously cached the usage spec at a predictable path under ${TMPDIR:-/tmp}. Because /tmp is typically world-writable and the filename is guessable, another local user could pre-plant a symlink there and have the completion script's >| / save -f overwrite an arbitrary file owned by the invoking user. Caches now live in a per-user directory created with mode 700:

    • bash / zsh / fish: ${XDG_CACHE_HOME:-$HOME/.cache}/usage
    • nu: ($env.XDG_CACHE_HOME? | default (home-dir | path join ".cache") | path join "usage")

    Because ~/.cache persists across reboots (unlike /tmp), version-keyed cache files are now reaped on a cache miss if they haven't been regenerated in 30 days. The prune is age-based and scoped to the current bin, so running two versions of the same tool concurrently no longer thrashes the cache. Users who regenerate their completion scripts will pick up the fix; the cache location change is otherwise transparent.

  • nu: completion cache dir permissions and nushell 0.110+ compatibility (#​731). Nushell's builtin mkdir has no mode flag, so the initial fix in #​727 created the nu cache dir at the process umask (usually 755, world-readable). The generator now runs ^chmod 0700 on the dir at creation time (non-Windows only) to match bash/zsh/fish. Separately, $nu.home-path was renamed to $nu.home-dir in nushell 0.110.0, which broke the completer on any recent nushell even when XDG_CACHE_HOME was set (because default's argument is evaluated eagerly). The lookup now uses optional access with a fallback that works on both old and new nushell:

    let spec_dir = ($env.XDG_CACHE_HOME? | default ($nu.home-dir? | default $nu.home-path? | path join ".cache") | path join "usage")
  • markdown: preserve HTML inside fenced code blocks (#​720) — thanks @​risu729. The Markdown renderer's HTML-escape filter processed lines independently and would turn < into &lt; even inside multiline fenced code blocks, corrupting examples like echo <value>. It now tracks fenced-block state across lines and leaves content between column-zero triple-backtick fences untouched, while still escaping < in surrounding prose. Addresses the escaping problem reported in jdx/mise#6949.

  • cli: avoid trailing semicolon in macro expression position (#​729). The two miette::bail!("unsupported shell: ...") match arms in complete_word and usage_spec were wrapped in a block so the macro expands in statement position. This clears the semicolon_in_expressions_from_macros lint that is already a hard error on nightly Rust. Runtime behavior is unchanged.

  • lib: remove needless borrows in format! args (#​726) — minor cleanup for newer clippy.

Full Changelog: jdx/usage@v3.5.5...v3.5.6

💚 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.

v3.5.5: : Hyphen-prefixed flag values

Compare Source

A small patch release that lets value-taking flags accept hyphen-prefixed values (such as passthrough args to a wrapped CLI), plus a redesigned logo.

Fixed

  • parse: allow hyphen-prefixed flag values (#​715, fixes #​713). Flags that carry passthrough values (e.g. forwarding args to terraform/terragrunt) previously lost values that started with - when the first letter collided with an existing short flag — ./repro -a -destroy would tokenize -destroy as -d estroy and silently drop the intended value of -a. Value flags can now opt in via allow_hyphen_values=#true, and the parser will consume the next -… token as that flag's value before short/long flag parsing kicks in:

    flag "-a --args <ARGS>" allow_hyphen_values=#true

    This works for -a -destroy, --args=-destroy, and repeated variadic values like -a -val1 -a -val2. Flags without the opt-in keep their existing behavior. The built-in usage complete-word --cword flag now sets this internally so negative cword indices parse correctly.

Documentation

  • Redesigned logo (#​714). Replaces the previous raster logo with a clean flat vector flag mark — an ink flagpole with a green (#&#8203;22c55e) swallowtail banner carrying the -- flag prefix. All derived favicons and app icons were regenerated from the new vector source, and an SVG favicon is now served for browsers that support it.

Full Changelog: jdx/usage@v3.5.4...v3.5.5

💚 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.

v3.5.4: : Quieter fish completions

Compare Source

A small patch release focused on fixing noisy fish shell startup for users with execute-only or setuid binaries on $PATH, plus a Tera template engine upgrade that slightly tweaks generated docs and CLI help.

Fixed

  • complete(fish): skip unreadable files in the shebang completion scan (#​707 by @​GrantD-ADSK, fixes #​706). The conf.d script emitted by usage generate completion-init fish scans every executable on $PATH and peek-reads the first 128 bytes to detect a usage shebang. Files that are executable but not readable by the current user (such as macOS's setuid-root sudo or execute-only visudo) caused fish's own redirection layer to print a warning on every new shell — the existing 2>/dev/null only silenced the read builtin, not fish's redirection setup. A test -r $file; or continue guard now skips those files before the read is attempted. Re-run usage generate completion-init fish and reload your shell to pick up the fix.

Changed

  • docs: upgrade Tera template engine to v2 (#​705). The switch produced two small output changes worth noting:
    • Subcommands are now listed alphabetically (sorted by usage string) in both usage generate markdown output and in the usage CLI help output. Previously they followed spec order.
    • Long help text under arguments and flags in CLI help is now indented by 4 spaces instead of 2, matching typical CLI conventions.

Full Changelog: jdx/usage@v3.5.3...v3.5.4

💚 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.

v3.5.3: : Zsh default completion and negated flag help fixes

Compare Source

A small patch release with two fixes for the generated zsh completion init and CLI help rendering.

Fixed

  • zsh: preserve options for default completion (#​693 by @​jdx, fixes #​692). The _usage_default_complete handler emitted by usage generate completion-init zsh called emulate -L zsh, which reset shell options before falling back to _files for non-usage commands. With nomatch re-enabled, zsh treated internal tags like *:globbed-files as real globs, producing errors such as no matches found: *:globbed-files when completing things like emacs <TAB>. The generated init now runs setopt localoptions nonomatch extendedglob immediately after emulate -L zsh, so the _files fallback sees the option state it expects. Re-run usage generate completion-init zsh and reload your shell to pick up the fix.

  • docs: show negated flags in CLI help (#​694 by @​jdx). Boolean flags declared with a negate alias previously rendered only the positive form in usage CLI help output. They now render as --flag / --no-flag in both short and long help, and the help column width is calculated from the displayed usage so descriptions stay aligned:

    Flags:
      --compress / --no-compress  Compress output
      --verbose                   Verbose output
    

Full Changelog: jdx/usage@v3.5.2...v3.5.3

💚 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.5.2: : musl publish fix

Compare Source

A patch release that restores publishing of the x86_64-unknown-linux-musl prebuilt binary, which failed to upload in v3.5.1.

Fixed

  • musl and other prebuilt binaries publish again (#​687 by @​jdx). The v3.5.1 publish job for x86_64-unknown-linux-musl failed with can't find crate for 'core' after cross fell back to host cargo without the target installed. The publish workflow now runs rustup target add ${{ matrix.target }} for each matrix entry (skipping the synthetic universal-apple-darwin target) before invoking upload-rust-binary-action, so musl and other non-default triples build and upload reliably.

Full Changelog: jdx/usage@v3.5.1...v3.5.2

💚 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.5.0: : Type-Safe SDKs and Zsh Colon Fixes

Compare Source

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

Note

PR body was truncated to here.


Configuration

📅 Schedule: (UTC)

  • Branch creation
    • At any time (no schedule defined)
  • Automerge
    • At any time (no schedule defined)

🚦 Automerge: Disabled by config. Please merge this manually once you are satisfied.

Rebasing: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox.

🔕 Ignore: Close this PR and you won't be reminded about this update again.


  • If you want to rebase/retry this PR, check this box

This PR was generated by Mend Renovate. View the repository job log.

@renovate
renovate Bot force-pushed the renovate/jdx-usage-6.x branch from 13fdb38 to c55e8b6 Compare August 23, 2026 00:39
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

0 participants