github jdx/usage v3.6.0
v3.6.0: effect= and four silent SpecCommand bugs

latest release: v4.0.0
3 hours ago

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

Don't miss a new usage release

NewReleases is sending notifications on new releases.