101 lines
5.2 KiB
Markdown
101 lines
5.2 KiB
Markdown
# ADR 0010: Separate the core facade from optional integration modules
|
|
|
|
## Status
|
|
|
|
Accepted. Partially supersedes
|
|
[ADR 0003](0003-public-facade.md) as described below.
|
|
Partially superseded by [ADR 0011](0011-captured-declarations-and-installation.md)
|
|
for the consumer-migration consequence during the unreleased prototype
|
|
transition. It also supplies the registration and invocation-lifetime
|
|
decisions left open here. The module
|
|
boundary and remaining principles continue to apply; this record's decision
|
|
text is retained.
|
|
|
|
## Date
|
|
|
|
2026-10-09
|
|
|
|
## Context
|
|
|
|
CommandKit serves consumers that need its command infrastructure with different
|
|
combinations of library integrations, including none. A consumer using only the
|
|
core should not acquire dependencies belonging to optional integrations.
|
|
|
|
ADR 0003 establishes deliberate public contracts and an internal CLI backend
|
|
boundary. Those principles remain appropriate. Its initial single root facade,
|
|
however, combines core and integration responsibilities. Separate packages within
|
|
one module would separate imports while retaining shared module requirements.
|
|
|
|
## Decision
|
|
|
|
Retain the root `commandkit` package as the core module's public facade. It owns
|
|
core command declarations, registration, typed inputs, dispatch, help/version,
|
|
shared syntax, diagnostics, and invocation outcomes.
|
|
|
|
Provide optional library integrations as separate Go modules with their own
|
|
public package contracts. Each integration owns the standard command handlers,
|
|
provider contracts, reports, and adapters appropriate to its responsibility.
|
|
Applications select integrations and explicitly register their commands; importing
|
|
an integration does not install a command family.
|
|
|
|
Integrations provide convenient registration of their standard command families,
|
|
with standard declarations and handlers supplied by the integration. Applications
|
|
provide acquisition and domain-specific context without assembling individual
|
|
standard commands or repeating adapter plumbing. More specialized composition
|
|
remains available where concrete consumer needs justify it.
|
|
|
|
Dependencies point from integrations toward the core. The core's public API,
|
|
implementation, and module requirements remain independent of optional
|
|
integration libraries. An integration may depend on another integration when
|
|
its responsibility requires that relationship. Document such dependencies so
|
|
consumers can understand the modules they select.
|
|
|
|
Integrations compose through supported public core contracts and preserve
|
|
CommandKit's standard grammar, command ownership, help, and outcome conventions.
|
|
They do not access private core state or backend structures. Add public contracts
|
|
where concrete integration needs justify them, without requiring a general plugin
|
|
or backend-selection framework.
|
|
|
|
### Relationship to ADR 0003
|
|
|
|
The root-facade and public-type ownership provisions of ADR 0003 now apply to
|
|
the core module. Integration-owned public types and operations belong in their
|
|
respective public packages. The permission to expose deliberately selected
|
|
upstream library types applies within the integrations that depend on them;
|
|
it does not justify optional integration dependencies in the core.
|
|
|
|
ADR 0003's remaining principles continue to apply across the core and
|
|
integrations: deliberate exports, private implementation state, proportionate
|
|
internal layering, no exposure of internal or backend types, and preservation of
|
|
documented ownership, presence, callback lifetime, and error semantics. Application
|
|
input types and caller-supplied values and errors retain their existing handling.
|
|
Cobra/pflag remain behind the core's internal adapter.
|
|
|
|
This decision changes the scope of the single-facade decision rather than
|
|
replacing its contract discipline. ADR 0003 is partially superseded and its
|
|
original decision text remains intact.
|
|
|
|
## Alternatives considered
|
|
|
|
| Alternative | Analysis |
|
|
| --- | --- |
|
|
| Keep integrations in the root package | Preserves existing imports and simplifies releases, but core consumers acquire optional library dependencies. |
|
|
| Use separate packages within one module | Separates compiled imports and retains one release unit, but keeps integration requirements in the shared module graph. |
|
|
| Have applications implement integration handlers | Keeps the core independent, but recreates duplicated inspection commands and weakens consistent operator behavior. |
|
|
| Introduce universal provider contracts in the core | Could support several libraries through a common model, but adds abstractions and conversion obligations before concrete needs justify them. |
|
|
|
|
## Consequences
|
|
|
|
Consumers can adopt the core independently and add supported integrations as
|
|
needed. Integrations remain maintained parts of CommandKit, with shared CLI
|
|
conventions and owning-library semantics. Dependency independence does not mean
|
|
the core has no external implementation dependencies.
|
|
|
|
Moving existing integration APIs requires a documented consumer migration.
|
|
Integration modules add module-specific dependency, validation, and release work.
|
|
Core tests, examples, and tools must not reintroduce the optional dependencies
|
|
that this boundary removes.
|
|
|
|
Exact registration mechanics and release cadence are not selected here.
|
|
Current GoDoc and CLI contracts continue to own implemented behavior.
|