50 KiB
CommandKit CLI standard proposal
Status: proposed; no commands in this document are implemented by CommandKit.
Date: 2026-10-06.
This proposal defines the command suite, operator behavior, and ownership boundary recommended for CommandKit. Audita, Narratio, Notarius, and Scriptorium provide evidence, rather than compatibility requirements. Adoption is expected to produce breaking changes. The decisions recorded below are accepted; other recommendations remain proposed. Implementation details and exact Go API declarations remain future work.
Accepted planning decisions
- Use namespace/resource first:
app config showandapp promptkit show. Whether the first noun describes a resource or a library namespace does not change the command grammar or its ownership boundary. - Assemble families from declared capabilities. Each family defines its own supported verbs; configuration scopes expose their available operations.
- Keep ordinary version output focused on the application. Explicit
version --scope commandkitreports embedded CommandKit identity. - Govern CommandKit's own behavior and provider contracts. Shared loading and callback organization are consumer guidance.
- Put PromptKit definition inspection under the single
promptkitfamily. CommandKit does not reserve the rootpromptandprofilenames. - Support
config show --scope all, with the application configuration followed by the PromptKit configuration when registered, as separate YAML documents. - Defer JSON output from the initial implementation. YAML supports automated consumption as well as operator inspection; JSON may never be needed and is not a promised later milestone. JSON Pointer remains the configuration path syntax and is independent of report format.
1. Purpose and ownership
Recommendation: CommandKit owns the entire config command family, root help,
and version reporting. It also offers the standard promptkit inspection family
for applications that integrate PromptKit. Applications own commands
outside these families, such as narratio session restore, narratio publish,
audita process, and scriptorium serve.
Ownership includes command names, accepted flags and arguments, defaults, help, report shapes, diagnostic presentation, streams, and exit behavior. Applications provide configuration schemas, source acquisition, domain resolution, validation, build metadata, and PromptKit engine construction. These collaborators supply data and perform domain work; they do not replace CommandKit's handlers or renderers.
CommandKit assembles standard families from registered capabilities and preserves its contracts for enabled operations. It rejects replacement standard handlers and private operations under its reserved families. Each family defines its own operation set; providers can supply supported subsets. Help and discovery expose that availability. New shared operations enter through versioned library changes. ADR 0001 owns this decision.
Applications may register context selectors and typed configuration overrides through the extension mechanism described in section 5. This is a defined input extension, not permission to alter standard operations or output.
Alternatives:
- Share helpers while applications own their handlers. Easy to integrate, but permits the same naming, scope, and output drift that motivates CommandKit.
- Allow arbitrary subcommands beneath standard families. Convenient initially, but makes the standard unpredictable and creates future name collisions.
- Own every command in every application. Unnecessary for the stated goals; domain operations have responsibilities that a shared inspection library cannot usefully prescribe. CommandKit can supply common parsing and help machinery without owning their business semantics.
2. Evidence and conclusions
The current checkouts demonstrate both reuse opportunities and choices that need to be replaced rather than preserved.
| Evidence | Conclusion for the standard |
|---|---|
Audita uses config print-effective; Notarius uses config effective; Narratio and Scriptorium use config show. |
Select one verb: show. |
Audita combines settings, selected profiles, and provenance under --view; Notarius uses --scope; Scriptorium has a separate framework configuration family. |
Separate the operation from the inspected configuration scope. |
Narratio's config sources reports field ownership; Scriptorium lists acquired source records. |
Give source inventory and field explanation distinct contracts. |
| Scriptorium's application and framework handlers repeat parsing, loading, warnings, dispatch, and output handling. | CommandKit should implement one inspection command family. |
| Notarius and Scriptorium inspect named PromptKit profiles; Scriptorium also inspects prompts. | Definition inspection is another demonstrated shared capability. |
| Narratio compares resolved overlays, rather than YAML file text. | Include semantic comparison of effective configuration. |
| Help, flag placement, validation success output, and error statuses differ. | Specify those behaviors centrally. |
Narratio invokes the other applications and interprets Scriptorium's status 2 as output validation failure. |
Breaking adoption requires coordinated consumer updates. |
Evidence sources, relative to this roadmap in the sibling workspace checkouts:
- Audita CLI contract and configuration parsing.
- Narratio CLI contract, configuration inspection, and comparison.
- Notarius CLI contract and configuration commands.
- Scriptorium CLI contract, application inspection, and framework inspection.
- ConfigKit inspection API, source records, and configuration contract.
- PromptKit configuration inspection and consumer guide.
These links document review evidence; they are not build dependencies. When the standard becomes implemented behavior, its durable reference should be owned by CommandKit rather than relying on sibling checkout links.
3. Recommended command inventory
Standard configuration operation inventory
| Command | Operator question or task |
|---|---|
app help [COMMAND ...] |
How do I use this command? |
app version |
Which application build am I running? |
app config scopes |
Which configuration scopes can I inspect? |
app config validate |
Is the selected configuration valid? |
app config show [--scope app|promptkit|all] |
What effective configuration will the application use? |
app config sources |
Which inputs contributed to this configuration? |
app config explain --path POINTER |
Why does this path have this value, or why was it removed? |
app config diff --against-config PATH or --against-overlay NAME |
How do two effective configurations differ? |
app is a placeholder for the application's executable name. Section 4 defines
scope defaults; section 5 defines selectors shared by configuration operations.
Optional PromptKit suite
| Command | Operator question or task |
|---|---|
app promptkit list prompts |
Which prompt IDs and versions are available? |
app promptkit list profiles |
Which execution profiles are available? |
app promptkit show prompt ID [--prompt-version VERSION] |
What is the selected prompt's definition metadata? |
app promptkit show profile ID |
What execution target does this named profile resolve to? |
Accepted: put this suite under promptkit, using the same namespace/resource
first pattern as config. The root names prompt and profile remain available
to applications.
Recommendation: use explicit resource operands after list and show.
Plural collection names select catalogs; singular names select one definition.
This keeps prompt IDs and execution profile IDs unambiguous even when they overlap.
Registration reserves the promptkit family and supplies handlers for its
declared definition capabilities. Its configuration scope is a separate capability;
definition operations and configuration inspection can be integrated independently.
Configuration inspection remains config show --scope promptkit; the definition
commands report metadata and resolved execution targets, not a second configuration
display path.
Definition catalogs require upstream API work; their absence today is an implementation dependency, not evidence against a useful command standard.
Alternatives:
- Bare
promptkit list. Could display a combined catalog with resource type, ID, and prompt version. Useful for discovery, but potentially noisy. An explicit resource gives each catalog a clear report shape; a combined listing can be considered as an additional operation later. promptkit show ID --type profile. Explicit and compact, but places the resource identity partly in a flag. Prefer the resource operand.promptkit show ID. Requires cross-collection lookup and ambiguity rules. Do not make inspection depend on prompt and profile IDs being globally unique.promptkit profiles list/show. Retains the accepted namespace boundary and is viable, but adds another resource grouping before the operation. The proposedpromptkit list/show RESOURCElayout puts the operation immediately after its owning namespace, as inconfig show.- Put definitions under
config, such asconfig profile. Mixes source configuration with backend-completed execution settings and givesconfigan unrelated resource vocabulary. - Include only the core suite initially. A reasonable delivery phase. Keep individual PromptKit capabilities pending until their public APIs are available; their absence leaves existing inspection capabilities available.
run, execute, render, serve, session, and artifact catalogs are not
CommandKit-owned commands in this proposal. Recommend run for a new application's
principal execution operation, but retain application ownership of that choice.
4. Configuration scopes
Recommendation: use --scope NAME on configuration operations, with these
standard identifiers:
app: the application's effective configuration, including defaults, imports, the selected overlay, explicit overrides, and recorded domain resolution. Each application's configuration schema remains its own.promptkit: the captured configuration of the PromptKit engine assembled from that application's selected inputs and registered assets, when integrated.all: a selector available toconfig validateandconfig show, meaning every registered scope. It is not itself a configuration scope or a merged document.
show, sources, explain, and diff default to app. validate defaults to
all: a bare validation command should establish that the configured application
and its integrated framework definitions are valid. --scope app provides the
explicit narrower check without constructing PromptKit. A non-PromptKit
application's all selection consists only of app. show --scope all is an
explicit request for a YAML stream of all selected scopes. sources, explain,
and diff continue to select one scope and reject all in this proposal.
The differing default for validation is intentional: routine inspection starts with the application configuration, while general validation performs a complete configuration check. An operator can request the combined inspection explicitly. Help must state these defaults prominently.
config scopes lists scope ID, description, and whether it is the default for
inspection, together with supported operations. It uses registration metadata,
so it works when files are missing or
configuration is invalid. List app first, promptkit second when registered,
then additional scopes sorted by ID; use this same order for show --scope all.
It accepts --format text|yaml and no loading selectors. Unsupported scope names
are usage errors, with the
available names in the diagnostic; there is no fallback to app.
Scopes use stable semantic names rather than executable names such as notarius.
Additional independently meaningful configuration scopes declare their supported
inspection operations and applicable providers. CommandKit validates declared
wiring and coordinates explicit dependencies, reusing compatible provider results
within an invocation. Scope inventory and help report the supported operations.
An unsupported scope-operation selection receives a usage diagnostic before
acquisition. all retains its all-scope meaning and checks coverage for the
requested operation. ADR 0009 owns the model.
A configuration scope targets configuration, while a command family targets its
own resources. A future FeedKit family could supply list and show; FeedKit
configuration inspection could separately register a configuration scope.
Alternatives:
- Default every operation to
app, requiringvalidate --scope all. Very uniform syntax, but easy to mistake application-only validation for validation of all definitions needed by the application. - Separate paths, such as
config promptkit show. Makes the scope visible in the command path; produces duplicated operation trees and complicates adding scopes. This remains a viable alternative if scope flags feel too indirect. - A scope-keyed wrapper for
show --scope all. Scope identity survives parsing in one document, but requires additional presentation work and indentation of the native reports. The accepted initial approach keeps separate native YAML documents; its output and ordering contract are defined below. - Require every inspection operation per scope. Gives a uniform inventory. A missing upstream operation then blocks useful existing capabilities. The selected approach exposes operation availability explicitly.
5. Shared inputs and command syntax
Configuration selection and overrides
Recommendation: register selection inputs according to provider applicability.
--scope NAME selects the configuration. Providers using an application root
accept --config PATH; ConfigKit overlay integrations accept --overlay NAME.
These names retain the same meanings wherever applicable. Additional source models
can declare their own selectors through the standard input extension mechanism.
--config selects the application root configuration even for promptkit scope;
the application constructs the selected framework inputs from that root and its
other explicit selectors. A supplied empty path is a usage error. A supplied
missing or invalid file is a load failure and never triggers discovery fallback.
Relative CLI paths use the invocation working directory. File-relative resources
retain the owning library's source-context semantics.
When --config is omitted, CommandKit invokes the registered acquisition callback
with that absence preserved. It exposes supplied discovery, environment, and
default-only metadata in help. Sharing acquisition code with ordinary execution is
recommended consumer practice; execution loading and filesystem discovery remain
application choices. ADR 0010 owns the
parsing and propagation contract.
--overlay always selects a configuration overlay, never a PromptKit execution
profile. Follow ConfigKit's naming and resolution semantics: omission, an empty
name, and the exact name default select the base; other names select one overlay.
An overlay name is not a file path. Replace --config-overlay with this standard
spelling rather than silently maintaining two conventions.
The registration API accepts domain context selectors, such as Narratio's
--campaign and --campaign-file, and typed configuration overrides. CommandKit
parses them, exposes their declared applicability in help, and passes values to
the selected callback. Field mapping and domain checks remain callback behavior.
CommandKit validates declared combinations and applicability before loading and
reports collisions with standard flags. Shared selector names keep their defined
meaning on the operations where they are registered.
CommandKit preserves explicit flag presence. Omission, an empty string, false, zero, and null retain their registered meanings. Using ConfigKit's recorded overrides and domain resolution is recommended for coherent values and provenance; CommandKit passes typed inputs to the registered integration callback. Execution-only controls such as resume, output directories for generated artifacts, or lane execution do not belong on generic configuration commands.
Alternatives:
- Require
--configon every operation. Simple and explicit, but makes inspection use a different entry path from normal execution and limits defaults-only applications. - Prescribe one global discovery sequence now. Could improve consistency, but expands this command proposal into deployment and configuration discovery policy. Evaluate that separately rather than preserving current differences by assumption or inventing paths without deployment evidence.
- Only expose root, overlay, and scope flags. Keeps the surface small but cannot inspect Narratio's resolved campaign contributions or explicit settings used by execution. A controlled registration mechanism is more effective.
- Offer a generic
--set path=value. Convenient for advanced operators, but requires a new value syntax and typing contract and makes overrides harder to discover. Defer until typed, documented flags prove insufficient.
Flag placement and repeated flags
Recommendation: put the complete command path before its options; allow flags and operands to be interspersed within the selected leaf command. For example:
app config show --config ./config.yml --scope promptkit
app promptkit show profile team.summary --config ./config.yml
app promptkit show profile --config ./config.yml team.summary
Standard flags use --long-name; -h is the standard help shorthand. Accept
--name value and --name=value; boolean false uses --name=false. -- ends
option parsing and makes subsequent tokens operands. Standard configuration
operations reject positional operands; promptkit list accepts a collection name,
and promptkit show accepts a resource name and its one documented ID. Flags may
appear before or after these operands. help accepts command-path operands.
Singleton flags reject repeated occurrences, including mixed --name value and
--name=value spellings. Repeatable source or domain flags combine in documented
order. Do not infer singleton presence from its parsed value. Unknown flags are
usage errors. New names use hyphens rather than underscores.
This is the contract for CommandKit-owned commands. Recommend the same grammar for application commands and supply reusable parsing machinery, while leaving their operand counts and domain rules application-owned.
Alternatives:
- Verb first, such as
app show config. Considered and not selected. It groups operations by action but spreads one namespace across root verb families and requires ownership at individual routes. Namespace/resource first gives each standard family a clear ownership boundary. - Require flags before all operands. Fits Go's
flagparser directly but retains the ordering burden the user wants to remove. - Allow common flags before or between command-path components. Familiar in some command frameworks; increases command routing complexity. A single documented position after the complete path is sufficient initially.
- Let the last singleton occurrence win. Convenient for argument assembly, but conceals conflicting operator instructions. Applications already have useful repeatable inputs; declare those explicitly instead.
Go's standard flag parser
stops at the first operand; pflag
supports interspersed options. The accepted backend decision
selects Cobra with pflag for the initial implementation. Any required adaptation must use
registered flag metadata, honor --, and correctly handle values beginning with
-; do not replicate Notarius's hand-maintained flag-name lists in every consumer.
6. Configuration command contracts
config validate
Recommendation: invoke each selected scope's declared validation capability. CommandKit checks support and coordinates required provider calls. The provider implements acquisition, composition, defaults, decoding, and domain resolution according to its public result contract. The PromptKit adapter requests upstream configuration validation with all-definition coverage. Missing upstream support is a dependency of that capability, rather than the entire integration. ADR 0008 owns this boundary.
CommandKit's validation handler requests the declared configuration-validation
operation and writes its result. Request preparation, execution, and operational
preflight belong to custom domain handlers, such as session validate. Source
acquisition and effects inside callbacks remain provider behavior. Registered
input applicability determines the selectors used by standard validation.
Default text output is one concise success line identifying the validated scopes.
--format yaml returns a structured success report containing the scope IDs.
Warnings go to stderr and do not alone make configuration invalid. Failure emits
no success report and returns status 1. Complete each scope's dependency loading
once; stop on a fatal loading failure rather than promising a report of every
possible defect across invalid inputs.
Credential requirements follow the genuine configuration lifecycle: ConfigKit loads can resolve typed secret references and therefore require the referenced environment values, whereas PromptKit inspection does not itself resolve provider credentials. Describe these requirements in scope help. Offline means no provider or remote execution; it does not promise credential-independent loading. Existing explicit credential-file bootstrap may run as part of acquisition, with its safe report through the supplied diagnostic channel. Callback effects and bootstrap policy remain application-owned; focused acquisition is recommended practice.
Alternatives:
- Only check decoding/schema validity. Useful as a distinct lower-level operation, but too weak for an unqualified application validation command.
- Validate only definitions selected by a planned run. Audita provides useful evidence for selected-profile checks, but a generic configuration command should find invalid configured definitions before a later selection reaches them.
- Silent success. Scriptorium demonstrates this and scripts can use the exit status. A short scope summary is clearer for interactive use; structured output supports automation without parsing prose.
- Skip secret resolution by default. Valuable for inspection without runtime credentials, but requires an explicit upstream ConfigKit lifecycle design. Do not simulate credentials or bypass native validation to deliver it.
config show
Recommendation: show the complete final effective configuration for the selected
scope, or each registered scope when --scope all is supplied.
Use the captured inspection snapshot, including recorded resolution, rather than
raw file text, an application-selected subset, or a fresh marshal of mutable
runtime structs. Loading necessarily performs the validation required to obtain
a usable snapshot. Single-scope display loads only that scope and its dependencies;
all loads every registered scope and reuses their shared dependencies.
Output is native redacted YAML without a status line. A single-scope report has no heading or document marker added by CommandKit. Preserve ConfigKit's distinction between null, empty containers, and absent values, its stable mapping order, and sequence order. This is an inspection document, not a guaranteed reloadable configuration file.
Accepted: --scope all writes the application configuration followed by the
PromptKit configuration when registered, then any additional scopes in the order
reported by config scopes. Each scope is a separate document, introduced by
--- and a # scope: NAME comment. CommandKit adds those separators and labels
around the native writer output without merging mappings or serializing runtime
structs. Even a one-scope all report uses this labeled document form.
---
# scope: app
server:
addr: localhost:8080
---
# scope: promptkit
profiles: {}
The stream provides a complete inspection in one invocation, preserves native rendering and redaction, and avoids collisions between scopes' mapping keys. Its tradeoffs are larger output and the need for automated consumers to decode multiple documents. Comments are human labels, not parsed metadata; scope identity for automated consumers follows the documented order. This is suitable YAML for automation, but it is not one configuration document or a reloadable combined file.
Check operation availability, acquire all selected views, and complete validation
required by their provider contracts before starting output. A scope load failure
returns 1 without a partial successful report. Writer failures can still leave
partial output. A broken PromptKit configuration can therefore prevent --scope all
from displaying otherwise usable application settings; --scope app remains
available for that narrower inspection.
config show has one initial report format, YAML, and does not need a --format
selector. JSON is deferred without a delivery commitment. The combined display
uses existing native writers and does not require a new structured effective
snapshot API solely for formatting.
Alternatives:
- A scope-keyed single YAML document. Scope names become machine-readable keys, but the renderer must wrap and indent each native document. This could replace comment/order identification if consumers need scope identity in parsed data.
- Emit each scope as soon as it loads. Reduces waiting before output, but a later load failure would leave an incomplete combined report. Prefer loading all scopes first.
- Raw composed input. Shows directives and authored values, but omits defaults and resolution and therefore answers a different question.
- Application-defined compact views. Audita's selected-profile summary is useful domain reporting, but does not replace a complete effective snapshot.
- A reloadable export command. Potential future feature with a different contract; do not imply that inspection output supports round trips.
config sources
Recommendation: list the acquired and synthetic input sources for the selected scope in the owning library's recorded order. Preserve every source's ID, label, path when available, layer, kind, underlay index, and import parent location. Do not sort sources alphabetically or flatten them into one winning file per field. Composite and inheritance provenance belongs to explanation records.
Default text output is a readable table; --format yaml returns the common source
report with an ordered sources sequence. Defaults-only loading may legitimately
produce an empty sequence. Defaults and domain derivations are not fabricated file
sources. Both application and PromptKit scopes use the same complete record
shape, replacing Scriptorium's differing source projections.
Alternatives:
- Field ownership under
sources. Narratio's report is useful but answers why a field has its value. Useconfig explainfor that task. - Only list filenames. Short, but loses underlays, non-file sources, import relationships, and CLI contributions that help diagnose configuration.
- YAML by default. Suitable for automation and consistent with native configuration reports. Prefer a table for interactive discovery and an explicit YAML format for structured consumption. Scriptorium's current JSON default is evidence to evaluate, not a format requirement for CommandKit.
config explain
Recommendation: require --path POINTER; an explicitly supplied empty string
selects the root. Use ConfigKit JSON Pointer semantics, including ~0 and ~1
escaping, mapping keys containing dots, and effective or historical paths. Omitted
path and malformed pointer are usage errors; a well-formed unknown path is a
command failure. Do not impose additional canonical-spelling restrictions beyond
the owning library's supported path contract without a demonstrated need.
Default text output delegates to the native safe explanation writer. It includes the effective value and presence, effective origin, composite source locations, inheritance, chronological before/after values, resolution reasons and dependencies, and safe secret-reference metadata when available. Historical deleted paths remain explainable. Values receive native historical redaction.
--format yaml projects the native structured explanation into CommandKit's
structured report. Keep value snapshots as records with present, redacted, and
yaml fields, matching the upstream representation rather than inventing a typed
value model for historical values. The yaml field holds native snapshot text
as a string rather than decoding it into a new value. History remains chronological.
app config explain --path /server/addr
app config explain --scope promptkit --path '/profiles/team~1summary/model'
app config explain --path ''
Alternatives:
- One positional pointer. Notarius demonstrates this and it is concise, but a named flag makes the required empty root explicit and allows a future distinct operand without ambiguity. Either convention could work if used everywhere.
- Value-free provenance only. Audita and Narratio demonstrate useful compact reports; native redacted history gives a more complete explanation. A future summary format could omit values without changing this command's meaning.
explain --alllisting every field. Useful for audits but potentially very large and expensive. Root explanation provides a starting point; defer exhaustive field-origin reporting until its traversal and summary contract are designed.
config diff
Recommendation: compare two independently resolved effective configurations in
the same scope. The ordinary selectors define the left side. At least one of
--against-config PATH or --against-overlay NAME explicitly defines the right
side; together they can change both root and overlay. Unspecified selectors are
copied from the resolved left selection, rather than running discovery again.
An omitted right overlay inherits the left overlay; --against-overlay default
explicitly selects the base. Domain context selectors and typed overrides apply
identically to both sides in this version.
app config diff --config ./config.yml --overlay staging --against-overlay production
app config diff --config ./old.yml --against-config ./new.yml --against-overlay default
For a scope declaring safe comparison support, acquire both views through the
registered provider's loading/validation contract. Compare effective values, including
defaults and recorded domain resolution, rather than YAML formatting, source IDs,
file order, or overlay names. Recursively compare mappings; keep sequences atomic,
preserving their order. Distinguish absence, null, empty mappings, and empty
sequences. Sort differences by JSON Pointer and report added, removed, and
changed with safe before/after snapshots. Root or container replacement must not
produce redundant descendant differences.
Default text output is a readable change report, or no differences when
appropriate. --format yaml supplies a structured report with selection metadata,
an ordered differences sequence, and explicit information about redacted comparison
gaps. Successful comparison returns 0 whether differences exist or not.
Compare only values that the owning library makes available for inspection.
Secret bytes must never be fetched to improve a comparison. A masked value is
not an ordinary literal string and identical masks do not prove secret equality.
Apply the union of both sides' sensitivity classifications to before/after
values so a value classified on either side cannot leak from the other report.
When sensitivity prevents comparison, identify the path as not comparable; do
not print no differences as an unqualified equality claim. This needs upstream
structured sensitivity metadata, not string matching on [REDACTED].
Alternatives:
- Two positional overlay names. Narratio demonstrates a simple interface, but it cannot also compare different root files without another syntax.
- Fully separate left/right domain selector sets. More flexible for campaign comparisons; adds substantial flag duplication. Shared context covers the existing overlay use case. Add independent contexts later if needed.
- Diff rendered YAML lines. Easy to implement, but formatting changes obscure meaningful changes and identical masks conceal comparison gaps.
- Return a special nonzero status for differences. Useful for CI assertions, but makes a successful inspection look like a failed command. Consider an explicit future check mode; keep ordinary comparison successful.
7. PromptKit definition inspection
Recommendation: optional definition commands use the same application root,
overlay, and registered framework source selectors as config --scope promptkit.
They always target PromptKit, so they do not accept --scope. They load the engine
once and use its captured definitions without provider calls, capacity admission,
request preparation, artifact loading, or credential lookup by PromptKit.
promptkit list prompts reports available (ID, version) pairs sorted by ID then
version; promptkit list profiles reports exact profile IDs sorted lexically.
IDs are identifiers, not filesystem paths, and prompt versions need not be semantic
versions.
promptkit show prompt ID uses PromptKit's existing version-selection rules:
omission of --prompt-version works only when that ID has one available version.
Show the definition ID, selected
version, opaque equality hash, declared default profile, declared inputs, and
output contract. It does not resolve the declared default profile or render
request-specific message templates. A command to show fully rendered requests
would need inputs and belongs to application preparation such as render.
promptkit show profile ID reports the backend-completed named execution target:
profile ID, backend, endpoint, model, configured provider controls, credential
reference name,
and whether a direct credential will be required. Do not suggest that a named
profile is the profile selected by every request, that zero indicates a provider
default, or that credential references establish credential availability.
All four commands default to readable text and accept --format yaml. Report
fields and their structured YAML shapes are defined by CommandKit; arbitrary
public Go structs are not an output contract. Unknown IDs or unavailable versions
return 1; missing
or empty required IDs and invalid argument counts return 2.
Provider parameter redaction belongs upstream in PromptKit. Notarius's curated
profile report is useful evidence, while Scriptorium's profile output does not
share configuration inspection's redaction contract. Establish a supported safe
profile reporting API before adding arbitrary provider parameters to the standard
report. Do not duplicate credential-name heuristics in CommandKit or assume that
raw InspectProfile results have native configuration redaction.
Alternatives:
- Inspect definitions only through
config show/explain. Adequate for source presence and history, but does not clearly expose backend-completed targets or catalog discovery. - Show raw prompt message content by default. Can help authors, but the current public prompt inspection reports metadata, and request rendering is a different operation. Add content inspection deliberately upstream if needed.
- List definitions by parsing effective YAML in CommandKit. Avoids new APIs, but takes ownership of PromptKit's schema and version model. Public catalog methods are the better boundary.
8. Help and version
Help
Recommendation: app, app help, app --help, and app -h print root help
and succeed. A command group with no execution handler, such as app config,
prints group help on bare invocation and succeeds. Runnable commands follow their
registered handler and operand requirements, including when they also have
subcommands. ADR 0006 records this distinction.
app help config explain and
app config explain --help print the same leaf help with status 0.
Help never acquires configuration, constructs PromptKit, resolves credentials, or allocates runtime state. Generate it from registered commands and flags, including application-owned commands, available scopes, selector applicability, format choices, and examples. An unknown command path is a usage error. A help request bypasses missing required operands; it does not make an otherwise unknown command or unknown flag valid.
Alternatives:
- Only root help. Notarius's current leaf help errors demonstrate why this is insufficient for an operator trying to discover arguments.
- Error on a bare root or family. Narratio and Scriptorium do this in some cases. Printing help successfully makes exploration consistent; an explicitly malformed leaf invocation still fails.
- Maintain separate help strings. Straightforward, but they drift from parsing definitions. Registration should be the shared source.
Version
Accepted: app version prints app VERSION and a newline; root
app --version reports the same application identity. The version command defaults
to --scope app. app version --scope commandkit explicitly reports the embedded
CommandKit release version. --format yaml changes presentation of the selected
identity. Version subjects are separate from configuration scopes. CommandKit
uses build metadata with acquisition callbacks left uninvoked.
Future component identities can use registered version metadata. ADR 0004 records version selection.
Applications supply build identity, with tagged Go build information usable when
available. An unversioned development build reports dev; unknown revision or
build time stays absent rather than being invented. The CommandKit release version
identifies the library and its standard CLI contracts. Compatibility changes
follow the release policy.
Alternatives:
- Only the command or only the flag. Either could be consistent; supporting both familiar discovery paths costs little and gives them one implementation.
- Emit all build and dependency information by default. Helpful for debugging, but unnecessarily verbose and unstable for a simple identity check. Structured output should expose the selected fields.
- List dependency versions alongside application version by default. Adds diagnostic detail to an identity check. Explicit subject selection keeps each report focused.
- Use a combined dependency-version option. Useful for a broad inventory. Scoped selection also supports querying one embedded component.
- Add a separate integer CLI standard revision. Rejected during ADR review. The tagged CommandKit release version provides the shared compatibility identity.
9. Output, diagnostics, and failures
Recommendation: successful reports go to stdout; warnings, loading diagnostics, bootstrap reports, and errors go to stderr. Emit each diagnostic once, retain library source coordinates and source-ID legends, and use library-safe messages. No progress messages or banners may enter report output.
| Operation | Default | Other initial format |
|---|---|---|
help |
text | none |
version |
text | YAML |
config scopes, validate, sources, explain, diff |
text | YAML |
config show (one scope or all) |
YAML | none |
promptkit list/show |
text | YAML |
Format names are lowercase. Unsupported formats are usage errors. Use --format
consistently for commands that offer text and YAML; do not add a selector to
YAML-only config show. Structured reports other than the native config show
documents use a defined operation-specific schema and the applicable scope or
selection metadata. Define their exact YAML field shapes before implementation;
do not make native explanation prose or Go struct field spelling a machine
contract. Structured YAML reports contain one document with a trailing newline;
config show --scope all deliberately uses a multi-document stream.
Accepted: defer JSON output for the initial implementation across the suite. YAML is suitable for automated consumption, and the native inspection writers already preserve its value semantics. There are no initial JSON format flags, JSON-specific report schemas, or JSON-driven upstream API requirements. Adding JSON is optional future work only if a concrete need emerges; it may never be needed. JSON Pointer paths remain supported independently of output format.
Inspection formats use upstream secret classification; there is no unredacted output option in this standard. Redaction does not classify every sensitive prompt or arbitrary application value. The proposal preserves library confidentiality semantics rather than promising that every report is safe for public disclosure.
Default to stdout and shell redirection; do not initially add --out or --output
to standard reports. Ordinary writer failures may leave partial output and return
1; checking status before decoding is recommended caller practice. This avoids adding filesystem
creation, replacement, and retention behavior to inspection.
| Status | CommandKit-owned command meaning |
|---|---|
0 |
Successful operation, including help, valid configuration, or comparison that found differences. |
1 |
Loading, validation, lookup, explanation, comparison, cancellation, diagnostics delivery, or output failed after valid syntax. |
2 |
Unknown command/flag/scope, invalid format, missing or malformed argument, repeated singleton, or invalid flag combination. |
Applications retain domain result statuses for their own commands. CommandKit must
not globally reinterpret Scriptorium's execution validation status or Notarius's
artifact rejection semantics. Common usage errors can use the shared status 2,
but business outcomes remain explicit application mappings.
Alternatives:
- Structured YAML everywhere by default. Works for automation, but text help, tables, and native explanations are useful for interactive inspection. Offer YAML explicitly where the default is text.
- JSON as an additional output format. Deferred by the accepted decision. It would add serializers, report contracts, and possible representation issues without a demonstrated benefit over the initial YAML reports.
- An output-file flag on every command. Convenient but duplicates shell redirection and introduces file semantics. Add it later if concrete consumers need behavior beyond redirection.
- One nonzero status for every failure. Narratio and Scriptorium demonstrate simplicity, but distinguishing malformed invocation from a failed valid command is useful and already demonstrated by Notarius.
- One exit policy for all application execution outcomes. Would exceed the ownership boundary. Coordinate changes to owned commands without claiming domain statuses for unrelated commands.
10. Implementation dependencies and delivery
Recommendation: implement the common command behavior against narrow inspection
providers, with ConfigKit and PromptKit retaining ownership of configuration
semantics. Publish upstream API improvements before adopting them in CommandKit
and the applications. Do not import sibling internal packages or turn source
checkout proximity into an architectural dependency.
Existing public APIs already support native YAML, native explanation text, structured explanation records, source records, and named definition inspection. They do not yet provide everything recommended here:
| Needed capability | Implementation work for that capability |
|---|---|
| Semantic diff | A safe structured effective snapshot from ConfigKit, preserving value semantics and per-path sensitivity; expose it through PromptKit inspection. This serves comparison rather than JSON output. |
| Combined configuration display | Compose native writers as labeled separate YAML documents after all selected scopes load; no new snapshot API is needed just to concatenate these reports. |
| Prompt/profile catalogs | Public PromptKit methods enumerating captured IDs and prompt versions without reparsing source YAML. |
| Safe rich profile reports | PromptKit-owned redacted inspection data for provider parameters. |
| Narratio's final application snapshot | Adapt its configuration boundary so campaign-derived effective values and provenance are recorded in the inspected result; avoid an unrelated typed-struct dump. |
| Cross-scope validation | Registered validation capabilities and dependencies, with their actual acquisition and credential requirements exposed in help. |
Suggested sequence:
- Resolve the remaining proposed command contracts and alternatives, preserving the accepted planning decisions above.
- Define the structured YAML report schemas and minimal upstream inspection additions. Record accepted ownership decisions in durable architecture documentation.
- Implement core dispatch, syntax, help, version, scopes, validation, native
display (including
show --scope all), source inventory, and explanation using existing APIs. - Integrate Scriptorium and Notarius to exercise both scopes and remove duplicated handlers. Register and report the supported capabilities; additional upstream features can be integrated independently.
- Add safe semantic comparison and additional PromptKit definition capabilities as their upstream APIs are released.
- Integrate Audita and Narratio, moving domain reports outside reserved families and aligning their standard operations. Update consumer adapters and docs for the intentional breaking releases.
CommandKit installs supported operations with their standard meanings and exposes actual capabilities in help and scope metadata. Missing comparison or catalog support leaves other operations available. Each family's resources determine its supported verb set. Initial ConfigKit/PromptKit reports retain their chosen formats; future families define suitable report contracts for their own resources.
Later implementation validation should exercise genuine contract risks: help with
invalid configuration, leaf flag placement and --, explicit empty/false/zero
overrides, source order, historical paths, independent diff selections, sensitivity
changes between sides, multi-document scope order, all-scope load failures before
output, warning delivery and failed writers, and Narratio's subprocess consumers.
Breaking adoption replaces divergent spellings and behavior. Compatibility aliases are not required; introduce one only for a concrete transition need with an explicit retirement decision. Application execution commands outside the reserved suite remain independently owned, even when their implementations use CommandKit helpers.
Alternatives:
- Extract one existing application's command family unchanged. Fast, but carries its omissions and incidental decisions into the standard. Use existing implementations to inform and exercise the selected contract instead.
- Build one universal runtime/application framework. Could absorb more code, but would expand ownership into lifecycle and domain execution without improving the demonstrated inspection boundary.
- Implement missing upstream semantics inside CommandKit. Avoids release coordination, but duplicates configuration projection, redaction, and definition knowledge. Those responsibilities should remain with the libraries that own them.
11. Explicitly deferred commands
Recommendation: defer configuration mutation (set, edit, init, migrate),
reloadable export, credential diagnostics, live provider probes, completion
installation, exhaustive field-origin inventories, request preparation, and domain
artifact catalogs from this standard. Their semantics are not established by the
repeated inspection code under review. Add a shared command when its operator
purpose and ownership can be specified as clearly as the suite above.
JSON output is also deferred, with no assumption that it will eventually be added.
Alternatives:
- Add a generic
doctorcommand now. Attractive for troubleshooting, but mixes offline configuration, credentials, network health, and domain resources. Specify those checks before choosing a shared name and success meaning. - Standardize
runin this first suite. Could further improve vocabulary, but requires comparing execution semantics and their consumer contracts. A recommended verb is useful now; reserving its complete contract is separate work.