173 lines
9.2 KiB
Markdown
173 lines
9.2 KiB
Markdown
# CLI Internals
|
|
|
|
This document describes **internal/cli**, Notarius's production composition
|
|
root. The [CLI reference](../cli.md) owns command syntax and exit statuses;
|
|
[Configuration](../config.md) owns configuration values; and
|
|
[Operations](../operations.md) owns filesystem layout, recovery, and operator
|
|
procedures.
|
|
|
|
## Inputs, Outputs, And Boundaries
|
|
|
|
The CLI accepts process arguments, standard streams, and injectable options
|
|
used by tests and embedding code. It writes command results to the supplied
|
|
streams and returns a process exit status. For a run, it also creates the
|
|
production catalog and runtime collaborators, hands a prepared pipeline and
|
|
source bytes to the framework, and places the logical files returned by the
|
|
runner.
|
|
|
|
It is the only boundary allowed to compose concrete registries, LLM clients,
|
|
cache/checkpoint collaborators, debug recorders, and physical output paths.
|
|
Pipeline modules receive interfaces and request data rather than CLI streams or
|
|
filesystem roots. The [Architecture](../policy/architecture.md) defines this
|
|
composition-root boundary; [Pipeline Internals](pipeline.md) owns resolution,
|
|
preparation, and runner mechanics after their inputs are supplied.
|
|
|
|
## Dispatch And Configuration Handoff
|
|
|
|
The root dispatcher handles help, configuration validation, pipeline listing,
|
|
and a pipeline run. It normalizes injectable options before dispatch so that a
|
|
missing production dependency fails as a command error rather than reaching
|
|
execution.
|
|
|
|
Commands that need configuration use one shared loader. The CLI discovers the
|
|
file, parses it through **internal/core/config**, starts from defaults, applies
|
|
the file and supported environment overrides, and then validates it for the
|
|
command. The configured discovery and precedence contract is in
|
|
[Configuration](../config.md), while the loading and resolution mechanics are
|
|
in [Configuration Internals](configuration.md).
|
|
|
|
Configuration validation without a selected pipeline checks structural
|
|
configuration only. Validation with a selected pipeline also builds the
|
|
effective catalog, resolves the pipeline, and verifies every explicit effective
|
|
PromptKit profile. Selected LLM-backed input, chunk, lane, output, and validator
|
|
profiles are inspected
|
|
against the configured PromptKit source and backend registrations without
|
|
loading a prompt or performing generation, so an unknown or invalid profile
|
|
fails before pipeline preparation. Credential availability remains an
|
|
execution-time concern. Pipeline listing validates configuration before
|
|
returning normalized, sorted identifiers.
|
|
|
|
## Production Composition
|
|
|
|
The production composition helper allocates every framework registry and the
|
|
prompt-asset registry, then registers the generic, Seriatim, and D&D module
|
|
families in that order. The resulting registries provide both the module
|
|
catalog used for resolution and the concrete constructors used for preparation.
|
|
Tests may provide a catalog or registries instead; production code must not
|
|
silently merge an injected partial catalog with production registrations.
|
|
|
|
The production LLM factory builds one PromptKit-backed client from the resolved
|
|
**promptkit.profile_dir** or **promptkit.profile_file** source, attaches the
|
|
profile-provenance recorder, creates one scheduler from the effective global
|
|
LLM limit, and wraps the client before it reaches modules. Registration and LLM
|
|
construction errors are returned before a pipeline is prepared. Configuration
|
|
field definitions remain in [Configuration](../config.md#promptkit-profiles);
|
|
the D&D registrar's fallback profile assets and the adapter mechanics remain in
|
|
[LLM Runtime](llm.md).
|
|
|
|
The factory also accepts `LLMRuntimeOverrides`, whose reasoning pointer
|
|
preserves inherit, replace, and clear states across the composition boundary.
|
|
Run orchestration constructs this value from the mutually exclusive
|
|
`--reasoning-effort` and `--clear-reasoning-effort` controls. Absence preserves
|
|
a nil pointer, replacement is trimmed, and clear uses a non-nil empty string.
|
|
The same override reaches the one shared production client, checkpoint
|
|
identity, and debug invocation metadata. Persistent reasoning configuration
|
|
remains owned by PromptKit profiles; Notarius configuration has no reasoning
|
|
field.
|
|
|
|
## Run Orchestration
|
|
|
|
After parsing and validating a run invocation, the CLI performs this ordered
|
|
handoff:
|
|
|
|
1. load and validate configuration, then apply command-level operational
|
|
overrides;
|
|
2. create and validate a safe run identity, then allocate a debug bundle only
|
|
when requested;
|
|
3. build the effective catalog, resolve requested reference changes, resolve
|
|
the effective pipeline, and inspect its explicit effective PromptKit
|
|
profiles;
|
|
4. materialize external or generated references and record redacted invocation
|
|
and resolution provenance when debug capture is enabled;
|
|
5. construct registries, the scheduled LLM client, and prepared modules;
|
|
6. read the source input once, resolve its effective session from the explicit
|
|
override or resolved input module and raw bytes, then construct requested
|
|
checkpoint collaborators and invoke the framework runner with that same
|
|
value; and
|
|
7. write the runner's logical output files only after a successful run, then
|
|
complete the command report and user-facing result.
|
|
|
|
Preparation happens before source parsing, so module construction and
|
|
dependency failures cannot begin stage execution. The CLI also preserves the
|
|
framework's result and warning information when it writes summaries and the
|
|
final command result. Detailed state lifecycle, resume handling, and physical
|
|
path confinement are maintained in [Run State Internals](state.md) and
|
|
[Operations](../operations.md).
|
|
|
|
The CLI owns the versioned generated-session policy and resolves the sole
|
|
effective value before checkpoint construction. It records that value in the
|
|
final debug invocation summary when capture is enabled and passes it unchanged
|
|
to checkpoint identity and `pipeline.RunInput`. The public flag and stability
|
|
contract are defined by the [CLI reference](../cli.md#run); framework and LLM
|
|
packages only transport the supplied value.
|
|
|
|
For `run --json`, the CLI constructs and encodes its private run-result receipt
|
|
after a successful runner result is available, before it publishes logical
|
|
output files. It writes the prepared receipt to standard output only after
|
|
output publication and requested debug terminalization succeed. A receipt-write
|
|
failure exits with runtime status 1 and may leave partial standard-output bytes,
|
|
but the already-published output bundle remains complete and requested debug
|
|
reporting remains successfully terminalized. The CLI reports a bounded
|
|
command-owned error and does not repeat terminal reporting. The receipt remains
|
|
a CLI reporting concern rather than a framework or output-module responsibility;
|
|
its public contract is the
|
|
[run-result receipt](../integrations/run-result.md).
|
|
|
|
## Failure Mapping And Terminal Reporting
|
|
|
|
Argument, flag, and invocation-combination failures are reported to standard
|
|
error before runtime composition and use the syntax error class. Once an
|
|
invocation is syntactically valid, configuration loading and validation,
|
|
resolution, registration, profile checks, reference materialization, module
|
|
construction, input reads, runner failures, output publication, and requested
|
|
debug handling use the runtime failure class. The public status numbers and
|
|
stream contract are defined in the [CLI reference](../cli.md#output-streams-and-exit-statuses).
|
|
|
|
When debug capture has been allocated, one command-state value records the
|
|
known run result. Guarded terminalization writes a success report once, or
|
|
attempts a failure report and error record once. A persistence failure is
|
|
reported in addition to the original failure and never replaces it. If a debug
|
|
path exists, failure output includes that path so the retained diagnostic data
|
|
is discoverable.
|
|
|
|
## Invariants To Preserve
|
|
|
|
- Only the CLI composes production implementations and physical runtime roots.
|
|
- Configuration and resolved composition failures occur before module
|
|
preparation or source parsing.
|
|
- A runner's logical files are published only after a successful run.
|
|
- Production registries and a caller-supplied catalog or registries are
|
|
alternative composition sources, not an implicit mixture.
|
|
- A requested debug bundle has one terminal report attempt; its persistence
|
|
errors supplement rather than obscure the primary command error.
|
|
- User-facing flags, paths, exit codes, and configuration fields are defined
|
|
by their public documentation, not duplicated here.
|
|
|
|
## Focused Tests
|
|
|
|
- **internal/cli/command_contract_test.go** covers dispatch, help, syntax and
|
|
runtime error classes, discovery, validation, and listing.
|
|
- **internal/cli/run_contract_test.go** covers the run handoff, publication,
|
|
debug reporting, and command-owned state collaborators.
|
|
- **internal/cli/production_contract_test.go** covers registrar composition,
|
|
production catalog contents, assets, and representative configuration
|
|
validation.
|
|
- **internal/cli/reference_contract_test.go** covers CLI reference overrides,
|
|
origin separation, and materialization boundaries.
|
|
- **internal/cli/state_hardening_test.go** covers safe run identity, state
|
|
roots, and failure ordering.
|
|
|
|
Run **go test ./internal/cli** after changing command composition or command
|
|
behavior. Pair it with **go test ./internal/core/config** when the configuration
|
|
handoff changes.
|