Files
commandkit/docs/roadmap/aliases.md

253 lines
12 KiB
Markdown

# Application-owned aliases
Status: command- and flag-alias directions accepted; implementation has not
started. Public API and remaining routing details are open. This roadmap records
the target and work needed before implementation.
## Purpose and ownership
Make alternate command paths and flag spellings simple for consuming
applications to declare. CommandKit core owns alias registration, resolution,
and integration with routing and help. Applications choose their aliases.
Integrated libraries continue to own their canonical command behavior.
Aliases occupy a separate application routing layer above installed canonical
commands:
```text
CLI argument tokens
→ command-path alias resolution
→ canonical command selection
→ applicable flag-alias resolution using canonical flag metadata
→ canonical parsing
→ ordinary invocation lifecycle
```
Alias declarations do not install new handlers or modify the canonical command
tree. An alias spelled inside `promptkit` therefore does not add an
application-owned operation to the integration's namespace. The ownership and
placement rules in [ADR 0011](../adr/0011-captured-declarations-and-installation.md)
and the [architecture policy](../policy/architecture.md) continue to govern
canonical command installation.
Flag aliases likewise leave canonical flag definitions and typed bindings
unchanged. This is one conceptual routing layer; its internal implementation
cooperates with the existing parser to preserve token interpretation.
## Current baseline
Core captures reusable `Command` declarations and installs them through `New`
and `App.Register`. Installation validates a batch before registry mutation.
Optional standard families own their installed root namespaces. Core routing
and the internal backend coordinate parsing, help, and execution through one
invocation lifecycle.
The current public model has no application alias layer. PromptKit already
exposes the collection catalog and smoke-test commands used in the examples
below. These examples illustrate alternate routes to existing capabilities;
they do not introduce new PromptKit operations.
The [CLI reference](../cli.md) owns current grammar. Options follow the complete
command path, can be interspersed with operands, and use `--` to terminate
option parsing. Aliasing preserves the target's grammar and typed binding
contracts.
## Selected command-alias behavior
### Paths and resolution
Declare mappings between command paths relative to the application root. The
executable name is not part of either path:
| Alias path | Target path |
| --- | --- |
| `list collections` | `promptkit list collections` |
| `promptkit test full` | `promptkit test all` |
| `list` | `promptkit list` |
Aliases can target individual commands or groups. A group alias preserves
remaining subcommand tokens. For example, `list collections` can reach
`promptkit list collections` through the `list` group alias.
Match complete argument tokens at the beginning of the command path. Resolve
overlapping alias paths using the longest match. Preserve trailing arguments,
including flags, operands, explicit empty values, and `--`, for canonical
parsing. Values and operands are not searched for alias text.
Support alias chains and resolve them to their canonical target. Validate
targets and reject cycles during installation. Resolution must terminate;
the treatment of group-prefix composition is part of the remaining detailed
design.
The initial command-alias feature maps command paths. Preset flags, operand
transformation, and arbitrary argument rewriting are outside this delivery.
### Installation and collisions
Provide a small core API for aliases that composes with installation of
application and integration commands. The public declaration and registration
shape remains open; earlier illustrative `Alias` calls are not a settled Go API.
An alias target may already be installed or be supplied in the same installation
batch. Declaration order within that batch does not affect resolution. Missing
targets, collisions, and cycles produce installation errors with useful path
context. Failed installation preserves the existing application registry and
alias mappings under the existing batch-atomicity model.
Reject aliases that shadow existing canonical command paths. Preserve that
protection when later registration adds commands. Detailed prefix interactions
remain open below. Aliases do not create canonical parent groups, merge
integration trees, or replace handlers.
### Execution and help
An invocation through an alias uses the canonical target's flags, operands,
defaults, typed bindings, input preparation, providers, diagnostics, and
outcomes. Execute the ordinary lifecycle once. Alias registration, resolution,
and help do not invoke application input/state factories or acquisition callbacks.
Retain the entered alias path and resolved canonical path for routing and
presentation. Whether this identity is exposed through the public invocation
API remains open.
Support both help forms:
```text
scriptorium help list collections
scriptorium list collections --help
```
Alias help describes the canonical target's inputs using the alias invocation
path and identifies the canonical command. Root help presents aliases separately
from canonical commands. Group help and discovery details remain to be specified.
## Selected flag-alias behavior
### Spellings and scopes
Applications can declare alternate spellings for canonical flags, including
`--hlep` mapping to `--help`. Declaring a flag alias should be as simple as
declaring a command alias; the exact Go API remains open.
Support application-wide mappings and mappings scoped to a canonical command.
The selected canonical command determines the applicable flag aliases, so a
command-scoped mapping works through every command alias that reaches that
target. An application-wide help alias provides the same convenience throughout
the application. Scope precedence and handling of targets unavailable on some
commands remain open.
### Token interpretation
Resolve command aliases and identify the canonical command before applying its
flag aliases. Use canonical flag metadata to distinguish flag names from values.
Preserve the existing grammar, including flags interspersed with operands.
| Input | Effect |
| --- | --- |
| `list collections --hlep` | Resolve the command path and route `--hlep` to canonical help. |
| `foo --colour=blue` | With `--colour` mapped to `--color`, preserve `blue` as the value. |
| `foo --message=--hlep` | Preserve the value `--hlep`. |
| `foo --message --hlep` | When `--message` consumes a value, preserve `--hlep` as that value. |
| `foo -- --hlep` | Preserve the operand `--hlep` after the option terminator. |
Only tokens interpreted as flag names participate in flag aliasing. Preserve
values, explicit empty strings, and operands. The routing layer cooperates with
the existing parser rather than maintaining a separate interpretation of flag
arity, boolean syntax, or option termination.
### Canonical binding behavior
An alias feeds the same typed binding as its canonical flag. The target retains
its value conversion, defaults, required-value checks, presence tracking,
repetition rules, and behavior. Mixed spellings retain invocation order:
```text
foo --color red --colour blue
```
With `--colour` mapped to singleton `--color`, the normal last-occurrence rule
selects `blue`. Earlier invalid occurrences remain errors under the existing
conversion contract. For a repeatable target, occurrences through either
spelling accumulate in order. Alias resolution adds no second conversion or
input-preparation lifecycle.
Flag aliases do not change canonical flag ownership or add new provider
capabilities. Short-flag support, chains, collisions, installation validation,
and help presentation remain open below.
## Work needed from the baseline
1. Settle the public alias API and the open routing details with consumer examples
covering a command shortcut, a synonym inside an integration namespace, and
a group shortcut, an application-wide help flag alias, and a command-scoped
flag alias reached through a command shortcut.
2. Capture the durable separation between application alias routing and canonical
command and flag ownership in an ADR. Keep exact API, matching, and presentation
details in their appropriate contracts. No relaxation of canonical namespace
ownership is selected.
3. Extend installation to validate aliases and commands against the complete
candidate batch, preserving retained errors and atomicity. Keep aliases
independent of optional-library dependencies and backend-specific exports.
4. Integrate command and flag alias resolution with canonical routing, help, and
invocation identity. Use canonical flag metadata and the existing parser to
preserve values and operands, and reuse typed execution machinery.
5. Add focused behavioral evidence for both example mappings, group aliases,
longest matches, chains and cycles, collisions, missing targets, same-batch
resolution, later registration, argument preservation, help without
acquisition, and a single execution lifecycle. Cover application-wide and
command-scoped flag mappings, attached and separate values, option termination,
mixed canonical/alias repetitions, and unchanged typed binding semantics.
6. Add maintained consumer examples and update GoDoc, the CLI reference, consumer
guidance, and internal documentation when implementation lands. Validate the
affected modules under the [developer guide](../development.md).
Completion means consumers can declare alternate command paths and flag
spellings with minimal wiring and invoke canonical behavior and help through
them while canonical ownership and binding semantics stay intact. Command alias
installation provides the selected validation; flag alias installation follows
the validation rules still to be settled.
## Open Decisions
### OD-1: Public declaration and registration API
What are the exact command- and flag-alias declaration, path representation, and installation
signatures? How do alias declarations compose with groups, reusable declarations,
and later `App.Register` calls? What are the duplicate-declaration semantics?
### OD-2: Prefix interactions and canonical reachability
How are collisions determined when alias sources or targets overlap canonical
groups or runnable commands with children? How does longest matching interact
with operand boundaries? Which later registrations conflict with existing
aliases? How are ambiguous paths reported?
### OD-3: Chains and group aliases
How do group aliases compose with more specific aliases and with aliases inside
their target paths? At what boundaries is resolution repeated? How are cycles
and nonterminating prefix expansion detected without confusing operands with
command-path tokens?
### OD-4: Help and discovery
How are aliases listed, grouped, and described in help? What happens when an
operator requests a parent of an alias path that has no canonical group? How
does group-alias help present descendants? How are entered and canonical paths
shown in usage errors?
### OD-5: Invocation identity
Does the public invocation API expose entered and canonical command paths?
What identity is retained through a chain, and how is it represented for help
and diagnostic presentation?
### OD-6: Flag alias scope and composition
How do application-wide and command-scoped mappings interact when both apply?
How is an application-wide mapping treated on commands lacking its target flag?
How are aliases applied to built-in help on groups and at the application root?
Which short-flag forms are supported? Are flag-alias chains supported, and how
are collisions, cycles, and missing targets validated at installation and later
registration? How are flag aliases exposed in help and diagnostic spelling?