11. CLI¶
Purpose¶
Define observable CLI behavior: argument handling, summaries, output writing, and exit routing.
Observable surface only
This chapter covers scripting-visible behavior and user-facing CLI output categories. Rich styling details may evolve as long as markers, exit semantics, and deterministic output contracts stay stable.
Public surface¶
- Public entrypoint:
codeclone/main.py:main - CLI orchestration:
codeclone/surfaces/cli/workflow.py:_main_impl - Parser:
codeclone/config/argparse_builder.py:build_parser - Summary renderer:
codeclone/surfaces/cli/summary.py:_print_summary - Output path validation and writes:
codeclone/surfaces/cli/reports_output.py - Message catalog:
codeclone/ui_messages/*(help,labels,runtime,markers,formatters,controller,styling; stable names re-exported from__init__.py)
Data model¶
CLI modes:
- normal mode
- gating mode (
--ci,--fail-on-new, explicit metric gates) - baseline update mode (
--update-baseline,--update-metrics-baseline) - controller query mode (
--blast-radius,--patch-verify) - workspace query modes (
--session-stats,--audit,--audit-json) - development diagnostics mode (
codeclone observability trace)
Summary metrics include:
- files found/analyzed/cache hits/skipped
- structural counters for lines/functions/methods/classes
- function/block/segment clone groups
- suppressed clone groups from
golden_fixture_paths - dead-code active/suppressed status
- dependency depth profile (
avg_depth,p95_depth,max_depth) when metrics are computed - adoption/API/coverage-join facts when computed
- new vs baseline
Refs:
codeclone/surfaces/cli/summary.py:_print_summarycodeclone/surfaces/cli/runtime.py:_metrics_flags_requestedcodeclone/surfaces/cli/runtime.py:_metrics_computedcodeclone/surfaces/cli/report_meta.py:_build_report_meta
Contracts¶
- Help output includes canonical exit-code section and project links.
- Bare report flags write to deterministic default paths under
.codeclone/. --open-html-reportis layered on top of--html; it does not imply HTML output.--timestamped-report-pathsrewrites only default report paths requested via bare flags.- In interactive VS Code terminals, the CLI may print a one-time extension hint
after summary output. The hint is suppressed in
--quiet, CI, and non-TTY contexts, and is tracked per CodeClone version next to the resolved project cache path. - In interactive non-CI runs, the CLI may print one-time migration notes when a
trusted baseline was produced by a release whose dead-code reachability model
is known to be narrower than the current version, such as
2.0.0->2.0.1or2.0.1->2.0.2. Notes explain expected dead-code count reductions from refined reachability evidence and are remembered next to the resolved project cache path. - The same tips mechanism also covers cohesion (LCOM4) applicability changes,
such as
2.0.2->2.1.0: when a trusted baseline was generated by2.0.2, the CLI may print a one-time note that cohesion counts can change because Protocol interfaces and Pydantic validation hooks are excluded from the LCOM4 graph. - After a normal interactive analysis run, the CLI may print a workspace
hygiene tip when the repository root
.gitignoredoes not cover.codeclone/(or the broader.cache/tree). The tip is advisory only, suppressed in--quiet, CI, and non-TTY contexts, and repeats on each eligible run until.gitignorecovers the cache path. CodeClone never edits.gitignoreautomatically. - Changed-scope review uses:
--changed-only--diff-against--paths-from-git-diff
- Controller query mode is terminal-only:
--blast-radius FILE [FILE...]builds the canonical report in memory and renders the same blast-radius projection used by MCP.--patch-verifycompares the current run against the trusted clone baseline for baseline-relative regressions, previews gate status, and exits3for blocking violations inciorstrictmode. Cannot combine with changed-scope flags; patch-local before-run to after-run regression claims require MCP change-control verify.
- Session query mode is terminal-only:
--session-statsshows workspace session status: active agents, intents, and lease health. Read-only, does not run analysis.
- Audit query mode is terminal-only:
--auditshows the local Controller audit trail from the configured audit database. Read-only, does not run analysis. Requiresaudit_enabled=truein effective configuration ([tool.codeclone]or resolved defaults).--audit-jsonoutputs audit payload footprint as JSON. Uses the same audit collector as--auditbut does not set the--auditflag for combination validation. Requiresaudit_enabled=truein effective configuration.
- Engineering Memory commands (
codeclone memory) are terminal-only and read-only with respect to source files, baselines, and analysis cache:init [--refresh] [--dry-run] [--from-report PATH] [--no-docs] [--no-tests]— create or refresh the local SQLite memory store from canonical report + git + docs + tests (omit docs/tests with the--no-*flags; seed from an existing report with--from-report).status,for-path,search,stale,vacuum,coverage— query modes mirroring MCPquery_engineering_memory(vacuumpurges per retention config; no--dry-run).semantic status|rebuild|search— optional LanceDB sidecar (requires[tool.codeclone.memory.semantic] enabled = true, extracodeclone[semantic-lancedb], and a successful rebuild — MCP agents usemanage_engineering_memory(action=rebuild_semantic_index)). For semantic-quality local recall, installcodeclone[semantic-local]and configureembedding_provider = "fastembed";semantic-lancedbalone can still run the deterministic diagnostic provider.review-candidates,approve,reject,archive— human governance for draft records (CLI and VS Code Memory; not MCP agent tools). Direct CLIapprove/reject/archiverequire--i-know-what-im-doingunless routed through the IDE governance channel. Use--by NAME(defaulthuman) to record the approver; there is no--verified-byflag.trajectory status|rebuild|list|search|show|agents|anomalies|dashboard|export— audit-derived narratives, quality passports, analytics, and local Patch Trail export (requires audit + rebuild).jobs status|enqueue|run-once|list— projection rebuild queue (semantic + trajectory + Experience projections).searchaccepts--match any|allfor FTS token matching (defaultany) and--semanticto blend vector proximity when the index is available.- Requires a prior normal analysis run or cached report for
init. - Full contract: Engineering Memory.
- Platform Observability commands are terminal-only, read-only diagnostics of
CodeClone's own runtime:
codeclone observability trace --root .prints JSON.--last,--operation, and--correlationselect a bounded trace.--json PATHand--html PATHwrite machine-readable or self-contained cockpit views.- A missing local store is an informational success state.
- Full contract: Platform Observability.
- Corpus Analytics commands are terminal-only, offline clustering of historical
intents (requires
codeclone[analytics]):codeclone analytics snapshot|embed|cluster|build|clusters|cluster-show|outlierscodeclone analytics profiles list|show|validatebuildruns snapshot → embed → cluster.--use-recommendedrequires--sweep. With--profile, it renders the profile-batch winner; without a profile it renders the global heuristic winner.--profile PROFILE_IDimplies sweep;--profile autoresolves only from configureddefault_profile_id. No profile is applied implicitly.- Single-run overrides:
--pca-dimensions,--min-cluster-size,--min-samples,--cluster-selection-method. - Sweep-axis overrides:
--sweep-pca,--sweep-min-cluster-size,--sweep-min-samples,--sweep-selection-method. Any sweep-axis flag implies--sweep. cluster --select-run RUN_IDappends a selection event.--selection-profile none|PROFILE_ID|PROFILE_BATCH_IDcontrols scope;--selected-byand--selection-rationalepreserve governance context.- Representations:
description(default) ordescription_with_frame. - Artifacts live under
.codeclone/analytics/(SQLite metadata + LanceDB vectors). - JSON export schema
1.3and HTML use one interpretation projection: formally valid runs receive full metrics/previews; invalid or failed runs remain inspectable as limited diagnostics with invariant codes. - Sweep output includes every persisted candidate for the generation.
Invalid candidates are unranked and show dominant metrics as unavailable.
cluster-showmay therefore export a resolved run that is not eligible for full interpretation. - Expected capability, schema, ownership, and integrity errors exit
2without a traceback. Inspection/export commands require only the base install and open analytics metadata read-only. - Full contract: Corpus Analytics.
- Controller and workspace query flags are mutually exclusive where enforced:
--blast-radiusand--patch-verifycannot be combined.--strictness {ci,strict,relaxed}is valid only with--patch-verify.--session-statsand--auditcollect payloads fromcodeclone/controller_insights/(same facts as IDE-only MCP tools when the server runs with--ide-governance-channel).--session-statscannot combine with explicit--audit,--blast-radius, or--patch-verify.--audit-jsonis not treated as--auditfor this check (run one pre-analysis query per invocation).- explicit
--auditcannot combine with--blast-radiusor--patch-verify. - controller and workspace query modes cannot combine with changed-scope
flags (
--changed-only,--diff-against,--paths-from-git-diff). - controller and workspace query modes do not write reports, baselines, or analysis cache data.
- Contract errors use
CONTRACT ERROR:. - Gating failures use
GATING FAILURE:. - Internal errors use
fmt_internal_errorand include traceback only in debug mode.
Refs:
codeclone/contracts/__init__.py:cli_help_epilogcodeclone/ui_messages/__init__.py:fmt_contract_errorcodeclone/ui_messages/__init__.py:fmt_internal_errorcodeclone/surfaces/cli/changed_scope.py:_validate_changed_scope_argscodeclone/surfaces/cli/workflow.py:_validate_controller_query_flags
Invariants (MUST)¶
- Report writes are path-validated and write failures are contract errors.
--open-html-reportrequires--html.--timestamped-report-pathsrequires at least one requested report output.--changed-onlyrequires a diff source.--blast-radiusand--patch-verifyare mutually exclusive.--session-statscannot combine with explicit--audit,--blast-radius, or--patch-verify.- explicit
--auditcannot combine with--blast-radiusor--patch-verify. - Controller and workspace query modes are incompatible with changed-scope flags
(
--changed-only,--diff-against,--paths-from-git-diff). - Controller and workspace query modes are incompatible with report output flags, baseline update flags, and changed-scope flags.
--patch-verifyrequires a trusted clone baseline.--auditand--audit-jsonrequireaudit_enabled=truein effective configuration.- Browser-open failure after successful HTML write is warning-only.
- In gating mode, unreadable source files are contract errors with higher priority than clone/metric gate failures.
Refs:
codeclone/surfaces/cli/reports_output.py:_validate_output_pathcodeclone/surfaces/cli/reports_output.py:_validate_report_ui_flagscodeclone/surfaces/cli/workflow.py:_main_impl
Failure modes¶
Failure precedence
Contract failures take precedence over gating failures. In CI and scripted
flows, invalid config or unreadable sources must surface as exit 2 before
any clone or metrics gate can fail with exit 3.
| Condition | User-facing category | Exit |
|---|---|---|
| Invalid CLI flag | contract | 2 |
| Invalid output extension/path | contract | 2 |
| Invalid changed-scope flag combination | contract | 2 |
| Invalid controller query flag combination | contract | 2 |
--audit with audit_enabled=false |
contract | 2 |
--patch-verify without trusted baseline |
contract | 2 |
| Baseline untrusted in CI/gating | contract | 2 |
| Coverage/API regression gate without required baseline capability | contract | 2 |
| Unreadable source in CI/gating | contract | 2 |
New clones with --fail-on-new |
gating | 3 |
Blocking --patch-verify contract violation |
gating | 3 |
Untested coverage hotspots with --fail-on-untested-hotspots |
gating | 3 |
| Threshold or metrics gate exceeded | gating | 3 |
| Unexpected exception | internal | 5 |
Determinism / canonicalization¶
- Summary metric ordering is fixed.
- Compact summary mode is fixed-format text.
- Help epilog is generated from static constants.
- Git diff path inputs are normalized to sorted repo-relative paths.
Refs:
codeclone/surfaces/cli/summary.py:_print_summarycodeclone/contracts/__init__.py:cli_help_epilogcodeclone/surfaces/cli/changed_scope.py:_normalize_changed_paths
Locked by tests¶
tests/test_cli_unit.py::test_cli_help_text_consistencytests/test_cli_help_snapshot.py::test_cli_help_snapshottests/test_cli_unit.py::test_argument_parser_contract_error_marker_for_invalid_argstests/test_cli_inprocess.py::test_cli_summary_format_stabletests/test_cli_inprocess.py::test_cli_unreadable_source_fails_in_ci_with_contract_errortests/test_cli_inprocess.py::test_cli_contract_error_priority_over_gating_failure_for_unreadable_source
Non-guarantees¶
- Rich styling details are not machine-facing contract.
- Warning phrasing may evolve if category markers and exit semantics stay stable.