2026-10-19 14:41:10 +00:00
# Application-owned aliases implementation plan
2026-10-19 19:46:22 +00:00
Status: in progress; Stages 1– 11 completed.
2026-10-19 14:41:10 +00:00
## Authority, baseline, and scope
Implement [Application-owned aliases ](aliases.md ), governed by
[ADR 0013 ](../adr/0013-application-alias-routing.md ),
[ADR 0011 ](../adr/0011-captured-declarations-and-installation.md ), and the
[architecture policy ](../policy/architecture.md ). The feature roadmap owns the
selected behavior; this document owns the work sequence and implementation
choices. Follow the [agent ](../policy/agents.md ),
[testing ](../policy/testing.md ), and [documentation ](../policy/documentation.md )
policies. Read [the developer guide ](../development.md ) first.
The inspected baseline is commit `f3b8a129d99d04230f998d0327ffad05f6002d7a` .
Core v0.2.0, ckconfig v0.1.0, and ckprompt v0.1.0 have been published.
`New` and `Register` currently accept `...Command` ; there are no routing-rule
declarations. `Invocation` currently contains context and streams only.
The Cobra adapter selects canonical commands, parses their flags, and renders
help. Core owns typed conversion, input construction, dispatch, and outcomes.
This sprint delivers command and flag alias declarations, joint installation,
resolution, invocation identity, help, diagnostics, examples, and documentation.
It includes the selected canonical short-option empty-value correction.
It does not implement operand synonyms, preset arguments, shell completion,
new upstream operations, a replacement backend, or release publication.
## How to execute the plan
- Perform Stage 1 through Stage 17 in order. Each stage is sized as a separate
Luna implementation prompt. Add its completion evidence here and commit each
completed nonempty unit under the agent policy.
- Inspect the current tree before editing; preserve unrelated work. Prefer the
code knowledge graph for code discovery, falling back when it is insufficient.
- Reuse current behavior and tests where they express accepted contracts.
Replace mechanics when needed; do not add compatibility wrappers around the
old installation signatures or a second application parsing lifecycle.
- Stages include the focused tests needed for their work. Run those during
implementation, not during this planning pass. Do not make later stages
depend on unverified termination or token-interpretation assumptions.
- Keep tests about CommandKit adaptation, presentation, and lifetimes. Upstream
libraries own their domain tests. Use local callbacks and fixtures; no live
providers or credentials are needed.
- Preserve eager declaration capture, reusable declarations, namespace ownership,
binding identity, presence, wrapped causes, and existing outcome delivery.
Do not add concurrent-dispatch, arbitrary deep-copy, performance, or public
ordering guarantees.
- New private records and helpers described below are implementation choices.
Their names and exact organization can change without altering public behavior.
Do not expose them through the facade or add backend selection APIs.
- Keep published release records unchanged. Local source verification does not
authorize creating tags, pushing, or publishing another release.
## Implementation decisions used by the stages
### Owners and data flow
| Owner | Work |
| --- | --- |
| Root `commandkit` package | Public declarations, retained errors, candidate installation, alias records, routing coordination, invocation identity, typed conversion, and outcome presentation. |
| New `internal/commandpath` package | Shared path representation and token/path operations used by core, neutral metadata, and the adapter. It has no backend or optional-library imports. |
| New `internal/alias` package | Private command-prefix lookup and termination analysis over paths; no handlers, application factories, or backend types. Keep its model limited to the selected routing rules. |
| `internal/commandmeta` | Neutral canonical metadata and the routing, spelling-provenance, and help-view records actually needed across the adapter boundary. |
| `internal/cobra` | Canonical backend sessions, alias-aware flag interpretation, and rendering selected help views without installing alias command nodes. |
| Optional integrations | Continue returning canonical `Command` declarations and owning their providers. Only source migrations, focused composition evidence, and maintained consumer changes are needed here. |
Core retains canonical commands and routing rules separately. A candidate
installation compiles relationships against the complete prospective registry,
then publishes them together. Derived lookup metadata is reusable within an App;
parse state and entered-route provenance remain invocation-local.
Use the same private route lookup for execution, explicit help-target lookup,
and discovery-help views. It returns a canonical command identity or a distinct
alias-prefix discovery context, plus entered/canonical paths and remaining
arguments. Keep lookup independent of execution and rendering. This is current
routing/help machinery, not a completion API.
### Public declarations and invalid values
Implement the roadmap's signatures:
```go
type Declaration interface { commandkitDeclaration() }
func New(identity Identity, declarations ...Declaration) (*App, error)
func (a *App) Register(declarations ...Declaration) error
func Alias(path, target string) RoutingRule
func FlagAlias(spelling, target string) RoutingRule
func FlagAliasFor(commandPath, spelling, target string) RoutingRule
func (inv Invocation) EnteredPath() string
func (inv Invocation) CanonicalPath() string
```
`Command` and opaque `RoutingRule` implement the private marker. Their factories
capture values and retain errors; alias factories do not return errors or run
callbacks. Keep `Group` , `RootGroup` , and `CommandSpec.Children` command-only.
`WithError` and `NoCommand` keep their current command contracts; do not add an
absence rule or a general extension/plugin declaration kind.
A nil declaration, invalid zero `Command` , and zero `RoutingRule` are
installation errors, not no-ops. Handle nil pointers without panics; normalize
non-nil pointers to the supplied opaque declaration types to their values.
Dispatch only the supported CommandKit declaration kinds, without reflection or
calling application-defined assembly callbacks. `NoCommand` remains the explicit
absence case, with retained errors checked before it is skipped.
An identical normalized routing rule can be contributed repeatedly. It is
idempotent, including across calls to `Register` . Do not extend that exception
to duplicate canonical command declarations. Identity uses declared kind,
source, target, and scope, not merely the final resolved endpoint: different
declared targets remain competing mappings even if they reach the same command
or binding. Invalid later registration leaves both registries and derived
metadata intact.
Store invocation paths privately as normalized strings, populated by dispatch.
Accessors on an otherwise caller-created zero invocation return empty strings.
The original context and stream fields remain usable in keyed literals.
### Paths and provenance
Parse declaration paths on whitespace once at capture. Reuse canonical
one-token name validation; do not introduce a stricter name alphabet. Path
rendering, prefix comparison, normalized keys, and exact backend lookup use
shared helpers. Never split or trim already-tokenized argv elements.
Route tokens retain their association with the original argv prefix as aliases
replace command-path components. This is needed to identify the entered path
without guessing from the length of the final canonical path. For
`smoke all` with `smoke → promptkit test` , the entered command path is `smoke` ,
the canonical path is `promptkit test` , and `all` is still an operand.
For `pk list bundles` , both original `list` and `bundles` belong to the entered
path when its resolved command is `promptkit list collections` .
Only the leading command portion participates in command rewriting. A flag or
`--` stops command-path lookup. Canonical command structure and operand metadata
establish where trailing non-option tokens become operands. Longest explicit
rules beneath an alternate spelling still take precedence as selected in the
roadmap; do not reserve all operand space beneath an alternate spelling.
### Exact termination analysis
Use a finite pushdown analysis of the deterministic longest-prefix rewriter.
This is private installation machinery. It avoids rejecting valid consuming
repetitions or accepting a growing loop that never repeats an entire path.
Keep it isolated so its correctness can be established before dispatch uses it.
The implementation has two parts, split across Stages 2 and 3:
1. Compile a prefix trie into a finite-state stack machine. The top of the
stack is the beginning of the unresolved path. Lookup remembers the deepest
matching rule, inspects only the finite source-prefix length, and restores
any inspected suffix when replacing that source with its target. A failed
longer match selects the saved shorter match; it does not invent a route.
No match halts rewriting. End-of-path and the boundary before flags are
terminal markers, never command components that a rule can consume.
2. The finite stack alphabet contains literal tokens used by rules, an `OTHER`
equivalence class for tokens not used by any rule, and an end marker.
Preserve original arbitrary tokens in the runtime resolver; this quotient
is only for proving termination. All alias sources are nonempty.
3. Normalize transitions to `(p,A) → (q,w)` with `w` of length zero, one, or two,
using finite helper states for longer pushes. Remember which original rules
participate so an error can identify mappings. The compiler's lookup and
restoration phases must be acyclic; only completing a rule can return to
the lookup start. The bottom/end marker is never popped or duplicated.
4. Compute the finite least fixed point `Pop(p,A,q)` : starting in control `p`
with top `A` , the machine can remove that symbol and finish in `q` without
inspecting the stack below it. Seed pop transitions. A one-symbol push uses
one existing pop summary; a two-symbol push composes two summaries in
left-to-right order. Retain witness information, not copies of arbitrary
stack contents.
5. Build a graph of heads `(control, top-symbol)` . A transition pushing `B`
gives an edge to `(q,B)` . One pushing `BC` gives an edge to `(q,B)` and,
for every `Pop(q,B,r)` , to `(r,C)` . A pop transition alone gives no edge.
These edges summarize nonempty paths that never pop below their starting
stack level. A directed cycle, including a self-edge, witnesses a repeatable
computation and hence nontermination.
6. Check the model's scope explicitly: installation is checking all finite
command-token suffixes, not just each bare source or target. For this
compiler, helper phases cannot run forever without returning to the lookup
start, and every finite token stack at that start is a possible input.
Therefore a repeatable computation must correspond to a possible alias
invocation; do not reject an abstract cycle introduced only by an invalid
end-marker configuration. Restrict marker transitions accordingly and
record this reasoning with the implementation tests.
For the fixed-point step, a rule `(p,A) → (r,BC)` adds `Pop(p,A,q)` only when
both `Pop(r,B,s)` and `Pop(s,C,q)` hold for some `s` . This distinction matters:
the head-graph edge to `(s,C)` requires only the first summary and represents
continuing at `C` , rather than having removed it.
Do not substitute an ordinary graph of alias declarations, a decreasing-length
rule, a maximum chain length, a fixed suffix-enumeration depth, or a timeout
for this analysis. Use a straightforward finite fixed point and cycle detector;
no external model-checker dependency or public automaton abstraction is needed.
Bounded examples are regression evidence, not the proof of universal termination.
If implementation exposes a flaw in the compiler or analysis, correct that
isolated stage before proceeding; do not weaken the selected alias contract.
After termination succeeds, resolve each declared target through the same
longest-prefix semantics and require an exact canonical command/group endpoint,
with no injected operand tokens. Validate literal canonical reachability using
the complete candidate command tree and its argument bounds, without invoking
value parsers or application checks. Follow canonical child selection before
treating unmatched tokens as operands. Do not reject a route solely because a
runnable ancestor exists: it must actually intercept that command's declared
operand space or a canonical route.
### Flag resolution and parsing
Normalize a flag declaration into a long or individual one-byte short spelling,
without a value. Reuse the existing canonical spelling rules, allowing built-in
help as a destination. Do not interpret clusters or attached values in a rule
declaration. A command-scoped path must be an exact canonical path, not an alias
or an operand-bearing invocation.
For each canonical command/group and the application root, form effective
mappings from application-wide rules plus command-local overrides. Include
canonical `--help` and `-h` . Resolve chains with canonical spellings as endpoints,
apply availability to the final endpoint, and validate active source collisions
separately. Application-wide missing destinations stay inactive; explicit scoped
missing destinations are errors. Detect mapping cycles, including in reusable
global chains, and recompute relationships when registration changes the context.
Discovery-help contexts have core help flags and global rules only.
Keep the flag-name/value interpretation in the internal adapter. Use one
metadata-driven token pass for canonical and alias spellings, including mixed
short clusters. Normalize reached spellings to canonical backend flags, retain
their original occurrence spellings, and pass values/operands unchanged.
Cobra/pflag remain the backend; this pass adapts the selected token grammar and
does not convert typed application values. Do not independently scan or rewrite
tokens in core as a second flag parser.
Once a value-taking flag consumes an attached suffix or the next token, neither
that value nor anything following `--` is searched for aliases. Explicit
boolean values require `=` ; a bare boolean contributes `true` . Normalize
`-c=` as an explicitly empty value, and `-v=` as an empty value for boolean
conversion, including when these are canonical short spellings. Keep occurrence
order within each canonical binding and raw values available for the existing
typed converter; do not add a cross-binding converter-order guarantee.
Retain private per-occurrence spelling provenance through conversion. An
internal conversion error can carry a canonical binding/occurrence index and
wrap the original cause so presentation can identify the entered spelling.
Do not rerun converters or stringify and replace their errors. Preserve
`CaptureFlags` /`FlagValues` binding identity and application-input semantics.
## Stage 1: Introduce shared command-path primitives
**Work**
1. Add `internal/commandpath` with capture parsing, component validation,
equality/prefix operations, normalized keys, formatting, and owned token copies
at capture boundaries. Distinguish a root lookup path from a declaration
path: root lookup is valid; an empty alias declaration path is invalid.
2. Move or delegate the existing command-name check to the shared validator.
Migrate canonical bridge paths, exact help lookup, and core path formatting
where they currently join/split the same paths repeatedly.
3. Keep argv as tokens throughout. Do not change canonical routing, public API,
command names, or name restrictions in this refactor.
**Evidence:** focused path tests for whitespace-normalized declarations,
literal quotes/backslashes, invalid option components, empty declarations,
root lookup, and a single argv token containing whitespace. Existing routing
and help tests remain green.
2026-10-19 15:08:00 +00:00
**Completed:** Added shared command-path parsing, validation, relations, keys,
formatting, and token-copy helpers. Core command validation and path diagnostics,
plus adapter route comparison and exact help lookup, now use the shared package.
Verified with `go test ./internal/commandpath ./internal/cobra .` .
2026-10-19 14:41:10 +00:00
## Stage 2: Model deterministic prefix rewriting
**Work**
1. Add private normalized command-rule records and longest-prefix lookup under
`internal/alias` , using Stage 1 paths. A simple trie is sufficient.
2. Implement the finite stack-machine compiler described above, including saved
shorter matches, mismatch restoration, token equivalence classes, end-marker
handling, and normalized short push transitions.
3. Add a small test interpreter for the compiled machine and compare finite
cases with the direct longest-prefix resolver. Do not expose this interpreter
or use a test step bound as the production validity decision.
4. Keep compiler phase transitions explicit so lookup/restoration cannot create
an internal loop unrelated to completing alias rewrites.
**Evidence:** chains; overlap chosen by token count rather than character
count; target expansion; group suffix preservation; shorter fallback after
a failed longer token match; unknown tokens; empty suffixes. The compiler
and direct resolver agree on these terminating cases.
2026-10-19 15:11:43 +00:00
**Completed:** Added the independent longest-prefix resolver and compiled its
trie into a finite stack machine with literal and `OTHER` symbols, end and
flag-boundary markers, shorter-match fallback, restoration, and normalized
pushes. A test-only interpreter matches direct resolution for the recorded
finite cases. Verified with `go test ./internal/alias` .
2026-10-19 14:41:10 +00:00
## Stage 3: Prove and test termination validation
**Work**
1. Implement pop-summary saturation, head-graph construction, and cycle
detection from the implementation decisions. Return useful participating
rule context for a rejection. Document why the abstraction neither misses
growing loops nor invents invalid marker loops.
2. Cover direct cycles and `a → b extra` , `b → a` , whose paths grow without
repeating. Cover a suffix-dependent cycle using `a → b` , `b → group` ,
`b x → a x` : bare `a` terminates but `a x` does not.
3. Accept consuming repetitions: with canonical group `group` , `a → group`
and `group again → a` must accept `a again again` and consume both suffix
tokens before ending at `group` .
4. Cover longest-match suppression of a potential shorter-rule loop: with
`a → b x` , `b → a` , `b x → group` , actual resolution terminates. A naive
rule-dependency cycle detector would incorrectly reject it.
5. Include a valid chain longer than any tempting small fixed hop limit and
vary rule registration order. Keep no artificial public alias-count limit.
**Complete when:** the exact finite analysis is justified and the focused
cases distinguish it from conservative declaration-cycle or bounded simulation
checks. Do not integrate an approximate validator and defer correctness.
2026-10-19 15:16:07 +00:00
**Completed:** Added worklist saturation for finite pop summaries, head-graph
construction, cycle detection, and errors naming participating mappings.
Terminal-marker transitions preserve the unique bottom marker, and tests verify
markers cannot be popped. Direct, growing, and suffix-dependent loops are
rejected; consuming repetition, longest-match suppression, and 80-rule chains
in either registration order are accepted. Verified with
`go test ./internal/alias -count=1` .
2026-10-19 14:41:10 +00:00
## Stage 4: Add captured declaration types and factories
**Work**
1. Add `Declaration` , opaque `RoutingRule` , the three alias factories, and
private captured rule records with retained construction errors.
2. Capture and normalize command paths and flag spellings immediately. Preserve
the existing `Command` capture, `WithError` , and absence behavior.
3. Change `New` /`Register` to `...Declaration` , normalizing supported values and
pointers at the installation boundary. Keep group children command-only.
4. Convert internal `[]Command` expansions used for installation into explicit
declaration slices where necessary, including built-in assembly and affected
consumers/tests. Do not add a bundle API or generalize `Group` .
**Evidence:** a core-only public consumer can capture mixed declarations;
invalid paths/spellings are reported at installation; nil and zero declarations
are handled as selected; canonical command-only calls continue to work. No
factories, loaders, or handlers run during capture.
2026-10-19 17:23:32 +00:00
**Completed:** Added the opaque `Declaration` and `RoutingRule` types, command
and flag alias factories, eager normalized capture with retained issues, and
value/pointer normalization at `New` and `Register` . Built-in and consumer
installation slices now use declarations explicitly. Verified with root and
both integration module suites under the local workspace.
2026-10-19 14:41:10 +00:00
## Stage 5: Install canonical commands and command aliases atomically
**Work**
1. Replace the current root-command-only pending map with a candidate containing
existing/new canonical commands and separate normalized routing records.
Reuse existing canonical placement and namespace checks.
2. Validate retained errors, exact canonical-source collisions, competing rule
mappings, prefix termination, exact resolved targets, and canonical operand
interception before publishing the candidate. Same-batch target order is
irrelevant. Missing targets and operand-bearing destinations are errors.
3. Accept identical normalized mappings, including repeated contributions across
registration calls. Revalidate existing aliases when a new canonical batch
changes reachability. Invalidate derived snapshots only on accepted changes.
4. Preserve old registry/help behavior after every failed batch. Aliases inside
an installed standard-family spelling remain routing records and never
bypass canonical root-only placement or merge command trees.
**Evidence:** both registration orders; retained wrapped errors; duplicates;
missing/forward targets; existing and same-batch collisions; canonical children
versus runnable operand space; valid longer aliases beneath `r → run` ; failed
registration after a snapshot was used. Explicitly reject
`promptkit test full → promptkit test all` under a `test KIND` fixture.
2026-10-19 17:27:17 +00:00
**Completed:** Replaced direct registry mutation with a candidate that validates
the complete canonical tree and normalized routing rules before publishing.
Alias chains and termination, missing or operand-bearing targets, canonical
source and operand collisions, duplicate idempotence, later command conflicts,
and failed-batch preservation are covered. Verified with
`go test ./... -count=1` .
2026-10-19 14:41:10 +00:00
## Stage 6: Compile effective flag aliases during installation
**Work**
1. Extend the candidate with global and canonical-command-scoped flag rules.
Build effective mappings from neutral canonical flag metadata and core help
spellings, without preparing application inputs.
2. Resolve chains, apply scoped precedence, check final availability and active
canonical-source collisions, and reject cycles. Handle long-to-short,
short-to-long, and canonical short endpoints consistently.
3. Accept globals whose destinations are currently absent. Recompute all
affected contexts when later commands arrive; reject the whole batch if a
newly active global now overloads a canonical spelling.
4. Add the root and group contexts; support the restricted help context for
alias-only prefixes. Keep command-scoped aliases local to their canonical
command rather than implicitly inheriting through descendants.
**Evidence:** different-target duplicates versus identical duplicates; explicit
unknown scopes; inactive globals; scoped overrides inside a chain; cycles;
`--colour → --color` terminating at canonical `--color` even with an inactive
global `--color → --missing` ; collision after `--missing` becomes available;
root/group help targets and failed-batch preservation.
2026-10-19 17:33:39 +00:00
**Completed:** Installation candidates now compile effective global and
canonical-command-scoped flag aliases from captured canonical metadata and
built-in help spellings. Chain resolution applies scope precedence, tracks
inactive global destinations, detects cycles, and rejects newly active
canonical-source collisions without publishing failed candidates. Root, group,
command, and alias-prefix discovery contexts retain only their applicable
spellings. Verified with root and both integration module suites using the
local workspace.
2026-10-19 14:41:10 +00:00
## Stage 7: Resolve entered routes to canonical commands
**Work**
1. Add alias lookup records to the App snapshot without adding alias nodes or
runners to the canonical command tree. Reuse the validated longest-prefix
semantics and Stage 1 paths.
2. Implement command/group rewriting with token provenance, remaining argv,
canonical selection, and a distinct discovery-prefix result. Stop path
matching at flag/terminator boundaries and canonical operands.
3. Retain the original entered endpoint and final canonical endpoint, not
intermediate chain names. Do not use the final path length to slice original
argv. Unknown paths retain the entered route without a fabricated target.
4. Ensure a failed longer explicit mapping never retries a shorter mapping.
Centralize this lookup for execution and help consumers in later stages.
**Evidence:** `collections → list collections → promptkit list collections` ;
`pk → promptkit` composed with `promptkit list bundles` ; longest explicit
`pk list bundles` override; `smoke all` retaining its operand; `r full` choosing
an explicit longer route while canonical `run full` remains unchanged;
flags/values/space-containing argv tokens never becoming command components.
2026-10-19 17:37:59 +00:00
**Completed:** Routing snapshots now retain canonical path metadata and the
separate command-alias resolver. Execution resolves command prefixes before
parsing, tracks the original input-token origins through alias chains, and
preserves the remaining argv. Canonical operands, flags, terminators, unknown
paths, and alias-only discovery prefixes receive distinct route results.
Verified with root and both integration module suites using the local workspace.
2026-10-19 14:41:10 +00:00
## Stage 8: Integrate parser-aware flag aliasing and short grammar
**Work**
1. Pass the selected canonical/discovery context's effective spellings to the
internal adapter through neutral records. Keep Cobra/pflag imports internal.
2. Implement the single alias-aware token interpretation pass described above.
Canonical and aliased short flags use the same cluster logic. Preserve raw
values, explicit empties, `--` , and interspersed operands.
3. Feed canonical backend flags without invoking a typed parser twice. Collect
original spelling provenance per occurrence alongside canonical raw values.
4. Correct canonical `-c=` and boolean `-v=` at this same boundary; do not patch
aliases alone or pre-rewrite every token beginning with a dash in core.
**Evidence:** every token example in the roadmap's flag sections; mixed
canonical/alias clusters; `-cvq` consuming `vq` ; `-qv=false` ; explicit empty
values for long, short, and aliased spellings; missing values; unknown cluster
members; `--message --hlep` as a value; `--message=--hlep` ; post-`--` operands.
2026-10-19 19:31:23 +00:00
**Completed:** The routed flag context now reaches the adapter through neutral
flag-alias records. One adapter pass interprets canonical and alternate long
and short spellings, preserves option values and terminator operands, and feeds
only canonical flags to pflag. Raw values retain per-occurrence source
spellings. Canonical short empty values now follow the same long-form boundary.
Verified with root and both integration module suites using the local workspace.
2026-10-19 14:41:10 +00:00
## Stage 9: Wire execution and invocation identity
**Work**
1. Use the route result to select the existing canonical payload and its input
preparation. Populate both Invocation accessors for ordinary and alias
invocations, including callbacks reached by private built-in plumbing.
2. Replace the current directly constructed Invocation in the typed runner with
the coordinated context so metadata reaches handlers without changing their
signature. Retain caller context and streams.
3. Keep canonical parsing/conversion, required checks, input/state lifetimes,
`CaptureFlags` , provider acquisition, and domain outcome classification on
their existing paths. No handler delegates to another alias handler.
4. Keep failed routing, invalid flags, and help from constructing application
input or running acquisition. Preserve the existing distinction that help
still converts supplied values but skips execution-required checks.
**Evidence:** a canonical handler observes equal endpoints directly and distinct
endpoints through aliases; operands are absent from both path strings; alias
and canonical forms reach the same binding/callback once; repeated calls and
declaration reuse do not leak invocation values; zero Invocation accessors
are empty. Existing cancellation and domain outcome checks remain green.
2026-10-19 19:33:49 +00:00
**Completed:** Invocation now retains the entered and canonical route paths
alongside the caller's context and streams. Public typed handlers and private
callbacks receive the same resolved identity. Tests cover canonical and alias
calls with operands, repeated calls, declaration reuse across Apps, private
callback plumbing, and zero-value accessors. Verified with the root, ckconfig,
and ckprompt suites under the local workspace.
2026-10-19 14:41:10 +00:00
## Stage 10: Add alias-aware help and discovery views
**Work**
1. Route `help COMMAND...` targets through the shared metadata lookup, despite
those tokens being operands of the built-in help command. Do not globally
rewrite arbitrary operands to obtain this special help-target behavior.
Keep the help command's invocation identity separate from its requested
view: `help list collections` invokes canonical `help` , while rendering the
entered target `list collections` and its resolved canonical command.
2. Coordinate `ALIAS --help` , bare canonical groups, and aliases to groups with
the same help selection. Render canonical inputs with entered usage paths
and a canonical-target annotation when the paths differ.
3. List explicit root aliases separately from canonical commands. Group views
include relevant aliases separately from children, accounting for more-specific
overrides. Do not enumerate every possible composed shortcut or chain hop.
4. Implement help for alias-only prefixes without canonical nodes or namespaces.
Bare incomplete prefixes are usage failures pointing to help. Global help
flag aliases work on these views; descendant flags do not become available.
5. Add only effective flag aliases to each canonical input's help, resolving
chains to endpoints and describing the canonical input once. Keep lookup
records independent of rendering and provider callbacks.
**Evidence:** root/group/alias/discovery help; `help list collections` and
`list collections --hlep` ; `help promptkit list` showing `bundles` ; group
shortcut help with a more-specific destination override; inactive/scoped flag
visibility; no input/state factories or providers called. Preserve existing
help output-delivery handling.
2026-10-19 19:40:55 +00:00
**Completed:** Help targets and `--help` routes now use shared command-alias
resolution. Canonical help views render entered usage paths with canonical
target annotations; root and group views list applicable declared aliases and
effective flag aliases. Alias-only prefixes render discovery help through
`help PREFIX` or global help spellings, while bare incomplete prefixes return a
usage failure pointing to help. Verified help selection, scoped/global
visibility, more-specific group overrides, and input/run callback lifetimes
with root and both integration module suites under the local workspace.
2026-10-19 14:41:10 +00:00
## Stage 11: Preserve entered spellings in errors and delivery outcomes
**Work**
1. Thread flag occurrence provenance into private conversion-error context.
Identify the actual failing occurrence, including an earlier invalid value
followed by a valid overwrite. Wrap rather than replace application causes.
2. Update usage presentation to use entered command paths, identify a resolved
canonical target, and preserve the target's diagnostic content. An unresolved
route does not acquire an invented canonical label.
3. Use existing usage/operational/domain classifications and diagnostic-delivery
ownership. Route aliases must not duplicate already delivered diagnostics.
Preserve writer errors, short writes, cause identity, and incomplete reports.
4. Check alias-related help/usage presentation against failed and successful
registration so a stale snapshot does not mislabel the selected operation.
**Evidence:** malformed aliased scalar and repeatable occurrences; mixed
spellings; wrapped `errors.Is` /`errors.As` ; usage paths with canonical annotation;
unknown routes and flags; cancellation; output and diagnostic failures. Assert
semantic fragments and identities, not entire backend wording snapshots.
2026-10-19 19:46:22 +00:00
**Completed:** Flag conversion failures now retain the binding, entered
spelling, occurrence number, and original wrapped cause. Usage diagnostics use
entered alias paths and identify resolved canonical commands; unresolved routes
receive no invented canonical label. Successful and failed registration during
execution preserve the selected route. Verified with root, ckconfig, and
ckprompt suites under the local workspace, including existing cancellation,
diagnostic deduplication, writer failure, short-write, and incomplete-report
coverage.
2026-10-19 14:41:10 +00:00
## Stage 12: Verify registration and routing interactions end to end
**Work**
1. Extend public external-package tests with command-only and simulated
root-only family fixtures. Exercise construction, later registration,
retained declaration errors, reuse across Apps, and failed-batch recovery.
2. Verify canonical invocations retain their declared operand space in both
installation orders, while longer mappings beneath alternate spellings work.
Cover optional, required, and repeated operand metadata without calling
domain value converters at installation.
3. Verify same-batch alias chains and globals see the entire candidate, and
later command additions trigger full relationship validation. Check cached
lookup/help before and after successful and failed registration.
4. Include a core-only consumer proving alias infrastructure needs no optional
integration imports. Keep alias records out of the canonical handler tree.
**Evidence:** run the focused external registration, routing, and help suites.
Fill missing cross-boundary cases rather than duplicating the private algorithm
test inventory. No concurrent-dispatch contract is introduced.
## Stage 13: Verify typed bindings and integration composition
**Work**
1. Cover singleton last-occurrence behavior, conversion of every supplied
occurrence, repeatable ordering, explicit false/zero/empty presence, required
checks, and fresh invocation state with mixed flag spellings.
2. Verify captured selector bindings still reach selected typed integration
inputs. Test a command-scoped flag alias reached through a command shortcut,
and global help on standard families, without rechecking upstream semantics.
3. Add focused ckprompt composition cases for actual installed collection and
named-inspection commands, plus the valid `smoke → promptkit test` shortcut.
Use local callbacks; smoke tests should assert forwarded kind and returned
report/outcome, not perform network requests.
4. Reject the invalid smoke operand-synonym mapping against the actual
`promptkit test KIND` declaration. Preserve ordinary canonical calls in the
same application. Use a small ckconfig alias case for selector forwarding.
**Evidence:** root binding suites and affected integration suites under the
local workspace. Do not claim nested modules' pinned core v0.2.0 graph validates
new alias APIs. See Stage 17 for independent local-source graph verification.
## Stage 14: Update maintained consumer examples
**Work**
1. Extend `examples/core` with application command shortcuts, a group shortcut,
a global help typo alias, and a scoped flag alias. Demonstrate a mixed
`[]Declaration` collection and the two Invocation path accessors with small
application-owned behavior.
2. Extend the composed ckprompt consumer with
`list collections → promptkit list collections` ,
`promptkit list bundles → promptkit list collections` , and `pk → promptkit` .
Add scoped `--fmt → --format` for named prompt inspection and
`--hlep → --help` globally. Keep canonical suite loading and domain commands
unchanged; install aliases alongside the complete canonical declarations.
3. Add the valid smoke command-path shortcut if useful for the existing local
smoke fixture. Do not represent `all` as a child command or alias target.
4. Update example tests to show aliases reaching canonical operations, help
without acquisition, and ordinary canonical commands still working. Keep
outputs local and deterministic.
**Evidence:** root and composed-example tests pass against the new local core;
the examples remain complete, copyable artifacts. Explain local source testing
and forthcoming core dependency adoption in their developer-facing guidance;
do not claim published core v0.2.0 has alias support.
## Stage 15: Reconcile public and internal documentation
**Work**
1. Add GoDoc for `Declaration` , `RoutingRule` , factories, installation changes,
and Invocation accessors. Explain eager capture, factory errors retained for
installation, nil/zero handling, duplicate rules, and canonical scope paths.
2. Update `docs/cli.md` with implemented alias routing, command/operand
boundaries, flag scope/availability, short grammar and empty-value correction,
entered-path diagnostics, and help/discovery behavior. Preserve canonical
upstream command and report contracts.
3. Update the consumer guide and example READMEs for `[]Declaration` , direct
`Command` calls, slice conversion, and explicit root installation of rules.
Include a minimal real integration composition example and links to the
maintained complete consumers.
4. Update the internal overview and applicable architecture provisions for the
separate canonical/routing layers and joint installation. ADR 0013 already
authorizes this architecture; do not rewrite accepted decisions or add an ADR
for incidental algorithm or presentation details.
5. Update developer navigation to the roadmap/plan while work is active and
preserve `deferred.md` . Keep shell completion as future direction only.
**Evidence:** local links and fragments resolve; volatile behavior has its
canonical owner; no future alias APIs are described as existing before their
implementation is present. Prose checks and relevant examples agree.
## Stage 16: Record compatibility impact for the next core release
**Work**
1. Prepare the next core minor release note, `docs/releases/v0.3.0.md` , with
the product title, short summary, migration guidance, and required immutable
licensing footer under the release procedure. Do not edit published notes.
2. Explain the `...Command` to `...Declaration` change, especially `[]Command`
expansion and function-value signature changes; command/group factories
still return `Command` . Note private Invocation path storage's impact on
positional struct literals and recommend keyed construction when needed.
3. Explain command/flag aliases and the explicit short-option empty-value
correction. Go 1.26.0 and the current upstream/backend selections need not
change for this feature.
4. Keep publication and real integration dependency bumps separate. The next
core must be published before dependent module release preparation downloads
that version and records actual sums, as required by `docs/release.md` .
Do not invent core v0.3.0 sums, commit local replacements, or rewrite the
integrations' existing v0.1.0 release notes. Report this release-preparation
dependency in the final implementation handoff.
**Evidence:** note explains consumer action and candidate-local link paths and
footer are correct. No release launcher, remote push, or tag operation occurs
as part of implementing this plan.
## Stage 17: Verify the complete target and finish
**Work**
1. Format changed Go sources and run the complete deterministic root suite and
both integration suites using the local three-module workspace described by
the developer guide. Use the documented Go 1.26.8 maintainer toolchain; this
feature does not raise the consumer minimum.
2. Root independent validation uses `GOWORK=off` and its actual module graph.
For nested modules needing unpublished local core APIs in tests/examples,
use disposable copies of each `go.mod` /`go.sum` through `-modfile` , with a
local core replacement; replace ckconfig with its local source for composed
verification where needed. Run `GOWORK=off` module suites against those
copies. Permit only disposable metadata to change and inspect it separately.
This verifies local source composition, not published-version availability.
3. Leave committed dependency constraints and genuine sums intact until their
separately authorized release preparation. Do not run nested suites against
old published core and count failures as feature failures or count old code's
success as evidence for new aliases. Do not publish dependencies to make
this implementation sprint's checks pass.
4. Confirm core still has no optional-library dependency, backend imports stay
internal, integration factories remain canonical `Command` factories, and
alias lookup requires no application/provider initialization.
5. Audit every roadmap behavior against the evidence index below. Verify
metadata paths, help views, errors, and failed-registration recovery, not
only successful alias execution. Reuse existing focused evidence rather
than creating an additional redundant test framework or release gate.
6. Run prose whitespace and local-link checks; inspect all diffs and intended
files. Mark stages complete with actual evidence, update the feature
roadmap's status, commit remaining intended work, and report validation plus
any release-preparation steps still required. Preserve completed planning
records until cleanup is requested.
After selecting the documented toolchain and preparing the existing dependency
cache, the independent graph checks can be performed from the repository root
as follows. The workspace checks above are still needed; these commands exercise
each module's own metadata with only the indicated local source substitutions.
The temporary-file updates accommodate unpublished source without changing
tracked version requirements or synthesizing published checksums.
```sh
(
set -eu
commandkit_alias_repo=$(pwd)
commandkit_alias_verify=$(mktemp -d /tmp/commandkit-alias-verify.XXXXXX)
trap 'rm -rf "$commandkit_alias_verify"' EXIT
export GOTOOLCHAIN=local GOWORK=off
export GOPROXY=off GONOPROXY=none GOSUMDB=off
go test -mod=readonly ./...
cp integrations/ckconfig/go.mod "$commandkit_alias_verify/ckconfig.mod"
cp integrations/ckconfig/go.sum "$commandkit_alias_verify/ckconfig.sum"
go mod edit -modfile="$commandkit_alias_verify/ckconfig.mod" \
-replace="gitea.maximumdirect.net/eric/CommandKit=$commandkit_alias_repo"
(cd integrations/ckconfig &&
go test -mod=mod -modfile="$commandkit_alias_verify/ckconfig.mod" ./...)
cp integrations/ckprompt/go.mod "$commandkit_alias_verify/ckprompt.mod"
cp integrations/ckprompt/go.sum "$commandkit_alias_verify/ckprompt.sum"
go mod edit -modfile="$commandkit_alias_verify/ckprompt.mod" \
-replace="gitea.maximumdirect.net/eric/CommandKit=$commandkit_alias_repo"
go mod edit -modfile="$commandkit_alias_verify/ckprompt.mod" \
-replace="gitea.maximumdirect.net/eric/CommandKit/integrations/ckconfig=$commandkit_alias_repo/integrations/ckconfig"
(cd integrations/ckprompt &&
go test -mod=mod -modfile="$commandkit_alias_verify/ckprompt.mod" ./...)
)
```
If an offline command reports an absent dependency, prepare that dependency
separately and rerun the affected check. Do not turn an offline suite into a
network-enabled test run or silently substitute older published implementation.
These local-source graph checks do not add a permanent release gate.
**Complete when:** the accepted feature works through the public consumer
boundary, the selected checks pass against local source, documentation matches
the implementation, and no unresolved feature decisions or implementation work
remain. Publishing and dependent-version availability are separate operations.
## Target evidence index
| Accepted behavior | Primary stages |
| --- | --- |
| Public factories, capture, absence/zero/nil handling, slices | 1, 4, 5, 12, 15, 16 |
| Exact chains, longest matches, group composition, universal termination | 2, 3, 5, 7, 12 |
| Canonical ownership, operand boundaries, no preset operands | 5, 7, 12, 13 |
| Same-batch and later installation, duplicates, rollback | 5, 6, 12 |
| Global/scoped flag aliases, chains, endpoints, availability, collisions | 6, 8, 12, 13 |
| Values, operands, clusters, empty values, presence, repeat order | 8, 9, 11, 13 |
| Entered/canonical identity and ordinary lifecycle | 7, 9, 11, 13 |
| Root/group/alias-prefix help, effective flag help, target-aware usage | 7, 10, 11, 12 |
| Error identity, cancellation, report/diagnostic delivery | 9, 11, 13 |
| Real consumer composition and module boundaries | 12, 13, 14, 17 |
| Future-completion lookup separation without completion delivery | 7, 10, 15 |
| Migration, current references, release-note preparation | 14, 15, 16, 17 |