# 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. The ADRs record architectural choices and their rationale. Detailed selection, acquisition coordination, report formatting, and diagnostic-delivery mechanics below remain proposals unless explicitly marked accepted. Their presence here does not establish additional contracts in the ADRs. ### 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. - 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. - 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. 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. 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 ### 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 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 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 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 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. This roadmap proposes coordinating explicit dependencies and reusing compatible provider results within an invocation; the coordination contract remains API design work. 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. **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. - **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. The detailed selection and propagation rules in this section remain proposals for integration API design. `--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 `--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` **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. The acquisition lifecycle and dependency coordination described here remain proposals for provider API design. 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. ```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. 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. 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 ``` 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](../adr/0006-command-grammar.md) 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. Registration of future component identities remains an API design proposal. [ADR 0004](../adr/0004-standard-inspection-surface.md) records version subjects; this roadmap retains the selected command syntax. 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](../policy/release.md#versioning-and-compatibility). **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: 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 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. 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. 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 `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.