Skip to content

fix(help): a command's page should say what that command does - #911

Merged
jdx merged 9 commits into
mainfrom
agent/help-describes-the-command
Aug 16, 2026
Merged

fix(help): a command's page should say what that command does#911
jdx merged 9 commits into
mainfrom
agent/help-describes-the-command

Conversation

@jdx

@jdx jdx commented Aug 16, 2026

Copy link
Copy Markdown
Owner

First of the help findings from the communique dogfood, and the clearest.

communique generate --help printed this:

communique 1.3.1
Editorialized release notes powered by AI

Usage: communique generate [FLAGS] <TAG> [PREV_TAG]

and never once said what generate does. Every page carried the root's banner and description, so the one thing a subcommand's help is for was the one thing missing from it. clap prints the command's own description there.

After:

Generate release notes for a git tag

Usage: communique generate [FLAGS] <TAG> [PREV_TAG]

The root keeps its banner and the program's description — it has no command of its own to describe, and a program's page is where a program introduces itself.

Changed in usage-lib and usage-argv together, so the gate still holds them byte-identical over mise's 211 commands. The point of that gate is that two implementations agree, not that either is frozen; and doing it this way means every usage-based CLI gets the fix, not only the ones using the derive.

Verification

mutation result
every page shows the program's description (the old behaviour) FAILED
every page shows the banner FAILED

every_short_help_matches_the_reference and every_long_help_matches_the_reference still green over mise's whole spec. Workspace suite green, clippy clean.


The rest of the help differences, for your call

Measured on the same page, clap vs usage. I have not acted on these — they are judgement calls about what is best rather than bugs, and you said you are not tied to either.

1. Global flags are missing from subcommand pages. communique generate accepts --config, --verbose and --quiet; its help lists none of them. clap lists all three. This is the other content loss and I think it should be fixed — a flag a user can type and cannot discover is the worst case.

2. Long forms do not align. clap indents so every long form starts at the same column:

      --github-release           Push editorialized notes to the GitHub release
  -n, --dry-run                  Generate notes without updating GitHub

we print both at column 2:

  --github-release           Push editorialized notes to the GitHub release
  -n --dry-run               Generate notes without updating GitHub

clap's is easier to scan. This is the one I would change next.

3. No comma between short and long. -n --dry-run vs clap's -n, --dry-run. The comma is near-universal.

