github jdx/usage v4.0.0
v4.0.0: effect= on flags and args

one hour ago

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

Don't miss a new usage release

NewReleases is sending notifications on new releases.