Files
commandkit/docs/consumers/guide.md

7.2 KiB

Consumer guide

CommandKit is distributed as three Go modules. Start with the core and add an integration module only when the application uses that library. Each module returns core commandkit.Command declarations, which the application installs through commandkit.New or App.Register.

Module selection

Import Use when
gitea.maximumdirect.net/eric/CommandKit The application needs typed command declarations and common CLI behavior.
gitea.maximumdirect.net/eric/CommandKit/integrations/ckconfig The application wants ConfigKit-backed configuration scopes and reports.
gitea.maximumdirect.net/eric/CommandKit/integrations/ckprompt The application wants PromptKit engine configuration or named prompt/profile inspection.

The two integrations are independent optional imports. ckprompt uses the public scope and error contracts from ckconfig; importing it does not add the config family. An application that wants both families passes both returned declarations to core. The maintained examples show core-only, ConfigKit-only, and composed applications.

Go compatibility

All three modules declare a consumer minimum of Go 1.26.0. The root module also selects ReleaseKit v0.4.0 as a Go tool, which makes that tool's module graph part of the root consumer module requirements even though production packages do not import ReleaseKit. The release policy defines the support assumption. Maintainers use Go 1.26.8 for validation and publication; see the release procedure.

Core commands

Declare typed flags and operands with CommandSpec[I], then capture them with NewCommand. Bindings deliver Supplied[T], which distinguishes an omitted default from an explicitly supplied empty, false, or zero value.

package example

import (
	"fmt"
	"strconv"

	commandkit "gitea.maximumdirect.net/eric/CommandKit"
)

type GreetInput struct {
	Count commandkit.Supplied[int]
}

func Greeting() commandkit.Command {
	countDefault := 1
	return commandkit.NewCommand(commandkit.CommandSpec[GreetInput]{
		Name: "greet", Summary: "Write a greeting.",
		Flags: []commandkit.Flag[GreetInput]{
			commandkit.ValueFlag(
				commandkit.FlagMeta{Name: "count", Usage: "Number of greetings."},
				&countDefault, strconv.Atoi,
				func(input *GreetInput, value commandkit.Supplied[int]) {
					input.Count = value
				},
			),
		},
		Run: func(invocation commandkit.Invocation, input GreetInput) commandkit.Outcome {
			_, _ = fmt.Fprintln(invocation.Streams.Out, input.Count.Value)
			return commandkit.Success()
		},
	})
}

The application supplies context.Context, argv without the executable name, and output streams to App.Execute; it decides how the returned status maps to process exit. New installs generated help/version and caller declarations as one batch. Register validates each call as a batch before changing that App. Invalid declaration errors retain their wrapped identity for errors.Is and errors.As.

Declarations copy their metadata and slice inputs when captured, retain callback references, and can be reused across applications. Copies of a typed binding preserve its identity; a separately constructed lookalike does not. Supplied values convert before input construction. A command's NewInput creates input only when execution reaches it; help does not construct caller input or run provider callbacks.

ConfigKit scopes

For an application with one ordinary app configuration loader, ckconfig.AppCommand supplies the state-free convenience declaration:

app, err := commandkit.New(
	commandkit.Identity{Name: "Example", Version: "dev"},
	ckconfig.AppCommand(loadAppConfig),
)

loadAppConfig has the signature func(context.Context, ckconfig.Selection) (*configkit.Result[T], error). Construction, installation, and help do not call it. Selection preserves whether config and overlay paths were explicitly supplied, including empty values.

Use ckconfig.Command(ckconfig.Suite[I, S]{...}) when the application needs multiple named scopes, selector flags, scope-aware input checks, or shared acquisition state. Each selected scope receives its own initialized input. The suite's NewState runs once for the inspection invocation after selected input checks pass, and the resulting state is shared by selected acquisitions. The application owns the state type and what it caches. ckconfig.FromConfigKit adapts a typed ConfigKit loader without calling it during construction.

The config family provides scope discovery, validation, native effective YAML, source inventory, and path explanation for the capabilities declared by its scopes. The CLI reference owns operator syntax and report details.

PromptKit configuration and definitions

ckprompt.ConfigScope(loadEngine) returns a ckconfig.Scope for the PromptKit engine's captured configuration. Add that scope to a ckconfig.Suite to expose it under config; it does not install named definition commands.

ckprompt.FromEngine(loadEngine) supplies PromptKit named prompt and profile inspection callbacks. Set its NewInput, NewState, selectors, or validation when the application needs them, then pass ckprompt.Command(suite) to core. Prompt and profile capabilities can be installed independently by providing only the corresponding callback. Each selected inspection gets a fresh input and one shared state value for that invocation. The loader receives the invocation context, explicitly supplied selection, input, and state. The adapter uses PromptKit's public inspection methods and preserves acquisition diagnostics and error identity.

Definition inspection does not execute a prompt, contact a model provider, or resolve credential values. Credential fields in reports identify environment variable names and requirements only; they do not report credential availability.

The composed example combines app and PromptKit config scopes, independently registers profile inspection, and adds an application-owned session restore command.

Outcomes and ownership

Core classifies usage and operational failures while preserving application domain outcomes and supported error identity. Report and diagnostic delivery errors remain inspectable separately from the operation cause. The caller owns process startup, signal handling, and exit mapping; Execute never exits the process.

Go declarations and GoDoc own exact exported contracts. ConfigKit owns configuration decoding, validation, and provenance. PromptKit owns prompt formats, profile resolution, and inspection details. See the ConfigKit inspection API, PromptKit engine methods, configuration inspection, and inspection types.