2026-10-06 16:32:59 +00:00
# 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 show` and `app promptkit show` .
Whether the first noun describes a resource or a library namespace does not
change the command grammar or its ownership boundary.
2026-10-06 23:36:06 +00:00
- 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 commandkit` reports embedded CommandKit identity.
- Govern CommandKit's own behavior and provider contracts. Shared loading and
callback organization are consumer guidance.
2026-10-06 16:32:59 +00:00
- Put PromptKit definition inspection under the single `promptkit` family.
CommandKit does not reserve the root `prompt` and `profile` names.
- 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.
2026-10-06 23:36:06 +00:00
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 ](../adr/0001-command-dispatch-and-inputs.md ) owns this decision.
2026-10-06 16:32:59 +00:00
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 ](../../../audita/docs/cli.md ) and
[configuration parsing ](../../../audita/internal/cli/config_input.go ).
- [Narratio CLI contract ](../../../narratio/docs/cli.md ),
[configuration inspection ](../../../narratio/internal/app/config_commands.go ),
and [comparison ](../../../narratio/internal/app/config_diff.go ).
- [Notarius CLI contract ](../../../notarius/docs/cli.md ) and
[configuration commands ](../../../notarius/internal/cli/configkit_commands.go ).
- [Scriptorium CLI contract ](../../../scriptorium/docs/cli.md ),
[application inspection ](../../../scriptorium/internal/adapter/cli/config.go ),
and [framework inspection ](../../../scriptorium/internal/adapter/cli/framework_config.go ).
- [ConfigKit inspection API ](../../../ConfigKit/inspection.go ),
[source records ](../../../ConfigKit/records.go ), and
[configuration contract ](../../../ConfigKit/docs/config.md ).
- [PromptKit configuration inspection ](../../../promptkit/configuration_inspection.go )
and [consumer guide ](../../../promptkit/docs/consumers/pkg-promptkit.md ).
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
2026-10-06 23:36:06 +00:00
### Standard configuration operation inventory
2026-10-06 16:32:59 +00:00
| 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.
2026-10-06 23:36:06 +00:00
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.
2026-10-06 16:32:59 +00:00
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 proposed
`promptkit list/show RESOURCE` layout puts the operation immediately after its
owning namespace, as in `config show` .
- **Put definitions under `config` , such as `config profile` .** Mixes source
configuration with backend-completed execution settings and gives `config` an
unrelated resource vocabulary.
- **Include only the core suite initially.** A reasonable delivery phase. Keep
2026-10-06 23:36:06 +00:00
individual PromptKit capabilities pending until their public APIs are available;
their absence leaves existing inspection capabilities available.
2026-10-06 16:32:59 +00:00
`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 to `config validate` and `config 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
2026-10-06 23:36:06 +00:00
inspection, together with supported operations. It uses registration metadata,
so it works when files are missing or
2026-10-06 16:32:59 +00:00
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` .
2026-10-06 23:36:06 +00:00
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 ](../adr/0009-configuration-scopes.md ) 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.
2026-10-06 16:32:59 +00:00
**Alternatives:**
- **Default every operation to `app` , requiring `validate --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.
2026-10-06 23:36:06 +00:00
- **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.
2026-10-06 16:32:59 +00:00
## 5. Shared inputs and command syntax
### Configuration selection and overrides
2026-10-06 23:36:06 +00:00
**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.
2026-10-06 16:32:59 +00:00
`--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.
2026-10-06 23:36:06 +00:00
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 ](../adr/0010-configuration-selection.md ) owns the
parsing and propagation contract.
2026-10-06 16:32:59 +00:00
`--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.
2026-10-06 23:36:06 +00:00
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.
2026-10-06 16:32:59 +00:00
Execution-only controls such as resume, output directories for generated artifacts,
or lane execution do not belong on generic configuration commands.
**Alternatives:**
- **Require `--config` on 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:
```sh
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 `flag` parser 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 ](https://pkg.go.dev/flag#hdr-Command_line_flag_syntax )
stops at the first operand; [pflag ](https://github.com/spf13/pflag#command-line-flag-syntax )
supports interspersed options. The accepted [backend decision ](03-backend.md )
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`
2026-10-06 23:36:06 +00:00
**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 ](../adr/0008-inspection-lifecycle.md ) owns this boundary.
2026-10-06 16:32:59 +00:00
2026-10-06 23:36:06 +00:00
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.
2026-10-06 16:32:59 +00:00
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
2026-10-06 23:36:06 +00:00
report through the supplied diagnostic channel. Callback effects and bootstrap
policy remain application-owned; focused acquisition is recommended practice.
2026-10-06 16:32:59 +00:00
**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.
```yaml
---
# 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.
2026-10-06 23:36:06 +00:00
Check operation availability, acquire all selected views, and complete validation
required by their provider contracts before starting output. A scope load failure
2026-10-06 16:32:59 +00:00
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. Use `config explain` for 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.
```sh
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 --all` listing 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.
```sh
app config diff --config ./config.yml --overlay staging --against-overlay production
app config diff --config ./old.yml --against-config ./new.yml --against-overlay default
```
2026-10-06 23:36:06 +00:00
For a scope declaring safe comparison support, acquire both views through the
registered provider's loading/validation contract. Compare effective values, including
2026-10-06 16:32:59 +00:00
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
2026-10-06 23:36:06 +00:00
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 ](../adr/0006-command-grammar.md ) records this distinction.
`app help config explain` and
2026-10-06 16:32:59 +00:00
`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
2026-10-06 23:36:06 +00:00
**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 ](../adr/0004-standard-inspection-surface.md ) records version selection.
2026-10-06 16:32:59 +00:00
Applications supply build identity, with tagged Go build information usable when
available. An unversioned development build reports `dev` ; unknown revision or
2026-10-06 23:36:06 +00:00
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 ](../policy/release.md#versioning-and-compatibility ).
2026-10-06 16:32:59 +00:00
**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.
2026-10-06 23:36:06 +00:00
- **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.
2026-10-06 16:32:59 +00:00
## 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
2026-10-06 23:36:06 +00:00
`1` ; checking status before decoding is recommended caller practice. This avoids adding filesystem
2026-10-06 16:32:59 +00:00
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:
2026-10-06 23:36:06 +00:00
| Needed capability | Implementation work for that capability |
2026-10-06 16:32:59 +00:00
| --- | --- |
| 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. |
2026-10-06 23:36:06 +00:00
| Cross-scope validation | Registered validation capabilities and dependencies, with their actual acquisition and credential requirements exposed in help. |
2026-10-06 16:32:59 +00:00
Suggested sequence:
1. Resolve the remaining proposed command contracts and alternatives, preserving
the accepted planning decisions above.
2. Define the structured YAML report schemas and minimal upstream inspection
additions. Record accepted ownership decisions in durable architecture
documentation.
3. Implement core dispatch, syntax, help, version, scopes, validation, native
display (including `show --scope all` ), source inventory, and explanation using
existing APIs.
4. Integrate Scriptorium and Notarius to exercise both scopes and remove duplicated
2026-10-06 23:36:06 +00:00
handlers. Register and report the supported capabilities; additional upstream
features can be integrated independently.
5. Add safe semantic comparison and additional PromptKit definition capabilities
as their upstream APIs are released.
2026-10-06 16:32:59 +00:00
6. 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.
2026-10-06 23:36:06 +00:00
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.
2026-10-06 16:32:59 +00:00
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 `doctor` command 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 `run` in 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.