Files
commandkit/docs/cli.md

16 KiB

Command line reference

CommandKit owns command routing and syntax for commands registered with its App. The caller supplies argv without the executable name, a context, and the output and diagnostic writers. App.Execute returns an Outcome; it does not exit the process.

Help

The root help command lists registered commands and their summaries. Help is available through a bare invocation, --help, -h, and help:

example
example --help
example -h
example help
example help config show
example config --help

help [COMMAND...] resolves an exact registered path. A command group without an execution handler displays its help when invoked by itself. A runnable command with children runs its handler when invoked without help; add --help to inspect that command and its children.

Help uses registered descriptions, command summaries, local flags, defaults, required and repeatable flag metadata, and operand names and counts. It does not construct the selected command's input or invoke its handler. Supplied flag and operand values are still parsed so malformed values and unknown flags remain usage errors. Missing execution-required values and input-combination checks are skipped for help.

Version

version reports the application identity by default:

example version
example version --scope commandkit
example version --format yaml

The supported flags are:

Flag Values Default Meaning
--scope app, commandkit app Select the caller's application identity or the embedded CommandKit module identity.
--format text, yaml text Select the output format.

Text output is NAME VERSION, followed by (REVISION) when the selected identity has a revision. An empty application version is displayed as dev; the revision remains empty when omitted.

CommandKit identity uses the version of its module in build information. A versioned module replacement supplies the effective version. A local or versionless replacement, an untagged module, or missing build information displays dev. The CommandKit identity name is CommandKit; dependency build metadata does not supply a revision.

YAML output uses these explicit fields, including an empty revision:

name: ExampleApp
version: dev
revision: ""

Registered command syntax

Options are parsed after the complete command path and may be interspersed with declared operands. Flags are local to the selected command. Use -- to end option parsing; all later tokens are operands.

Value flags accept --name value and --name=value. Boolean flags accept presence as true and explicit values such as --enabled=false. A singleton flag accepts repeated occurrences; the last successfully parsed occurrence supplies its value. Every supplied occurrence is converted, so an earlier malformed value remains an error. Repeatable flags preserve occurrence order, with each occurrence treated as one value, including strings containing commas.

Typed inputs keep supplied state separate from defaults. An explicit empty, false, or zero value is supplied. Help and version are available without constructing application command inputs.

Configuration scopes

An application installs the declaration returned by ckconfig.Command(ckconfig.Suite[Input, State]{...}) through commandkit.New or App.Register. For the common single application scope, ckconfig.AppCommand returns a convenience declaration. The installed config scopes command lists scope names and the configuration operations currently available for those scopes:

example config scopes
example config scopes --format yaml

Text output uses one scope: operation, operation line per scope. YAML uses a scopes sequence with explicit name and operations fields. Scope order is app, then promptkit, then other names alphabetically. A metadata-only scope can be listed without an acquisition callback. Discovery does not construct a runtime context or acquire configuration. It reports the intersection between declared scope capabilities and installed handlers, so an operation is listed only when the corresponding command is available.

Applications can add ckprompt.ConfigScope(loadEngine) to the ConfigKit suite to expose PromptKit engine configuration through these handlers. This scope does not install PromptKit prompt or profile definition commands.

Validate configuration

config validate loads and validates the selected scope. The default scope is app; --scope all validates every registered scope and is available when each scope declares validation. The command checks all selected capabilities before calling scope providers. Its default format is text; --format yaml emits a scopes sequence with name and valid: true for each scope that completed successfully.

example config validate
example config validate --scope promptkit --format yaml
example config validate --scope all

Each successful scope is reported as SCOPE: valid. Aggregate validation stops at the first load or output failure; records from earlier successful scopes may already have been written. Provider warnings go to the diagnostic stream and do not alone make validation fail. --config and --overlay preserve whether an empty value was explicitly supplied, so a scope callback can map those inputs to its own ConfigKit load policy. Help and invalid syntax do not call scope providers.

Show effective configuration

