Files
commandkit/docs/roadmap/aliases.md

19 KiB

Application-owned aliases

Status: command- and flag-alias directions accepted; implementation has not started. Consumer registration conventions are selected; the installer declaration type 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:

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 and the architecture policy 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 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 declaration and registration conventions

Commands and aliases use the same installation boundary through New and App.Register. Core validates the complete batch together while retaining aliases as separate routing records internally. No separate alias-registration API is needed.

Use space-separated strings for command paths, interpreted as sequences of command names without shell quoting or expansion. Application-wide flag aliases use FlagAlias; command-scoped aliases use FlagAliasFor with an explicit canonical command path. The selected consumer-facing shape is:

app, err := commandkit.New(
    identity,
    ckprompt.Command(suite),
    commandkit.Alias("list collections", "promptkit list collections"),
    commandkit.FlagAlias("--hlep", "--help"),
    commandkit.FlagAliasFor("promptkit show prompt", "--ver", "--version"),
)

This illustrates planned APIs. The declaration type accepted by the installer still needs design; aliases remain routing records rather than fabricated canonical command nodes. Later registration uses the same model and validation.

Accept identical duplicate alias mappings as harmless, including when reusable helpers contribute them. Identity includes the alias kind, source, target, and scope where applicable. Different-target command mappings for the same source remain errors; overlap between flag scopes is addressed under OD-6.

Alias support lives entirely in core and works with built-in commands, application commands, optional integrations, or any combination. Validation uses the commands and flags installed in that application. No integration dependency is required for alias support. Core continues to supply help and version automatically, including for applications whose other commands are entirely application-defined.

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 exact, complete argument tokens at the beginning of the command path; list does not match listing. Resolve overlapping alias paths using the longest matching path, measured by the number of command-path tokens, not character count. This rule applies at each command-alias lookup and is independent of registration order. Sorting by descending token count and taking the first matching prefix is one possible implementation; the algorithm remains an implementation choice.

For example, with list → promptkit list and list collections → application collections, the more specific mapping wins for list collections, while list prompts uses the list mapping.

Once a matching alias is selected, resolve that route and apply canonical validation. A validation failure reports an error; it does not retry a shorter alias that could invoke a different command.

Preserve trailing arguments, including flags, operands, explicit empty values, and --, for canonical parsing. Values and operands are not searched for alias text.

The initial command-alias feature maps command paths. Preset flags, operand transformation, and arbitrary argument rewriting are outside this delivery.

Chains and group composition

Support alias chains and resolve them to their canonical target. At each lookup, select the longest matching command-path prefix, replace it with its target, and preserve the remaining tokens. Repeat command-path resolution until the canonical route is reached, then parse its inputs normally. Flags, flag values, and operands remain outside command-alias matching under the command/operand boundary rules below.

A group shortcut provides access to routes beneath its target, including aliases:

pk                  → promptkit
promptkit test full → promptkit test all

Here, pk test full resolves through promptkit test full to promptkit test all. An explicitly declared pk test full alias would take precedence over pk at the initial lookup. Ordinary chains follow the same rules, for example collections → list collections → promptkit list collections.

Validate composition during installation and reject cycles and nonterminating prefix expansion with diagnostics identifying the participating mappings. Checking only for repeated complete paths is insufficient: a → b extra and b → a continually expand the path without repeating it. Analyze prefix composition so these configuration errors are caught before invocation. An arbitrary runtime hop limit is not a substitute for installation validation and must not reject an otherwise valid long chain.

Installation and collisions

Use the shared declaration and installation conventions above for aliases, application commands, and integration commands.

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.

An alias cannot conflict with or overload a canonical command path. Reject such a declaration during installation as invalid application configuration. Apply the same protection when later registration adds a canonical command conflicting with an existing alias. Reject competing mappings from the same source path to different targets; registration order must not select a winner. Identical duplicate mappings are accepted under the shared registration conventions.

Aliases do not create canonical parent groups, merge integration trees, or replace handlers.

Prefix interactions and canonical reachability

Alias paths may share prefixes with canonical paths when they introduce a distinct route. Preserve existing canonical invocations, including the declared operand space of runnable commands.

Canonical declaration Proposed alias Result
promptkit test all promptkit test full → promptkit test all Allow the distinct route beneath the shared prefix.
list projects list collections → promptkit list collections Allow the distinct route beneath the shared prefix.
list group list → promptkit list Reject replacement of the canonical group path.
run accepts an operand run full → another command Reject interception of full in the canonical command's operand space.

Determine command and operand boundaries from declared command structure and argument metadata, without executing handlers or application validation. Longest-path matching chooses among valid aliases; it does not authorize consumption of canonical operands. Sharing a runnable ancestor alone does not establish a conflict: check whether the proposed route intercepts that ancestor's operands or an existing canonical child route.

Check these conflicts against the complete candidate registry when adding either aliases or canonical commands, including later registration. Report the conflicting paths and preserve batch atomicity. Apply the chain and group composition rules above when validating resolved routes.

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:

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 lists explicitly declared command aliases separately from canonical commands, showing their resolved canonical targets. Ordinary help need not show intermediate chain mappings or enumerate every route reachable through group shortcuts.

Group help includes relevant aliases separately from canonical children. For example, help promptkit test shows full → promptkit test all. Help reached through a group alias uses that spelling in usage examples and presents the routes available through it, including applicable aliases beneath the target. Account for more-specific mappings so displayed destinations match routing.

Provide discovery help for alias-only prefixes. If list collections and list prompts are declared without a canonical list group, both help list and list --help display the available routes. This help view is derived from alias declarations and creates no canonical group or namespace ownership. Bare list reports an incomplete command and points to that help.

Usage errors use the entered path and identify the canonical target when one has been resolved, while preserving the canonical command's diagnostic content:

Usage: scriptorium list collections [flags]
Alias for: scriptorium promptkit list collections

If resolution fails before identifying a target, report the entered route without assigning a canonical identity.

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, using the shared registration conventions above.

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.

Match the complete flag name. Length precedence does not apply: --out and --output are different names, and only --out participates in alias lookup in --out=value. Scope precedence remains a separate decision. Resolution must be deterministic and must not depend on registration order.

Canonical flag collisions

An alias cannot conflict with or overload an applicable canonical flag spelling. Reject conflicts during installation as invalid application configuration. Check a command-scoped alias against that command's canonical flags, and an application-wide alias across the commands where it applies. Apply the same checks when later registration adds canonical declarations. Failed batches preserve existing commands and alias mappings.

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:

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, alias-to-alias scope conflicts, target validation, and help presentation remain open below.

Work needed from the baseline

  1. Finalize the installer declaration type and 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, group composition, cycles and nonterminating prefix expansion, 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.

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. Installation rejects conflicts with canonical commands and applicable flags in either registration order. Remaining flag-target and alias-composition validation details are still to be settled.

Open Decisions

OD-1: Installer declaration type and composition details

The shared installation API, path strings, explicit flag scopes, identical duplicate handling, and core-only availability are selected above. What public declaration type lets New and App.Register accept commands and aliases together? How do collections of reusable declarations and group composition interact with application-root alias paths? What exact whitespace parsing and path validation rules accompany the selected string representation?

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 in that API? Help and diagnostic presentation are selected above.

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 alias-to-alias conflicts, cycles, and missing targets validated at installation and later registration? How are flag aliases exposed in help and diagnostic spelling?