github jdx/usage v4.1.0
v4.1.0: MCP server, repository metadata, and self-declared effects

9 hours ago

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

Don't miss a new usage release

NewReleases is sending notifications on new releases.