config show writes the provider's native effective YAML for one scope. Its default scope is app; --format yaml is accepted and YAML is the only initial format. Single-scope output is passed through unchanged, without a CommandKit header or document marker.

example config show
example config show --scope promptkit
example config show --scope all

--scope all acquires every selected scope and checks each effective writer before writing output. It then emits one YAML document per scope in discovery order, with a # scope: NAME comment at each document boundary. For ordinary block documents the comment follows the marker. When a native opening marker contains inline content, the comment precedes that marker so it does not interrupt the native value. Existing native markers and leading comments are retained; documents without a marker receive one. Scope labels containing line control characters are quoted to keep them on one comment line. A provider failure leaves the output stream empty. A rendering or output failure may leave an aggregate prefix, and the outcome reports incomplete report delivery.

List configuration sources

config sources reports the source inventory captured during the selected scope's acquisition. It reads the source facet once and does not reload configuration. The default scope is app; --scope all is unsupported. Text is the default format, and --format yaml returns a structured report:

scope: app
sources:
  - id: source-1
    label: "application config"
    path: /etc/example/config.yml
    layer: base
    kind: file
    underlay_index: 0
    imported_from: null

Each source includes id, label, path, layer, kind, underlay_index, and imported_from. The import location is null when absent; otherwise it has source_id, line, and column. Owning values and source order are preserved, including empty fields, zero coordinates, and synthetic sources without paths. An empty inventory is sources: []. Text output begins with the scope heading and then prints the same source fields, quoting labels and paths.

Explain a configuration path

config explain --path POINTER explains the effective and historical value at a JSON Pointer path. --path is required; an explicitly empty value selects the root. The default scope is app; --format yaml selects structured output, and text is the default. --scope all is unsupported.

example config explain --path /server/addr
example config explain --path /profiles/team~1summary --format yaml
example config explain --path= --format yaml

Pointer tokens use JSON Pointer escaping: ~1 represents / and ~0 represents ~. A malformed pointer is a usage error with status 2 and is rejected before acquisition. A well-formed path that is unknown in the selected configuration is an operational error with status 1. Text output comes from the scope's native explanation writer.

YAML output uses these root fields:

scope: app
path: /server/addr
effective:
  present: true
  redacted: false
  yaml: "localhost:8080\n"
origin:
  layer: base
  locations:
    - source_id: source-1
      line: 4
      column: 9
  operation: ""
  inheritance: []
history: []
secret_reference: null

Snapshot yaml values remain strings, including null and empty fragments. Origin and history retain source locations, operation names, inheritance paths, ordered reasons and dependencies. Secret references contain only the owning environment-variable name; effective and historical secret fragments remain redacted. Empty location, inheritance, history, reason, and dependency lists are serialized as [].

Compare configuration selections

config diff prepares two selections for one scope that declares comparison and invokes its comparison provider after input checks pass. The default scope is app; --scope all is unsupported. The PromptKit engine scope does not currently declare comparison, so selecting --scope promptkit is a usage error. --config and --overlay select the left side. --against-config and --against-overlay independently override the right side. When a right-side field is omitted, it inherits the corresponding left value and supplied state; an explicit empty string overrides it and remains supplied. Equal selections are allowed; their equality alone does not cause CommandKit to skip the provider.

YAML is the only format and the default. Explicit --format yaml is accepted; text and other formats are usage errors. For example:

example config diff --config before.yml --against-config after.yml
example config diff --config base.yml --against-overlay candidate
example config diff --config base.yml --overlay current --against-overlay ""

ConfigKit compares frozen effective typed values after defaults and resolution; source or provenance differences alone do not create a change. The report is one YAML document with additions, changes, and deletions in that order. Additions and changes preserve semantic paths and contain safe right-side values. Deletions contain canonical JSON Pointer paths. Explicit null is a value; it is not a deletion. Changed sequences and native structural replacement regions stay atomic.

