Refresh operator documentation and CLI help

This commit is contained in:
2026-11-07 23:31:14 +00:00
parent 69fe35c480
commit c648d1de33
24 changed files with 1088 additions and 812 deletions

View File

@@ -1,26 +1,22 @@
# CommandKit # CommandKit
CommandKit is a Go library for typed command declarations, shared CLI behavior, CommandKit helps Go applications build consistent command-line interfaces. It
and application-owned execution. The core `commandkit` module is usable by provides typed flags and arguments, help, output formatting, and error reporting.
itself. ConfigKit and PromptKit support lives in separately versioned optional Optional integrations add commands for inspecting configuration and working with
modules, so applications choose which upstream libraries they add. PromptKit.
The core captures reusable command declarations, validates installation batches CommandKit is in alpha. Start with the [consumer guide](docs/consumers/guide.md#core-commands)
before changing an application's registry, converts typed inputs before to define a command, or run the [core example](examples/core/README.md).
constructing them, and returns outcomes without exiting the process. Its Applications supply their own command handlers and decide when to exit;
[consumer guide](docs/consumers/guide.md) covers declaration, invocation CommandKit returns the result of each invocation.
and reporting. Each handler receives one invocation reporter for
substantive output, categorized messages, and terminal explanations; `Execute`
returns delivery observations with the outcome. The [CLI reference](docs/cli.md)
defines the shared visibility policy.
## Modules ## Modules
| Module | Package | Provides | | Module | Package | Provides |
| --- | --- | --- | | --- | --- | --- |
| `go.maximumdirect.net/commandkit` | `commandkit` | Typed commands, bindings, execution reporting and outcomes, help, and version. | | `go.maximumdirect.net/commandkit` | `commandkit` | Commands, typed inputs, shared output and error reporting, help, and version. |
| `go.maximumdirect.net/ckconfig` | `ckconfig` | ConfigKit-backed `config` scopes, including configuration source evidence. | | `go.maximumdirect.net/ckconfig` | `ckconfig` | Commands to view, validate, explain, and compare ConfigKit configuration. |
| `go.maximumdirect.net/ckprompt` | `ckprompt` | PromptKit engine configuration/comparison, five catalogs, named inspection, requirements discovery, concrete request validation, and native smoke tests. | | `go.maximumdirect.net/ckprompt` | `ckprompt` | Commands to list and inspect PromptKit resources, discover required inputs, validate and preview requests, and run smoke tests. |
Importing an integration does not install commands. Core and the integrations Importing an integration does not install commands. Core and the integrations
are versioned separately; see the [consumer guide](docs/consumers/guide.md#module-selection) are versioned separately; see the [consumer guide](docs/consumers/guide.md#module-selection)

View File

@@ -32,8 +32,8 @@ func (a *App) builtinCommands() []Declaration {
help := captureCommand(CommandSpec[helpInput]{ help := captureCommand(CommandSpec[helpInput]{
Name: "help", Name: "help",
Summary: "Show help for commands.", Summary: "Show help for commands.",
Description: "Describe registered commands and their inputs.", Description: "Show available commands, flags, and arguments.",
Arguments: []Argument[helpInput]{RepeatArgument(ArgumentMeta{Name: "COMMAND", Usage: "registered command path"}, 0, -1, Arguments: []Argument[helpInput]{RepeatArgument(ArgumentMeta{Name: "COMMAND", Usage: "Command path to describe."}, 0, -1,
func(value string) (string, error) { return value, nil }, func(value string) (string, error) { return value, nil },
func(input *helpInput, value Supplied[[]string]) { input.Targets = value })}, func(input *helpInput, value Supplied[[]string]) { input.Targets = value })},
}, func(current commandExecution, input helpInput) Outcome { }, func(current commandExecution, input helpInput) Outcome {
@@ -43,9 +43,9 @@ func (a *App) builtinCommands() []Declaration {
version := NewCommand(CommandSpec[versionInput]{ version := NewCommand(CommandSpec[versionInput]{
Name: "version", Name: "version",
Summary: "Show application or CommandKit version.", Summary: "Show application or CommandKit version.",
Description: "Report identity and build metadata without loading application configuration.", Description: "Show the name, version, and revision without loading application configuration.",
Flags: []Flag[versionInput]{ Flags: []Flag[versionInput]{
ValueFlag(FlagMeta{Name: "scope", Usage: "version subject", Completion: CompleteChoices(CompletionChoice{Value: "app"}, CompletionChoice{Value: "commandkit"})}, &scopeDefault, parseVersionScope, func(input *versionInput, value Supplied[string]) { input.Scope = value.Value }), ValueFlag(FlagMeta{Name: "scope", Usage: "Show the app or CommandKit version.", Completion: CompleteChoices(CompletionChoice{Value: "app"}, CompletionChoice{Value: "commandkit"})}, &scopeDefault, parseVersionScope, func(input *versionInput, value Supplied[string]) { input.Scope = value.Value }),
}, },
Run: func(invocation Invocation, input versionInput) Outcome { Run: func(invocation Invocation, input versionInput) Outcome {
identity := a.identity identity := a.identity

16
doc.go
View File

@@ -1,8 +1,10 @@
// Package commandkit provides the core instance-owned CLI dispatcher, typed // Package commandkit helps Go applications build consistent command-line
// command declarations, application-owned command and flag aliases, input // interfaces with typed flags and arguments, help, and shared output formatting.
// bindings, invocation-scoped reporting, and outcomes with separate operation // Define commands with NewCommand and install them with New or App.Register.
// causes and presentation observations. New and App.Register accept canonical // Commands and command or flag aliases can be installed together.
// Command declarations and RoutingRule declarations together. Optional //
// integration modules provide ConfigKit and PromptKit-specific commands; // App.Execute runs a command and returns an Outcome; the application decides
// importing those modules does not install their commands. // when to exit. Handlers use Invocation.Reporter for output and messages.
// Optional ckconfig and ckprompt modules add inspection and testing commands;
// applications install those commands explicitly.
package commandkit package commandkit

File diff suppressed because it is too large Load Diff

View File

@@ -1,40 +1,46 @@
# Consumer guide # Consumer guide
CommandKit is distributed as three Go modules. Start with the core and add an Start with core to build commands with typed inputs and shared output
integration module only when the application uses that library. Core and formatting. Add an integration when your application uses ConfigKit or
compatible integration command factories return canonical `commandkit.Command` values. PromptKit. The [core command example](#core-commands) below shows the basic
Applications may install those alongside application-owned `RoutingRule` API; the [maintained examples](../../README.md#examples) show complete
declarations through `commandkit.New` or `App.Register`; routing rules are applications.
installed at the application root, not as group children.
## Module selection ## Module selection
| Import | Use when | | Import | Use when |
| --- | --- | | --- | --- |
| `go.maximumdirect.net/commandkit` | The application needs typed command declarations and common CLI behavior. | | `go.maximumdirect.net/commandkit` | You need commands, typed inputs, help, and common output handling. |
| `go.maximumdirect.net/ckconfig` | The application wants ConfigKit-backed configuration scopes and reports. | | `go.maximumdirect.net/ckconfig` | You want operators to view, validate, explain, and compare ConfigKit configuration. |
| `go.maximumdirect.net/ckprompt` | The application wants PromptKit engine configuration/comparison, five catalogs, named inspection, requirements discovery, request validation, or native smoke testing. | | `go.maximumdirect.net/ckprompt` | You want operators to inspect PromptKit resources, check and preview requests, or run smoke tests. |
Core v0.4.0 is published. The previously published matched releases are core The following distinguishes published combinations from the current checkout:
v0.3.0, ckconfig v0.2.0, and ckprompt v0.2.0.
The published ckconfig v0.3.0 uses ConfigKit v1.1.0 and does not compose
with ckprompt v0.2.0, which retains ckconfig v0.2.0 and ConfigKit v0.8.0.
Install the current core with `go get go.maximumdirect.net/commandkit@v0.4.0`.
For the older matched integration set, select core v0.3.0 and the corresponding
ckconfig or ckprompt v0.2.0 release together.
Published ckconfig v0.4.0 uses core v0.4.0 and ConfigKit v1.1.0. The ckprompt | Selection | Core | ckconfig | ckprompt | Upstream libraries and status |
v0.3.0 candidate targets those releases and PromptKit v0.20.0. A Go 1.27.0 | --- | --- | --- | --- | --- |
workspace may compose the three local modules. Current ckprompt source uses a | Published core | v0.4.0 | — | — | Usable independently. |
diagnostic helper introduced in local ckconfig source that is absent from | Published ConfigKit integration | v0.4.0 | v0.4.0 | — | ConfigKit v1.1.0. |
released ckconfig v0.4.0; independent ckprompt builds require release and | Earlier matched integration set | v0.3.0 | v0.2.0 | v0.2.0 | ConfigKit v0.8.0 and PromptKit v0.16.0, using their earlier import paths. |
dependency alignment described in [future work](../roadmap/future.md#pending-release-and-integration-work). | Current source | Local | Local | Local | ConfigKit v1.1.0 and PromptKit v0.20.0; use an aligned workspace until release dependencies are updated. |
The two integrations are independent optional imports. `ckprompt` uses the Install the published core with:
public scope and error contracts from `ckconfig`; importing it does not add the
`config` family. An application that wants both families passes both returned ```sh
declarations to core. The [maintained examples](../../README.md#examples) show go get go.maximumdirect.net/commandkit@v0.4.0
core-only, ConfigKit-only, and composed applications. ```
Core v0.5.0 and ckprompt v0.3.0 have unpublished candidate notes. Current
ckprompt source calls `ckconfig.AdaptDiagnostics`, which is absent from its
selected released ckconfig v0.4.0 dependency. It therefore needs local
ckconfig source in the workspace until [release
alignment](../roadmap/future.md#pending-release-and-integration-work) is
complete. Published ckconfig v0.3.0 also uses ConfigKit v1.1.0 and does not
compose with ckprompt v0.2.0's earlier ConfigKit dependency.
Importing a module does not install its commands. Pass commands to
`commandkit.New` or `App.Register` explicitly. ckprompt depends on ckconfig's
public APIs, but you can install its `promptkit` commands without installing
the `config` family.
## Go compatibility ## Go compatibility
@@ -57,7 +63,6 @@ default from an explicitly supplied empty, false, or zero value.
package example package example
import ( import (
"fmt"
"strconv" "strconv"
commandkit "go.maximumdirect.net/commandkit" commandkit "go.maximumdirect.net/commandkit"
@@ -81,8 +86,12 @@ func Greeting() commandkit.Command {
), ),
}, },
Run: func(invocation commandkit.Invocation, input GreetInput) commandkit.Outcome { Run: func(invocation commandkit.Invocation, input GreetInput) commandkit.Outcome {
if _, err := fmt.Fprintln(invocation.Reporter().Output(), input.Count.Value); err != nil { greetings := []string{}
return commandkit.Failure("Could not write the greeting.").WithCause(err) for i := 0; i < input.Count.Value; i++ {
greetings = append(greetings, "Hello!")
}
if err := invocation.Reporter().Report(commandkit.Report{Value: greetings}); err != nil {
return commandkit.Failure("Could not write the greetings.").WithCause(err)
} }
return commandkit.Success() return commandkit.Success()
}, },
@@ -90,6 +99,10 @@ func Greeting() commandkit.Command {
} }
``` ```
Install `Greeting()` with `commandkit.New(identity, Greeting())`. By default,
`greet` prints `Hello!`; `greet --count=2` prints it twice. Add `--format
json` to receive a JSON list. A count of zero produces an empty list.
The application supplies `context.Context`, argv without the executable name, The application supplies `context.Context`, argv without the executable name,
and output streams to `App.Execute`; it decides how the returned status maps to 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 process exit. `New` installs generated help/version and caller declarations as
@@ -134,15 +147,13 @@ installation alongside aliases and integration commands.
## Invocation reporting ## Invocation reporting
`Invocation.Reporter()` supplies the reporter for the current handler. Use Use `Invocation.Reporter().Report` to print a value in the selected output
`Report()` for formatted substantive values and optional text templates; format. Pass ordinary Go values and, optionally, a `text/template` for text
use `Output()` or `RenderOutput()` for deliberate raw output. Use `Warn`, `Info`, output. Use `Warn`, `Info`, `Progress`, and `Debug` for categorized messages.
`Progress`, and `Debug` for categorized messages. Queue a summary with Queue a summary with `AtEnd().Info` when it belongs after the handler returns.
`AtEnd().Info` when it belongs after the handler returns. Deferred submissions Deferred submissions are accepted until finalization begins; later submissions
are accepted until finalization begins; later submissions return return `ErrReporterClosed`. The [CLI reference](../cli.md#reporting) owns flag
`ErrReporterClosed`. The grammar, visibility, prefixes, and status behavior.
[CLI reference](../cli.md#reporting) owns flag grammar, visibility, prefixes,
and status behavior.
Reports use JSON serialization to establish the common value representation Reports use JSON serialization to establish the common value representation
for YAML and JSON. A text template receives the original value; without one, for YAML and JSON. A text template receives the original value; without one,
@@ -159,22 +170,29 @@ write to their supplied writer only while the callback runs; they must not
submit another message or start another rendering operation through the same submit another message or start another rendering operation through the same
reporter. reporter.
For example, a handler can report a count as a small mapping:
```go ```go
Run: func(invocation commandkit.Invocation, input GreetInput) commandkit.Outcome { if err := invocation.Reporter().Report(commandkit.Report{
if _, err := fmt.Fprintln(invocation.Reporter().Output(), input.Count.Value); err != nil { Value: map[string]int{"count": input.Count.Value},
return commandkit.Failure("Could not write the greeting.").WithCause(err) }); err != nil {
} return commandkit.Failure("Could not write the count.").WithCause(err)
return commandkit.Success()
} }
return commandkit.Success()
``` ```
This uses YAML automatically and supports `--format json` without a separate
encoder. Use `Output()` or `RenderOutput()` instead when you deliberately need
raw output; `--format` does not reformat those bytes.
After `App.Execute`, inspect the returned `Outcome`. Its `Cause` retains the After `App.Execute`, inspect the returned `Outcome`. Its `Cause` retains the
operation error; `Presentation.Output` and `Presentation.Diagnostics` report operation error; `Presentation.Output` and `Presentation.Diagnostics` report
delivery state and the first rendering or write errors for their destinations. delivery state and the first rendering or write errors for their destinations.
CommandKit does not retain a message transcript. Reporter operations for one Joined operation errors support `errors.Is` and `errors.As` where the
invocation are safe concurrently, but concurrent submission order is not underlying errors do. CommandKit does not retain a message transcript.
specified. The caller owns the writers passed to `Execute`; CommandKit does not Reporter operations for one invocation are safe concurrently, but concurrent
close them. submission order is not specified. The caller owns the writers passed to
`Execute`; CommandKit does not close them.
## Application-owned aliases ## Application-owned aliases
@@ -235,18 +253,22 @@ values.
Use `ckconfig.Command(ckconfig.Suite[I, S]{...})` when the application needs Use `ckconfig.Command(ckconfig.Suite[I, S]{...})` when the application needs
multiple named scopes, selector flags, scope-aware input checks, or shared multiple named scopes, selector flags, scope-aware input checks, or shared
acquisition state or a custom comparison provider. A declared `Diff` capability acquisition state or a custom comparison provider. A declared `Diff`
uses `Scope.Compare`; `ckconfig.FromConfigKit` and `AppCommand` provide the capability uses `Scope.Compare`; `ckconfig.FromConfigKit` and `AppCommand`
ConfigKit-backed implementation. `Selector.AgainstName` opts a selector into an provide the ConfigKit-backed implementation. `Selector.AgainstName` opts a
independent right-side flag. Each comparison side gets its own initialized and selector into an independent right-side flag. Each comparison side gets its
checked input, with only its supplied selectors applied; state is shared by the own initialized and checked input, with only its supplied selectors applied;
invocation. Factory results state is shared by the invocation. Factory results remain caller-owned, so
remain caller-owned, so separate initialization calls do not guarantee distinct separate initialization calls do not guarantee distinct objects. See
objects. See
[ckconfig.Suite's GoDoc](../../integrations/ckconfig/contracts.go) for factory [ckconfig.Suite's GoDoc](../../integrations/ckconfig/contracts.go) for factory
timing, omitted-factory zero values (including nil pointers), and ownership. timing, omitted-factory zero values (including nil pointers), and ownership.
The application owns the state type and what it caches. `ckconfig.FromConfigKit` The application owns the state type and what it caches.
adapts a typed ConfigKit loader without calling it during construction. `ckconfig.FromConfigKit` adapts a typed ConfigKit loader without calling it
during construction. The bundled comparison adapters call the loader for the
left side before the right, retain left diagnostics if right loading fails,
and collect diagnostics from both loads before native comparison. Custom
comparison callbacks own their loading and diagnostics; loader calls need not
reread sources if the application caches them.
The `config` family provides scope discovery, validation, safe effective configuration display, The `config` family provides scope discovery, validation, safe effective configuration display,
source inventory, path explanation, and ConfigKit-backed comparison for the source inventory, path explanation, and ConfigKit-backed comparison for the
@@ -274,6 +296,8 @@ it does not install PromptKit catalog, definition, or requirements commands.
Its override feature is disabled because the released PromptKit configuration Its override feature is disabled because the released PromptKit configuration
loader does not accept ConfigKit override records. loader does not accept ConfigKit override records.
### Install resource commands and optional checks
`ckprompt.FromEngine(loadEngine)` supplies nine callbacks: prompt, profile, `ckprompt.FromEngine(loadEngine)` supplies nine callbacks: prompt, profile,
backend, namespace, and collection catalogs; named prompt, profile, and backend backend, namespace, and collection catalogs; named prompt, profile, and backend
inspection; and native requirements discovery. Concrete request validation, inspection; and native requirements discovery. Concrete request validation,
@@ -308,6 +332,8 @@ suite := ckprompt.WithRequestValidation(
validationCommand := ckprompt.Command(suite) validationCommand := ckprompt.Command(suite)
``` ```
### Request builders and loading
If the loader is nil, the returned suite retains a wiring issue for installation 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 to report, even if capabilities are narrowed later. A builder runs before the
engine loader and receives the seed request, selection, typed input, shared engine loader and receives the seed request, selection, typed input, shared
@@ -357,6 +383,8 @@ same canonical request flags into their own input types. Each collection exposes
individual handles and an `All` method, so a command can choose its applicable individual handles and an `All` method, so a command can choose its applicable
subset. The application decides how to apply the resulting values to its request. subset. The application decides how to apply the resulting values to its request.
### Enable namespace flags
`ckprompt.WithNamespaces` enables standard resource namespace selection from `ckprompt.WithNamespaces` enables standard resource namespace selection from
application-supplied defaults. Loaders used with this option should leave view application-supplied defaults. Loaders used with this option should leave view
selection to the adapter. Without it, a loader can supply its own engine view. selection to the adapter. Without it, a loader can supply its own engine view.

View File

@@ -62,7 +62,7 @@ capability proposals in [future work](roadmap/future.md).
| Public facade or adapter boundaries | [Internal overview](internal/overview.md), [ADR 0002](adr/0002-public-facade-and-cli-backend.md), [ADR 0004](adr/0004-optional-integration-modules.md), and the architecture policy | | Public facade or adapter boundaries | [Internal overview](internal/overview.md), [ADR 0002](adr/0002-public-facade-and-cli-backend.md), [ADR 0004](adr/0004-optional-integration-modules.md), and the architecture policy |
| Module ownership and public contracts | [Consumer guide](consumers/guide.md), [internal overview](internal/overview.md), [core GoDoc](../doc.go), [ckconfig GoDoc](../integrations/ckconfig/doc.go), [ckprompt GoDoc](../integrations/ckprompt/doc.go), and applicable ADRs | | Module ownership and public contracts | [Consumer guide](consumers/guide.md), [internal overview](internal/overview.md), [core GoDoc](../doc.go), [ckconfig GoDoc](../integrations/ckconfig/doc.go), [ckprompt GoDoc](../integrations/ckprompt/doc.go), and applicable ADRs |
| Unfinished work and capability proposals | [Future work](roadmap/future.md) | | Unfinished work and capability proposals | [Future work](roadmap/future.md) |
| Documentation refresh sprint | [Documentation roadmap](roadmap/documentation-refresh.md) | | Documentation refresh record | [Documentation roadmap](roadmap/documentation-refresh.md) |
| Completed planning and implementation history | [Completed dependency upgrades, PromptKit validation, discovery, smoke testing, and remediation](https://gitea.maximumdirect.net/eric/CommandKit/src/commit/a6278a6d9f940948ec7745955d745523aaff0734/docs/roadmap), [earlier ConfigKit and PromptKit adoption and remediation](https://gitea.maximumdirect.net/eric/CommandKit/src/commit/8a82620dfcd34c0ae56bbecb0d014eb49786bc92/docs/roadmap), [earlier retired records](https://gitea.maximumdirect.net/eric/CommandKit/src/commit/6bc37e7ba64ca0920b4d0cc77039a18d4006b24e/docs/roadmap), and [completed module implementation and remediation](https://gitea.maximumdirect.net/eric/CommandKit/src/commit/bb2528532b78d30e52f5082e491a5e1fd9b0fb99/docs/roadmap) in Git history | | Completed planning and implementation history | [Completed dependency upgrades, PromptKit validation, discovery, smoke testing, and remediation](https://gitea.maximumdirect.net/eric/CommandKit/src/commit/a6278a6d9f940948ec7745955d745523aaff0734/docs/roadmap), [earlier ConfigKit and PromptKit adoption and remediation](https://gitea.maximumdirect.net/eric/CommandKit/src/commit/8a82620dfcd34c0ae56bbecb0d014eb49786bc92/docs/roadmap), [earlier retired records](https://gitea.maximumdirect.net/eric/CommandKit/src/commit/6bc37e7ba64ca0920b4d0cc77039a18d4006b24e/docs/roadmap), and [completed module implementation and remediation](https://gitea.maximumdirect.net/eric/CommandKit/src/commit/bb2528532b78d30e52f5082e491a5e1fd9b0fb99/docs/roadmap) in Git history |
| Release tooling | [Maintainer release procedure](release.md) | | Release tooling | [Maintainer release procedure](release.md) |
| Performance maintenance | [Internal overview](internal/overview.md), existing benchmarks, and [possible further efficiency work](roadmap/future.md#possible-further-efficiency-work) | | Performance maintenance | [Internal overview](internal/overview.md), existing benchmarks, and [possible further efficiency work](roadmap/future.md#possible-further-efficiency-work) |
@@ -107,8 +107,16 @@ Sibling-checkout references in retired planning records are historical review
evidence, not build dependencies. Implemented contracts belong in CommandKit evidence, not build dependencies. Implemented contracts belong in CommandKit
under their canonical owners. under their canonical owners.
The root module does not traverse nested modules. Preserve the ignored `go.work` The root module does not traverse nested modules. With Go 1.27.0 on `PATH`,
and `go.work.sum`; use `GOWORK=off GOTOOLCHAIN=local` for dependency preparation create the local workspace from the repository root if `go.work` is absent:
```sh
go work init . ./integrations/ckconfig ./integrations/ckprompt
```
If a workspace already exists, ensure it includes these three modules. Preserve
the ignored `go.work` and `go.work.sum`; do not commit them. Use
`GOWORK=off GOTOOLCHAIN=local` for dependency preparation
and independent module suites. The integrations select released core v0.4.0; and independent module suites. The integrations select released core v0.4.0;
ckprompt also selects released ckconfig v0.4.0. ckprompt also selects released ckconfig v0.4.0.
Current ckprompt source requires a ckconfig helper absent from that release, so Current ckprompt source requires a ckconfig helper absent from that release, so

View File

@@ -1,32 +1,28 @@
# CommandKit v0.5.0 # CommandKit v0.5.0
CommandKit v0.5.0 fixes defects in deferred reporting and YAML value preservation, CommandKit v0.5.0 fixes lost deferred messages and preserves YAML value types
reduces repeated work in command installation and alias help, and simplifies more accurately. It also reduces repeated work when installing commands and
typed input preparation and replay of captured flags. showing alias help, and refreshes documentation and help text.
## Changes ## Changes
- Acceptance of deferred messages now closes atomically when invocation finalization - Deferred messages accepted before finalization are retained for final reporting;
begins. Concurrent submissions are included in the final batch or rejected they can no longer be silently lost when a handler finishes. Later submissions return
with `ErrReporterClosed`; accepted messages can no longer be silently lost `ErrReporterClosed`.
between batch detachment and closure. - Finished invocations release their direct references to output and diagnostic
- Finalized reporting state releases its direct references to borrowed output writers while keeping delivery results available. Applications still own the
and diagnostic writers while retaining presentation results. Writers remain writers.
caller-owned. - `DecodeYAMLReport` preserves numeric-looking strings as strings. YAML report
- `DecodeYAMLReport` follows resolved YAML scalar tags, preserving numeric-looking output also preserves explicitly tagged numbers beyond the YAML resolver's
strings as strings. YAML report rendering preserves explicit numeric meaning ordinary numeric range.
for values beyond the resolver's ordinary numeric range. - Command installation, alias help, and typed input handling avoid repeated
- Compilation of flag aliases reuses resolved chain suffixes. Alias discovery and work. Parsing and completion share flag handling while retaining their
help reuse the existing source tree, and declaration validation reuses one different treatment of errors and unfinished input.
scratch path across siblings, formatting paths only for diagnostics. - The reporting example now works when its optional scenario is omitted, and
- Typed input preparation reconstructs occurrence order without general sorting; the interactive completion fixture no longer conflicts with `--format`.
replay of captured flags merges already ordered streams. Parsing and completion `FlagMeta` documents existing naming and reserved-spelling rules.
share flag-consumption mechanics while retaining their distinct handling of - READMEs, CLI instructions, examples, and generated help use clearer language
errors and incomplete input. and explain common tasks before implementation details.
- The core reporting example preserves its default scenario when the optional
operand is omitted. The interactive completion fixture no longer collides with
the reserved `--format` flag. `FlagMeta` documentation now states the existing
naming and reserved-spelling rules.
## Compatibility and upgrade ## Compatibility and upgrade

View File

@@ -1,7 +1,7 @@
# Documentation refresh # Documentation refresh
Status: agreed scope; ready for implementation planning. The refresh has not Status: implemented and verified. Release/dependency alignment remains separate
been implemented. work in [future.md](future.md#pending-release-and-integration-work).
## Purpose ## Purpose
@@ -197,18 +197,57 @@ Do not add wording snapshots, readability gates, or a new checker framework.
Record workspace and independent-module results separately, including any Record workspace and independent-module results separately, including any
dependency limitation. This work adds no release gates. dependency limitation. This work adds no release gates.
- [ ] README openings explain purpose and give a clear starting path. - [x] README openings explain purpose and give a clear starting path.
- [ ] CLI sections explain operator tasks before reference detail; necessary - [x] CLI sections explain operator tasks before reference detail; necessary
behavior, report fields, status rules, and limitations remain discoverable. behavior, report fields, status rules, and limitations remain discoverable.
- [ ] Example setup is explicit, commands have nearby explanations, and intended - [x] Example setup is explicit, commands have nearby explanations, and intended
failures are labeled. failures are labeled.
- [ ] Consumer guidance demonstrates formatted reporting, has a coherent initial - [x] Consumer guidance demonstrates formatted reporting, has a coherent initial
example, and distinguishes published compatibility from current source needs. example, and distinguishes published compatibility from current source needs.
- [ ] Package introductions and generated help use clear, accurate language; - [x] Package introductions and generated help use clear, accurate language;
precise API contracts remain intact. precise API contracts remain intact.
- [ ] Unpublished release notes explain benefits and consumer impact while - [x] Unpublished release notes explain benefits and consumer impact while
historical records and required notices remain preserved. historical records and required notices remain preserved.
- [ ] Changed commands, snippets, and help have appropriate verification; local - [x] Changed commands, snippets, and help have appropriate verification; local
links and Markdown whitespace checks pass. links and Markdown whitespace checks pass.
- [ ] Final review confirms consistent terminology, canonical ownership, and no - [x] Final review confirms consistent terminology, canonical ownership, and no
unintended behavior or contract changes. unintended behavior or contract changes.
## Implementation and verification
Completed the six work areas above. READMEs and package introductions now lead
with purpose and starting points; the CLI reference separates operator tasks
from report detail and developer wiring. Examples are grouped by task with
setup, expected results, and intentional failures explained nearby. The consumer
guide demonstrates shared report formatting and distinguishes published modules
from current source. Help strings and unpublished candidate notes use the same
plain language. Exact symbol contracts and runtime behavior were preserved.
Verification used Go 1.27.0 and existing cached dependencies:
- The aligned workspace suites passed for core, ckconfig, and ckprompt, including
their maintained examples.
- Independent core and ckconfig suites passed with `GOWORK=off`.
- Independent ckprompt compilation confirmed the existing dependency limitation:
released ckconfig v0.4.0 lacks `AdaptDiagnostics`. No module requirements,
checksums, or workspace files were changed to hide it. Its README, example,
consumer guidance, and candidate note identify the pending alignment.
- All 48 `go run` invocations in the three example READMEs were exercised with
binaries built from the aligned workspace, from the documented directories.
Results matched the walkthroughs, including two failed-load examples, missing
request input, and comparison status 3. Shared help and completion behavior
also passed the existing suites; representative rendered help was inspected.
- Both new consumer-guide report snippets compiled in a temporary consumer using
local core. Six checks confirmed greeting counts, empty-list output, and YAML
and JSON formatting.
- Local Markdown links, including incoming links to renamed sections, and
whitespace were checked. Go source changes are limited to help strings,
package comments, and formatting; no new tests or validation framework were
added.
- The authoritative remote had neither the core v0.5.0 nor ckprompt v0.3.0 tag
when their candidate notes were revised. Published notes, accepted ADRs,
policies, and license/attribution records were left intact.
The updated ckprompt candidate still requires dependency guidance to be finalized
when release alignment occurs. This is release preparation, not unfinished
editorial work or evidence of an independently buildable candidate.

View File

@@ -1,7 +1,7 @@
# Future work # Future work
Status: documentation refresh, pending release/dependency alignment, optional Status: pending release/dependency alignment, optional shell validation, and
shell validation, and future capability proposals. future capability proposals.
No delivery dates are selected here. No delivery dates are selected here.
## Purpose and authority ## Purpose and authority
@@ -30,13 +30,6 @@ an idea here does not select its syntax, API, priority, or delivery date.
## Pending release and integration work ## Pending release and integration work
### Documentation refresh
The agreed [documentation roadmap](documentation-refresh.md) owns the upcoming
clarity refresh, its scope, sequence, and completion checklist. The work covers
operator instructions and public introductions while retaining necessary
technical detail in developer documentation.
### Audit remediation release alignment ### Audit remediation release alignment
The audit remediation is complete in source. The released ckconfig v0.4.0 does The audit remediation is complete in source. The released ckconfig v0.4.0 does

View File

@@ -1,38 +1,70 @@
# Core example # Core example
Run the example from the repository root: This example shows typed flags, command shortcuts, shared reporting, and shell
completion. It needs no external service. See the [consumer guide](../../docs/consumers/guide.md#go-compatibility)
for Go requirements; maintainers use the toolchain in the
[developer guide](../../docs/development.md#documentation-validation).
Run from the repository root, with that Go toolchain on `PATH`:
```sh ```sh
export GOWORK=off GOTOOLCHAIN=local
go run ./examples/core workspace greet --count=2
```
The result shows the selected count and whether it was supplied. It also shows
the entered command path and the original command path, which differ when you
use a shortcut.
## Try shortcuts and explicit values
```sh
# The hello shortcut runs workspace greet; --times means --count.
go run ./examples/core hello --times=0 --tag=first go run ./examples/core hello --times=0 --tag=first
# ws is a shortcut for the workspace group.
go run ./examples/core ws greet --count=2 go run ./examples/core ws greet --count=2
# Inspect the group or use the example's global help alias.
go run ./examples/core ws --help go run ./examples/core ws --help
go run ./examples/core hello --hlep go run ./examples/core hello --hlep
```
An explicit zero remains a supplied value. The handler prints both
`Invocation.EnteredPath()` and `Invocation.CanonicalPath()` so you can see how
shortcuts resolve.
## Try reporting
```sh
go run ./examples/core report
go run ./examples/core report --verbose
go run ./examples/core report --quiet
```
The default scenario succeeds and writes its result. Verbose mode also shows
warnings and information; quiet mode hides the result. The
[CLI reference](../../docs/cli.md#reporting) defines the shared visibility rules.
## Try shell completion
```sh
go build -o core-example ./examples/core go build -o core-example ./examples/core
./core-example completion bash ./core-example completion bash
``` ```
The example installs a canonical `workspace greet` command together with a This prints the Bash completion script. Initialize `bash-completion`, then load
command shortcut, a group shortcut, a scoped flag alias, and a global help the script as described in the [CLI reference](../../docs/cli.md#shell-completion).
alias. Its declaration slice mixes the canonical group and routing rules as Use the executable basename `core-example` and try completing
`[]commandkit.Declaration`. The handler prints `Invocation.EnteredPath()` and `core-example report d` or `core-example ws gr`. Other supported shells are
`Invocation.CanonicalPath()` so the alternate route and its canonical target listed in the reference.
are visible in the output.
The example also installs `Completion("core-example")` and gives the `report` ## How it is wired
scenario argument static choices. Initialize `bash-completion` first if using
Bash. Build it with the basename shown above, load
the script for your shell using the [CLI reference](../../docs/cli.md#shell-completion),
and try completing `core-example report d` or `core-example ws gr`.
Compatible integration factories also return `commandkit.Command` and can be The example installs `workspace greet` alongside command and flag aliases in a
passed directly to `New` beside `commandkit.Alias` or flag-alias declarations. `[]commandkit.Declaration`. It also installs `Completion("core-example")` and
The matched ckconfig and ckprompt releases use the new core identity. For a provides static choices for the reporting scenario argument. The
command-only `[]commandkit.Command`, convert its elements into a
`[]commandkit.Declaration` before appending routing rules; Go cannot expand the
command slice as `...commandkit.Declaration`. The
[consumer guide](../../docs/consumers/guide.md#application-owned-aliases) [consumer guide](../../docs/consumers/guide.md#application-owned-aliases)
shows both forms, and the [composed consumer](../../integrations/ckprompt/examples/composed) explains declaration composition; the [composed example](../../integrations/ckprompt/examples/composed)
is the maintained integration example. adds integration commands.
These aliases require core v0.3.0. Repository contributors can run its test with Run `GOWORK=off GOTOOLCHAIN=local go test ./examples/core` from the repository
`go test ./examples/core` from the root. root to check this example.

View File

@@ -1,36 +1,30 @@
# CommandKit ckconfig # CommandKit ckconfig
`ckconfig` is the optional ConfigKit integration for CommandKit. It adapts `ckconfig` adds configuration inspection commands to Go applications that use
ConfigKit loaders and scopes into reusable `commandkit.Command` declarations; CommandKit and ConfigKit. Operators can view settings, validate configuration,
installing the integration is explicit and does not modify an application by find where values came from, and compare two configurations.
itself.
The application chooses which commands to install. Importing the package alone
does not install commands.
## Module ## Module
The module path is `go.maximumdirect.net/ckconfig`. Version v0.4.0 requires Go The module path is `go.maximumdirect.net/ckconfig`. It does not import PromptKit.
1.27.0 and uses `go.maximumdirect.net/commandkit v0.4.0` and See the [consumer guide](https://forge.maximumdirect.net/base-layer/commandkit/src/branch/main/docs/consumers/guide.md#module-selection)
`go.maximumdirect.net/configkit v1.1.0`; it does not import PromptKit. See the for compatible releases and Go requirements.
[consumer guide](https://gitea.maximumdirect.net/eric/CommandKit/src/branch/main/docs/consumers/guide.md#configkit-scopes)
for exact callback and lifetime contracts.
## Example ## Example
For one application configuration scope, install the convenience declaration: To inspect one application configuration, pass your loader to `AppCommand`:
```go ```go
app, err := commandkit.New(identity, ckconfig.AppCommand(loadAppConfig)) app, err := commandkit.New(identity, ckconfig.AppCommand(loadAppConfig))
``` ```
Use `ckconfig.Command(ckconfig.Suite[Input, State]{...})` to define named For multiple named configurations or application-specific flags, use
scopes, selectors, input checks, and state shared by the selected acquisitions `ckconfig.Command` with a `ckconfig.Suite`. The
or comparison in a config invocation. `ckconfig.FromConfigKit` adapts a typed [integration guide](https://forge.maximumdirect.net/base-layer/commandkit/src/branch/main/docs/consumers/guide.md#configkit-scopes)
ConfigKit loader. The `config` command family exposes scope discovery and the explains loader setup, inputs, and shared state.
validate, show, sources, explain, and diff operations supported by the declared
scopes. Source reports include native destination, placement, destination
fallback, version evidence, and empty-import selections. Comparison returns
ConfigKit's native records to shared report rendering; the
[CLI reference](https://gitea.maximumdirect.net/eric/CommandKit/src/branch/main/docs/cli.md#compare-configuration-selections)
owns its operator details.
The maintained [simple example](examples/simple) shows a complete consumer. The maintained [simple example](examples/simple) shows a complete consumer.
The [CommandKit CLI reference](https://gitea.maximumdirect.net/eric/CommandKit/src/branch/main/docs/cli.md#configuration-scopes) The [CommandKit CLI reference](https://gitea.maximumdirect.net/eric/CommandKit/src/branch/main/docs/cli.md#configuration-scopes)

View File

@@ -1,10 +1,11 @@
// Package ckconfig, provided by go.maximumdirect.net/ckconfig, provides // Package ckconfig adds commands to view, validate, explain, and compare
// CommandKit's optional ConfigKit v1.1.0 integration, requiring Go 1.27.0. Its // ConfigKit configuration in CommandKit applications.
// canonical Command declaration installs the standard config command family //
// through the core commandkit package. Applications can install CommandKit // Use AppCommand for one application configuration loader, or Command with a
// RoutingRule declarations alongside it through commandkit.New or // Suite for multiple named configurations and application-specific flags.
// App.Register. Source reports preserve ConfigKit's destination, placement, // Install the returned command with commandkit.New or App.Register.
// version, and empty-import evidence. Invocation reporting applies CommandKit's shared // Importing this package alone installs no commands.
// visibility and delivery policy; provider warnings remain independent of //
// failure explanations. Importing ckconfig alone installs no commands. // ConfigKit owns configuration loading and interpretation. CommandKit formats
// reports and messages using its shared reporting policy.
package ckconfig package ckconfig

View File

@@ -1,37 +1,90 @@
# Simple consumer # ConfigKit example
This example imports `go.maximumdirect.net/ckconfig` and This example adds configuration inspection and a custom `greet` command to a
`go.maximumdirect.net/commandkit`; ckconfig v0.4.0 uses core small application. It uses local fixtures and in-memory defaults, with no
v0.4.0, ConfigKit v1.1.0, and Go 1.27.0. Set `GOWORK=off GOTOOLCHAIN=local` external services. See [module selection](../../../../docs/consumers/guide.md#module-selection)
for the commands below. for dependencies and Go requirements. Use Go 1.27.0 on `PATH` for this checkout.
Run the maintained example with: From the repository root:
```sh ```sh
cd integrations/ckconfig/examples/simple
export GOWORK=off GOTOOLCHAIN=local
go run . config show go run . config show
go run . config show --config fixtures/before.yml --verbose ```
go run . config show --config fixtures/before.yml --quiet
The output includes the default greeting, `Hello`, and schema version 2.
This example can run against its declared released dependencies with the
workspace disabled.
## Inspect and override a value
```sh
# Discover configuration paths under schema.
go run . config explain --list --under /schema go run . config explain --list --under /schema
# Change the greeting for this invocation and show just that value.
go run . config show --path /greeting --set '/greeting="Hi"' go run . config show --path /greeting --set '/greeting="Hi"'
```
The second command prints `Hi`. It does not edit a file.
## Compare configurations
```sh
go run . config diff --config fixtures/before.yml --against-config fixtures/after.yml go run . config diff --config fixtures/before.yml --against-config fixtures/after.yml
```
The report includes `changes.greeting: Goodbye`.
```sh
# Expected status 3: the overridden greeting differs from the ordinary default.
go run . config diff --set '/greeting="Hi"' --details --check go run . config diff --set '/greeting="Hi"' --details --check
```
This compares the overridden left side with ordinary configuration on the
right. `go run` prints `exit status 3` and itself exits with status 1; a built
executable returns the application's status 3 directly.
## Inspect warnings and failed loads
```sh
# Schema version 1 produces a warning, visible in verbose mode.
go run . config show --config fixtures/before.yml --verbose
# Quiet mode hides the configuration report and warning.
go run . config show --config fixtures/before.yml --quiet
```
Ordinary mode hides the warning but still displays configuration.
```sh
# Intentional failure: show detailed validation findings for the invalid fixture.
go run . config validate --config fixtures/invalid.yml --details --severity error go run . config validate --config fixtures/invalid.yml --details --severity error
# Intentional failure: still show the source recorded before loading failed.
go run . config sources --config fixtures/invalid.yml --source-id source-1 go run . config sources --config fixtures/invalid.yml --source-id source-1
```
Both commands retain the load failure. `source-1` belongs to this fixture's
load; other configurations can have different source IDs. See the
[CLI reference](../../../../docs/cli.md#configuration-scopes) for report and status rules.
## Try a custom command
```sh
go run . greet go run . greet
go run . greet --count=0 --tag=first --tag second go run . greet --count=0 --tag=first --tag second
``` ```
The `config` family comes from one typed ConfigKit scope. The custom `greet` The handler reports its greeting, count, and tags. It distinguishes an omitted
command uses CommandKit's typed bindings and shows the difference between an count from an explicitly supplied zero and preserves repeated tag order.
omitted `--count` and an explicitly supplied zero, plus ordered repeated tags.
With no `--config`, application settings use the in-memory default. A supplied ## How it is wired
configuration and overlay are passed to ConfigKit unchanged. The comparison
command loads the two local fixtures and reports `changes.greeting: Goodbye`. One ConfigKit scope supplies the standard `config` commands. Without `--config`,
The before fixture uses schema version 1, which ConfigKit reports as a provider its loader uses an in-memory default. Supplied configuration and overlay values
warning in verbose mode. Ordinary mode hides the warning while preserving the are passed to ConfigKit unchanged. The scope enables temporary overrides and
effective YAML report; quiet mode suppresses that report. passes them into its ordinary ConfigKit load. The
The invalid fixture demonstrates a failed-load report and captured source [consumer guide](../../../../docs/consumers/guide.md#configkit-scopes) explains
inventory; `source-1` is the ID from that fixture's acquisition. The scope opts loader and scope setup.
in to transient overrides and passes them into its normal ConfigKit load. The
diff example compares an overridden left side with ordinary configuration on Run `GOWORK=off GOTOOLCHAIN=local go test ./...` from this example directory to
the right and returns status 3 because the values differ. check it against its declared dependencies.

View File

@@ -73,13 +73,13 @@ func newConfigOperationCommand[I, S any](prepared *preparedSuite[I, S], operatio
scopeChoices = append(scopeChoices, commandkit.CompletionChoice{Value: "all"}) scopeChoices = append(scopeChoices, commandkit.CompletionChoice{Value: "all"})
} }
flags := []commandkit.Flag[*configCommandInput[I, S]]{ flags := []commandkit.Flag[*configCommandInput[I, S]]{
commandkit.ValueFlag(commandkit.FlagMeta{Name: "scope", Usage: "Configuration scope name or all where supported.", Completion: commandkit.CompleteChoices(scopeChoices...)}, &defaultScope, parseConfigString, commandkit.ValueFlag(commandkit.FlagMeta{Name: "scope", Usage: "Select a named configuration, or all where supported.", Completion: commandkit.CompleteChoices(scopeChoices...)}, &defaultScope, parseConfigString,
func(input **configCommandInput[I, S], value commandkit.Supplied[string]) { (*input).scope = value }), func(input **configCommandInput[I, S], value commandkit.Supplied[string]) { (*input).scope = value }),
commandkit.ValueFlag(commandkit.FlagMeta{Name: "config", Usage: "Configuration source.", Completion: commandkit.CompleteFiles()}, (*string)(nil), parseConfigString, commandkit.ValueFlag(commandkit.FlagMeta{Name: "config", Usage: "Select the configuration source.", Completion: commandkit.CompleteFiles()}, (*string)(nil), parseConfigString,
func(input **configCommandInput[I, S], value commandkit.Supplied[string]) { func(input **configCommandInput[I, S], value commandkit.Supplied[string]) {
(*input).selection.Config = value (*input).selection.Config = value
}), }),
commandkit.ValueFlag(commandkit.FlagMeta{Name: "overlay", Usage: "Overlay source.", Completion: commandkit.CompleteFiles()}, (*string)(nil), parseConfigString, commandkit.ValueFlag(commandkit.FlagMeta{Name: "overlay", Usage: "Select the configuration overlay.", Completion: commandkit.CompleteFiles()}, (*string)(nil), parseConfigString,
func(input **configCommandInput[I, S], value commandkit.Supplied[string]) { func(input **configCommandInput[I, S], value commandkit.Supplied[string]) {
(*input).selection.Overlay = value (*input).selection.Overlay = value
}), }),
@@ -89,11 +89,11 @@ func newConfigOperationCommand[I, S any](prepared *preparedSuite[I, S], operatio
} }
if operation == Validate { if operation == Validate {
flags = append(flags, flags = append(flags,
commandkit.BoolFlag(commandkit.FlagMeta{Name: "details", Usage: "Show native validation findings."}, false, func(input **configCommandInput[I, S], value commandkit.Supplied[bool]) { (*input).details = value }), commandkit.BoolFlag(commandkit.FlagMeta{Name: "details", Usage: "Show detailed validation findings."}, false, func(input **configCommandInput[I, S], value commandkit.Supplied[bool]) { (*input).details = value }),
commandkit.RepeatFlag(commandkit.FlagMeta{Name: "severity", Usage: "Filter detailed findings by error or warning."}, []configkit.Severity(nil), parseValidationSeverity, func(input **configCommandInput[I, S], value commandkit.Supplied[[]configkit.Severity]) { commandkit.RepeatFlag(commandkit.FlagMeta{Name: "severity", Usage: "Filter detailed findings by error or warning."}, []configkit.Severity(nil), parseValidationSeverity, func(input **configCommandInput[I, S], value commandkit.Supplied[[]configkit.Severity]) {
(*input).severities = value.Value (*input).severities = value.Value
}), }),
commandkit.RepeatFlag(commandkit.FlagMeta{Name: "code", Usage: "Filter detailed findings by exact native code."}, []string(nil), parseConfigString, func(input **configCommandInput[I, S], value commandkit.Supplied[[]string]) { commandkit.RepeatFlag(commandkit.FlagMeta{Name: "code", Usage: "Filter detailed findings by exact diagnostic code."}, []string(nil), parseConfigString, func(input **configCommandInput[I, S], value commandkit.Supplied[[]string]) {
(*input).codes = value.Value (*input).codes = value.Value
}), }),
) )
@@ -114,16 +114,16 @@ func newConfigOperationCommand[I, S any](prepared *preparedSuite[I, S], operatio
flags = append(flags, flags = append(flags,
commandkit.ValueFlag(commandkit.FlagMeta{Name: "path", Usage: "JSON Pointer path to explain."}, (*string)(nil), parseConfigString, func(input **configCommandInput[I, S], value commandkit.Supplied[string]) { (*input).path = value }), commandkit.ValueFlag(commandkit.FlagMeta{Name: "path", Usage: "JSON Pointer path to explain."}, (*string)(nil), parseConfigString, func(input **configCommandInput[I, S], value commandkit.Supplied[string]) { (*input).path = value }),
commandkit.BoolFlag(commandkit.FlagMeta{Name: "list", Usage: "List configuration paths."}, false, func(input **configCommandInput[I, S], value commandkit.Supplied[bool]) { (*input).list = value }), commandkit.BoolFlag(commandkit.FlagMeta{Name: "list", Usage: "List configuration paths."}, false, func(input **configCommandInput[I, S], value commandkit.Supplied[bool]) { (*input).list = value }),
commandkit.BoolFlag(commandkit.FlagMeta{Name: "historical", Usage: "Include historical-only paths when listing."}, false, func(input **configCommandInput[I, S], value commandkit.Supplied[bool]) { (*input).historical = value }), commandkit.BoolFlag(commandkit.FlagMeta{Name: "historical", Usage: "Include paths that exist only in configuration history."}, false, func(input **configCommandInput[I, S], value commandkit.Supplied[bool]) { (*input).historical = value }),
commandkit.ValueFlag(commandkit.FlagMeta{Name: "under", Usage: "List paths under a JSON Pointer."}, (*string)(nil), parseConfigString, func(input **configCommandInput[I, S], value commandkit.Supplied[string]) { (*input).under = value }), commandkit.ValueFlag(commandkit.FlagMeta{Name: "under", Usage: "List paths under a JSON Pointer."}, (*string)(nil), parseConfigString, func(input **configCommandInput[I, S], value commandkit.Supplied[string]) { (*input).under = value }),
commandkit.BoolFlag(commandkit.FlagMeta{Name: "explicit", Usage: "Filter listed current paths by explicitness."}, false, func(input **configCommandInput[I, S], value commandkit.Supplied[bool]) { (*input).explicit = value }), commandkit.BoolFlag(commandkit.FlagMeta{Name: "explicit", Usage: "Filter current paths by whether ConfigKit marks them explicit."}, false, func(input **configCommandInput[I, S], value commandkit.Supplied[bool]) { (*input).explicit = value }),
) )
} }
if operation == Show { if operation == Show {
flags = append(flags, commandkit.ValueFlag(commandkit.FlagMeta{Name: "path", Usage: "JSON Pointer to one effective value."}, (*string)(nil), parseConfigString, func(input **configCommandInput[I, S], value commandkit.Supplied[string]) { (*input).path = value })) flags = append(flags, commandkit.ValueFlag(commandkit.FlagMeta{Name: "path", Usage: "JSON Pointer to one effective value."}, (*string)(nil), parseConfigString, func(input **configCommandInput[I, S], value commandkit.Supplied[string]) { (*input).path = value }))
} }
if operation == Sources { if operation == Sources {
flags = append(flags, commandkit.ValueFlag(commandkit.FlagMeta{Name: "source-id", Usage: "Select one source ID from this acquisition."}, (*string)(nil), parseConfigString, func(input **configCommandInput[I, S], value commandkit.Supplied[string]) { (*input).sourceID = value })) flags = append(flags, commandkit.ValueFlag(commandkit.FlagMeta{Name: "source-id", Usage: "Show one source ID from this configuration load."}, (*string)(nil), parseConfigString, func(input **configCommandInput[I, S], value commandkit.Supplied[string]) { (*input).sourceID = value }))
} }
flags = append(flags, commandkit.CaptureFlags(prepared.bindingsByOperation[operation], func(input **configCommandInput[I, S]) *commandkit.FlagValues[I] { flags = append(flags, commandkit.CaptureFlags(prepared.bindingsByOperation[operation], func(input **configCommandInput[I, S]) *commandkit.FlagValues[I] {
if input == nil || *input == nil { if input == nil || *input == nil {
@@ -160,7 +160,7 @@ func newConfigOperationCommand[I, S any](prepared *preparedSuite[I, S], operatio
func comparisonOperationFlags[I, S any]() []commandkit.Flag[*configCommandInput[I, S]] { func comparisonOperationFlags[I, S any]() []commandkit.Flag[*configCommandInput[I, S]] {
return []commandkit.Flag[*configCommandInput[I, S]]{ return []commandkit.Flag[*configCommandInput[I, S]]{
commandkit.BoolFlag(commandkit.FlagMeta{Name: "details", Usage: "Show native before and after difference evidence."}, false, func(input **configCommandInput[I, S], value commandkit.Supplied[bool]) { (*input).details = value }), commandkit.BoolFlag(commandkit.FlagMeta{Name: "details", Usage: "Show before and after values with presence and redaction details."}, false, func(input **configCommandInput[I, S], value commandkit.Supplied[bool]) { (*input).details = value }),
commandkit.BoolFlag(commandkit.FlagMeta{Name: "check", Usage: "Return status 3 when differences are found."}, false, func(input **configCommandInput[I, S], value commandkit.Supplied[bool]) { (*input).check = value }), commandkit.BoolFlag(commandkit.FlagMeta{Name: "check", Usage: "Return status 3 when differences are found."}, false, func(input **configCommandInput[I, S], value commandkit.Supplied[bool]) { (*input).check = value }),
commandkit.ValueFlag(commandkit.FlagMeta{Name: "against-config", Usage: "Configuration source for the right side.", Completion: commandkit.CompleteFiles()}, (*string)(nil), parseConfigString, commandkit.ValueFlag(commandkit.FlagMeta{Name: "against-config", Usage: "Configuration source for the right side.", Completion: commandkit.CompleteFiles()}, (*string)(nil), parseConfigString,
func(input **configCommandInput[I, S], value commandkit.Supplied[string]) { func(input **configCommandInput[I, S], value commandkit.Supplied[string]) {
@@ -191,7 +191,7 @@ func operationDeclaration(operation Operation) (string, string) {
case Explain: case Explain:
return "explain", "Explain a configuration path." return "explain", "Explain a configuration path."
case Diff: case Diff:
return "diff", "Compare two configuration selections." return "diff", "Compare two configurations."
default: default:
return string(operation), "Inspect configuration." return string(operation), "Inspect configuration."
} }

View File

@@ -1,37 +1,40 @@
# CommandKit ckprompt # CommandKit ckprompt
`ckprompt` is the optional PromptKit integration for CommandKit. It adapts `ckprompt` adds PromptKit inspection and testing commands to Go applications
PromptKit engine configuration, native comparison, five catalogs, named that use CommandKit. Operators can list prompts, profiles, and backends, inspect
inspection, requirements discovery and validation, and native smoke tests. their settings, discover required inputs, validate and preview requests, and
Importing it does not install either command family. run smoke tests.
The application chooses which commands to install. Importing the package alone
does not install commands.
## Module ## Module
The module path is `go.maximumdirect.net/ckprompt`. This source uses Go 1.27.0, The module path is `go.maximumdirect.net/ckprompt`. See the
`go.maximumdirect.net/commandkit v0.4.0`, `go.maximumdirect.net/ckconfig v0.4.0`, [consumer guide](https://forge.maximumdirect.net/base-layer/commandkit/src/branch/main/docs/consumers/guide.md#module-selection)
`go.maximumdirect.net/configkit v1.1.0`, and `go.maximumdirect.net/promptkit v0.20.0`. See the for compatible releases, Go requirements, and the current source's dependency
[consumer guide](https://gitea.maximumdirect.net/eric/CommandKit/src/branch/main/docs/consumers/guide.md#promptkit-configuration-definitions-and-requirements) alignment requirement.
for callback, input, state, and acquisition contracts.
## Example ## Example
Add `ckprompt.ConfigScope(loadEngine)` to the scopes passed to Pass your engine loader to `FromEngine` to add resource listings, inspection,
`ckconfig.Command` when the application wants PromptKit engine configuration and requirements discovery:
and native comparison in the `config` family. Install
`ckprompt.Command(ckprompt.FromEngine(loadEngine))` separately for catalogs, ```go
named inspections, and requirements discovery. `FromEngine` supplies nine app, err := commandkit.New(identity, ckprompt.Command(ckprompt.FromEngine(loadEngine)))
PromptKit-backed callbacks: four inspections and five catalogs. Applications ```
may narrow, wrap, or replace them before capture or provide custom callbacks
with `ckprompt.Suite`. Add concrete request validation, prepared-request preview, Add request validation, preview, and smoke tests with `WithRequestValidation`,
and smoke testing explicitly with `WithRequestValidation`, `WithRequestPreparation`, and `WithSmokeTesting`. To expose engine configuration
`WithRequestPreparation`, and `WithSmokeTesting`. Inspection, under `config`, add `ckprompt.ConfigScope(loadEngine)` to a `ckconfig.Suite`.
requirements, and catalog operations do not execute prompts or contact model The [integration guide](https://forge.maximumdirect.net/base-layer/commandkit/src/branch/main/docs/consumers/guide.md#promptkit-configuration-definitions-and-requirements)
providers; application loaders and callbacks retain their own effects. Smoke explains these choices; the [composed example](examples/composed) shows them together.
testing invokes the selected native PromptKit operation; the
application retains ownership of client and configuration choices. See the Inspection commands do not call the model. Smoke tests can use the application's
[CLI reference](https://gitea.maximumdirect.net/eric/CommandKit/src/branch/main/docs/cli.md#promptkit-smoke-testing) configured client or network probes. Applications own engine setup, credentials,
for operator commands and report semantics. The maintained and any effects of their loaders and callbacks. See the
[composed example](examples/composed) shows complete application wiring. [CLI reference](https://forge.maximumdirect.net/base-layer/commandkit/src/branch/main/docs/cli.md#promptkit-smoke-testing)
for commands and results.
## License and attribution ## License and attribution

View File

@@ -91,7 +91,7 @@ func buildCommand[I, S any](suite Suite[I, S], aliases *[]commandkit.Declaration
showCommands = append(showCommands, newPreparationCommand(suite, aliases)) showCommands = append(showCommands, newPreparationCommand(suite, aliases))
} }
if len(showCommands) != 0 { if len(showCommands) != 0 {
rootCommands = append(rootCommands, commandkit.Group("show", "Show a named PromptKit definition.", showCommands...)) rootCommands = append(rootCommands, commandkit.Group("show", "Show PromptKit definitions or preview a prepared request.", showCommands...))
} }
listCommands := make([]commandkit.Command, 0, 5) listCommands := make([]commandkit.Command, 0, 5)
if suite.ListPrompts != nil { if suite.ListPrompts != nil {
@@ -110,7 +110,7 @@ func buildCommand[I, S any](suite Suite[I, S], aliases *[]commandkit.Declaration
listCommands = append(listCommands, newCatalogListCommand(suite, "collections")) listCommands = append(listCommands, newCatalogListCommand(suite, "collections"))
} }
if len(listCommands) != 0 { if len(listCommands) != 0 {
rootCommands = append(rootCommands, commandkit.Group("list", "List PromptKit catalogs.", listCommands...)) rootCommands = append(rootCommands, commandkit.Group("list", "List available PromptKit resources.", listCommands...))
} }
requirementsCommands := make([]commandkit.Command, 0, 2) requirementsCommands := make([]commandkit.Command, 0, 2)
if suite.InspectRequirements != nil { if suite.InspectRequirements != nil {
@@ -125,7 +125,7 @@ func buildCommand[I, S any](suite Suite[I, S], aliases *[]commandkit.Declaration
if suite.SmokeTest != nil { if suite.SmokeTest != nil {
rootCommands = append(rootCommands, newSmokeTestCommand(suite, aliases)) rootCommands = append(rootCommands, newSmokeTestCommand(suite, aliases))
} }
command := commandkit.RootGroup("promptkit", "Inspect, list, validate requests, and run PromptKit smoke tests.", rootCommands...) command := commandkit.RootGroup("promptkit", "Inspect PromptKit resources, check requests, and run smoke tests.", rootCommands...)
for _, issue := range suite.issues { for _, issue := range suite.issues {
command = commandkit.WithError(command, issue) command = commandkit.WithError(command, issue)
} }
@@ -140,16 +140,16 @@ func newCatalogListCommand[I, S any](suite Suite[I, S], name string) commandkit.
return &(*input).captured return &(*input).captured
}) })
flags = append(flags, flags = append(flags,
commandkit.ValueFlag(commandkit.FlagMeta{Name: "config", Usage: "Configuration input path.", Completion: commandkit.CompleteFiles()}, (*string)(nil), parseDefinitionString, commandkit.ValueFlag(commandkit.FlagMeta{Name: "config", Usage: "Select the configuration input path.", Completion: commandkit.CompleteFiles()}, (*string)(nil), parseDefinitionString,
func(input **catalogInput[I], value commandkit.Supplied[string]) { (*input).selection.Config = value }), func(input **catalogInput[I], value commandkit.Supplied[string]) { (*input).selection.Config = value }),
commandkit.ValueFlag(commandkit.FlagMeta{Name: "overlay", Usage: "Configuration overlay path.", Completion: commandkit.CompleteFiles()}, (*string)(nil), parseDefinitionString, commandkit.ValueFlag(commandkit.FlagMeta{Name: "overlay", Usage: "Select the configuration overlay path.", Completion: commandkit.CompleteFiles()}, (*string)(nil), parseDefinitionString,
func(input **catalogInput[I], value commandkit.Supplied[string]) { (*input).selection.Overlay = value }), func(input **catalogInput[I], value commandkit.Supplied[string]) { (*input).selection.Overlay = value }),
) )
if name == "prompts" || name == "profiles" || name == "backends" { if name == "prompts" || name == "profiles" || name == "backends" {
flags = append(flags, flags = append(flags,
commandkit.ValueFlag(commandkit.FlagMeta{Name: "namespace", Usage: "Select one native namespace."}, (*string)(nil), parseDefinitionString, commandkit.ValueFlag(commandkit.FlagMeta{Name: "namespace", Usage: "List resources in one namespace."}, (*string)(nil), parseDefinitionString,
func(input **catalogInput[I], value commandkit.Supplied[string]) { (*input).namespace = value }), func(input **catalogInput[I], value commandkit.Supplied[string]) { (*input).namespace = value }),
commandkit.BoolFlag(commandkit.FlagMeta{Name: "all-namespaces", Usage: "Select identities from every namespace."}, false, commandkit.BoolFlag(commandkit.FlagMeta{Name: "all-namespaces", Usage: "List resources from every namespace."}, false,
func(input **catalogInput[I], value commandkit.Supplied[bool]) { (*input).allNamespaces = value }), func(input **catalogInput[I], value commandkit.Supplied[bool]) { (*input).allNamespaces = value }),
) )
} }
@@ -243,9 +243,9 @@ func newDefinitionCommand[I, S any](suite Suite[I, S], name string, aliases *[]c
return &(*input).captured return &(*input).captured
}) })
flags = append(flags, flags = append(flags,
commandkit.ValueFlag(commandkit.FlagMeta{Name: "config", Usage: "Configuration input path.", Completion: commandkit.CompleteFiles()}, (*string)(nil), parseDefinitionString, commandkit.ValueFlag(commandkit.FlagMeta{Name: "config", Usage: "Select the configuration input path.", Completion: commandkit.CompleteFiles()}, (*string)(nil), parseDefinitionString,
func(input **definitionInput[I], value commandkit.Supplied[string]) { (*input).selection.Config = value }), func(input **definitionInput[I], value commandkit.Supplied[string]) { (*input).selection.Config = value }),
commandkit.ValueFlag(commandkit.FlagMeta{Name: "overlay", Usage: "Configuration overlay path.", Completion: commandkit.CompleteFiles()}, (*string)(nil), parseDefinitionString, commandkit.ValueFlag(commandkit.FlagMeta{Name: "overlay", Usage: "Select the configuration overlay path.", Completion: commandkit.CompleteFiles()}, (*string)(nil), parseDefinitionString,
func(input **definitionInput[I], value commandkit.Supplied[string]) { func(input **definitionInput[I], value commandkit.Supplied[string]) {
(*input).selection.Overlay = value (*input).selection.Overlay = value
}), }),
@@ -288,11 +288,11 @@ func newRequirementsCommand[I, S any](suite Suite[I, S], aliases *[]commandkit.D
return &(*input).captured return &(*input).captured
}) })
flags = append(flags, flags = append(flags,
commandkit.ValueFlag(commandkit.FlagMeta{Name: "config", Usage: "Configuration input path.", Completion: commandkit.CompleteFiles()}, (*string)(nil), parseDefinitionString, commandkit.ValueFlag(commandkit.FlagMeta{Name: "config", Usage: "Select the configuration input path.", Completion: commandkit.CompleteFiles()}, (*string)(nil), parseDefinitionString,
func(input **requirementsInput[I], value commandkit.Supplied[string]) { func(input **requirementsInput[I], value commandkit.Supplied[string]) {
(*input).selection.Config = value (*input).selection.Config = value
}), }),
commandkit.ValueFlag(commandkit.FlagMeta{Name: "overlay", Usage: "Configuration overlay path.", Completion: commandkit.CompleteFiles()}, (*string)(nil), parseDefinitionString, commandkit.ValueFlag(commandkit.FlagMeta{Name: "overlay", Usage: "Select the configuration overlay path.", Completion: commandkit.CompleteFiles()}, (*string)(nil), parseDefinitionString,
func(input **requirementsInput[I], value commandkit.Supplied[string]) { func(input **requirementsInput[I], value commandkit.Supplied[string]) {
(*input).selection.Overlay = value (*input).selection.Overlay = value
}), }),
@@ -308,8 +308,8 @@ func newRequirementsCommand[I, S any](suite Suite[I, S], aliases *[]commandkit.D
spec := commandkit.CommandSpec[*requirementsInput[I]]{ spec := commandkit.CommandSpec[*requirementsInput[I]]{
Name: "show", Name: "show",
Summary: "Inspect requirements for a named PromptKit prompt.", Summary: "Discover the inputs and variables a prompt needs.",
Description: "Profile selection establishes the reported profile identity, not a different set of requirements. A profile namespace qualifies an explicitly supplied short profile ID, not the prompt’s stored default reference.", Description: "List required inputs without running the prompt. Choosing a profile changes the reported profile ID, not the requirements. A profile namespace applies to a short profile ID supplied here; it does not change the prompt’s stored default reference.",
NewInput: func() *requirementsInput[I] { NewInput: func() *requirementsInput[I] {
return &requirementsInput[I]{} return &requirementsInput[I]{}
}, },

View File

@@ -1,13 +1,13 @@
// Package ckprompt, provided by go.maximumdirect.net/ckprompt, provides optional // Package ckprompt adds PromptKit inspection and testing commands to CommandKit
// PromptKit configuration comparison, // applications. Operators can list resources, inspect definitions, discover
// prompt catalogs, named inspections, requirements discovery and validation, // required inputs, validate and preview requests, and run smoke tests.
// prepared-request preview, and native smoke testing for CommandKit. Command //
// returns a canonical declaration; Declarations adds scoped flag aliases. // Start with FromEngine and add optional operations with WithRequestValidation,
// Applications can install those alongside other declarations through // WithRequestPreparation, and WithSmokeTesting. Command returns the command
// commandkit.New or App.Register. Importing ckprompt installs neither family; callers compose its // family; Declarations also includes its convenience flag aliases. Install
// declarations with core and ckconfig explicitly. Provider diagnostics remain // these with commandkit.New or App.Register.
// passive until the owning command submits them through the invocation //
// reporter, separately from any terminal explanation. This module uses // ConfigScope separately exposes engine configuration through ckconfig.
// PromptKit v0.20.0 and its native engine inventory, including configured // Importing this package installs neither command family. Applications own
// bundled resources. // engine construction, credentials, and client configuration.
package ckprompt package ckprompt

View File

@@ -1,27 +1,40 @@
# CommandKit ckprompt v0.3.0 # CommandKit ckprompt v0.3.0
CommandKit ckprompt v0.3.0 adopts PromptKit v0.20.0 and ConfigKit v1.1.0, This unpublished candidate adds PromptKit v0.20.0 support, including request
and requires CommandKit core v0.4.0, ckconfig v0.4.0, and Go 1.27.0. preview, namespace selection, and shared text, YAML, and JSON output. It uses
The integration uses shared core reporting for text, YAML, and JSON output. ConfigKit v1.1.0 and requires Go 1.27.0.
Prompt, profile, and backend commands report PromptKit's native resource ## Operator features
inspections. Applications may opt into prepared-request preview, concrete
request validation, smoke testing, and namespace selectors independently.
Reusable request flag collections support application-owned commands;
`ckprompt.Declarations` installs the standard family with scoped aliases.
Literal and file inputs retain their command-line order. Provider parameters
can be supplied for preparation and applicable diagnostics.
The PromptKit configuration scope exposes native metadata and load-failure - Inspect prompts, profiles, and backends, and list available resources.
evidence through ckconfig, including independent comparison selections, - Preview rendered requests without calling the model, or validate that a
detailed differences, and validation findings. Smoke reports retain native request can be prepared with the supplied inputs.
evidence and operation failures separately from presentation failures. - Choose namespaces and override request settings for supported commands.
- Run smoke tests and inspect their results, including incomplete or unsupported
checks and reports returned alongside errors.
- Inspect engine configuration through `config`, including detailed validation
findings, source information after failed loads, and configuration comparisons.
This pre-1.0 release changes resource report shapes, input flags, formatting, Applications choose which commands to enable. Reusable flag collections also
and configuration comparison behavior. Applications should update declarations let application commands offer the same request flags. `ckprompt.Declarations`
and report consumers to the current [CLI reference](../../../../docs/cli.md#promptkit-definition-inspection) adds the standard commands with their shorter flag aliases. Literal and file
and [consumer guide](../../../../docs/consumers/guide.md#promptkit-configuration-definitions-and-requirements). inputs keep their command-line order.
Applications continue to own engine construction, credentials, and execution.
## Compatibility and preparation
This candidate changes resource report shapes, input flags, formatting, and
configuration comparison behavior. Review the current
[CLI reference](../../../../docs/cli.md#promptkit-definition-inspection) and
[consumer guide](../../../../docs/consumers/guide.md#promptkit-configuration-definitions-and-requirements)
when updating declarations or code that reads reports. Applications continue to
own engine construction, credentials, and execution.
The current source requires `ckconfig.AdaptDiagnostics`, which is absent from
its selected ckconfig v0.4.0 dependency. Before publication, complete
[dependency alignment](../../../../docs/roadmap/future.md#pending-release-and-integration-work)
and update this candidate's dependency guidance to the selected releases.
The [module selection table](../../../../docs/consumers/guide.md#module-selection)
distinguishes published combinations from the current workspace.
[COPYRIGHT](https://forge.maximumdirect.net/base-layer/commandkit/src/tag/integrations/ckprompt/v0.3.0/integrations/ckprompt/COPYRIGHT) | [COPYRIGHT](https://forge.maximumdirect.net/base-layer/commandkit/src/tag/integrations/ckprompt/v0.3.0/integrations/ckprompt/COPYRIGHT) |
[LICENSE](https://forge.maximumdirect.net/base-layer/commandkit/src/tag/integrations/ckprompt/v0.3.0/integrations/ckprompt/LICENSE) | [LICENSE](https://forge.maximumdirect.net/base-layer/commandkit/src/tag/integrations/ckprompt/v0.3.0/integrations/ckprompt/LICENSE) |

View File

@@ -1,141 +1,172 @@
# Composed consumer # ConfigKit and PromptKit example
This example is part of the ckprompt module and uses core v0.4.0, ckconfig This example combines application and PromptKit configuration, resource
v0.4.0, ConfigKit v1.1.0, and PromptKit v0.20.0. It requires Go 1.27.0. inspection, request checks, and smoke tests. It uses local fixtures and an
in-memory model client. **No model service or credentials are required.**
This example composes application configuration, PromptKit configuration, Use Go 1.27.0 on `PATH` and an aligned workspace containing all three local
PromptKit comparison and catalogs, definition and requirements inspection, and modules. Follow the [workspace setup](../../../../docs/development.md#documentation-validation)
one application-owned command: from the repository root first. Current ckprompt source needs a helper in local
ckconfig source that its released dependency does not yet contain; independent
builds remain pending [release alignment](../../../../docs/roadmap/future.md#pending-release-and-integration-work).
The [consumer guide](../../../../docs/consumers/guide.md#module-selection) owns
version and compatibility details.
From the repository root:
```sh ```sh
cd integrations/ckprompt/examples/composed
export GOWORK=auto GOTOOLCHAIN=local
go run . config scopes go run . config scopes
go run . promptkit list prompts --campaign spring
go run . promptkit show prompt briefing --campaign spring --format yaml
```
The first command lists `app` and `promptkit` configurations and their available
operations. The next commands find and inspect the `briefing` prompt.
`--campaign` is a selector supplied by this example, not a standard PromptKit flag.
## Validate and compare configuration
```sh
go run . config validate --scope all --campaign spring --limit=0 go run . config validate --scope all --campaign spring --limit=0
go run . config diff --scope app --config fixtures/before.yml --against-config fixtures/after.yml go run . config diff --scope app --config fixtures/before.yml --against-config fixtures/after.yml
go run . config diff --scope app --config fixtures/before.yml --against-config fixtures/after.yml --campaign spring --limit=0
go run . config diff --scope app --campaign spring --limit=0 --against-campaign autumn --against-limit=0 --set '/campaigns/spring/model="left"' --against-set '/campaigns/spring/model="right"' --details
go run . config diff --scope promptkit --config fixtures/before.yml --against-config fixtures/after.yml --campaign spring --against-campaign spring go run . config diff --scope promptkit --config fixtures/before.yml --against-config fixtures/after.yml --campaign spring --against-campaign spring
go run . promptkit list prompts --config fixtures/before.yml --campaign spring ```
The application scope requires `--limit=0` when `--campaign` is supplied.
The app comparison reports a changed default campaign and `campaigns.spring.model`.
The PromptKit comparison selects spring on both sides and reports the changed
profiles list as one value.
The two sides have independent selectors and overrides:
```sh
go run . config diff --scope app --campaign spring --limit=0 --against-campaign autumn --against-limit=0 --set '/campaigns/spring/model="left"' --against-set '/campaigns/spring/model="right"' --details
```
Only the application scope supports `--set` here. The released PromptKit loader
has no override handoff, so its configuration scope does not enable the feature.
An aggregate operation that includes that scope rejects overrides.
## List resources and select namespaces
```sh
go run . promptkit list profiles --config fixtures/after.yml --campaign autumn --format yaml go run . promptkit list profiles --config fixtures/after.yml --campaign autumn --format yaml
go run . promptkit list backends --campaign spring go run . promptkit list backends --campaign spring
go run . promptkit list namespaces --campaign spring go run . promptkit list namespaces --campaign spring
go run . promptkit list collections --campaign spring go run . promptkit list collections --campaign spring
go run . list collections --campaign spring
go run . pk list bundles --campaign spring
go run . promptkit list prompts --namespace field-notes --campaign spring go run . promptkit list prompts --namespace field-notes --campaign spring
go run . promptkit show prompt briefing --campaign spring --format yaml
go run . promptkit show prompt briefing --campaign spring --prompt-namespace field-notes go run . promptkit show prompt briefing --campaign spring --prompt-namespace field-notes
go run . promptkit show prepared briefing --campaign spring --input topic=sprint --profile spring --extra-params '{"campaign":"preview"}'
go run . pk show prompt briefing --campaign spring --fmt yaml
go run . promptkit show profile spring --campaign spring go run . promptkit show profile spring --campaign spring
```
The profile list includes the selected `autumn` profile. PromptKit's default
bundle contributes additional resources. The example also supplies a
`field-notes` collection containing a backend, profile, and prompt. Listing
filters and resource namespace flags let you inspect that collection.
## Discover inputs, then check a request
```sh
go run . promptkit requirements show briefing --campaign spring go run . promptkit requirements show briefing --campaign spring
go run . promptkit requirements show briefing --campaign spring --var mode=full --format yaml go run . promptkit requirements show briefing --campaign spring --var mode=full --format yaml
```
The first report is incomplete: the `notes` input is conditional and `mode` is
missing. Supplying `mode=full` selects that branch and makes `notes` required.
Both commands succeed; discovery alone does not establish that a request can run.
```sh
go run . promptkit requirements validate briefing --campaign spring --llm-input-file topic=fixtures/topic.txt go run . promptkit requirements validate briefing --campaign spring --llm-input-file topic=fixtures/topic.txt
go run . promptkit requirements validate briefing --campaign spring --llm-input-file topic=fixtures/topic.txt --llm-var mode=full --llm-input-file notes=fixtures/notes.txt --format yaml go run . promptkit requirements validate briefing --campaign spring --llm-input-file topic=fixtures/topic.txt --llm-var mode=full --llm-input-file notes=fixtures/notes.txt --format yaml
```
Both commands check request preparation and report `prompt_id` and `valid: true`.
The builder provides campaign-specific variable defaults; the operator supplies
the input files. For comparison, this command intentionally fails because the
required `topic` input is missing:
```sh
# Intentional failure: missing topic input.
go run . promptkit requirements validate briefing --campaign spring go run . promptkit requirements validate briefing --campaign spring
```
Preview a request with literal input instead of a file:
```sh
go run . promptkit show prepared briefing --campaign spring --input topic=sprint --profile spring --extra-params '{"campaign":"preview"}'
```
The preview includes rendered messages and effective provider settings.
Validation and preview do not call the model or guarantee later execution.
## Run smoke tests
```sh
go run . promptkit test text_inference --campaign spring --prompt briefing --profile spring go run . promptkit test text_inference --campaign spring --prompt briefing --profile spring
go run . smoke text_inference --campaign spring --llm-prompt briefing --llm-profile spring # Some diagnostics can fail or be unsupported; inspect the retained report.
go run . promptkit test all --campaign spring --llm-prompt briefing --llm-profile spring go run . promptkit test all --campaign spring --llm-prompt briefing --llm-profile spring
```
Inference uses the example's in-memory client. HTTP checks may be unsupported
or not applicable because the local backend has no network probe. The aggregate
can return a failure while still showing results. Read the facts in the report;
a successful command status does not mean every observation is positive.
For any command that returns nonzero, `go run` prints `exit status N` and itself
exits with status 1. A built executable returns the application's status directly.
The [CLI reference](../../../../docs/cli.md#promptkit-smoke-testing) explains the
standard test kinds, results, and statuses.
## Try aliases and application commands
```sh
go run . list collections --campaign spring
go run . pk list bundles --campaign spring
go run . pk show prompt briefing --campaign spring --fmt yaml
go run . smoke text_inference --campaign spring --llm-prompt briefing --llm-profile spring
go run . pk --hlep go run . pk --hlep
go run . session restore session-42 --campaign spring go run . session restore session-42 --campaign spring
go run . request inspect --llm-prompt briefing --llm-profile= --llm-model example --llm-input-text topic=sprint --format json go run . request inspect --llm-prompt briefing --llm-profile= --llm-model example --llm-input-text topic=sprint --format json
``` ```
`newApp` installs application-owned command and flag aliases alongside the The first two commands reach `promptkit list collections`. `pk` shortens the
complete `ckconfig` and `ckprompt` declarations. `list collections` and PromptKit group; `--fmt` is an alias on prompt inspection and `--hlep` is a global
`promptkit list bundles` both reach the canonical collection command; `pk` help alias. `smoke` shortens `promptkit test` while leaving the test kind as an
shortens the PromptKit group. `--fmt` is scoped to named prompt inspection and argument. The session command uses an in-memory store. `request inspect` shows
`--hlep` is available globally. The `smoke` shortcut retains the canonical how an application command can reuse canonical `--llm-*` flag collections without
`promptkit test KIND` operand, including the special `all` aggregate. installing PromptKit's short aliases.
The example installs `Completion("composed-example")`. Build it as ## Try shell completion
`go build -o composed-example .`. Initialize `bash-completion` first if using
Bash, then load a shell script as described in the
[CLI reference](../../../../docs/cli.md#shell-completion). Try completion after
`composed-example pk show prompt briefing --fmt=` or after the filename prefix
in `composed-example config show --config=fixtures/`. The already-entered `pk`
alias selects the PromptKit command context without loading an engine.
The composition installs `ckconfig.Command(suite)` and the complete ```sh
`ckprompt.Declarations(definitions)` in a `[]commandkit.Declaration` with go build -o composed-example .
root-installed routing rules. The PromptKit declarations include scoped aliases; ./composed-example completion bash
the application-owned `request inspect` command reuses the flag collections
with their canonical names and does not install those aliases.
Group children remain canonical `Command` values. For command-only slices,
convert each `Command` to `Declaration` before appending aliases. The
[consumer guide](../../../../docs/consumers/guide.md#application-owned-aliases)
includes minimal direct-call and slice-conversion examples; this README documents
the maintained complete consumer.
The sources and session store are small in-memory fixtures. `--campaign` is a
typed selector shared by the app and PromptKit configuration scopes. Their
`ckconfig.Suite[*inspectionInput, *runCache]` uses `NewInput` to initialize each
selected scope's input separately and `NewState` to create one cache shared by
that invocation's acquisitions. Prompt/profile inspection prepares its input and
cache independently for its invocation, using the same application and engine
loader functions. See the
[consumer guide](https://gitea.maximumdirect.net/eric/CommandKit/src/branch/main/docs/consumers/guide.md)
and the suites' GoDoc for initialization timing and ownership.
The application-scope comparison reports the changed default campaign and the
updated `campaigns.spring.model`. The PromptKit-scope comparison selects spring
on both sides and reports the native engine change in the atomic profiles list.
The application input check requires `--limit=0` when `--campaign` is supplied.
Catalogs use the same selection-aware loader: the prompt catalog includes
`briefing`, and the profile catalog includes the selected `autumn` profile.
Prompt inspection uses an ID only. The default PromptKit bundle also contributes
profiles and a backend to the engine inventory and source reports. The synthetic `field-notes` collection
provides one backend, profile, and prompt for collection discovery and native
namespace filtering. The example's shared run cache keys successful results by
the complete supplied configuration/overlay selection, CLI overrides, and the
supplied campaign, including presence. The campaign override and application
scope's `--set` records are applied through ConfigKit before loading. The
PromptKit configuration scope does not enable `--set` because its released
configuration loader has no override handoff. An aggregate operation therefore
rejects overrides when that scope is selected. These are choices for this
example's loaders and do not define a CommandKit cache policy.
Smoke testing is explicitly wired with `ckprompt.WithSmokeTesting` and its
optional request builder is nil, so CommandKit forwards the selected native
request. Applications that need to adjust the request can provide a typed
builder that starts with the seed and returns the chosen native request:
```go
definitions = ckprompt.WithSmokeTesting(definitions, loadEngine,
func(ctx context.Context, seed ckprompt.SmokeRequest, input *inspectionInput, state *runCache) (promptkit.SmokeTestRequest, error) {
request := seed.Request
request.ProfileID = "spring"
return request, nil
})
``` ```
The example injects a small in-memory `promptkit.LLMClient` through its shared Initialize `bash-completion` if using Bash, then load the generated script using
run state. Catalog, inspection, and requirements commands do not call it; the [CLI reference](../../../../docs/cli.md#shell-completion). Try completing
inference smoke commands do. No model service or credentials are required. `composed-example pk show prompt briefing --fmt=` or
Native HTTP checks may retain unsupported or not-applicable observations because `composed-example config show --config=fixtures/`. The already-entered `pk` alias
the selected local backend does not configure a network probe. An aggregate smoke command can selects the command context without loading an engine.
return an operational outcome for a native diagnostic while still delivering
the complete aggregate report.
The first requirements command reports incomplete discovery: PromptKit records ## How it is wired
the conditional `notes` input and a missing `mode` issue. Supplying `mode=full`
selects that branch, classifies the undeclared `notes` input as required, and
completes discovery. Both commands return successful reports; the result does
not execute the prompt or establish input, credential, or execution readiness.
See the [CLI reference](../../../../docs/cli.md#promptkit-requirements) for the
command and report contract.
The validation and preview commands exercise concrete PromptKit request preparation. The example installs `ckconfig.Command(suite)` and
The first uses the builder's campaign-specific default topic variable and the `ckprompt.Declarations(definitions)` with application-owned aliases in a
operator's topic file. The second also selects the notes branch and supplies its `[]commandkit.Declaration`. `NewInput` initializes scope inputs; `NewState`
file. Validation reports only `prompt_id` and `valid: true`; preview returns the creates a cache shared within an invocation. The loaders cache successful
prepared request, including rendered messages and effective provider settings. configuration results by the complete configuration/overlay selection,
Neither executes the prompt. The validation command without inputs intentionally overrides, and supplied campaign, including whether each value was supplied.
fails because the prompt's These are example choices, not a CommandKit cache policy.
required `topic` artifact is not supplied. The builder defaults variables from
the selected campaign but leaves artifact bindings to the operator. The
`requirements show` commands remain discovery reports: partial discovery can
succeed even when a concrete request would fail validation.
Run `GOWORK=off go test ./...` from this example directory to check it against Smoke testing uses `WithSmokeTesting` with a nil builder, forwarding the request
its declared dependencies. The [developer guide](../../../../docs/development.md#documentation-validation) selected by flags. Applications can supply a builder to customize that request.
also describes aligned workspace tests. See the [consumer guide](../../../../docs/consumers/guide.md#promptkit-configuration-definitions-and-requirements)
for suite composition, builders, and ownership, and the [source](main.go) for
the complete application.
Run `GOWORK=auto GOTOOLCHAIN=local go test ./...` from this example directory
for an aligned workspace check. Once dependency alignment is complete, also use
`GOWORK=off GOTOOLCHAIN=local go test ./...` to check the declared releases.

View File

@@ -39,9 +39,9 @@ func namespaceFlags[I any](destination func(*I) *namespaceInput, kinds ...string
} }
var namespaceFlagDefinitions = struct{ prompt, profile, backend requestFlagDefinition }{ var namespaceFlagDefinitions = struct{ prompt, profile, backend requestFlagDefinition }{
prompt: requestFlagDefinition{commandkit.FlagMeta{Name: "llm-prompt-namespace", Usage: "Prompt resource namespace."}, []string{"prompt-namespace"}}, prompt: requestFlagDefinition{commandkit.FlagMeta{Name: "llm-prompt-namespace", Usage: "Use this namespace for unqualified prompt IDs."}, []string{"prompt-namespace"}},
profile: requestFlagDefinition{commandkit.FlagMeta{Name: "llm-profile-namespace", Usage: "Profile resource namespace."}, []string{"profile-namespace"}}, profile: requestFlagDefinition{commandkit.FlagMeta{Name: "llm-profile-namespace", Usage: "Use this namespace for unqualified profile IDs."}, []string{"profile-namespace"}},
backend: requestFlagDefinition{commandkit.FlagMeta{Name: "llm-backend-namespace", Usage: "Backend resource namespace."}, []string{"backend-namespace"}}, backend: requestFlagDefinition{commandkit.FlagMeta{Name: "llm-backend-namespace", Usage: "Use this namespace for unqualified backend IDs."}, []string{"backend-namespace"}},
} }
func selectedNamespaces(defaults *promptkit.Namespaces, selected namespaceInput) *promptkit.Namespaces { func selectedNamespaces(defaults *promptkit.Namespaces, selected namespaceInput) *promptkit.Namespaces {

View File

@@ -35,24 +35,24 @@ var requestFlags = struct {
InputText requestFlagDefinition InputText requestFlagDefinition
InputFile requestFlagDefinition InputFile requestFlagDefinition
}{ }{
Endpoint: requestFlagDefinition{commandkit.FlagMeta{Name: "llm-endpoint", Usage: "Execution endpoint override."}, []string{"endpoint"}}, Endpoint: requestFlagDefinition{commandkit.FlagMeta{Name: "llm-endpoint", Usage: "Use this endpoint."}, []string{"endpoint"}},
Model: requestFlagDefinition{commandkit.FlagMeta{Name: "llm-model", Usage: "Execution model override."}, []string{"model"}}, Model: requestFlagDefinition{commandkit.FlagMeta{Name: "llm-model", Usage: "Use this model."}, []string{"model"}},
Temperature: requestFlagDefinition{commandkit.FlagMeta{Name: "llm-temperature", Usage: "Execution temperature override."}, []string{"temperature"}}, Temperature: requestFlagDefinition{commandkit.FlagMeta{Name: "llm-temperature", Usage: "Use this temperature."}, []string{"temperature"}},
MaxTokens: requestFlagDefinition{commandkit.FlagMeta{Name: "llm-max-tokens", Usage: "Execution maximum tokens override."}, []string{"max-tokens"}}, MaxTokens: requestFlagDefinition{commandkit.FlagMeta{Name: "llm-max-tokens", Usage: "Use this maximum token count."}, []string{"max-tokens"}},
TopP: requestFlagDefinition{commandkit.FlagMeta{Name: "llm-top-p", Usage: "Execution top-p override."}, []string{"top-p"}}, TopP: requestFlagDefinition{commandkit.FlagMeta{Name: "llm-top-p", Usage: "Use this top-p value."}, []string{"top-p"}},
TimeoutSeconds: requestFlagDefinition{commandkit.FlagMeta{Name: "llm-timeout-seconds", Usage: "Execution timeout override in seconds."}, []string{"timeout-seconds"}}, TimeoutSeconds: requestFlagDefinition{commandkit.FlagMeta{Name: "llm-timeout-seconds", Usage: "Set the request timeout in seconds."}, []string{"timeout-seconds"}},
ServiceTier: requestFlagDefinition{commandkit.FlagMeta{Name: "llm-service-tier", Usage: "Execution service tier."}, []string{"service-tier"}}, ServiceTier: requestFlagDefinition{commandkit.FlagMeta{Name: "llm-service-tier", Usage: "Use this service tier."}, []string{"service-tier"}},
ReasoningEffort: requestFlagDefinition{commandkit.FlagMeta{Name: "llm-reasoning-effort", Usage: "Execution reasoning effort override."}, []string{"reasoning-effort"}}, ReasoningEffort: requestFlagDefinition{commandkit.FlagMeta{Name: "llm-reasoning-effort", Usage: "Use this reasoning effort."}, []string{"reasoning-effort"}},
APIKeyEnv: requestFlagDefinition{commandkit.FlagMeta{Name: "llm-api-key-env", Usage: "Execution API key environment variable."}, []string{"api-key-env"}}, APIKeyEnv: requestFlagDefinition{commandkit.FlagMeta{Name: "llm-api-key-env", Usage: "Name the environment variable containing the API key."}, []string{"api-key-env"}},
TransientRetries: requestFlagDefinition{commandkit.FlagMeta{Name: "llm-transient-retries", Usage: "Inference transient retry count."}, []string{"transient-retries"}}, TransientRetries: requestFlagDefinition{commandkit.FlagMeta{Name: "llm-transient-retries", Usage: "Set the retry count for transient inference failures."}, []string{"transient-retries"}},
ExtraParams: requestFlagDefinition{commandkit.FlagMeta{Name: "llm-extra-params", Usage: "Execution provider parameters as a JSON object."}, []string{"extra-params"}}, ExtraParams: requestFlagDefinition{commandkit.FlagMeta{Name: "llm-extra-params", Usage: "Supply provider parameters as a JSON object."}, []string{"extra-params"}},
Prompt: requestFlagDefinition{commandkit.FlagMeta{Name: "llm-prompt", Usage: "PromptKit prompt ID."}, []string{"prompt"}}, Prompt: requestFlagDefinition{commandkit.FlagMeta{Name: "llm-prompt", Usage: "Select a prompt by ID."}, []string{"prompt"}},
Profile: requestFlagDefinition{commandkit.FlagMeta{Name: "llm-profile", Usage: "PromptKit profile ID."}, []string{"profile"}}, Profile: requestFlagDefinition{commandkit.FlagMeta{Name: "llm-profile", Usage: "Select a profile by ID."}, []string{"profile"}},
Backend: requestFlagDefinition{commandkit.FlagMeta{Name: "llm-backend", Usage: "PromptKit backend ID."}, []string{"backend"}}, Backend: requestFlagDefinition{commandkit.FlagMeta{Name: "llm-backend", Usage: "Select a backend by ID."}, []string{"backend"}},
SessionID: requestFlagDefinition{commandkit.FlagMeta{Name: "llm-session-id", Usage: "PromptKit session ID."}, []string{"session-id"}}, SessionID: requestFlagDefinition{commandkit.FlagMeta{Name: "llm-session-id", Usage: "Supply the session ID."}, []string{"session-id"}},
Var: requestFlagDefinition{commandkit.FlagMeta{Name: "llm-var", Usage: "Caller variable assignment KEY=VALUE."}, []string{"var"}}, Var: requestFlagDefinition{commandkit.FlagMeta{Name: "llm-var", Usage: "Supply a prompt variable as KEY=VALUE."}, []string{"var"}},
InputText: requestFlagDefinition{commandkit.FlagMeta{Name: "llm-input-text", Usage: "Literal prompt input assignment NAME=TEXT."}, []string{"input-text", "llm-input", "input"}}, InputText: requestFlagDefinition{commandkit.FlagMeta{Name: "llm-input-text", Usage: "Supply text for a prompt input as NAME=TEXT."}, []string{"input-text", "llm-input", "input"}},
InputFile: requestFlagDefinition{commandkit.FlagMeta{Name: "llm-input-file", Usage: "Prompt input file assignment NAME=PATH."}, []string{"input-file"}}, InputFile: requestFlagDefinition{commandkit.FlagMeta{Name: "llm-input-file", Usage: "Supply a file for a prompt input as NAME=PATH."}, []string{"input-file"}},
} }
// ExecutionInput contains request-scoped execution controls supplied on the CLI. // ExecutionInput contains request-scoped execution controls supplied on the CLI.

View File

@@ -29,11 +29,11 @@ func newSmokeTestCommand[I, S any](suite Suite[I, S], aliases *[]commandkit.Decl
return &(*input).captured return &(*input).captured
}) })
flags = append(flags, flags = append(flags,
commandkit.ValueFlag(commandkit.FlagMeta{Name: "config", Usage: "Configuration input path.", Completion: commandkit.CompleteFiles()}, (*string)(nil), parseDefinitionString, commandkit.ValueFlag(commandkit.FlagMeta{Name: "config", Usage: "Select the configuration input path.", Completion: commandkit.CompleteFiles()}, (*string)(nil), parseDefinitionString,
func(input **smokeCommandInput[I], value commandkit.Supplied[string]) { func(input **smokeCommandInput[I], value commandkit.Supplied[string]) {
(*input).selection.Config = value (*input).selection.Config = value
}), }),
commandkit.ValueFlag(commandkit.FlagMeta{Name: "overlay", Usage: "Configuration overlay path.", Completion: commandkit.CompleteFiles()}, (*string)(nil), parseDefinitionString, commandkit.ValueFlag(commandkit.FlagMeta{Name: "overlay", Usage: "Select the configuration overlay path.", Completion: commandkit.CompleteFiles()}, (*string)(nil), parseDefinitionString,
func(input **smokeCommandInput[I], value commandkit.Supplied[string]) { func(input **smokeCommandInput[I], value commandkit.Supplied[string]) {
(*input).selection.Overlay = value (*input).selection.Overlay = value
}), }),
@@ -54,13 +54,14 @@ func newSmokeTestCommand[I, S any](suite Suite[I, S], aliases *[]commandkit.Decl
return commandkit.NewCommand(commandkit.CommandSpec[*smokeCommandInput[I]]{ return commandkit.NewCommand(commandkit.CommandSpec[*smokeCommandInput[I]]{
Name: "test", Name: "test",
Summary: "Run one PromptKit smoke test.", Summary: "Run one or all PromptKit smoke tests.",
Description: "Tests use the configured client or probes and may contact a provider. The all option runs the four tests in order. Read the report: a successful command status does not mean every observation is positive.",
NewInput: func() *smokeCommandInput[I] { NewInput: func() *smokeCommandInput[I] {
return &smokeCommandInput[I]{} return &smokeCommandInput[I]{}
}, },
Flags: flags, Flags: flags,
Arguments: []commandkit.Argument[*smokeCommandInput[I]]{ Arguments: []commandkit.Argument[*smokeCommandInput[I]]{
commandkit.ValueArgument(commandkit.ArgumentMeta{Name: "kind", Usage: "Native smoke-test kind.", Completion: smokeKindCompletion()}, true, parseDefinitionString, commandkit.ValueArgument(commandkit.ArgumentMeta{Name: "kind", Usage: "Test kind: reachability, authentication, text_inference, structured_output, or all.", Completion: smokeKindCompletion()}, true, parseDefinitionString,
func(input **smokeCommandInput[I], value commandkit.Supplied[string]) { (*input).kind = value.Value }), func(input **smokeCommandInput[I], value commandkit.Supplied[string]) { (*input).kind = value.Value }),
}, },
CheckInput: func(input *smokeCommandInput[I]) error { CheckInput: func(input *smokeCommandInput[I]) error {

View File

@@ -31,11 +31,11 @@ func newConcreteRequestSpec[I, S any](suite Suite[I, S], path string, aliases *[
return &(*input).captured return &(*input).captured
}) })
flags = append(flags, flags = append(flags,
commandkit.ValueFlag(commandkit.FlagMeta{Name: "config", Usage: "Configuration input path.", Completion: commandkit.CompleteFiles()}, (*string)(nil), parseDefinitionString, commandkit.ValueFlag(commandkit.FlagMeta{Name: "config", Usage: "Select the configuration input path.", Completion: commandkit.CompleteFiles()}, (*string)(nil), parseDefinitionString,
func(input **concreteRequestInput[I], value commandkit.Supplied[string]) { func(input **concreteRequestInput[I], value commandkit.Supplied[string]) {
(*input).request.Selection.Config = value (*input).request.Selection.Config = value
}), }),
commandkit.ValueFlag(commandkit.FlagMeta{Name: "overlay", Usage: "Configuration overlay path.", Completion: commandkit.CompleteFiles()}, (*string)(nil), parseDefinitionString, commandkit.ValueFlag(commandkit.FlagMeta{Name: "overlay", Usage: "Select the configuration overlay path.", Completion: commandkit.CompleteFiles()}, (*string)(nil), parseDefinitionString,
func(input **concreteRequestInput[I], value commandkit.Supplied[string]) { func(input **concreteRequestInput[I], value commandkit.Supplied[string]) {
(*input).request.Selection.Overlay = value (*input).request.Selection.Overlay = value
}), }),
@@ -93,7 +93,7 @@ func newConcreteRequestSpec[I, S any](suite Suite[I, S], path string, aliases *[
func newValidationCommand[I, S any](suite Suite[I, S], aliases *[]commandkit.Declaration) commandkit.Command { func newValidationCommand[I, S any](suite Suite[I, S], aliases *[]commandkit.Declaration) commandkit.Command {
spec := newConcreteRequestSpec(suite, "promptkit requirements validate", aliases) spec := newConcreteRequestSpec(suite, "promptkit requirements validate", aliases)
spec.Name = "validate" spec.Name = "validate"
spec.Summary = "Validate a concrete PromptKit request without executing it." spec.Summary = "Check whether a request can be prepared without calling the model."
spec.Run = func(invocation commandkit.Invocation, input *concreteRequestInput[I]) commandkit.Outcome { spec.Run = func(invocation commandkit.Invocation, input *concreteRequestInput[I]) commandkit.Outcome {
return runRequestValidation(invocation, suite, input) return runRequestValidation(invocation, suite, input)
} }

View File

@@ -70,7 +70,7 @@ type CompletionResult struct {
} }
var reportingFlags = [...]Flag{ var reportingFlags = [...]Flag{
{Name: "quiet", Usage: "suppress substantive output and optional messages; keep failures visible", Default: "false", Boolean: true}, {Name: "quiet", Usage: "hide command output and optional messages; keep failures visible", Default: "false", Boolean: true},
{Name: "verbose", Usage: "show warning and informational messages", Default: "false", Boolean: true}, {Name: "verbose", Usage: "show warning and informational messages", Default: "false", Boolean: true},
{Name: "debug", Usage: "show debugging messages", Default: "false", Boolean: true}, {Name: "debug", Usage: "show debugging messages", Default: "false", Boolean: true},
{Name: "progress", Usage: "show progress messages", Default: "false", Boolean: true}, {Name: "progress", Usage: "show progress messages", Default: "false", Boolean: true},