Skip to content

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_summary
  • codeclone/surfaces/cli/runtime.py:_metrics_flags_requested
  • codeclone/surfaces/cli/runtime.py:_metrics_computed
  • codeclone/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-report is layered on top of --html; it does not imply HTML output.
  • --timestamped-report-paths rewrites 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.1 or 2.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 by 2.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 .gitignore does 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 .gitignore covers the cache path. CodeClone never edits .gitignore automatically.
  • 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-verify compares the current run against the trusted clone baseline for baseline-relative regressions, previews gate status, and exits 3 for blocking violations in ci or strict mode. 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-stats shows workspace session status: active agents, intents, and lease health. Read-only, does not run analysis.
  • Audit query mode is terminal-only:
    • --audit shows the local Controller audit trail from the configured audit database. Read-only, does not run analysis. Requires audit_enabled=true in effective configuration ([tool.codeclone] or resolved defaults).
    • --audit-json outputs audit payload footprint as JSON. Uses the same audit collector as --audit but does not set the --audit flag for combination validation. Requires audit_enabled=true in 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 MCP query_engineering_memory (vacuum purges per retention config; no --dry-run).
    • semantic status|rebuild|search — optional LanceDB sidecar (requires [tool.codeclone.memory.semantic] enabled = true, extra codeclone[semantic-lancedb], and a successful rebuild — MCP agents use manage_engineering_memory(action=rebuild_semantic_index)). For semantic-quality local recall, install codeclone[semantic-local] and configure embedding_provider = "fastembed"; semantic-lancedb alone 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 CLI approve / reject / archive require --i-know-what-im-doing unless routed through the IDE governance channel. Use --by NAME (default human) to record the approver; there is no --verified-by flag.
    • 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).
    • search accepts --match any|all for FTS token matching (default any) and --semantic to 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 --correlation select a bounded trace.
    • --json PATH and --html PATH write 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|outliers
    • codeclone analytics profiles list|show|validate
    • build runs snapshot → embed → cluster. --use-recommended requires --sweep. With --profile, it renders the profile-batch winner; without a profile it renders the global heuristic winner.
    • --profile PROFILE_ID implies sweep; --profile auto resolves only from configured default_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_ID appends a selection event. --selection-profile none|PROFILE_ID|PROFILE_BATCH_ID controls scope; --selected-by and --selection-rationale preserve governance context.
    • Representations: description (default) or description_with_frame.
    • Artifacts live under .codeclone/analytics/ (SQLite metadata + LanceDB vectors).
    • JSON export schema 1.3 and 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-show may therefore export a resolved run that is not eligible for full interpretation.
    • Expected capability, schema, ownership, and integrity errors exit 2 without 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-radius and --patch-verify cannot be combined.
    • --strictness {ci,strict,relaxed} is valid only with --patch-verify.
    • --session-stats and --audit collect payloads from codeclone/controller_insights/ (same facts as IDE-only MCP tools when the server runs with --ide-governance-channel).
    • --session-stats cannot combine with explicit --audit, --blast-radius, or --patch-verify. --audit-json is not treated as --audit for this check (run one pre-analysis query per invocation).
    • explicit --audit cannot combine with --blast-radius or --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_error and include traceback only in debug mode.

Refs:

  • codeclone/contracts/__init__.py:cli_help_epilog
  • codeclone/ui_messages/__init__.py:fmt_contract_error
  • codeclone/ui_messages/__init__.py:fmt_internal_error
  • codeclone/surfaces/cli/changed_scope.py:_validate_changed_scope_args
  • codeclone/surfaces/cli/workflow.py:_validate_controller_query_flags

Invariants (MUST)

  • Report writes are path-validated and write failures are contract errors.
  • --open-html-report requires --html.
  • --timestamped-report-paths requires at least one requested report output.
  • --changed-only requires a diff source.
  • --blast-radius and --patch-verify are mutually exclusive.
  • --session-stats cannot combine with explicit --audit, --blast-radius, or --patch-verify.
  • explicit --audit cannot combine with --blast-radius or --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-verify requires a trusted clone baseline.
  • --audit and --audit-json require audit_enabled=true in 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_path
  • codeclone/surfaces/cli/reports_output.py:_validate_report_ui_flags
  • codeclone/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_summary
  • codeclone/contracts/__init__.py:cli_help_epilog
  • codeclone/surfaces/cli/changed_scope.py:_normalize_changed_paths

Locked by tests

  • tests/test_cli_unit.py::test_cli_help_text_consistency
  • tests/test_cli_help_snapshot.py::test_cli_help_snapshot
  • tests/test_cli_unit.py::test_argument_parser_contract_error_marker_for_invalid_args
  • tests/test_cli_inprocess.py::test_cli_summary_format_stable
  • tests/test_cli_inprocess.py::test_cli_unreadable_source_fails_in_ci_with_contract_error
  • tests/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.