ref:main

Same operation, different verb and flag name depending on the noun #35

closed Opened by cole.christensen@gmail.com

Links

Related
  • 🔒 private issue

Cross-cutting naming inconsistencies found while auditing the whole command surface. Individually small; together they mean users cannot guess any command.

edit vs update

edit: pr edit, issue edit, label edit, milestone edit, board edit-column update: release update, requirement update, runner update

anvil release update <TAG> --title X and anvil pr edit <N> --title X are the same operation. Note the top-level anvil update means “replace this binary”, so update is overloaded.

delete vs remove vs revoke

delete: label delete, milestone delete, release delete, board delete-column, ci delete-secret, requirement delete remove: ssh-key remove, runner remove, label remove, epic remove-child

ssh-key remove and label delete are both “delete a thing you own” with different verbs. Sharpest case: registry token delete is named delete, its help says “Revoke a registry token by id” (registry.rs:29-30), and its success message says “Revoked registry token” (registry.rs:164) — three words for one operation in one command.

–state vs –status

--state (default open): pr list, issue list, epic list --status (no default): ci list, requirement list

Both are free-form String with no ValueEnum, so typos are only caught server-side — even though issue link --kind and release list --format do validate client-side.

–org vs –organization

--org: repo create, repo list, runner list, runner token --organization: all 8 requirement subcommands

–repo means three different things

  1. An org/repo pair (most commands)
  2. A repo slug within an org — requirement.rs:214-216, where passing org/repo builds a malformed URL
  3. A scope target mutually exclusive with --orgregistry.rs:47-49, runner.rs:172-176

–limit: four defaults, and absent from 16 list commands

repo/pr/issue list = 30, epic list = 50, ci/commit list = 20, runner logs --lines = 100. No pagination at all on branch list, label list, board list, milestone list, agent list, release list, ssh-key list, registry token list, deploy list, issue comments, issue links, pr reviews, ci secrets, release assets, runner list, requirement list.

Four encodings of a boolean

  • release create --draft (bool) vs release update --draft <BOOL> (takes a value) — same field, same noun
  • pr edit --draft/--ready (paired exclusive flags)
  • epic auto-close --on/--off

list vs bare plural noun

Nested list: registry token list, requirement applicability list, runner service list Bare plural: issue comments, issue links, issue milestones, pr reviews, agent sessions, release assets, ci secrets, epic children

runner service svc-* prefix

runner service has install, uninstall, list unprefixed but svc-start, svc-stop, svc-restart, svc-status prefixed (runner.rs:263-289). The prefix only exists to avoid a Rust enum-variant clash with RunnerCommand::Start/Stop/... — an implementation detail in the user-facing surface. It also leaves anvil runner stop and anvil runner service svc-stop as two similar names for different things.

Suggested approach

Pick one verb per operation, alias the losers for compatibility, and add a test that asserts the chosen vocabulary across the command tree so it cannot drift again.

Found during a CLI-wide consistency audit.

colechristensen cole.christensen@gmail.com commented 2026-07-30 21:37

#54 addresses the runner service svc-* prefix item only — the four verbs are now start|stop|restart|status with the svc- spellings kept as hidden clap aliases. Docs and the server-generated install script follow in fangorn/anvil#235 (tracked by fangorn/anvil#382).

Leaving this open: #54 does not add the vocabulary test across the command tree that the “Suggested approach” section asks for, and every other item here (edit/update, delete/remove/revoke, --state/--status, --org/--organization, the three meanings of --repo, the four --limit defaults, the four boolean encodings, list vs bare plural) is untouched. The near-collision this issue flags also survives the rename: anvil runner stop vs anvil runner service stop is arguably more confusable now that the distinguishing token has left the leaf verb.

One correction to the description while it’s open: the svc- prefix did not exist “to avoid a Rust enum-variant clash with RunnerCommand::Start/Stop/...”. ServiceCommand is a separate enum, and its variants were already plainly named Start, Stop, and Restart on main (src/commands/runner.rs:264,271,278 before #54) — only the clap #[command(name = "svc-…")] attribute carried the prefix. SvcStatus was the sole variant genuinely prefixed at the Rust level. There was no clash to avoid, so that rationale shouldn’t be used to defend keeping a prefix anywhere else.