Skip to content

feat(spec): select a subcommand from argv0 when multicall - #1028

Merged
jdx merged 2 commits into
cursor/plan-landed-gaps-66dbfrom
cursor/spec-multicall-66db
Aug 18, 2026
Merged

jdx merged 2 commits into
cursor/plan-landed-gaps-66dbfrom
cursor/spec-multicall-66db

Conversation

@jdx

@jdx jdx commented Aug 18, 2026

Copy link
Copy Markdown
Owner

Stacked on #1027. Adds clap's Command::multicall as spec-level multicall #true.

Semantics

argv[0]'s basename is a word unless it is the dispatcher (name or bin). A symlink ls -> busybox is parsed as if the first token were ls. busybox ls still selects ls: the dispatcher name is skipped. Path components and a trailing .exe are stripped so /usr/bin/ls and ls.exe agree.

An unknown applet is an unmatched word: it errors, is forwarded when the root declares external_subcommand, or is caught by default_subcommand. Invoking the dispatcher with no further words stays at the root.

Where argv0 is rewritten

  • usage-lib parse includes the program name. After pop_front, a non-dispatcher basename is pushed back.
  • usage-argv / derive parse_from / Go Parse take argv without the program name. parse() and the corpus adapters rewrite at process entry; parse_from stays unchanged because the caller already decided the words.
  • Helpers: multicall_basename / multicall_applet in usage-lib and usage-argv; Go RewriteMulticall.

Surfaces

  • Spec parse/emit/merge, clap is_multicall_set
  • Derive #[usage(multicall)] on the root (refused below it, and without subcommands)
  • Go JSON multicall, argv.RewriteMulticall
  • Corpus 12-multicall.json (argv0 on Vector; absent means the spec's bin)
  • usage lint reports multicall-no-subcommands
  • Shadows emit multicall for both usage and clap dialects

no_binary_name stays out of scope.

This comment was generated by Claude Code.

Open in Web Open in Cursor 

clap's busybox-style applets: `multicall #true` treats argv[0]'s basename
as the first word unless it is the dispatcher (`name` or `bin`). usage-lib
sees argv0 and rewrites after pop_front. usage-argv, the derive `parse()`,
and Go take argv without the program name, so they rewrite at process
entry (`parse_from` / `Parse` stay unchanged). Path components and a
trailing `.exe` are stripped.

Corpus `12-multicall.json` carries optional `argv0`. clap's
`is_multicall_set` reaches the spec.

Co-authored-by: jeff <jeff@jdx.dev>
@coderabbitai

coderabbitai Bot commented Aug 18, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

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

Review profile: CHILL

Plan: Pro Plus

Run ID: a0634528-429a-4f0f-8a75-8d3eb204b81a

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

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.

The iterator helper needed an explicit lifetime, and the round-trip
fixture had a subcommand without metadata. Use the same name-then-bin
checks usage-argv does, and emit `multicall` from an empty root.

Co-authored-by: jeff <jeff@jdx.dev>
@github-actions

Copy link
Copy Markdown
Contributor

Instruction counts

Nothing was compared, and so nothing was gated. No series appears on both sides: either the base has no measurements recorded, or the two were measured on different runner classes, which are deliberately not comparable — counts shift between machine types by more than a real regression does.

New, nothing to compare against: markdown on bamboo-v2-ubuntu24.04-x64-30vcpu-24gb-rust1.97.1, startup on bamboo-v2-ubuntu24.04-x64-30vcpu-24gb-rust1.97.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.

framework instructions, cold parse vs usage
usage 4220
argh 6292 1.5x
clap 5893652 1396x
bpaf 21917954 5193x
                                              min       p01       p10    median
usage-rs: argv -> struct                      187       190       193       196  ns
argh: argv -> struct                          285       289       293       299  ns
clap: build tree + parse -> struct         483347    485321    489077    495486  ns
bpaf: build parser + parse -> struct      1585062   1585062   1592298   1609874  ns

usage: argv -> struct                             199 ns      0.20 µs
clap: build tree + parse -> struct             498028 ns    498.03 µs
clap: parse -> struct, tree reused              23612 ns     23.61 µs
clap: build tree only                          307915 ns    307.91 µs

188cef88a288 vs 698b529649c7 · measured on the runner, not pushed to the history.

@jdx
jdx merged commit c76d1bf into cursor/plan-landed-gaps-66db Aug 18, 2026
10 checks passed
@jdx
jdx deleted the cursor/spec-multicall-66db branch August 18, 2026 15:34
jdx added a commit that referenced this pull request Aug 19, 2026
<!-- CURSOR_AGENT_PR_BODY_BEGIN -->
`external_subcommand` (#1021) and `default_if` (#1023) are in the
parser, the derive, and the corpus. PLAN.md still listed them as open
clap gaps.

This ticks those items, drops them from the fleet table, and splits
`multicall` from `no_binary_name` so the next PR can close one without
pretending the other landed. `no_binary_name` stays out of scope until a
fleet CLI needs it.

Also stops quoting a corpus vector count in PLAN.md and `go/README.md`,
matching the argv grammar page (#1024): agreement is measured on each
run rather than asserted as "154".

Stacked next: #1028 (`multicall`).

_This comment was generated by Claude Code._
<!-- CURSOR_AGENT_PR_BODY_END -->

<div><a
href="https://cursor.com/agents/bc-4de7e59e-aa2e-4ad0-a1d0-1c2e69c166db?cursor_ref=pr_footer&cursor_cta=open_in_web"><picture><source
media="(prefers-color-scheme: dark)"
srcset="https://cursor.com/assets/images/open-in-web-dark.png"><source
media="(prefers-color-scheme: light)"
srcset="https://cursor.com/assets/images/open-in-web-light.png"><img
alt="Open in Web" width="114" height="28"
src="https://cursor.com/assets/images/open-in-web-dark.png"></picture></a>&nbsp;<a
href="https://cursor.com/background-agent?bcId=bc-4de7e59e-aa2e-4ad0-a1d0-1c2e69c166db&cursor_ref=pr_footer&cursor_cta=open_in_cursor"><picture><source
media="(prefers-color-scheme: dark)"
srcset="https://cursor.com/assets/images/open-in-cursor-dark.png"><source
media="(prefers-color-scheme: light)"
srcset="https://cursor.com/assets/images/open-in-cursor-light.png"><img
alt="Open in Cursor" width="131" height="28"
src="https://cursor.com/assets/images/open-in-cursor-dark.png"></picture></a>&nbsp;</div>



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

* **New Features**
* Added BusyBox-style multicall support, selecting subcommands from the
executable name.
* Added support for paths, Windows `.exe` suffixes, dispatcher names,
symlink-style invocations, and external subcommands.
* Added aliases, hidden choices, and optional case-insensitive value
matching.
* Added multicall configuration across supported integrations and
generated specifications.

* **Bug Fixes**
* Added validation for invalid multicall configurations and clearer
unknown-applet behavior.

* **Documentation**
* Documented multicall behavior, value choices, supported invocation
patterns, and conformance status.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->

---------

Co-authored-by: Cursor Agent <cursoragent@cursor.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.

2 participants