99 lines
5.3 KiB
Markdown
99 lines
5.3 KiB
Markdown
# ADR 0002: Use Cobra and pflag as the initial internal CLI backend
|
|
|
|
## Status
|
|
|
|
Accepted.
|
|
|
|
## Date
|
|
|
|
2026-10-06
|
|
|
|
## Context
|
|
|
|
CommandKit's selected dispatcher model needs nested routing, flags and operands,
|
|
generated help, usage diagnostics, and invocation execution. Reimplementing this
|
|
generic infrastructure would add work beyond the suite-specific inspection and
|
|
consistency behavior that motivates the library.
|
|
|
|
Cobra and urfave/cli v3 were the finalists. The latter's destination bindings and
|
|
duplicate controls offered a close fit for the explicit-input model. The author
|
|
strongly preferred Cobra because of its broader adoption. Familiarity and the
|
|
availability of contributors who know the framework are useful maintenance
|
|
considerations across several related applications.
|
|
|
|
The selection was based on documentation and API review. Ecosystem adoption is
|
|
the selection rationale, not evidence that every backend default is an appropriate
|
|
CommandKit contract.
|
|
|
|
## Decision
|
|
|
|
Use Cobra with pflag as the sole initial CLI backend. CommandKit translates its
|
|
registrations into backend command trees, flag bindings, and execution callbacks.
|
|
Reuse their routing, option parsing, help, context, and stream mechanisms and add
|
|
adaptation where selected CommandKit semantics require it.
|
|
|
|
CommandKit retains its own public registration API, typed inputs, standard
|
|
families, and observable contracts. Its public registration and handler APIs
|
|
use CommandKit-owned definitions and typed inputs. Cobra commands and pflag
|
|
getters stay within CommandKit's internal adapter. Independent consumer framework
|
|
use remains application-owned. [ADR 0003](0003-public-facade.md) records the
|
|
adapter and root-owned public contracts.
|
|
|
|
Applications retain process lifecycle and domain execution. ConfigKit and
|
|
PromptKit retain configuration and inspection semantics. Framework selection
|
|
does not transfer those responsibilities to Cobra or CommandKit.
|
|
|
|
Build fresh backend command/flag state and input storage per invocation. A fresh
|
|
command tree constructed from registered definitions is the initial approach.
|
|
CommandKit's tree construction uses registered metadata and leaves acquisition
|
|
callbacks uninvoked. Application startup and callback effects retain their own
|
|
lifecycle.
|
|
|
|
Implement one concrete backend. There is no initial public backend selector or
|
|
pluggable framework. A future replacement can change internal implementation
|
|
while preserving the public API and selected behavioral contracts.
|
|
|
|
## Alternatives considered
|
|
|
|
| Alternative | Advantages | Reason not selected |
|
|
| --- | --- | --- |
|
|
| urfave/cli v3 | Destination bindings for flags and named operands, presence queries, and duplicate controls fit the chosen input model closely. | Credible alternative; Cobra's broader adoption is the preferred maintenance tradeoff. |
|
|
| pflag alone | Established parsing with a smaller integration surface. | Leaves more routing, help integration, and command infrastructure to implement. |
|
|
| Kong | Compact typed-struct and tag-driven declarations. | Its main declaration model differs from the explicit-binding API; adaptation reduces its benefit. |
|
|
| Standard `flag` alone | Familiar variable binding and custom value parsing. | First-operand stopping requires adaptation for the intended syntax, with more custom command infrastructure. |
|
|
| Expose Cobra as the public API | Less adapter code and the full framework surface. | Couples consumers to backend structures and framework-specific configuration. |
|
|
| Interchangeable backends immediately | Future integration flexibility. | Adds abstraction and behavior surfaces without a current requirement. |
|
|
|
|
## Consequences
|
|
|
|
The framework supplies established generic CLI machinery. CommandKit still owns
|
|
registration conflicts, reserved families, typed bindings and presence, standard
|
|
help and diagnostics, provider integration, and selected reports and outcomes.
|
|
|
|
The adapter must accommodate explicit empty/false/zero values, fresh state,
|
|
selected repetition and operand rules, and help without configuration. Backend
|
|
features do not expand the standard automatically: for example, completion
|
|
commands remain deferred unless deliberately selected.
|
|
|
|
Backend error handling must preserve application outcomes, avoid duplicate
|
|
diagnostics, and return control to the application's entry point. Native YAML
|
|
inspection and multi-document scope display remain integration work using the
|
|
owning libraries. Choosing a framework introduces no JSON report requirement.
|
|
|
|
Exact dependency versions and attribution are selected when dependencies are
|
|
incorporated. Meaningful integration evidence must exercise the real adapter
|
|
against selected contracts. A dependency update or replacement can change CLI
|
|
behavior even with unchanged Go signatures and is subject to compatibility policy.
|
|
|
|
The [architecture policy](../policy/architecture.md) owns normative boundaries.
|
|
[ADR 0001](0001-command-dispatch-and-inputs.md) records the dispatcher and input
|
|
model.
|
|
|
|
Reviewed primary references from the selection:
|
|
|
|
- [Cobra API](https://pkg.go.dev/github.com/spf13/cobra).
|
|
- [Cobra command and help guide](https://github.com/spf13/cobra/blob/main/site/content/user_guide.md).
|
|
- [Cobra flag bindings](https://cobra.dev/docs/how-to-guides/working-with-flags/).
|
|
- [pflag syntax and extension points](https://github.com/spf13/pflag).
|
|
- [urfave/cli v3 API](https://pkg.go.dev/github.com/urfave/cli/v3).
|