Record proposed CLI decisions and clarify CommandKit boundaries

This commit is contained in:
2026-10-06 23:36:06 +00:00
parent 6a0467148e
commit 84234275eb
15 changed files with 1243 additions and 331 deletions

View File

@@ -41,23 +41,22 @@ inspection uses the single `promptkit` namespace; root `prompt` and `profile`
names remain available to applications. This provides a clear family ownership
boundary without spreading a namespace across root verbs.
Applications register commands outside reserved families. They cannot replace
standard handlers or add private operations underneath a reserved family.
Standard-family context selectors and typed overrides use the defined input
extension mechanism rather than introducing application-owned operations there.
CommandKit accepts custom commands outside its reserved standard families and
reports registration errors for attempts to replace standard handlers or add
private operations beneath them. Its input extension mechanism accepts context
selectors and typed overrides for standard operations.
Applications retain `main`, signal handling, context creation, stream selection,
runtime construction, and final process exit. CommandKit returns invocation
outcomes and does not terminate the process. Configuration schemas, acquisition,
domain resolution and validation, and provider construction remain application
integration responsibilities. ConfigKit and PromptKit retain their own
configuration, provenance, safe inspection, and native rendering semantics.
CommandKit accepts caller-supplied context, streams, handlers, and inspection
providers and returns invocation outcomes. It leaves process termination to the
caller. Executable startup, signals, runtime construction, schemas, acquisition,
and domain resolution remain application choices. CommandKit integrates ConfigKit
and PromptKit through their supported public semantics.
### Explicit registry and capability installation
Each explicitly constructed application instance owns a registry. Applications
register individual commands and composable groups. There is no package-global
registry or import-time `init` registration.
Each explicitly constructed CommandKit instance owns a registry. Its API accepts
individual commands and composable groups. Registration uses explicit instance
state with caller-controlled construction and composition.
Definitions provide paths, descriptions, flags and defaults, repetition and
presence metadata, operand requirements, and execution handlers. One definition
@@ -65,41 +64,49 @@ supplies routing, parsing, and help. Duplicate paths and attempts to replace
reserved commands return registration errors; order does not select a winner.
Help and version are installed automatically using supplied application identity
and build metadata. Configuration and PromptKit families are installed when the
application supplies their providers. Supplying a capability installs its complete
standard family, not a collection requiring manual operation-by-operation wiring.
and build metadata. CommandKit assembles standard families from declared provider
capabilities, installing their supported handlers and metadata together. Each
family defines its own resource model, supported verbs, and per-operation data
contracts. Configuration scopes declare their available inspection operations.
Registering providers does not execute them. Construction may diagnose missing
or invalid wiring without reading configuration, resolving credentials, or
building engines. Invalid configuration is an invocation-time failure. Command
declarations, help, and version remain available independently of application
initialization. The selected handler acquires dependencies when it needs them.
The API allows supported capabilities to be integrated independently. Adding
comparison, catalogs, or other inspection features extends the installed surface
according to the supplied providers. Shared verbs have consistent purposes across
families, while the available subsets reflect their resources and capabilities.
Help and discovery expose those subsets. Registration validates the wiring of
declared capabilities and reports unsupported selections before acquisition.
Do not install placeholder commands. Omitting the configuration provider does
not make a partial integration a complete core adopter. PromptKit is optional;
its selected family is installed as a complete capability. The CLI roadmap owns
the proposed command inventory and the remaining choices for that standard.
CommandKit registration validates declarations with acquisition callbacks left
uninvoked. Its construction, help, and version paths use metadata. The selected
handler requests dependencies when its operation needs them. Invalid configuration
returned by an acquisition callback is an invocation-time failure. Caller code
executed before registration and effects inside callbacks remain caller-owned.
CommandKit installs handlers for supplied capabilities and describes actual
availability. Each enabled operation retains its standard meaning and output
contract. The exact operation inventory and remaining command contracts are
separate design decisions.
### Typed inputs with explicit bindings
Use application-defined input structs for custom commands and CommandKit-defined
inputs for standard handlers. Explicit registration binds flags and operands to
their input fields. The declarations also supply parsing and help metadata.
Handlers do not retrieve primitive values by flag name or parse the complete argv.
The public binding contract accepts application-defined input structs for custom
commands and uses CommandKit-defined inputs for standard handlers. Explicit
registration binds flags and operands to fields and supplies parsing and help
metadata. CommandKit delivers parsed typed inputs to registered handlers.
Use ordinary typed fields where omission has no separate meaning. Where it does,
keep supplied/not-supplied state beside the value in a presence-aware field.
Defaults do not mark input as explicitly supplied. Preserve explicit empty,
false, and zero values.
Bindings support ordinary typed fields and presence-aware fields where omission
has a separate meaning. CommandKit records supplied state independently of values
and defaults, preserving explicitly supplied empty, false, and zero values.
Create fresh input storage per invocation. Registered commands must not capture
one mutable input permanently or retain prior values, collections, or presence.
This decision addresses lifetime without establishing concurrent dispatch.
CommandKit creates fresh input storage per invocation and keeps its previous
parsed values, collections, and presence out of subsequent invocations. Handler
closures and application state retain their own lifecycle. Fresh CommandKit state
addresses invocation lifetime; concurrent dispatch is a separate contract.
Supply context and stream access separately from CLI inputs. Input declarations
and binding setup must not construct execution dependencies. Applications perform
domain validation and may interpret parsed domain values or supply a custom value
parser through the binding system.
The invocation API supplies context and streams separately from CLI inputs.
CommandKit creates its declarations and bindings from metadata and defers its
acquisition calls to the selected handler. The binding system accepts domain value
parsers; domain interpretation and validation belong to registered callbacks.
The public factory, binding, registration, and handler signatures and presence
type names remain API design choices. No illustrative declaration establishes
@@ -111,17 +118,35 @@ Resolve the command and handle help/version before loading application state.
For execution, allocate fresh inputs, apply shared parsing and operand checks,
then invoke the typed handler. Return its invocation outcome to the application.
Shared usage errors and standard-family outcomes belong to CommandKit. Custom
handlers must communicate application-specific outcomes without silent generic
reclassification. For example, Scriptorium output validation and Notarius artifact
outcomes remain application concerns. Do not classify domain errors by matching
message strings or print usage unconditionally for runtime failures.
CommandKit classifies shared usage errors and standard-family outcomes. Its
handler result contract accepts application-specific outcomes and preserves their
supplied classification. Scriptorium output validation and Notarius artifact
outcomes, for example, remain domain results. CommandKit translates results from
explicit classification and emits usage guidance for usage failures.
Common mechanics do not require a common success-report format for custom
commands. The application owns its artifact and operational output contracts.
Exact result/error interfaces and unresolved grammar choices are separate design
work, not approvals implied by this decision.
### Contract scope and consumer guidance
This decision governs CommandKit's public contracts and implemented behavior.
Each operation specifies the inputs, result semantics, callback lifetimes, and
metadata its provider supplies. Consumers choose how to implement those callbacks
and how to structure loading, execution, startup, and process status mapping.
Sharing acquisition and resolution between inspection and execution, and keeping
acquisition focused on producing inspection views, are recommended practices.
CommandKit supports those patterns through reusable inputs and lazy provider
hooks. Its API preserves declared results and coordinates its own calls; arbitrary
application internals remain application-owned.
Cobra isolation applies to CommandKit's exports and internal adapter. Independent
consumer use of another CLI library remains an application choice. Additional
families and source models can use capability contracts appropriate to their
resources, with standard meanings preserved for operations that are installed.
## Alternatives considered
### Dispatcher and ownership
@@ -132,7 +157,7 @@ work, not approvals implied by this decision.
| Standard definitions mounted into an application's framework | Reuses routing infrastructure, but application configuration can preserve inconsistent behavior outside mounted families. Internal framework reuse remains compatible with this decision. |
| Shared metadata/help with separate routing | Unifies discovery but adds synchronization among metadata, routing, and parsing. One dispatcher avoids it. |
| Both full dispatch and embeddable family handlers | Serves established external CLI architectures but adds integration surfaces and maintenance. Add embedding only for a concrete need. |
| Raw-argument handlers for custom commands | Eases migration but leaves parsing and help responsibilities with applications. A future transition adapter needs explicit limitations and is not full adoption. |
| Raw-argument handlers for custom commands | Eases migration but leaves parsing and help responsibilities with applications. A future transition adapter would need to describe its separate parsing and help contract. |
| Universal application runtime framework | Could absorb startup and operational services, but expands beyond the demonstrated CLI boundary and domain ownership. |
| Verb-first standard paths | Groups actions but distributes namespace ownership among individual routes. Namespace/resource-first paths keep family ownership clear. |
| Reserve root `prompt` and `profile` | Provides short resource paths but consumes application namespaces. A single `promptkit` family gives the library one ownership boundary. |
@@ -152,7 +177,7 @@ work, not approvals implied by this decision.
| Parsed-value accessor object | Uniform handlers, but string-based lookup, runtime type errors, and repeated assembly remain. |
| Individual typed parameters | Clear for small commands; grows into long signatures and adapter machinery. Typed structs scale more naturally. |
| Reflection and struct tags | Compact declarations, but adds a tag language, field-discovery rules, and runtime declaration validation. Explicit bindings keep declarations visible. |
| Typed command objects | Can organize complex handlers; must separate fresh input from dependency and execution lifetimes. Applications may use objects without making them mandatory. |
| Typed command objects | Can organize complex handlers. CommandKit's fresh input contract remains separate from caller-owned object lifetimes; objects are an application option. |
| Generated bindings/adapters | Can combine compact authoring and typing, but adds tooling and generated-file maintenance without demonstrated need. |
| Raw arguments | Simple routing integration, but returns common parsing and help to applications. |
@@ -169,11 +194,10 @@ support consistent mechanics without requiring reflection or generated code.
Shared parsing defects can affect every adopter. Consumer and backend integration
evidence must protect selected semantics, including ownership conflicts, help
without configuration, presence, fresh input, cancellation, and domain outcomes.
Intentional migration changes require coordinated application documentation and
subprocess-consumer updates.
CommandKit releases document intentional compatibility changes. Coordinated
application documentation and subprocess-caller updates are recommended migration
practices.
The [architecture policy](../policy/architecture.md) owns normative boundaries.
The [dispatcher roadmap](../roadmap/02-dispatch.md) owns implementation status and
pending API design. The [CLI roadmap](../roadmap/01-cli-plan.md) retains command
proposals and their approval status. [ADR 0002](0002-cobra-backend.md) selects the
backend, and [ADR 0003](0003-public-facade.md) defines its public/internal boundary.
[ADR 0002](0002-cobra-backend.md) selects the backend, and
[ADR 0003](0003-public-facade.md) defines its public/internal boundary.