Files
commandkit/docs/adr/0010-optional-integration-modules.md

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.