ConfigKit pairs sensitivity across both loads. A concealed change can therefore appear even when its two safe snapshots are equal. The report omits separate redaction and hidden-change metadata: a reported masked region changed, but that does not mean every member inside it changed. Marker-looking public strings stay ordinary YAML values. An empty comparison succeeds with this shape:

additions: {}
changes: {}
deletions: []

The reduced report is a partial safe view, not a reloadable configuration or an automatically applicable patch. Exceptional whole-root empty/null transitions can be ambiguous because the report has no root envelope; ordinary field-level null values and deletions retain their distinction.

Successful comparisons return status 0, including concealed or empty results. Unsupported scopes and format errors are usage errors; input checks retain the existing usage/operational classification. Load and native comparison failures are operational and preserve supported error identity.

The bundled FromConfigKit and AppCommand adapters invoke the supplied loader for each reached side, left before right, then call native comparison. They label native diagnostics with their left/right side and source legend, retain left diagnostics if right loading fails, and gather both loads' diagnostics before native comparison. Custom pair providers own their loading and diagnostics; application loaders and caches determine whether a loader call reads sources again.

The complete report is prepared before writing. Report preparation failures and cancellation observed before report delivery starts leave CommandKit's report output empty. Once writing starts, CommandKit does not interrupt the supplied writer or roll back delivered bytes. A write error or short write uses the existing incomplete-report delivery outcome and can leave partial output.

PromptKit definition inspection

Applications can install prompt and profile inspection independently with ckprompt.Command(suite), passing the resulting declaration to core. The ckprompt.FromEngine(loadEngine) adapter supplies callbacks that acquire an engine only after input checks pass and inspection is reached. The loader receives invocation context, selection, input, and state; its implementation controls whether an engine is constructed or reused. Direct suite callbacks retain their own implementation and lifecycle.

CommandKit's inspection path does not execute prompts, contact model providers, or resolve provider credential values. Application acquisition and direct callback effects remain application-owned. Prompt definitions and profile resolution remain owned by PromptKit's inspection API.

example promptkit show prompt customer/summary --version 2 --format yaml
example promptkit show prompt customer/summary
example promptkit show profile customer-support --format yaml

Both commands require one ID operand and accept --config, --overlay, and --format text|yaml (default text). Prompt inspection also accepts singleton --version, defaulting to the empty string. PromptKit owns version selection: an omitted version works for a single-version ID, while an ambiguous ID is an operational error. These commands have no built-in --scope selection; their namespace is promptkit.

Prompt YAML has these fields. Input order is preserved and an empty input list is []. The prompt hash is an opaque owning-library equality value.

prompt_id: customer/summary
prompt_version: "2"
prompt_hash: opaque-value
default_profile_id: customer-support
inputs:
  - name: topic
    required: true
    content_type: text/plain
    description: Topic to summarize
output_contract:
  format: json
  validation_mode: basic
  schema_path: ""
  repair_attempts: 2

Profile YAML preserves the effective values reported by PromptKit, including zero values and nested provider parameters. api_key_env is only an environment-variable name. api_key_required reports a direct credential requirement; neither field reports credential availability. A nil provider parameter map is displayed as {}.

profile_id: customer-support
effective_model_params:
  backend_id: local
  endpoint: https://example.invalid/v1
  model: support-model
  temperature: 0
  max_tokens: 0
  top_p: 0
  timeout_seconds: 600
  service_tier: ""
  reasoning_effort: ""
  api_key_env: ""
  extra_params: {}
api_key_required: true

Text uses labeled fields and includes nested extra_params values. A missing ID is a usage error. Blank, unknown, and ambiguous definition selections reach the owning inspection API and produce operational results with supported public error identity. Cancellation is also operational: standard handlers check the caller's context at inspection boundaries, and PromptKit can return cancellation from its own inspection methods. Supported cancellation identity is preserved.

Outcome status

CommandKit usage failures use status 2; operational failures use status 1. Successful operations use status 0. Application handlers may return a domain classification and status of their choice, which Execute preserves. The caller chooses how to map an outcome to process exit.