4. -h, --help is not listed (nor --version, per #909). The existing reasoning is that a spec declares neither, so listing one would make the page disagree with the spec — sound for the spec, but help is for people, and clap lists both. Worth revisiting.

5. [FLAGS] vs clap's [OPTIONS]. Cosmetic; OPTIONS is the commoner convention and what clap 4 settled on.

Where we are already better: our wrapping. clap runs to 100+ columns and lets the terminal break lines mid-word; we wrap with a hanging indent, which is much better on a narrow terminal. I would keep that.

Say which of 1–5 you want and I will do them in order; 1 and 2 are the two I would pick.

AI-assisted — Tool: Claude Code; model: anthropic/claude-opus-5; version: unavailable.


Note

Low Risk
User-visible help text only; behavior aligns with clap and keeps usage-argv and usage-lib in sync. Clap conversion fix is correctness for derived specs, not security-sensitive.

Overview
Subcommand --help / -h no longer repeats the root name, version, and program about; it leads with that command’s own short or long description (clap-style). The root page still shows the banner and program intro.

The same rules are applied in usage-argv (short_help / long_help) and usage-lib (Tera templates get a root flag from empty full_cmd).

Clap → Spec conversion now runs set_subcommand_ancestors like KDL parsing, so nested commands get correct full_cmd and non-empty usage strings (e.g. go fast instead of a blank command path).

Conformance tests cover subcommand vs root help; a unit test covers clap-derived subcommand paths.

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

Summary by CodeRabbit

  • New Features

    • Improved CLI help output to clearly distinguish the root command from subcommands.
    • Root help now displays program name, version, and description.
    • Subcommand help now displays the relevant command description, including long-form text when available.
    • Nested subcommands now show accurate command paths and usage information.
  • Bug Fixes

    • Prevented root-level metadata from appearing on subcommand help pages.
    • Improved parsing and help behavior for commands with options such as --env.

jdx and others added 6 commits August 16, 2026 19:57
The first thing dogfooding turned up. communique keeps `src/command_effects.rs` — two
hundred lines of a table keyed by command path, plus its own tests to keep the table in
step with the CLI — for one reason: clap cannot say `effect`, so the classification is
applied to the generated spec afterwards. mise has the same file for the same reason.

Declared beside the command now. `#[usage(effect = "read")]` on an `Args`, and on a flag
where the flag is what changes the answer: `communique generate` only prints, and
`communique generate --github-release` writes. A table keyed by command path cannot say
that at all, which is why the flag half of communique's file exists as a second table
keyed by (command, flag).

Unsaid stays distinguishable from `read`. A consumer treats the absence as "ask", so it
has to survive as `None` rather than collapsing into the safe answer.

Refused on the root, beside `mount` and `restart_token`: bare `communique` does nothing
to the world, one of its commands does, and the spec writer already asserts it — so
accepting it here would trade a message for a `debug_assert!` inside the writer.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Three from review, one shape: declared, stored, and silently dropped.

`effect` on a positional. `arg_meta` has no field for one, so it compiled and vanished.
A positional is the thing being acted on rather than a choice to act, which is why the
metadata has nowhere to put it — refused with that as the reason.

`effect` on a `#[usage(subcommand)]` field. That branch looked for `subcommand` and
*ignored* everything else written beside it, so the declaration was never even parsed.
Refused as a class rather than one option at a time: the field holds a set of commands,
and everything the attribute can otherwise say describes a value or a flag. `long`,
`default` and `global` on a subcommand field were equally quiet before this.

And the docs table said `effect` describes a flag, when it also goes on an `Args` — where
it says what *running* the command does, which is the half communique needed most.

Found by Cursor Bugbot, greptile and CodeRabbit, which all three flagged the positional.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
… can read the spec

The other two gaps from the communique dogfood.

**A value is named after its flag, shouted.** clap prints `--max-tokens <MAX_TOKENS>`
and `<TAG> [PREV_TAG]`; the derive printed `<max-tokens>` and `<tag>`. A visible change
in `--help` for a CLI that changed nothing, which is the one thing this crate is trying
not to do.

From the *form* rather than the field, which the existing rule already had right and
clap agrees with: `#[usage(long = "type")] type_` renders `--type <TYPE>`, not `<TYPE_>`.
Underscores restored on the way, since the flag is kebab to type and snake to read — all
three shapes measured from clap 4 rather than remembered.

Set in the derive rather than in the renderers, so the metadata says what help prints.
Two fallbacks would be two answers, and the spec is what docs and completions read.

**`min_usage_version` is declarable and emitted first**, before anything an old `usage`
would choke on. Declared rather than worked out: computing it means a table from every
property to the version that introduced it, kept in step by hand, and such a table rots
into a spec that claims to be readable by a `usage` that chokes on it. communique writes
the line by hand today for exactly this reason.

Not done, because it is not a gap: the spec-level `usage "Usage: …"` line that
`clap_usage` emits. usage-lib parses it, carries it into the docs model, and renders it
nowhere — commands compute their own. Emitting it would be replicating a field no reader
has.

The gate's help parity over mise's 211 commands still holds, which is what says the
placeholder change did not cost fidelity.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…m per spec

Two from review.

A short-only flag names its value before the shouting default runs, so `-j <jobs>` sat
beside `--jobs <JOBS>` — one CLI printing a placeholder two ways, and neither of them
what clap prints. Measured: clap gives `-j <JOBS>`.

And `min_usage_version` on an `Args` was parsed, stored, and dropped, because only the
root emits a spec. Refused where it is written, beside the other root-only options.

Found by Cursor Bugbot and greptile.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…m clap

Found by porting communique. Declaring a version put it in the spec and nowhere a user
could reach it: `communique --version` printed `error: unexpected argument '--version'`
where clap printed `communique 1.3.1`. A straight regression rather than a trade, so it
is the first of the dogfood findings to fix.

Supplied by the parser and *not* listed in help, exactly as `--help` is: a spec declares
neither, and a page listing a flag its spec does not declare disagrees with the spec it
was rendered from. That is this crate's existing answer for `--help`, and there is no
reason for the two to differ.

Three rules, measured from clap 4 rather than remembered: both spellings answer, the
root only, and a CLI that declares no version gets no flag — `--version` answering with
nothing is worse than not having one.

The root only is a *field* on the table rather than a rule about depth, so a CLI wanting
clap's `propagate_version` has somewhere to say so later.

Where a CLI declares one of the spellings itself, the declaration wins and the other
still answers: `-V` for `--verbose` leaves `--version` working, and a `--version <V>` that
takes a value leaves `-V` working. clap refuses that collision by panicking at startup
and telling you to disable its flag; nothing has to break here, and the rule is the one
`--help` and `-h` already follow.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The second thing porting communique turned up. `parse()` rendered a failure with `{:?}` —
`UnknownFlag { token: [45, 45, 110, 111, 112, 101] }` — while the clap-shaped rendering
sat in this crate unused. So communique's `main.rs` hand-rolled thirty-four lines to
reach it, which is not a thing an adopter should have to work out.

`parse()` is the entry point that *is* the process: it already printed a help page and
exited. It now prints the message to stderr and exits 2, which is clap's status, so a
script that checks for it keeps working. `parse_from` still hands the error back, for a
library embedding a CLI that wants to decide.

The renderer is reached through `render_failure` in usage-argv rather than by generating
a `#[cfg]`. That is not a stylistic choice: whether the good rendering exists is a
feature of *usage-argv in the adopter's graph*, and a `cfg` written into generated code
is evaluated in the adopter's crate, where the feature is not theirs to see — which is
exactly how a metadata field once got silently dropped. Without `diagnostics` the same
function gives the Debug form, which is what a parser-only build asked for.

With this and the commit below it, communique's port matches clap on `--version`, `-V`,
every error message tested, and every exit code — and `main.rs` is thirty-four lines
shorter than the port needed yesterday.

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

coderabbitai Bot commented Aug 16, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Central YAML (base), Organization UI (inherited)

Review profile: CHILL

Plan: Pro Plus

Run ID: 9ee31fb6-37e6-427d-99a7-461939d659c8

📥 Commits

Reviewing files that changed from the base of the PR and between 9fa599e and b0f7233.

📒 Files selected for processing (6)
  • argv/src/help.rs
  • conformance/tests/help_request.rs
  • lib/src/docs/cli/mod.rs
  • lib/src/docs/cli/templates/spec_template_long.tera
  • lib/src/docs/cli/templates/spec_template_short.tera
  • lib/src/spec/mod.rs

Included review availability: Your plan includes up to 4 reviews per rolling hour; 3 remain after this review.


📝 Walkthrough

Walkthrough

The change separates root help metadata from subcommand descriptions. It also populates complete nested command paths in generated specifications and adds conformance coverage for help output and argument parsing.

Changes

CLI help rendering

Layer / File(s) Summary
Complete command paths
lib/src/spec/mod.rs
Clap conversion now populates subcommand ancestor paths. A regression test verifies nested full_cmd and usage values.
Root and subcommand help
argv/src/help.rs, lib/src/docs/cli/...
Root help retains version and program descriptions. Subcommand help uses its own description, with long help preferring long_about. Templates receive a root-context flag.
Help conformance coverage
conformance/tests/help_request.rs
Tests verify root and subcommand help output and confirm that deploy --env prod parses correctly.

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

Merge Risk: ⚪ Minimal · up to b0f72

This PR makes subcommand help describe the command being invoked while preserving the root program description and adds coverage for the behavior; no actionable merge-blocking risk remains beyond normal checks and review.

Possibly related PRs

  • jdx/usage#746: Related CLI subcommand help and generated command metadata handling.
  • jdx/usage#818: Related nested subcommand paths and generated command specifications.
  • jdx/usage#866: Related root and subcommand help rendering in argv/src/help.rs.

Poem

A rabbit hops through help today,
Root words stay where roots should stay.
Subcommands speak in voices new,
Nested paths are gathered too.
deploy --env prod runs bright—
Clean command trails, and help done right!

🚥 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 and concisely describes the main change: subcommand help pages now explain what each command does.
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.

@greptile-apps

greptile-apps Bot commented Aug 16, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

The PR changes root and subcommand help presentation, adds ancestry initialization for clap-derived specs, and expands compiled parser metadata and conformance coverage.

  • Subcommand help now presents the selected command’s description instead of the program banner.
  • Clap-derived command trees now receive complete command paths and generated usage strings.
  • The compiled parser adds version handling, placeholder normalization, effect metadata, and minimum-consumer-version metadata.

Confidence Score: 4/5

The PR does not yet appear safe to merge because programmatically built nested commands can still be rendered as root pages.

The clap conversion now initializes command ancestry, but SpecCommandBuilder and spec_cmd! still leave nested commands with empty full_cmd; the help renderer consequently prints incorrect root-oriented help and command usage for those public construction paths.

Files Needing Attention: lib/src/spec/mod.rs, lib/src/spec/builder.rs, lib/src/docs/cli/mod.rs

Important Files Changed

Filename Overview
lib/src/spec/mod.rs Adds ancestry initialization for clap-derived command trees, but leaves the previously reported builder and macro construction paths unresolved.
lib/src/docs/cli/mod.rs Uses empty command ancestry to distinguish root help, so unresolved programmatic command trees are still misclassified.
argv/src/help.rs Separates root banners from subcommand descriptions in both short and long compiled help output.
derive/src/codegen.rs Extends generated parser behavior for version requests, failure rendering, and new spec metadata.
argv/src/lib.rs Adds built-in version request parsing and the corresponding command-table metadata.

Reviews (3): Last reviewed commit: "fix(spec): a clap-derived subcommand sho..." | Re-trigger Greptile

Comment thread lib/src/docs/cli/mod.rs
@github-actions

github-actions Bot commented Aug 16, 2026

Copy link
Copy Markdown
Contributor

Instruction counts

benchmark trend instructions Δ wall (min) Δ
markdown ▁▁▁▂▂▇███ 177,573,547 → 177,499,896 -0.04% 17.36 → 16.49ms -5.00%
startup █▃▃█▃▃▃▃▁ 1,221,836 → 1,221,774 -0.01% 1.05 → 1.02ms -2.99%

No instruction-count regression above 1%.

Only instruction counts gate. Wall clock is shown for context — on identical hardware it moves 4-20% run to run.

Measured by tak — instruction-counted CLI benchmarks, stored in this repository's git notes.

Shadow comparison

Parsing mise use -g node@20 against a shadow of mise's committed spec.
Reported, not gated: the shadow grows as the derive learns to express more, so
what to watch is the ratio rather than either column.

usage clap ratio
instructions, cold parse 72108 5893576 81x
usage: argv -> struct                            1234 ns      1.23 µs
clap: build tree + parse -> struct             499613 ns    499.61 µs
clap: parse -> struct, tree reused              22710 ns     22.71 µs
clap: build tree only                          308954 ns    308.95 µs

66dd3bcf4b8e vs 6bdf2219e320 · measured on the runner, not pushed to the history.

jdx and others added 3 commits August 16, 2026 21:47
`render_failure` styles for the terminal it finds itself in, so under `CLICOLOR_FORCE=1`
— or any TTY — the assertion read

    \x1b[1m\x1b[31merror:\x1b[0m unexpected argument '\x1b[33m--nope\x1b[0m' found

and failed on a message that was perfectly correct. A test whose result depends on the
ambient terminal is a flake waiting for the machine that has one.

Stripped before reading. What this test is about is the wording; the colouring has tests
of its own. Checked green under a plain run, `CLICOLOR_FORCE=1` and `NO_COLOR=1`.

Found by Cursor Bugbot.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
`communique generate --help` printed

    communique 1.3.1
    Editorialized release notes powered by AI

    Usage: communique generate [FLAGS] <TAG> [PREV_TAG]

and never once said what `generate` does — which is the question that was asked. Every
page carried the *root's* banner and description, so the one thing a subcommand's help
is for was the one thing missing from it. clap prints the command's own description.

Changed in usage-lib and usage-argv together, so the gate still holds them byte-identical
over mise's 211 commands — the point of that gate is that two implementations agree, not
that either is frozen. Every usage-based CLI gets this, not only the ones using the
derive.

The root keeps its banner and the program's description: it has no command of its own to
describe, and a program's page is where a program introduces itself.

Found by dogfooding communique, and it is the first of several help differences worth
weighing — the rest are in the pull request rather than assumed here.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
`set_subcommand_ancestors` ran only on the KDL path, so every subcommand of a spec built
from clap had `full_cmd` empty. Two things read it, and both were wrong:

`SpecCommand::usage()` joins `full_cmd`, so a clap-derived subcommand's usage line came
out with no command in it — `go`'s usage was the empty string.

And the root check this branch adds asks whether `full_cmd` is empty, which classified
every such subcommand as the root and gave it the program's banner — the exact thing the
commit below is fixing. Reported by greptile against that check; the check is right and
the data feeding it was not.

One pass, run where the other one is, and it walks all the way down.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@jdx
jdx force-pushed the agent/help-describes-the-command branch from 0b891c7 to 66dd3bc Compare August 16, 2026 21:48

jdx commented Aug 16, 2026

Copy link
Copy Markdown
Owner Author

Confirmed, and the cause is one level below the check — fixed in 66dd3bc.

I probed it rather than reasoning about it. For a spec built from clap:

full_cmd=[]  usage=""  usage()=""

set_subcommand_ancestors runs only in the KDL FromStr path (lib/src/spec/mod.rs:309); the From<&clap::Command> impl never called it. So the root check is right and the data feeding it was not — and this was already broken before this PR in a second place: SpecCommand::usage() joins full_cmd, so every clap-derived subcommand's usage line rendered with no command in it.

One pass, run where the other one is, walking all the way down:

let go = spec.cmd.subcommands.get("go").unwrap();
assert_eq!(go.full_cmd, ["go"]);
assert_eq!(go.usage, "go <SUBCOMMAND>");
let fast = go.subcommands.get("fast").unwrap();
assert_eq!(fast.full_cmd, ["go", "fast"]);
assert_eq!(fast.usage, "go fast");

That fixes the misclassification you flagged, for SpecCommandBuilder, spec_cmd! and the clap conversion alike, since all three land in the same Spec.

The gate stays green — every_short_help_matches_the_reference and every_long_help_matches_the_reference over mise's 211 commands.

AI-assisted — Tool: Claude Code; model: anthropic/claude-opus-5; version: unavailable.

Comment thread lib/src/spec/mod.rs
Base automatically changed from agent/parse-diagnostics to main August 16, 2026 22:08
@jdx
jdx force-pushed the agent/help-describes-the-command branch 2 times, most recently from b0f7233 to 66dd3bc Compare August 16, 2026 22:10
@jdx
jdx merged commit ca63970 into main Aug 16, 2026
10 of 12 checks passed
@jdx
jdx deleted the agent/help-describes-the-command branch August 16, 2026 22:21
jdx added a commit that referenced this pull request Aug 17, 2026
PR 2 of the help plan, and the content loss that started it.

`communique generate` accepts `--config`, `--verbose` and `--quiet` from
its root, and its page mentioned **none of them**. A flag a user can
type and cannot discover is the worst way for help to be wrong, and it
was true of every subcommand page in every usage CLI.

```
Flags:
      --base-url <BASE_URL>      Base URL for the LLM API
  -o, --output <OUTPUT>          Write output to a file instead of stdout

Global flags:
  -v, --verbose                  Enable verbose logging output
  -q, --quiet                    Suppress progress output
  -c, --config <CONFIG>          Path to config file (default: communique.toml in repo root)
```

**Under a heading of their own** — this is where the design differs from
clap on purpose, per your call. clap mixes them into the one list;
`--config` belongs to the program rather than to `generate`, and a
reader should be able to see which is which. One column across both
sections, so the page reads as one table with a rule through it rather
than two that happen to be adjacent.

## Shadowing, which I did not plan for and which the first version got
wrong

`in_scope` chains a command's own flags before its ancestors' and takes
the first match, so `mise use --raw` is *use's* `--raw` and never the
root's. My first version listed both:

```
      --raw    Connect backend install command stdin/stdout/stderr directly to the terminal
...
Global flags:
      --raw    Read/write directly to stdin/stdout/stderr instead of by line
```

Two descriptions for one spelling, one of which can never apply. Decided
nearest-ancestor-first and emitted root-first, which is the order a
reader meets them walking down. `mise use` now lists `--raw` once, with
the description that will actually be used.

**The root grows no such section**: its flags are its own, `global` or
not, and there is nothing above it to inherit from.

## What made it possible

`find` walked the tree and **threw the chain away**, returning only the
command — so neither renderer had ancestors to ask. It returns the chain
now. That also fixes the help half of the pointer-identity bug I
reported on the diagnostics PR: a `Subcommands` type mounted under two
parents is one `Command` at one address, and a page rendered for the
second mount showed the first one's ancestry.

In usage-lib the chain comes from `full_cmd`, which is the typed path —
exact, with none of the ambiguity a search would have. (That field only
became reliable for clap-derived specs in #911.)

## Verification

| mutation | result |
|---|---|
| globals not listed at all | FAILED |
| shadowing dropped | FAILED |
| non-`global` flags inherited too | FAILED |
| the root grows a global section | FAILED |

Gate green over mise's 211 commands, so both renderers moved together.
Workspace suite green, clippy clean.

*AI-assisted — Tool: Claude Code; model: anthropic/claude-opus-5;
version: unavailable.*

<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **Medium Risk**
> Help output changes for every subcommand page and shadowing must stay
in sync between usage-argv and usage-lib; behavior is heavily tested but
user-visible help text will differ widely.
> 
> **Overview**
> Subcommand **`-h` / `--help`** now lists flags inherited from
ancestors (only those marked **`global`**) under a **Global flags**
heading, separate from the command’s own **Flags** section, with one
shared column width across both.
> 
> **`help::find`** returns the full **`CommandMeta` ancestry chain**,
not just the leaf command. **`short_help`**, **`long_help`**,
**`render`**, and completion use that chain so inherited globals and
correct ancestry (e.g. shared subcommand mounts) are available
everywhere.
> 
> Inherited entries follow **parser shadowing**: nearer commands win on
duplicate spellings; hidden flags still reserve spellings; partial
multi-long/short survival; negations vs longs resolved like
**`long_flag`** (any long in scope before negations). **`usage-lib`**
mirrors the same logic in **`inherited_flags`** and Tera templates so
gate tests stay aligned with usage-argv.
> 
> Call sites and tests pass explicit chains (e.g. **`&[spec.root,
config, set]`**); new **`conformance/tests/global_flags.rs`** covers
listing, deduplication, and edge cases.
> 
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
5aab55a. Bugbot is set up for automated
code reviews on this repo. Configure
[here](https://www.cursor.com/dashboard/bugbot).</sup>
<!-- /CURSOR_SUMMARY -->

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

- **New Features**
- Subcommand help now displays inherited global flags in a dedicated
“Global flags” section.
- Global flag details—including aliases, descriptions, choices, and
environment variables—appear consistently in short and long help.
- Help output respects hidden flags, aliases, negations, and subcommand
overrides.

- **Bug Fixes**
  - Improved metadata resolution for nested commands.
- Help layouts now maintain consistent columns and wrapping across local
and inherited flags.

- **Tests**
- Added comprehensive coverage for inherited flags, visibility,
precedence, and nested command help.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->

---------

Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
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.

1 participant