319 lines
16 KiB
Markdown
319 lines
16 KiB
Markdown
# Consumer guide
|
|
|
|
CommandKit is distributed as three Go modules. Start with the core and add an
|
|
integration module only when the application uses that library. Core and
|
|
integration command factories return canonical `commandkit.Command` values.
|
|
Applications may install those alongside application-owned `RoutingRule`
|
|
declarations through `commandkit.New` or `App.Register`; routing rules are
|
|
installed at the application root, not as group children.
|
|
|
|
## Module selection
|
|
|
|
| Import | Use when |
|
|
| --- | --- |
|
|
| `gitea.maximumdirect.net/eric/CommandKit` | The application needs typed command declarations and common CLI behavior. |
|
|
| `gitea.maximumdirect.net/eric/CommandKit/integrations/ckconfig` | The application wants ConfigKit-backed configuration scopes and reports. |
|
|
| `gitea.maximumdirect.net/eric/CommandKit/integrations/ckprompt` | The application wants PromptKit engine configuration/comparison, five catalogs, named inspection, requirements discovery, request validation, or native smoke testing. |
|
|
|
|
The two integrations are independent optional imports. `ckprompt` uses the
|
|
public scope and error contracts from `ckconfig`; importing it does not add the
|
|
`config` family. An application that wants both families passes both returned
|
|
declarations to core. The [maintained examples](../../README.md#examples) show
|
|
core-only, ConfigKit-only, and composed applications.
|
|
|
|
## Go compatibility
|
|
|
|
All three modules declare a consumer minimum of Go 1.26.0. The root module also
|
|
selects ReleaseKit v0.4.2 as a Go tool, which makes that tool's module graph part
|
|
of the root consumer module requirements even though production packages do not
|
|
import ReleaseKit. The [release policy](../policy/release.md#consumer-minimum-and-release-toolchain)
|
|
defines the support assumption. Maintainers use Go 1.26.8 for validation and
|
|
publication; see the [release procedure](../release.md#release-toolchain).
|
|
|
|
## Core commands
|
|
|
|
Declare typed flags and operands with `CommandSpec[I]`, then capture them with
|
|
`NewCommand`. Bindings deliver `Supplied[T]`, which distinguishes an omitted
|
|
default from an explicitly supplied empty, false, or zero value.
|
|
|
|
```go
|
|
package example
|
|
|
|
import (
|
|
"fmt"
|
|
"strconv"
|
|
|
|
commandkit "gitea.maximumdirect.net/eric/CommandKit"
|
|
)
|
|
|
|
type GreetInput struct {
|
|
Count commandkit.Supplied[int]
|
|
}
|
|
|
|
func Greeting() commandkit.Command {
|
|
countDefault := 1
|
|
return commandkit.NewCommand(commandkit.CommandSpec[GreetInput]{
|
|
Name: "greet", Summary: "Write a greeting.",
|
|
Flags: []commandkit.Flag[GreetInput]{
|
|
commandkit.ValueFlag(
|
|
commandkit.FlagMeta{Name: "count", Usage: "Number of greetings."},
|
|
&countDefault, strconv.Atoi,
|
|
func(input *GreetInput, value commandkit.Supplied[int]) {
|
|
input.Count = value
|
|
},
|
|
),
|
|
},
|
|
Run: func(invocation commandkit.Invocation, input GreetInput) commandkit.Outcome {
|
|
if _, err := fmt.Fprintln(invocation.Reporter().Output(), input.Count.Value); err != nil {
|
|
return commandkit.Failure("Could not write the greeting.").WithCause(err)
|
|
}
|
|
return commandkit.Success()
|
|
},
|
|
})
|
|
}
|
|
```
|
|
|
|
The application supplies `context.Context`, argv without the executable name,
|
|
and output streams to `App.Execute`; it decides how the returned status maps to
|
|
process exit. `New` installs generated help/version and caller declarations as
|
|
one batch. `Register` validates each call as a batch before changing that App.
|
|
Invalid declaration errors retain their wrapped identity for `errors.Is` and
|
|
`errors.As`.
|
|
|
|
Declarations copy their metadata and slice inputs when captured, retain callback
|
|
references, and can be reused across applications. Copies of a typed binding
|
|
preserve its identity; a separately constructed lookalike does not. Supplied
|
|
values convert before input construction. A command's `NewInput` creates input
|
|
only when execution reaches it; help does not construct caller input or run
|
|
provider callbacks.
|
|
|
|
## Invocation reporting
|
|
|
|
`Invocation.Reporter()` supplies the reporter for the current handler. Use
|
|
`Output()` or `RenderOutput()` for substantive results; use `Warn`, `Info`,
|
|
`Progress`, and `Debug` for categorized messages. Queue a summary with
|
|
`AtEnd().Info` when it belongs after the handler returns. The
|
|
[CLI reference](../cli.md#reporting) owns flag grammar, visibility, prefixes,
|
|
and status behavior.
|
|
|
|
Return terminal text with `Failure(message, details...)`, `Usage(message,
|
|
details...)`, or `WithExplanation` on a domain outcome. Attach an optional Go
|
|
error separately with `WithCause`. A cause is preserved for inspection, but it
|
|
does not choose the outcome or become user-facing text. Rendering callbacks
|
|
write to their supplied writer only while the callback runs; they must not
|
|
submit another message or start another rendering operation through the same
|
|
reporter.
|
|
|
|
```go
|
|
Run: func(invocation commandkit.Invocation, input GreetInput) commandkit.Outcome {
|
|
if _, err := fmt.Fprintln(invocation.Reporter().Output(), input.Count.Value); err != nil {
|
|
return commandkit.Failure("Could not write the greeting.").WithCause(err)
|
|
}
|
|
return commandkit.Success()
|
|
}
|
|
```
|
|
|
|
After `App.Execute`, inspect the returned `Outcome`. Its `Cause` retains the
|
|
operation error; `Presentation.Output` and `Presentation.Diagnostics` report
|
|
delivery state and the first rendering or write errors for their destinations.
|
|
CommandKit does not retain a message transcript. Reporter operations for one
|
|
invocation are safe concurrently, but concurrent submission order is not
|
|
specified. The caller owns the writers passed to `Execute`; CommandKit does not
|
|
close them.
|
|
|
|
### Migrating from the previous reporting API
|
|
|
|
| Previous API | Current API |
|
|
| --- | --- |
|
|
| `invocation.Streams.Out` / `.Err` | `invocation.Reporter().Output()` and categorized reporter methods. `Streams` remains the argument to `App.Execute`. |
|
|
| `Failure(err)` / `Usage(err)` | `Failure("operator-facing explanation").WithCause(err)` / `Usage("usage explanation").WithCause(err)`. Choose the explanation deliberately; the cause alone is not printed. |
|
|
| `Outcome.Diagnostics` or terminal `SeverityError` | Submit independent messages through reporter methods. Put failure context in `Explanation`; provider `Acquired.Diagnostics` remains passive data for the owning integration to submit. |
|
|
| `ReportIncomplete`, `DiagnosticDelivery`, or `DeliveryError` | Inspect `Outcome.Presentation.Output` and `.Diagnostics`, including each `DeliveryResult.State`, `RenderError`, and `WriteError`. |
|
|
|
|
## Application-owned aliases
|
|
|
|
Pass commands and aliases together as declarations. Integration factories can
|
|
be called directly in the installation list, and command-scoped flag aliases
|
|
name the canonical command path:
|
|
|
|
```go
|
|
app, err := commandkit.New(
|
|
identity,
|
|
ckprompt.Command(suite),
|
|
commandkit.Alias("pk", "promptkit"),
|
|
commandkit.FlagAliasFor("promptkit show prompt", "--fmt", "--format"),
|
|
)
|
|
```
|
|
|
|
For a reusable collection, use `[]commandkit.Declaration`. Go does not expand a
|
|
`[]commandkit.Command` into `...commandkit.Declaration`, so convert command-only
|
|
slices when composing them with routing rules:
|
|
|
|
```go
|
|
commands := []commandkit.Command{ckprompt.Command(suite)}
|
|
declarations := make([]commandkit.Declaration, 0, len(commands)+1)
|
|
for _, command := range commands {
|
|
declarations = append(declarations, command)
|
|
}
|
|
declarations = append(declarations, commandkit.Alias("pk", "promptkit"))
|
|
app, err := commandkit.New(identity, declarations...)
|
|
```
|
|
|
|
New and Register validate each supplied batch before publishing its commands
|
|
and routing rules. Factories capture their inputs eagerly; malformed or
|
|
conflicting rules are reported at installation. Identical rules are safe to
|
|
contribute from reusable helpers. The [core example](../../examples/core) and
|
|
[composed consumer](../../integrations/ckprompt/examples/composed) show complete
|
|
maintained wiring with ordinary command behavior alongside aliases. The
|
|
[Go declarations and GoDoc](../../command.go) own the public API contracts;
|
|
the [CLI reference](../cli.md#application-owned-aliases) owns routing and
|
|
operator-visible behavior.
|
|
|
|
## ConfigKit scopes
|
|
|
|
For an application with one ordinary app configuration loader,
|
|
`ckconfig.AppCommand` supplies the state-free convenience declaration:
|
|
|
|
```go
|
|
app, err := commandkit.New(
|
|
commandkit.Identity{Name: "Example", Version: "dev"},
|
|
ckconfig.AppCommand(loadAppConfig),
|
|
)
|
|
```
|
|
|
|
`loadAppConfig` has the signature
|
|
`func(context.Context, ckconfig.Selection) (*configkit.Result[T], error)`.
|
|
Construction, installation, and help do not call it. `Selection` preserves
|
|
whether config and overlay paths were explicitly supplied, including empty
|
|
values.
|
|
|
|
Use `ckconfig.Command(ckconfig.Suite[I, S]{...})` when the application needs
|
|
multiple named scopes, selector flags, scope-aware input checks, or shared
|
|
acquisition state or a custom comparison provider. A declared `Diff` capability
|
|
uses `Scope.Compare`; `ckconfig.FromConfigKit` and `AppCommand` provide the
|
|
ConfigKit-backed implementation. Each comparison side gets its own initialized
|
|
and checked input, while state is shared by the invocation. Factory results
|
|
remain caller-owned, so separate initialization calls do not guarantee distinct
|
|
objects. See
|
|
[ckconfig.Suite's GoDoc](../../integrations/ckconfig/contracts.go) for factory
|
|
timing, omitted-factory zero values (including nil pointers), and ownership.
|
|
The application owns the state type and what it caches. `ckconfig.FromConfigKit`
|
|
adapts a typed ConfigKit loader without calling it during construction.
|
|
|
|
The `config` family provides scope discovery, validation, native effective YAML,
|
|
source inventory, path explanation, and ConfigKit-backed comparison for the
|
|
capabilities declared by its scopes. The [CLI reference](../cli.md#configuration-scopes)
|
|
owns operator syntax and report details.
|
|
|
|
## PromptKit configuration, definitions, and requirements
|
|
|
|
`ckprompt.ConfigScope(loadEngine)` returns a `ckconfig.Scope` for the PromptKit
|
|
engine's captured configuration. Add that scope to a `ckconfig.Suite` to expose
|
|
it under `config` with validate/show/sources/explain and native diff operations;
|
|
it does not install PromptKit catalog, definition, or requirements commands.
|
|
|
|
`ckprompt.FromEngine(loadEngine)` supplies eight callbacks: prompt, profile,
|
|
backend, namespace, and collection catalogs; named prompt and profile
|
|
inspection; and native requirements discovery. Concrete request validation and
|
|
smoke testing are separate capabilities, added explicitly with
|
|
`ckprompt.WithRequestValidation` and `ckprompt.WithSmokeTesting`. The suite has
|
|
ten independently optional callbacks in total. `ckprompt.Command(suite)` creates
|
|
only operations whose callbacks are present; discovery, validation, and smoke
|
|
testing can be installed independently. A composed suite can enable both
|
|
additional operations:
|
|
|
|
```go
|
|
suite := ckprompt.FromEngine(loadEngine)
|
|
suite = ckprompt.WithRequestValidation(suite, loadEngine, buildRequest)
|
|
suite = ckprompt.WithSmokeTesting(suite, loadEngine, nil)
|
|
suite.NewInput = newInput
|
|
suite.NewState = newState
|
|
suite.Selectors = selectors
|
|
definitionCommand := ckprompt.Command(suite)
|
|
```
|
|
|
|
A validation-only suite can start empty. With application types named `Input`
|
|
and `State`, a nil builder forwards the request fields populated by standard
|
|
flags directly to PromptKit:
|
|
|
|
```go
|
|
suite := ckprompt.WithRequestValidation(
|
|
ckprompt.Suite[Input, State]{}, loadEngine, nil,
|
|
)
|
|
validationCommand := ckprompt.Command(suite)
|
|
```
|
|
|
|
If the loader is nil, the returned suite retains a wiring issue for installation
|
|
to report, even if capabilities are narrowed later. A builder runs before the
|
|
engine loader and receives the seed request, selection, typed input, shared
|
|
state, and invocation context. It returns the
|
|
concrete request; the adapter does not merge seed fields back afterward. The
|
|
loader receives the original selection. Builders should start from the seed,
|
|
preserve operator values and bindings, and apply defaults only when a map key is
|
|
absent, so explicitly supplied empty values stay meaningful. Applications that
|
|
validate and then execute a request are encouraged to share their request
|
|
construction logic between those paths.
|
|
|
|
The eight catalog and inspection callbacks and the two explicit additions are
|
|
independently optional. For catalogs without named or requirements inspection,
|
|
narrow the suite before command capture:
|
|
|
|
```go
|
|
definitions := ckprompt.FromEngine(loadEngine)
|
|
definitions.InspectPrompt = nil
|
|
definitions.InspectProfile = nil
|
|
definitions.InspectRequirements = nil
|
|
definitionCommand := ckprompt.Command(definitions)
|
|
```
|
|
|
|
Each selected inspection, requirements, validation, smoke, or catalog operation
|
|
prepares one input, applies its captured selectors, checks that input, and
|
|
initializes one state value when those steps are reached. The bundled validation
|
|
adapter delegates concrete request preparation to PromptKit and carries its
|
|
native errors plus engine-loading diagnostics through the acquisition. It does
|
|
not call the model or retain a prepared execution snapshot. See
|
|
[ckprompt.Suite's GoDoc](../../integrations/ckprompt/adapters.go) for factory
|
|
timing, omitted-factory zero values, and caller-owned objects and effects.
|
|
The loader receives invocation context, explicitly supplied selection, input,
|
|
and state. `FromEngine` uses PromptKit's public listing and inspection methods,
|
|
including `Engine.InspectRequirements`; validation must be opted into separately
|
|
and uses `Engine.ValidateRequest`.
|
|
|
|
Catalog, named definition inspection, and requirements discovery do not render
|
|
messages or load request artifacts. Concrete request validation follows native
|
|
PromptKit preparation, which can resolve prompt/profile resources, load
|
|
artifacts and schemas, render messages, and perform applicable configuration
|
|
and credential checks. It does not make a model call or certify that a later
|
|
execution will succeed. Application loaders and direct callbacks retain their
|
|
own effects. Smoke testing explicitly invokes one native PromptKit diagnostic
|
|
or all four in order. Native inference checks use the configured public
|
|
`promptkit.LLMClient`; applications retain ownership of client and probe
|
|
configuration. A builder may customize the seeded native request, and its
|
|
complete return value is authoritative. The [CLI reference](../cli.md#promptkit-smoke-testing),
|
|
[definition inspection](../cli.md#promptkit-definition-inspection), and
|
|
[requirements contract](../cli.md#promptkit-requirements) own operator syntax
|
|
and reports.
|
|
|
|
The [composed example](../../integrations/ckprompt/examples/composed/README.md)
|
|
combines app and PromptKit config scopes, comparison and catalogs, named and
|
|
requirements inspection, request validation, smoke testing, and an
|
|
application-owned `session restore` command.
|
|
|
|
## Outcomes and ownership
|
|
|
|
Core classifies usage and operational failures while preserving application
|
|
domain outcomes and supported error identity. Applications choose domain
|
|
classification and status. A terminal explanation is presented separately from
|
|
the optional operation cause, while report and diagnostic delivery observations
|
|
are available in `Outcome.Presentation`. The caller owns process startup,
|
|
signal handling, and exit mapping; `Execute` never exits the process.
|
|
|
|
Go declarations and GoDoc own exact exported contracts. ConfigKit owns
|
|
configuration decoding, validation, and provenance. PromptKit owns prompt
|
|
formats, profile resolution, and inspection details. See the
|
|
[ConfigKit v0.8.0 inspection API](https://gitea.maximumdirect.net/eric/ConfigKit/src/commit/137769f3f18a370c68444242fb5d88e620e307e5/inspection.go),
|
|
[PromptKit engine methods](https://gitea.maximumdirect.net/eric/promptkit/src/commit/9178f3eb91c2b2138caa78e22be93c048b4bc992/engine.go),
|
|
[configuration inspection](https://gitea.maximumdirect.net/eric/promptkit/src/commit/9178f3eb91c2b2138caa78e22be93c048b4bc992/configuration_inspection.go),
|
|
[smoke diagnostics](https://gitea.maximumdirect.net/eric/promptkit/src/commit/9178f3eb91c2b2138caa78e22be93c048b4bc992/smoke_diagnostics.go),
|
|
and [PromptKit v0.16.0 consumer guidance](https://gitea.maximumdirect.net/eric/promptkit/src/commit/9178f3eb91c2b2138caa78e22be93c048b4bc992/docs/consumers/pkg-promptkit.md).
|