110 lines
5.8 KiB
Markdown
110 lines
5.8 KiB
Markdown
# ADR 0003: Own public contracts through a root facade and internal CLI adapter
|
|
|
|
## Status
|
|
|
|
Accepted.
|
|
|
|
## Date
|
|
|
|
2026-10-06
|
|
|
|
## Context
|
|
|
|
CommandKit needs room to change implementation while consumers retain stable
|
|
registration, input, and invocation contracts. Exposing backend assembly or
|
|
extension structures would let applications depend on details that maintainers
|
|
may later replace.
|
|
|
|
ConfigKit, PromptKit, and ReleaseKit demonstrate facades that own public types and
|
|
delegate through private state and explicit conversion. ConfigKit also translates
|
|
upstream YAML parser structures into an independent internal document model.
|
|
ReleaseKit has a second facade for a distinct lightweight runtime responsibility;
|
|
CommandKit has no corresponding requirement for another public package initially.
|
|
|
|
The Cobra selection is compatible with dependency isolation. Public API
|
|
independence needs a genuine contract boundary, and keeping backend structures
|
|
out of shared internal representations also makes future replacement easier.
|
|
|
|
## Decision
|
|
|
|
Use the module root `commandkit` as the sole initial supported public facade.
|
|
Define CommandKit's public named types there and expose only selected operations,
|
|
extension contracts, and documented methods. Handles keep implementation state in
|
|
private fields.
|
|
|
|
Implementation packages belong under Go's `internal/` boundary. Public code
|
|
forwards inward with explicit wrappers and conversions; internal production
|
|
packages do not import the root. Shared internal contracts live inside that
|
|
boundary. Additional public packages require a deliberate decision based on a
|
|
durable consumer responsibility.
|
|
|
|
Do not alias public types to internal or backend types, anonymously embed those
|
|
types to promote methods, or expose implementation bridge methods. Exported
|
|
fields, signatures, variables, callbacks, interface methods, constraints, and
|
|
method sets must not reveal internal or Cobra/pflag structures. Loosely typed
|
|
values and returned errors must not provide indirect backend-object access.
|
|
|
|
Standard contracts such as `context.Context` and `io.Writer` remain appropriate.
|
|
ConfigKit or PromptKit public types may be selected as deliberate integration
|
|
dependencies. Application input types remain application-owned. Go declarations
|
|
and GoDoc own exact exported contracts.
|
|
|
|
Confine Cobra/pflag types and operations to an internal adapter. Registry logic,
|
|
standard handlers, and shared definitions use CommandKit-owned representations.
|
|
The adapter translates paths, descriptions, bindings, presence, callbacks, and
|
|
selected help/outcome semantics into backend machinery. Do not reproduce Cobra's
|
|
complete API through renamed wrappers.
|
|
|
|
Typed input factories and handlers can cross the facade through private callbacks
|
|
without internal packages importing public declarations. Preserve fresh input and
|
|
backend state per invocation. Introduce narrow internal interfaces where actual
|
|
engine/adapter interaction justifies them; exact package names and splits remain
|
|
implementation choices.
|
|
|
|
Use one concrete backend initially. There is no public backend interface, plugin
|
|
registry, or requirement for a second implementation. Replacement is a future
|
|
maintainer change.
|
|
|
|
Translate backend-owned syntax failures into CommandKit diagnostics and outcomes.
|
|
Preserve useful public identity for application handler errors and cancellation
|
|
according to the invocation contract. Explicit conversions must preserve value
|
|
ownership, callback lifetime, presence, and supported error semantics.
|
|
|
|
## Alternatives considered
|
|
|
|
| Alternative | Analysis |
|
|
| --- | --- |
|
|
| Keep all machinery in the public root | Less forwarding, but harder consumer navigation and easier accidental public expansion. |
|
|
| Alias or embed implementation types | Less conversion code, but couples public type identity, fields, or method sets to internal choices. |
|
|
| Hide Cobra only behind the public facade | Hides types from applications but allows backend structures to spread through internal logic, complicating replacement. |
|
|
| Mirror Cobra's API with wrappers | Removes dependency names while preserving its conceptual coupling and compatibility surface. |
|
|
| Public packages for registry, bindings, backend, and other mechanisms | Adds supported imports and assembly contracts without a distinct consumer responsibility. |
|
|
| Selectable/pluggable backends immediately | Adds selection and extension machinery before a concrete need exists. |
|
|
|
|
## Consequences
|
|
|
|
Consumers depend on deliberate root contracts while internal algorithms,
|
|
collaborators, and package boundaries can evolve. Useful application registration
|
|
capabilities still need a proportionate API; minimizing accidental exports must
|
|
not recreate repetitive consumer infrastructure.
|
|
|
|
Explicit forwarding and conversion require maintenance. Type identity, ownership,
|
|
method sets, callback lifetime, and error semantics must be protected by evidence,
|
|
not inferred from package relocation.
|
|
|
|
Compiled public API checks protect aliases, fields, signatures, constraints, and
|
|
promoted methods. Import checks keep the backend in its adapter and internal
|
|
production code independent of root. External-package tests protect consumer
|
|
semantics through the real adapter. ConfigKit and ReleaseKit provide precedents
|
|
for these checks without requiring their full validation workflows.
|
|
|
|
Backend replacement can preserve the public Go API but must also preserve selected
|
|
CLI behavior or follow the release policy for intentional incompatibilities.
|
|
Backend defaults do not independently establish new CommandKit contracts.
|
|
|
|
The [architecture policy](../policy/architecture.md) owns normative boundaries.
|
|
The [facade roadmap](../roadmap/04-facade.md) owns implementation status, package
|
|
layout illustrations, and pending work. [ADR 0001](0001-command-dispatch-and-inputs.md)
|
|
records the dispatcher/input model, and [ADR 0002](0002-cobra-backend.md) selects
|
|
the initial backend. The CLI roadmap retains individual command approval status.
|