# Architecture Policy **Base Policy Version:** 1.3 **Last Updated**: 2026-10-26 **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. ## 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. ## Command And Application Ownership [ADR 0001](../adr/0001-command-dispatch-and-inputs.md) records the selected CommandKit-owned dispatcher, per-instance registry, and typed-input model. [ADR 0011](../adr/0011-captured-declarations-and-installation.md) refines declaration capture, installation, optional-family ownership, and invocation input lifetimes. 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 success-report formats. 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, under [ADR 0006](../adr/0006-command-grammar.md). 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 0014](../adr/0014-invocation-reporting.md) extends the outcome and delivery model in [ADR 0005](../adr/0005-invocation-outcomes.md). 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 outcome rules in ADR 0005 and ADR 0014. 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 under [ADR 0012](../adr/0012-typed-configuration-comparison-pairs.md). 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; rebuilding backend state is the initial strategy under [ADR 0002](../adr/0002-cobra-backend.md). 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 0010](../adr/0010-optional-integration-modules.md) scopes the root `commandkit` facade to the core module and selects separate optional integration modules with their own public package contracts. It partially supersedes [ADR 0003](../adr/0003-public-facade.md), whose remaining facade and internal adapter principles apply to the core and integrations alike. The core owns command declarations, registration, bindings, dispatch, help/version, shared syntax, diagnostics, and outcomes. Each integration owns its standard handlers, provider contracts, reports, adapters, and integration-specific public types. 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-cobra-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 native rendering. 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 0009](../adr/0009-configuration-scopes.md). Native report writers and safe inspection data preserve owning-library semantics. Loading all selected views before report output is a `config show` decision under [ADR 0007](../adr/0007-native-yaml-reports.md); other inspection operations define their own output timing. Semantic comparison exposes the adopted upstream comparison API, carrying its results and relevant metadata through the provider boundary. CommandKit owns report presentation under [ADR 0008](../adr/0008-semantic-configuration-diff.md). ## 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 [deferred-work record](../roadmap/deferred.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).