ADR-050: Frequently used commands get a second spelling, and one path stays canonical¶
A command people and agents reach for often, whose path runs deeper than the three levels gh never exceeds, or which gh spells differently, may be registered a second time under the shorter or more familiar path: bb pr checks beside bb pr build status, bb pr diff beside bb diff pr, bb repo permissions grant beside bb repo settings security permissions users grant. One of the two is canonical. internal/cli's shallowAliasCanonical names it for each alias, meta.command reports it for both (ADR-096), and the docs recommend it. A spelling that drops a path segment moves the distinction the segment carried into a flag, as bb repo permissions grant --group does for groups, and the path that names its subject stays canonical. bb repo create, fork and delete are canonical, and bb repo admin keeps them as aliases. Both spellings appear in the generated command reference. A gh verb for the same command on the same parent that takes nothing the command does not, such as pr view for pr get, is a Cobra alias of that command instead.
Prefer the canonical path in documentation, examples and scripts: it names its subject, so a dropped flag cannot change which principal it acts on. Either spelling is correct to run. When adding an alias, in the same change: extract a constructor that both registrations call rather than copying the body, add the alias to shallowAliasCanonical, say in its help that it is an alias, and name each spelling in the other's help, so a reader who arrived by the canonical path learns the shorter one too. TestEveryShallowAliasNamesACommandThatExists holds the map and the help to the tree. Add a live test asserting the alias writes the canonical path's output byte for byte; that assertion is what makes it an alias rather than a second implementation. Do not add an alias speculatively. The bar is a command reached for often enough that a wrong guess is a recurring cost, not a path that merely reads long.
Depth is a specific cost for an agent, which discovers the tree through --help: every level is a round trip, and an unfamiliar segment is a name to guess wrong. Familiarity is the other half: gh spells the pull request diff gh pr diff, and its checks gh pr checks. Keeping one path canonical makes this cheap. Nothing breaks, the reference stays unambiguous about which principal a command acts on, and the alias is free to be terser than a canonical name could responsibly be. A second copy drifts from its source unless something pins it, and the equality test is that pin.
Not chosen¶
- Flatten the deep paths outright and drop the long spellings: Breaks every existing script and document, and loses the unambiguous naming. bb repo settings security permissions groups grant says which principal it acts on in the path; bb repo permissions grant --group says it in a flag that is easy to omit. Both spellings existing means the safer one is still available and still documented.
- Add aliases for every deep path: The cost is in the few commands an agent reaches for, not in depth as such. Aliasing everything doubles the surface an equality test has to pin and what --help output has to explain, to shorten paths nobody walks.
- Keep one *cobra.Command value and add it to both parents: Fewer lines and immediately wrong. Cobra flag variables are captured per command, so the two registrations would share them, and a persistent --repo would resolve from whichever tree parsed last rather than the tree the caller invoked.
- Rely on
bb aiguidance and the generated reference instead of aliases: Correct for an agent that reads them and useless for one that guesses first, which is the behaviour being paid for. Documentation lowers the cost of a wrong guess; an alias removes it.