373 lines
22 KiB
Markdown
373 lines
22 KiB
Markdown
# Architecture Policy
|
|
|
|
**Base Policy Version:** 1.3
|
|
|
|
**Last Updated**: 2026-11-06
|
|
|
|
**Upstream Source:** [architecture.md](https://gitea.maximumdirect.net/eric/policy/src/commit/d84a38ebab26f048cafbe59a2246700c35d29843/docs/policy/architecture.md)
|
|
|
|
## Purpose And Ownership
|
|
|
|
CommandKit is an opinionated Go library for standard inspection commands,
|
|
consistent CLI syntax, and reduced application command infrastructure. It provides
|
|
useful operator access to capabilities owned by its integrated libraries through
|
|
shared command vocabulary, registration, selection, coordination, presentation,
|
|
and invocation outcomes. This policy owns normative responsibility boundaries,
|
|
dependency direction, and architectural constraints. ADRs own decision rationale; the
|
|
[implementation roadmaps](../development.md#task-specific-reading-guide) own
|
|
proposals, sequencing, and implementation status.
|
|
|
|
Architectural constraints govern future implementation. Concrete package
|
|
inventory and mechanics belong in internal documentation when implemented.
|
|
Exact exported contracts belong in Go declarations and GoDoc; implemented
|
|
operator behavior belongs in the CLI reference. Do not describe planned packages
|
|
or APIs as existing implementation.
|
|
|
|
## Ownership Boundaries
|
|
|
|
Applications and integration handlers choose the operation and report content;
|
|
CommandKit core supplies the shared CLI mechanics. Integrated libraries retain
|
|
ownership of their domain behavior. These boundaries govern current and planned
|
|
capabilities; they do not imply that a planned API is implemented.
|
|
|
|
| Area | CommandKit Owns | CommandKit Does Not Own |
|
|
| --- | --- | --- |
|
|
| **CLI output — core** | Format selection, serialization, template execution, and output delivery | Choosing report content or detail level; authoring application-specific text templates |
|
|
| **PromptKit/ConfigKit integrations** | Standard commands, flags, and report content that expose useful operator tasks through upstream public APIs | Helpers or convenience interfaces for application-internal use of upstream APIs |
|
|
| **CLI inputs** | CLI syntax, parsing, typed bindings, presence tracking, and usage diagnostics | Application business rules or upstream domain-validation semantics |
|
|
| **Upstream behavior** | Selecting and invoking supported capabilities, adapting their results, and preserving their meaning | Reimplementing upstream configuration resolution, prompt preparation, validation, or other domain algorithms |
|
|
| **Outcomes and errors — core** | Carrying and presenting selected outcomes; handling CommandKit's own parsing, rendering, and delivery failures | Deciding application recovery policy or terminating the process |
|
|
| **Application lifecycle** | Command dispatch and invocation reporting lifecycle | Application startup, engine construction, credential provisioning, signal handling, or long-lived application state |
|
|
|
|
## Success Criteria
|
|
|
|
Evaluate designs and adoption against both criteria:
|
|
|
|
1. Applications adopt consistent command vocabulary, syntax, and inspection
|
|
behavior for the standard suite.
|
|
2. Applications remove substantial repeated CLI infrastructure while keeping
|
|
clear ownership of domain behavior.
|
|
|
|
Existing applications supply evidence of needs, not compatibility requirements
|
|
for CommandKit. Adoption is expected to make breaking changes to divergent
|
|
consumer conventions. Once CommandKit publishes its own contracts, changes to
|
|
those contracts follow the [release policy](release.md).
|
|
|
|
Use representative simple and complex consumers to substantiate API designs.
|
|
Replacing parsing and dispatch plumbing with equally repetitive registration or
|
|
callback bookkeeping does not satisfy infrastructure reduction. Keep enough
|
|
flexibility to express genuine application requirements within one command model.
|
|
|
|
## Go Types And Facilities
|
|
|
|
CommandKit is a Go library for Go applications. Its APIs and implementation use
|
|
ordinary Go types, language features, and standard-library facilities. Their
|
|
documented semantics and representational limits are accepted design constraints.
|
|
CommandKit does not introduce substitute type systems or compatibility machinery
|
|
merely to circumvent those limits.
|
|
|
|
Ordinary parsing, application-defined domain types, and necessary serialization
|
|
adapters remain appropriate. Preserve values that the selected Go types can
|
|
represent; accepting their limits does not justify accidental rounding or
|
|
truncation during conversion. Keep CLI boundary conversions small and focused,
|
|
without turning them into general-purpose type-conversion frameworks.
|
|
|
|
Specific numeric parsing and report serialization contracts remain separate.
|
|
A CLI parser's selected numeric types do not establish a blanket restriction on
|
|
application-supplied values or silently redefine their serialization contracts.
|
|
GoDoc and CLI documentation own implemented behavior; roadmaps own pending work.
|
|
|
|
## Command And Application Ownership
|
|
|
|
[ADR 0001](../adr/0001-command-dispatch-and-inputs.md) records the selected
|
|
dispatcher, captured declarations, installation boundary, and typed-input model.
|
|
|
|
CommandKit owns dispatch, common parsing, presence tracking, help, shared syntax
|
|
diagnostics, and the handlers and CLI contracts of its standard families.
|
|
The integrated libraries own the domain semantics exposed through those handlers.
|
|
Applications register domain commands outside those families and own their
|
|
meaning, effects, domain validation, artifacts, and operational outcomes.
|
|
Namespaces provide the ownership boundary. Core construction reserves help and
|
|
version. Optional standard families, including config and promptkit, own their
|
|
root namespace when installed; importing an integration or declaring an absent
|
|
family claims no namespace. An application may occupy an uninstalled family name.
|
|
Installing the standard family then reports a collision, as does application
|
|
registration after the standard family is installed. Neither order merges groups
|
|
or replaces handlers. Installed standard families cannot acquire private
|
|
application operations beneath them. Standard-family declarations are root-only;
|
|
nesting a real family beneath another group reports an assembly error.
|
|
|
|
Applications own their executable entry points, context creation, signals,
|
|
stream selection, runtime construction, and final process exit. CommandKit
|
|
returns invocation outcomes and must not terminate the process. Its common
|
|
mechanics apply to custom commands without taking ownership of their domain
|
|
semantics or report content.
|
|
|
|
CommandKit's grammar applies to commands using its dispatcher and binding APIs.
|
|
Its documentation recommends the same grammar and vocabulary for application-owned
|
|
commands, including those outside its dispatcher. The
|
|
[CLI reference](../cli.md#registered-command-syntax) owns implemented grammar.
|
|
|
|
Use explicit instance construction and composable command registration, not
|
|
package-global or import-time registries. Applications and integrations supply
|
|
captured canonical command declarations through the core installation API.
|
|
Declaration factories capture metadata, bindings, and callback references eagerly;
|
|
construction errors remain attached for installation to report. Capture the
|
|
metadata collections needed to keep later edits to a source declaration from
|
|
changing a returned command. Application callback objects retain their ownership.
|
|
Canonical command declarations own handlers, parsing metadata, and help
|
|
metadata. Applications may provide separate routing rules in the same
|
|
installation batch; these rules resolve invocations to canonical commands and
|
|
do not add command nodes, handlers, or flags.
|
|
|
|
Validate each installation batch before mutating the instance registry. A failed
|
|
construction yields no usable application; a failed later registration leaves the
|
|
existing registry intact. Separate successful registration calls are not one
|
|
transaction. Duplicate canonical paths and attempts to replace reserved commands
|
|
report errors rather than letting registration order select a winner. Identical
|
|
routing rules are idempotent; competing targets for the same source and scope
|
|
report an error. Command-scoped flag routing refers to an exact canonical
|
|
command path.
|
|
|
|
Explicit absent-command declarations contribute no commands, help entries, or
|
|
namespace claims; attached errors are reported before skipping absence. An invalid
|
|
zero declaration is not absence. Integrations define their own empty-suite
|
|
semantics and retain invalid wiring errors even when capabilities are narrowed.
|
|
|
|
Standard families are assembled from declared provider capabilities. Each family
|
|
specifies its own resources and supported operations; shared verbs retain
|
|
consistent meanings across families. Configuration scopes describe their supported
|
|
inspection operations. CommandKit installs the supplied handlers and metadata and
|
|
reports actual availability through help and discovery. Missing upstream
|
|
capabilities leave other supported operations available.
|
|
|
|
Help and version use identity/build metadata. CommandKit's registration and
|
|
metadata paths leave acquisition callbacks uninvoked. Help and version remain
|
|
available with missing or invalid configuration. Callers retain their startup and
|
|
callback effects. Version reporting defaults to application identity; explicit
|
|
component selection reports embedded library identity.
|
|
|
|
These rules govern CommandKit's own API, dispatcher, and standard handlers.
|
|
Provider contracts define required inputs and results for enabled operations;
|
|
callback internals and application execution remain consumer choices. Shared
|
|
inspection/execution loading and focused acquisition callbacks are recommended
|
|
integration practices. Independent consumer use of other CLI frameworks remains
|
|
application-owned.
|
|
|
|
## Invocation Reporting And Outcomes
|
|
|
|
Use one reporting facility per invocation for command results, immediate messages,
|
|
and deferred messages. Core owns shared visibility, formatting, delivery, and
|
|
finalization. Applications and integrations choose their report content and
|
|
messages; callers choose the destinations.
|
|
[ADR 0006](../adr/0006-invocation-reporting.md) records this reporting and outcome
|
|
ownership model. Its accepted structured-report extension remains planned in the
|
|
[adoption roadmap](../roadmap/promptkit-v0.20.0.md#shared-core-report-output-prerequisite).
|
|
|
|
For that shared report handoff, core owns format selection, serialization,
|
|
template execution, and delivery. Applications and integrations select logical
|
|
report content and detail level, and author any report-specific text templates.
|
|
Changing format must not implicitly change that content or detail level.
|
|
Representations and encoders are core implementation choices; commands should
|
|
not maintain parallel rendering pipelines or a separate report tree per format.
|
|
|
|
Use ordinary Go report values and thin projections where upstream data needs
|
|
adaptation. Prefer standard serialization and template facilities to a new public
|
|
document model, tag convention, or template language. Shared rendering serves
|
|
both invocation reporting and direct writer use, while invocation delivery keeps
|
|
the existing visibility, outcome, and presentation-failure lifecycle. Exact
|
|
serialization conventions, format options, and API signatures belong in the
|
|
roadmap until implemented, then in their API and CLI contracts.
|
|
|
|
Applications decide how to respond to domain-specific errors. CommandKit may
|
|
provide shared helpers for carrying, inspecting, and presenting errors while
|
|
leaving those decisions with the application. Supplying an error cause alone
|
|
does not select an outcome or generate an operator-facing message. CommandKit
|
|
handles its own errors, including routing, parsing, and presentation failures.
|
|
|
|
Preserve application-defined domain classifications and supplied error identity.
|
|
Report rendering and delivery failures separately from the command's explanation
|
|
and cause, applying the [CLI reporting contract](../cli.md#presentation-failures).
|
|
Intentionally suppressed output is not a delivery failure. Present terminal
|
|
failure explanations after normal reporting finishes, avoid duplicate presentation
|
|
through core's own paths, and retain the explanation and any supplied cause in
|
|
the returned outcome.
|
|
|
|
Keep reporting state scoped to the invocation's presentation and returned outcome.
|
|
Logging and message history remain application concerns.
|
|
|
|
## Handler Inputs And Invocation State
|
|
|
|
Handlers receive typed input structs with explicit flag and operand bindings.
|
|
Use presence-aware fields where omission matters; preserve explicitly supplied
|
|
empty, false, and zero values independently of parser defaults. Context, streams,
|
|
and execution dependencies are separate from CLI inputs. Integration suites keep
|
|
their typed CLI input separate from shared acquisition state. For a configuration
|
|
operation, initialize and populate each selected scope's input independently,
|
|
applying only its applicable selector bindings; initialize shared state once for
|
|
the selected inspection invocation. Configuration input validation receives the
|
|
selected scope identity together with its applicable typed input. Named definition
|
|
inspection uses one input and one shared state. Complete applicable preflight
|
|
and input checks before shared state initialization and provider acquisition.
|
|
Factories need not run after a failure and remain uninvoked during construction,
|
|
installation, help, version, and scope discovery.
|
|
|
|
For two-selection configuration comparison, prepare and check each side's input
|
|
separately with its scope identity and selection, applying the same applicable
|
|
converted selector values to both. Finish both checks before initializing shared
|
|
state once and invoking the integration-owned pair provider. The
|
|
[consumer guide](../consumers/guide.md#configkit-scopes) and linked GoDoc own the
|
|
provider lifecycle; the [CLI reference](../cli.md#compare-configuration-selections)
|
|
owns current selector behavior. Required provider wiring follows declared
|
|
capabilities; a comparison-only scope does not require an unrelated ordinary
|
|
acquisition callback.
|
|
|
|
Omitted input and state factories supply the respective type's zero value,
|
|
including nil for pointers. Caller factories and callbacks retain responsibility
|
|
for objects they return or reference; do not promise arbitrary deep copies,
|
|
repair caller-created aliases, or silently allocate arbitrary pointer types.
|
|
Core-owned parsed collections stay independent where values are applied to
|
|
separate inputs.
|
|
|
|
Provide typed binding composition through supported public core contracts when
|
|
integrations need to apply captured converted values to selected inputs. Preserve
|
|
binding identity and presence without exposing private setters or backend state.
|
|
Required-value checks apply to the selected binding subset. Missing required
|
|
operator input is a usage failure; invalid binding selection or destination is a
|
|
wiring failure with operational classification when detected during invocation.
|
|
Metadata defects detectable during assembly remain installation errors. Input
|
|
composition does not create a second parser or a raw-argument handler model.
|
|
|
|
CommandKit keeps parsed values, collections, and presence from one invocation out
|
|
of subsequent runs. Storage allocation and safe reuse are implementation choices;
|
|
the [internal overview](../internal/overview.md#internalcobra) describes the
|
|
current backend lifecycle. Caller-owned closures and runtime state
|
|
retain their own lifecycle. Concurrent dispatch is a separate contract.
|
|
|
|
Applications may interpret parsed domain values and provide domain value parsers
|
|
through the binding system. Raw-argument parsing is not the primary handler model.
|
|
Keep input declarations available without application initialization.
|
|
|
|
## Public Facade And Dependency Direction
|
|
|
|
[ADR 0004](../adr/0004-optional-integration-modules.md) selects separate optional
|
|
integration modules with their own public package contracts. The facade and
|
|
backend isolation principles in
|
|
[ADR 0002](../adr/0002-public-facade-and-cli-backend.md) apply within those module
|
|
boundaries.
|
|
|
|
The core owns command declarations, registration, bindings, dispatch, help/version,
|
|
shared syntax, reporting mechanics, diagnostics, and outcomes. Each integration
|
|
owns its standard handlers, provider contracts, report content, adapters, and
|
|
integration-specific public types. Integrations expose operator-facing CLI tasks;
|
|
they do not provide convenience interfaces for application-internal upstream APIs.
|
|
Dependencies point from integrations toward the core; an integration may
|
|
depend on another integration when its responsibility requires that relationship.
|
|
Document those dependencies. Core public signatures, implementation imports, and
|
|
module requirements remain independent of optional integration libraries,
|
|
including dependencies introduced through tests, examples, or tools.
|
|
|
|
Public handles retain private implementation state and expose explicitly selected
|
|
methods. Any forwarding and conversions must preserve type identity, value
|
|
ownership, callback lifetime, presence, and supported public error semantics. Do
|
|
not alias public types to internal or backend types, anonymously embed those types
|
|
to promote methods, or expose implementation bridge methods.
|
|
|
|
Straightforward implementation may live in an owning public package without
|
|
expanding its exports. Introduce internal packages, interfaces, and conversions
|
|
where they simplify implementation or protect the backend boundary. Package organization and
|
|
the amount of internal layering follow implementation needs.
|
|
|
|
Public signatures, fields, callbacks, constraints, and method sets must not expose
|
|
internal or Cobra/pflag types. CommandKit does not expose its internal backend
|
|
objects or backend-specific syntax errors through its public API, including
|
|
through loosely typed values or returned errors. Caller-supplied values and errors
|
|
retain their documented handling; this boundary does not require inspecting or
|
|
transforming arbitrary application objects.
|
|
|
|
Standard contracts such as `context.Context` and `io.Writer` remain appropriate.
|
|
Upstream public types may be selected as deliberate dependencies in the
|
|
integrations that own them; that permission does not justify optional library
|
|
dependencies in the core. Core owns shared presentation categories,
|
|
and integrations adapt upstream diagnostics while preserving selected outcome
|
|
and error semantics. Application-owned input types remain application-owned.
|
|
Expose narrow core composition contracts for demonstrated integration needs,
|
|
without exporting private assembly or backend structures.
|
|
|
|
## Backend And Library Integration
|
|
|
|
[ADR 0002](../adr/0002-public-facade-and-cli-backend.md) selects Cobra with pflag
|
|
as the sole initial backend. Their types and operations stay inside an internal
|
|
adapter that translates CommandKit-owned definitions into backend machinery.
|
|
Registry logic, standard handlers, and shared internal representations remain
|
|
independent of backend-specific structures.
|
|
|
|
Reuse backend routing and parsing mechanisms, adapting them to selected
|
|
CommandKit semantics. Do not replicate Cobra's entire API through renamed
|
|
wrappers. Introduce narrow internal interfaces where actual interactions justify
|
|
them; a public backend selection or plugin framework is not part of the design.
|
|
|
|
ConfigKit and PromptKit own configuration composition, provenance, inspection
|
|
semantics, secret classification, and their native inspection representations.
|
|
Applications provide schemas, acquisition, domain resolution and validation,
|
|
and construction of inspection providers. CommandKit exposes those capabilities through supported
|
|
upstream APIs. The public contract of the adopted library version governs their
|
|
meaning and disclosure rules. When CommandKit adopts an upstream revision,
|
|
changes to those semantics flow through its integration. Adaptation and
|
|
documentation follow the adopted contract; descriptions of upstream behavior
|
|
do not establish a separate, fixed CommandKit specification of that behavior.
|
|
|
|
CommandKit owns presentation and may summarize or transform returned safe data
|
|
for different operator needs. Reports can evolve in format, organization, and
|
|
detail while respecting upstream disclosure rules and the evidence supplied by
|
|
the capability. Exact report contracts belong in the CLI reference when
|
|
implemented; changes to CommandKit's published contracts follow the release
|
|
policy.
|
|
|
|
Use independently released public contracts; do not import sibling internal
|
|
packages or depend on adjacent checkouts.
|
|
|
|
Use narrow integration contracts, reusing upstream public types where useful and
|
|
introducing CommandKit-owned abstractions where they simplify integration.
|
|
Concrete integration needs guide provider representations under
|
|
[ADR 0003](../adr/0003-configuration-scopes.md).
|
|
|
|
Use upstream safe inspection data to preserve owning-library meaning and
|
|
disclosure rules under [ADR 0004](../adr/0004-optional-integration-modules.md).
|
|
Do not reconstruct inspection reports from mutable runtime configuration or source
|
|
files when the upstream inspection API supplies captured, safe evidence. Explicit
|
|
adaptation into ordinary report values must preserve the selected evidence and
|
|
report conversion failures rather than silently changing its meaning.
|
|
|
|
CommandKit parses and forwards supplied CLI selections and overrides through the
|
|
declared acquisition boundary. Upstream libraries retain path validity,
|
|
resolution, precedence, conflict handling, and domain validation. Preserve their
|
|
errors instead of inventing a parallel override policy or retrying with altered
|
|
values. Application loading and application-owned overrides retain their own
|
|
responsibilities.
|
|
|
|
The [CLI reference](../cli.md#show-effective-configuration) owns current native
|
|
report formats and operation-specific preparation and delivery timing. Semantic
|
|
comparison exposes the adopted upstream comparison API and carries its evidence
|
|
through the provider boundary; it does not introduce a CommandKit equality engine.
|
|
|
|
## Scope And Non-goals
|
|
|
|
Keep packages and abstractions proportionate to cohesive responsibilities. The
|
|
library is not a general application runtime, dependency-injection framework,
|
|
logging system, hosted service, or standalone application. Shared vocabulary is
|
|
recommended for application-owned commands; their names and domain behavior
|
|
remain application choices.
|
|
|
|
Accepted ADRs and current CLI/API owners define selected contracts; the
|
|
[future work record](../roadmap/future.md) preserves remaining proposals.
|
|
Backend defaults and incidental consumer behavior do not establish new contracts.
|
|
A replacement backend must preserve published CLI behavior or follow deliberate compatibility
|
|
changes under the release policy.
|
|
|
|
Base restrictions and guarantees on selected requirements. Configuration and
|
|
prompt libraries retain their own confidentiality contracts; standard output
|
|
must use their safe inspection APIs without promising that arbitrary application
|
|
content is safe for public disclosure. New threat scope or restrictions require
|
|
a deliberate decision under the [agent policy](agents.md).
|