PROP-060 — Observable CLI operations
01Owner request, 2026-09-17: package installation and self-update must explain long waits while they occur, with overall and component progress, completed and active operations, and a verbose diagnostic option.
Human output and compatibility
02The global -v/--verbose flag requests detailed progress diagnostics. Default human output already reports meaningful progress. --quiet and --json suppress progress, including verbose progress; their existing summaries, document streams and exit codes remain unchanged. Progress is written to stderr; command results keep their existing stdout contract.
03An interactive terminal displays the overall operation, nested active components, elapsed time, and retained completion records. Known finite work displays completed/total with its unit and a progress bar; unknown work displays an indeterminate indicator and elapsed time. No percentage estimates elapsed-time completion or treats a discovered dependency count as the final closure. A redirected or dumb terminal receives flushed plain start, completion and failure records without cursor controls, with bounded periodic waiting updates for long silent work.
04Verbose diagnostics identify registry/cache/source selection, Git/network operation, selected version or revision, reuse/skip decisions, and phase durations. Child build diagnostics are visible during execution instead of buffered until exit. Messages are bounded and sanitized: no URL userinfo, query credential, authorization value, environment dump or raw secret-bearing argv; terminal control characters from external text cannot execute.
05Completion is explicit and occurs only after successful work. A dropped unfinished component is stopped, never successful; failures retain the responsible component and elapsed time. Rendering failure cannot change installation effects or mask the original operation error. Prompts and ordinary command output coexist with active bars without corrupting the display.
Shared observation, separate command policy
06A no-op-by-default, invocation-owned progress handle in vibe-core carries typed start, measurement, detail and terminal events through a thread-safe observer. Each task has an invocation-local identity and optional parent. Libraries emit observations through explicitly supplied handles and do not render, read terminal/environment settings, or use a mutable global reporter. The CLI alone selects the renderer. Observation does not decide package selection, locking, confirmation, activation or retry policy.
07The ordinary install path observes preparation, dependency resolution and per-package registry/cache work, materialization, boot generation and final recording. Fresh-lock and empty-world paths say which work they reuse or skip. Update paths that share these mechanisms expose the same lower-level observations. Observation begins before the blocking operation, not only after a plan or a large phase completes.
08The self install/update/reinstall paths identify source versus binary acquisition. Source execution observes source discovery/fetch/checkout, prerequisite preparation, each essential binary build, placement and activation. Binary execution observes release metadata, existing-generation verification or reuse, bounded download bytes, extraction/verification and activation. Existing immutable generations, offline admission and injected environment persistence remain unchanged.
09The same renderer covers self gc: start before store inspection, identify the selected action, observe protection checks and candidate preflight, name each version or cache being removed, and report state recording and optional managed-source cleanup. The existing candidate list provides finite instance counts; a guarded tree scan or recursive filesystem deletion remains indeterminate with elapsed time and waiting updates instead of an invented byte/file total or an extra counting pass. Active, rollback and running instances retain the existing protection law. Prompts suspend the display. Cancellation, an empty cache and a nothing-to-prune result are explicit skipped outcomes. Best-effort removal failures remain visible as failed/skipped components without changing exit codes, inventory mutation, or the deletion algorithm. Tests use only temporary stores.
10Progress must not scan a tree or repeat network work solely to invent a denominator. Known counters come from work already required. High-frequency updates are throttled at the renderer. Network and subprocess waits remain visibly active even before their first byte. Any performance optimization is separately justified by measured or deterministic evidence and preserves freshness semantics.
CLI-wide coverage, owner extension 2026-09-17
11Every finite CLI command that can wait on network, subprocesses, inventory, hashing, compilation or filesystem mutation has an invocation-owned activity before the first blocking stage. A closed command-policy match distinguishes existing operation roots, finite commands, interactive interfaces, stdio protocols and intentionally persistent servers. Adding a command must select its observation policy explicitly. Fast metadata/help/version paths may remain silent. A generic activity is a liveness fallback, not a substitute for named real stages at the blocking seams identified by the command audit.
12Coverage includes all self maintenance verbs; project and global application install/update/reinstall/uninstall; lifecycle/build/package/deploy/clean; registry/cache/workspace operations; package search/outdated; documentation inventory/build/check/shell acquisition; source inspection, analysis, traceability and refactoring. Components report their actual selection, scan, verification, transfer, compile, mutation or output stage. Existing observer ports are bridged where available. No additional full-tree scan exists solely for progress.
13Progress never enters stdout. Commands that render an interactive interface, serve a stdio protocol, run an intentionally persistent server or transfer terminal ownership to a child do not retain an animated parent display over that interface. Finite commands with raw or independently rendered stdout use plain stderr activity until their output is synchronized with the renderer. Known typed waiting/parked/cancelled outcomes are described honestly; invocation completion does not claim a persistent workflow's goal is complete. No observation may alter authentication, selection, mutation, exit status or command data formats.
14The global --no-progress flag or truthy VIBE_NO_PROGRESS disables progress and its verbose detail without suppressing ordinary final command output. Quiet and JSON modes continue to suppress progress independently. The environment is read only at the composition root. Deterministic documentation examples may use this documented opt-out to preserve their ordinary stdout assertions; this needs no regeneration of the documentation corpus or broad user-home/source snapshots.
15The command audit records each command family's policy, actual blocking stages and acceptance evidence. Focused fake network/process or tiny filesystem scenarios verify start-before-wait, named stages, progress suppression and stream preservation across representative families; the closed policy is checked against the CLI command inventory. Existing accepted install/self-update evidence remains valid for unchanged code. Destructive maintenance probes operate only in isolated temporary stores.
Decision record
16Decision: share observation in the existing core crate and implement one CLI renderer for the two real consumers. Why: registry resolution runs below the CLI, while self-update has a separate policy; both need identical progress semantics without a dependency on terminal code. Rejected: direct library printing (breaks machine consumers), a process-global reporter (crosses invocation ownership), and fixed percentages for unknown work (misrepresents completion). Revisit if a second surface needs persistent or remotely streamed progress; the current in-process events are not a durable wire protocol.
Acceptance
17Focused deterministic fixtures cover nesting and terminal outcomes, quiet/JSON compatibility, redirected output without ANSI, verbose redaction, progress before a delayed operation completes, finite download/materialization counts and source build output. Registry fixtures verify connection-pool reuse without changing source or freshness selection. Terminal rendering is checked against an in-memory terminal, including a narrow viewport. All probes use isolated project/settings/store roots and injected activation; no test updates the developer's real installation or durable shell environment.