Accept optional integration modules architecture

This commit is contained in:
2026-10-09 14:11:02 +00:00
parent 9456bef1c1
commit 76f923e619
3 changed files with 121 additions and 13 deletions

View File

@@ -2,7 +2,11 @@
## Status
Accepted.
Partially superseded by [ADR 0010](0010-optional-integration-modules.md).
ADR 0010 narrows the root facade and public-type ownership decision to the core
module and places optional library dependencies in integration modules. The
remaining principles continue to apply; this record's decision text is retained.
## Date

View File

@@ -0,0 +1,94 @@
# ADR 0010: Separate the core facade from optional integration modules
## Status
Accepted. Partially supersedes
[ADR 0003](0003-public-facade.md) as described below.
## 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.

View File

@@ -1,6 +1,7 @@
# Optional integration modules
Status: proposed implementation roadmap; no module extraction has begun.
Status: module boundary accepted in ADR 0010; implementation planning remains
in progress and no module extraction has begun.
## Purpose and authority
@@ -11,11 +12,13 @@ module dependencies. ConfigKit-only consumers should not acquire PromptKit.
This roadmap records the targeted end state, selected module layout, and
migration work. Recommendations under [Open Decisions](#open-decisions) remain
proposals. It does not supersede accepted ADRs or describe these changes
as implemented. The [architecture policy](../policy/architecture.md) and
[ADR 0003](../adr/0003-public-facade.md) govern the current boundary; an accepted
successor decision is needed before changing it. Current contracts remain in
GoDoc, the [CLI reference](../cli.md), and the
proposals. It does not describe these changes as implemented.
[ADR 0010](../adr/0010-optional-integration-modules.md) owns the accepted module
boundary and convenient registration principles; it partially supersedes
[ADR 0003](../adr/0003-public-facade.md), whose remaining principles still apply.
Alignment of the [architecture policy](../policy/architecture.md) remains part of
the work below. Current implemented contracts remain in GoDoc, the
[CLI reference](../cli.md), and the
[consumer guide](../consumers/guide.md).
## Current baseline
@@ -108,21 +111,24 @@ is an intentional consumer migration.
## Work sequence
### 1. Settle boundaries and record the decision
### 1. Align policy and settle implementation boundaries
Completed: ADR 0010 is accepted and ADR 0003 is marked partially superseded,
with its decision text preserved. The partial status follows the explicitly
authorized exception to the documentation policy for this decision.
- Resolve the remaining choices under Open Decisions before moving public
symbols, using the selected module paths and package names above.
- Create a successor ADR for the changed facade/module boundary and mark
ADR 0003 superseded according to the
[documentation policy](../policy/documentation.md#architecture-decision-records).
Preserve its decision history. Align the architecture policy and review other
- Align the architecture policy with ADR 0010 and review other
ADRs for affected ownership statements without reopening unrelated decisions.
- Inventory root exports, imports, private helper use, and family registration
behavior. Assign each to core or an integration; document the consumer-facing
old-to-new API mapping rather than freezing a full inventory in this roadmap.
- Sketch three representative consumers: core only, ConfigKit only, and both
libraries. Confirm that combined configuration scopes remain straightforward
and that moving code does not replace removed boilerplate with new plumbing.
and that registration meets ADR 0010's convenience principle without replacing
removed boilerplate with new plumbing. Use these examples to evaluate the
registration API; no fixed call count or particular options pattern is selected.
Completion: the dependency direction, public migration, and registration approach
are concrete enough to implement without inventing a general plugin framework.
@@ -220,6 +226,10 @@ Semantic comparison retains the upstream-contract dependency recorded in
### Registration across the new public boundary
ADR 0010 selects convenient family registration with specialized composition
where needed. The remaining decision is how to support it across module
boundaries.
**Recommendation:** first reuse public command/group registration and duplicate
path checks. Add only a narrow core registration capability if preserving the
existing standard-family ownership contract requires it. This keeps integrations