Skip to content

feat(cli): declare what each usage command does to the world - #751

Merged
jdx merged 1 commit into
mainfrom
claude/usage-own-effects
Jul 27, 2026
Merged

feat(cli): declare what each usage command does to the world#751
jdx merged 1 commit into
mainfrom
claude/usage-own-effects

Conversation

@jdx

@jdx jdx commented Jul 27, 2026

Copy link
Copy Markdown
Owner

usage added effect=, shipped it to mise, hk, pitchfork, aube and communique — and declared nothing for its own 16 commands. Anything pointed at usage's spec sees empty fields on the tool that invented the feature.

command effect flags that raise it
complete-word read
generate read
generate completion read
generate completion-init read
generate fig read --out-file → write
generate json read
generate manpage read --out-file → write
generate markdown read --out-dir, --out-file → write
generate sdk write
lint read
sponsors read

Why the shape is interesting

Most of these print to stdout and take an optional flag to write to a file instead, so they sit at read with the flag raising them. That's the composition rule earning its place rather than being asserted in a doc — usage g markdown -f x.kdl only reads; the same command with --out-file writes.

generate sdk is the exception. Its -o --output is required, so there is no read-only way to invoke it and the effect belongs on the command, not a flag.

Unclassified, deliberately

bash, fish, zsh, powershell and exec run a script the user supplied, so their effect is whatever that script does. Labeling them would be a lie in whichever direction it was labeled, and read in particular would be dangerous. A test asserts every unclassified command has an entry in UNCLASSIFIED with its reason, so a new command can't go unlabeled by accident.

How

clap can't express this, so it's applied to the derived spec through clap_usage::spec (#743), the same shape as mise's command_effects. Five tests cover stale command paths, stale flag names, the unclassified guard, and both composition cases above.

Also emits min_usage_version "4.0" — an older usage rejects a spec carrying effect= with "unsupported cmd prop effect", so the declaration and the floor move together. mise does the same.

The generated docs pick it up for free: usage generate sdk now reads Effect: modifies state, and --out-file on markdown reads Effect: modifies state under a read-only command.

This PR was generated by an AI coding assistant.


Note

Low Risk
Metadata and spec-generation path changes only; no runtime command behavior changes beyond richer --usage-spec output.

Overview
Adds command_effects so the usage CLI’s own --usage-spec output carries effect=read / effect=write on commands and flags (clap can’t express this; it’s patched onto the derived spec like mise/hk).

Most generators are read; --out-file, --out-dir, etc. raise matching flags to write. generate sdk is write at the command level because output is required. bash, exec, and other script runners stay unclassified, with tests guarding stale paths and accidental gaps.

usage_spec::generate now builds the spec via clap_usage::spec, runs apply, and emits min_usage_version "4.0" alongside the KDL. Regenerated usage.usage.kdl, commands.json, and CLI reference docs show read-only vs modifies-state in docs.

Reviewed by Cursor Bugbot for commit 9ee7a02. Bugbot is set up for automated code reviews on this repo. Configure here.

Summary by CodeRabbit

  • New Features

    • Added effect metadata to CLI commands and output flags, distinguishing read-only operations from actions that modify files or state.
    • Added minimum usage specification version metadata.
  • Documentation

    • Updated CLI reference documentation and command metadata to display read-only and state-modifying effects.
    • Clarified effects for generation commands and file output options.

usage added `effect=` and shipped it to mise, hk, pitchfork, aube and
communique, and then declared nothing for its own 16 commands. Anything
pointed at usage's spec — its docs, `usage mcp` — sees empty fields on
the tool that invented the feature.

    complete-word          read
    generate               read
    generate completion    read
    generate fig           read   --out-file  write
    generate manpage       read   --out-file  write
    generate markdown      read   --out-dir   write
                                  --out-file  write
    generate sdk           write
    lint                   read
    sponsors               read

Most of these print to stdout and take an optional flag to write to a
file instead, so they sit at `read` with the flag raising them. That is
the composition rule earning its place rather than being asserted in a
doc: `usage g markdown -f x.kdl` only reads, and the same command with
`--out-file` writes.

`generate sdk` is the exception. Its `-o --output` is required, so there
is no read-only way to invoke it and the effect belongs on the command.

The five shell commands — `bash`, `fish`, `zsh`, `powershell`, `exec` —
are deliberately unset, because they run a script the user supplied and
their effect is whatever that script does. `read` in particular would be
dangerous. A test asserts every unclassified command has an entry in
`UNCLASSIFIED` with its reason, so nothing goes unlabeled by accident.

Applied to the derived spec via `clap_usage::spec` (#743) since clap
cannot express it, the same shape as mise's `command_effects`. Also
emits `min_usage_version "4.0"`, because an older `usage` rejects a spec
carrying `effect=` with "unsupported cmd prop effect".

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Jul 27, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

The CLI now classifies command and output-flag effects, applies them during usage-spec generation, emits usage version metadata, and synchronizes the resulting effect annotations across usage specifications and CLI reference documentation.

Changes

CLI effect metadata

Layer / File(s) Summary
Effect classification and validation
cli/src/command_effects.rs
Adds command and flag effect mappings, nested command traversal, an unclassified allowlist, and tests validating configured paths, flags, and effect behavior.
Usage spec generation
cli/src/lib.rs, cli/src/usage_spec.rs, cli/usage.usage.kdl
Wires effect application into explicit spec generation and adds min_usage_version "4.0" with read/write command and output-flag metadata.
Reference metadata synchronization
docs/cli/reference/commands.json, docs/cli/reference/*.md, docs/cli/reference/generate/*.md
Documents command effects, output-flag effects, and the minimum usage version in generated CLI references.

Estimated code review effort: 3 (Moderate) | ~25 minutes

Sequence Diagram(s)

sequenceDiagram
  participant CliMetadata
  participant UsageSpec
  participant CommandEffects
  CliMetadata->>UsageSpec: build spec from CLI metadata
  UsageSpec->>CommandEffects: apply command and flag effects
  CommandEffects-->>UsageSpec: classified spec
  UsageSpec-->>CliMetadata: emit usage version and spec
Loading

Poem

I’m a rabbit with effects in my hat,
Read here, write there—imagine that!
Flags hop neatly into their place,
Specs bloom with metadata grace.
Documentation follows the trail,
And every stale path gets caught by the rail.

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly describes the main change: adding effect declarations for usage commands.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.