Files
commandkit/docs/adr/0001-command-dispatch-and-inputs.md

3.8 KiB

ADR 0001: Own dispatch through captured declarations and typed inputs

Status

Accepted. Consolidated during the alpha ADR cleanup.

Date

2026-11-07; consolidates decisions made on 2026-10-06 and 2026-10-10.

Context

Applications repeat routing, flag parsing, help, and inspection commands while also needing their own domain commands. Sharing only isolated command handlers would leave much of that infrastructure and its inconsistent behavior with each application. Optional integrations also need to assemble commands through the same public mechanisms as applications.

Decision

CommandKit owns dispatch, shared parsing, presence tracking, help, syntax failures, and standard command mechanics. Applications own their domain commands, validation, effects, runtime construction, and executable lifecycle. CommandKit accepts caller context and streams and returns outcomes rather than terminating the process.

Use an explicitly constructed, per-instance registry. Applications and integrations supply captured declarations containing routing, parsing, help metadata, and callback references. One declaration supplies those views of the command. Captured metadata is insulated from later edits to its source; application objects referenced by callbacks remain caller-owned.

Declarations share one installation boundary. Construction issues are retained for installation, and each installation batch is validated before registry mutation. Collisions are errors rather than order-dependent replacement. Optional standard families claim their namespaces when installed, not when imported. Their canonical operations remain integration-owned; application commands live outside installed standard families.

Handlers receive typed inputs through explicit flag and operand bindings. Presence is separate from value so omission differs from supplied empty, false, or zero values. Domain parsers and validation remain application-owned. Core provides typed composition for integrations without exposing parser state or requiring a second argument parser.

Parsed state is independent between invocations. Integration inputs for selected scopes or comparison sides are distinct from invocation-wide acquisition state. Applications own the objects and caches returned by their factories. CommandKit coordinates its own preparation and calls without promising arbitrary deep copies or concurrent dispatch.

Construction, installation, help, version, and capability discovery use metadata without acquiring application state. The selected operation acquires what it needs after applicable input checks. Caller startup and callback effects retain their own lifecycle.

Alternatives considered

  • Application dispatchers forwarding standard families would share handlers but leave custom-command parsing, root help, and diagnostics duplicated.
  • Raw-argument handlers or string-keyed input access would leave typed input assembly and presence handling with every consumer.
  • Reflection, struct tags, or generated bindings could shorten declarations but add another declaration language or toolchain.
  • Import-time registries or a separate integration registration framework would introduce hidden state or parallel assembly conventions.

Consequences

Applications use one command system while retaining domain ownership. Explicit bindings and captured declarations require deliberate assembly, but integrations can supply complete families through the same public contracts.

GoDoc owns declaration, installation, and callback contracts; the consumer guide explains their use. Exact grammar, commands, and outcomes belong in the CLI reference. Binding identity, absence handling, factory defaults, and operation-specific preparation timing can evolve within this architecture through deliberate API changes.