Skip to content

0.18.0 — 2026-10-23 — the release an agent can trust

Latest

Choose a tag to compare

@github-actions github-actions released this 23 Oct 11:26

ClusterVision 0.18.0 is the release an agent can trust. Every listing, count and search answer
is either exact or says what it skipped: counts are prompts and replies on every harness, a
session the store has not counted shows a dash, and search reads what the index has not seen.
One stored-format version replaces five; upgrading reads every session once. A write to a store
costs the session it touched, not the store: SQLite stores carry per-session certificates and
transcripts resume from their last mark, so cv index is cheap enough to run hourly or not at
all. No hidden limit decides what you get; the bounds that remain are flags you set or caps that
never change a result. Removed names exit 2 with a pointer; stored logs keep reading. Hooks cover
Codex as well as Claude, and cv doctor reports a harness release cv has not verified.

Breaking: commands, MCP, HTTP and JSON. A removed name exits 2 with a pointer to its replacement.

  • cv search --json (and MCP search) prints {"hits": [...], "total": M}, not an array; the table footer reads N of M matches.
  • /api/search adds X-Cv-Search-Total, every session that matched; its note says N of M matches when limit cut it.
  • cv events --json (/api/events, MCP) holds whole commands and error texts, newlines kept; the table marks cuts with …, and --wide prints them whole.
  • cv search --scan (scan=1, cv pack without an index) matches each session's whole exchange, streamed, instead of its first 256 KiB.
  • cv index --semantic reads each session as far as the model embeds (512 tokens × median token length) and prints it; the 64 KiB head is gone.
  • The full-text index holds a persisted tool output whole, not its first MiB, and snippets find a term anywhere; source::VERSION 9 rereads once.
  • Hooks read at most 8 MiB of transcript and say what they left unread: compact names the tail it read, start a row's commit search span.
  • cv show on a pipe prints the whole transcript (no 200 KB head+tail guard); MCP show adds no default last/max_bytes window.
  • MCP observe_stream returns everything appended by default; char_cap, when given, is stated with a truncated count.
  • Cursor counts only bubbles a read keeps (capability markers dropped); a composer with external bubble cells counts at cv index.
  • source::VERSION is 8: listings rediscover once, so rc.2's cached Cursor counts are recounted.
  • message_count counts prompts and replies only (no tool results or sub-agent returns) and is null, not 0, until counted: ls --json, /api/sessions, search rows.
  • cv archive ls counts turns like cv ls; catalog.jsonl keeps the raw count as messages_written; 0.17 rows show a dash until resynced.
  • extra.openclaw keys keep native camelCase (stopReason, customType, error.errorCode); custom_details and branch_from_id become details and fromId.
  • An IR or OpenSession 0.3 message without kind or origin is refused, not inferred from its role.
  • Fidelity-report deltas and cv formats findings are {what, a, b, expected, where}, replacing {field, before, after} and the old finding keys.
  • MCP tools omit --follow; a follow argument is refused, naming for.
  • cv scry on a pipe prints the sessions it would follow and exits 0; --follow follows, --for 30s|5m|2h bounds it.
  • Watch and observe_stream cursors are version 2; a 0.17 cursor starts a fresh baseline.
  • A tag-only decision (pre-0.15, nothing posed) reads as an assigned action, not a decision owed; the page's tagged-decision card is gone.
  • $CLAURDVOYANT_HOME and $CLAURDVOYANT_MAX_STALE_SECS exit 2, naming the CLUSTERVISION_ variables; claurdvoyant directories are no longer read.
  • Renamed: rewind --from-compaction (the default; --full for everything), deferrals --since is --at, dataset --out is --file.
  • cv tools --agent takes an exact id or unique prefix, else exits 2; --across with --agent, --tool or --timeline exits 2.
  • An unknown cv task events --kind (/api/events?kind=) exits 2 (400) listing the known kinds, instead of listing nothing.
  • cv workflow exits 2 on flags it dropped: run-only flags without a run, --revive-all without --revive, --revive with --json.
  • -q text: without an index reads live; past --live-bytes or under --frozen it exits 2 naming cv index (/api/stats: 503).
  • cv events, cv touched, cv blame and their HTTP routes fail on an event-catalog error instead of answering empty.

Breaking (library): cv-core, cv-search and cv-testkit.

  • ParseOptions/ExtraProjection → Demand { tier, spans, offsets }; MessageSink::extra_projection → tier; the five Watcher poll methods → poll/try_poll(Poll { .. }).
  • Adapter::resume/try_resume/resume_format → Adapter::transcript(r, demand, Start, sink); append_only returns bool.
  • Adapter::discover returns Discovered { refs, skipped } (out-of-tree: Ok(refs.into())); cline::discover_in returns it, cline_sdk::discover fills &mut Discovered.
  • Watcher::run is gone (callers schedule poll); poll_sources → offer_sources.
  • Text: over 4 KiB is Text::Source; Span is wire form only; malformed escapes and unresolved formatting error; matches_str and is_lazy replace equality and is_span.
  • lazy::json_string_span is gone; try_resolve_prefix budgets decoded bytes (max_raw → max); lazy::read_head → read_head_checked (Result).
  • ir::Head → projection::Head (separate byte and character budgets; push returns true when full); Counted::new builds Counted; hashing() captures SHA-256.
  • emit::Delta and formats::Finding → emit::Divergence {what, a, b, expected, at}; FindingKind::ManifestInvalid replaces source_file_missing for unparseable manifests.
  • SubagentInfo/claude::subagent_refs → ir::AgentRef/subagent_tree_of; claude::CARRIER_KEY → ir::CARRIER_KEY; SubagentEnd, ApiErrorNotice, TaskNotice move to lanes.
  • Return Result: agent end, return, task-notice and workflow-launch reads; forest and subagent-reference APIs; one_agent_across; wire::openai::tool_calls; store_affordances; json_files.
  • Return Result: codex::parse_str, gemini::parse_all_str[_for], ingest::ingest_files, events::{events_for, sessions_touching, sessions_editing, edits_touching_file}.
  • Renamed modules: handoff → codex_handoff, loom → splice, harness::harmony → harness::wire::harmony; decode_content takes a call-id generator (ir::derived_call_id).
  • export::{ChatGptExport, ClaudeExport} are gone: harness::for_harness_with_root(Harness::ChatGptExport, dir).
  • affordance: classify_tool, items_of, item_of → classify_tool_json/_view, items_of_view, item_of_view; Returns::ResultInPrompt is new (Roo's new_task).
  • affordance::{unwrap,rewrap}_deferred take a DeferredWrapper; wire::anthropic's owned Texter, block_from* and blocks_from are gone.
  • distill::distill → prepare_distill + distill_pack; Session::first_user_text and searchable_text are gone.
  • SearchRow::to_json → to_json_with(&SearchRowContext); scan::live_search → live_search_filtered.
  • Redaction and HTML rendering take a resolver (share_message(.., resolver)); Markdown uses write_md_message/write_md_block; scrub_value/scrub_cow are private (redact_with, redact_message, redact_text).
  • RedactOptions.keep_emails → classes.emails, inverted; task::AppendOutcome.replay_warnings is gone.
  • source::Published → Record<T> (Table<T: Payload>, admit replaces published/fresh); source::rename_consumer is gone; catalog::fill_count is gone.
  • resume::version returns String; resume::MarkUpdate is {session, mark}; publish::retract is gone (publish::Set owns rollback).
  • New fields break exhaustive literals: EmitOptions.parsed_at, PruneOptions/RewindOptions.skills_policy and results' skills, Stats.uncounted, HarnessCensus.first_error, LaneWork.unread.
  • EmitOptions.sidechain_of is Option<SidechainOf {root, agent}>; prune::prune_session takes the Harness first.
  • events::ingest_all takes IngestOptions; query::WindowPresence is gone (filter_refs_limited drops it); query::HAS_FLAGS rows are (name, help, Cost).
  • lanes::Lane.status is LaneStatus, LaneEvent.event is LaneEventKind; STRAND_PATTERNS is private (text_is_waiting).
  • ForestTools::for_workflow → tools::forest_tools_selected(r, None, Some(run_id), None); task::store::append_agent_event → TaskStore::default_store().append_agent_event.
  • cv-search: text_search*, enrich_text_snippets, semantic_search_filtered → Searcher::{search, search_in}; embed_all → embed_sessions; Searcher::semantic is private (Searcher::from).
  • fts::enrich_text_snippets returns Result<Option<String>> (a degradation note).
  • cv-testkit: heap::begin/end return Measurement; Env::enter_isolated returns Isolated(armed, Scope); claude::user(sid, uuid, ts, text).

After upgrading, once.

  • source::VERSION is 7: the first listing rebuilds the catalog (said on stderr; cv index does it ahead) and every mark, checkpoint and watch state.
  • The first cv index rebuilds the full-text index whole.

Listing and counts.

  • A plain .json OpenSession document is discovered wherever its top-level version key sits, not only within the first 64 KiB.

  • A first cv ls leaves Codex, Grok, Kimi, Kimi Code, Qwen, Hermes, Goose, Zed, Continue and OpenCode uncounted until a read or cv index.

  • cv stats reports "N not counted yet" (uncounted in --json, /api/stats); --sort-by messages ranks uncounted last.

  • A count survives refreshes of an unchanged source and is dropped when it changes; rewound or superseded Hermes rows no longer inflate it.

  • Kimi, Kimi Code and Grok titles are the recorded native title; Hermes, Goose and Zed list from metadata alone.

  • Cursor legacy counts exclude empty and malformed bubbles.

  • A listing racing cv index waits up to 5 s for it instead of discarding its update.

  • created: without a recorded creation time no longer matches on update time.

  • ls --json --asc with a query selects the same sessions as descending; absent sessions take no window slot; refreshed harnesses keep their tie order.

  • serve, mcp and followers see Gemini and Qwen projects registered after they started.

  • A read-only catalog still serves warm listings; builds without sqlite no longer spool unpublishable events.

  • Semantic indexing caps transcript heads at 64 KiB of decoded text.

  • cv search, /api/search and -q text: also read what the index has not seen, within --live-bytes (256 MiB); --frozen reads none.

  • cv search without an index answers from that live read instead of exiting 1.

  • Search staleness counts each session's preferred copy, not older duplicates.

  • Cold SQLite snapshots stage beside the catalog instead of in a multi-gigabyte tmpfs copy.

  • MCP observe_stream keeps every followed session's reader state server-side and reports rereads.

  • Codex rollouts over 8 MiB list the title and cwd a full read gives, not a head-and-tail sample.

  • An append or rewrite rereads only that session: Claude forks, Grok cwd groups and Kimi Code sub-agents no longer reread; Codex rereads appended records.

  • A store write rereads only changed sessions: Hermes, Goose, OpenCode, Devin, Zed, Cursor, OpenClaw, Cline SDK databases, Gemini and Qwen logs.json.

  • Discovery rescans only changed sources: Kimi, Kimi Code, Goose legacy, Cline, Roo, Continue, OpenSession files and OpenClaw stores.

  • Sub-agent trees (show --tree, --subagents, lanes) reuse unchanged agents' saved scans; Codex, Hermes, Devin and OpenClaw read their registries once per state.

  • cv index and live search read only what was appended since the last index; compressed Codex rollouts are read in parallel.

  • One changed session rewrites only its catalog row; cv show agent-…, workflow-name and ghost lookups read the catalog, not rediscovery.

  • The prompt hook, task mutations, cv task list and GET /api/tasks replay only task-log events appended since a stored fold.

  • The sessions API resumes its 1024 most recent sessions of any size; cv stats --tokens keeps every live session's cached usage.

  • Watch checkpoints and archive resume states of any size are kept (past 64 KiB or 1 MiB they were dropped).

  • A WAL-backed SQLite copy happens once per command; an export archive past the 8 MB cache is scanned once.

  • cv show --tree indents once per fork above a message, so a straight chain prints flat.

Reading.

  • cv index holds a few open files per worker, not two per compressed Codex rollout, so a cold index stays under macOS's 256-file limit.
  • cv search, /api/search, MCP search and -q text: read every session the index has not seen; --live-bytes (live_bytes) now only bounds it when given.
  • Global --frozen (CV_FROZEN=1) reads without updating cv stores, streaming stale events; commands that write stores or sessions exit 2.
  • Boundaries carry no invented text (Claude, OpenClaw, Goose, Hermes, Kimi, Kimi Code, Qwen); show labels them by kind and marks inferred ones synthesized.
  • Cursor and LM Studio (Harmony) tool calls without native ids get cv:<format>:<position>.
  • Codex: tool results carry only recorded status; usage-only records are notices; [error] outputs stay verbatim unless cv wrote the rollout.
  • Zed and Goose report the recorded model; the provider (extra.zed.provider, Goose metadata) never substitutes for it.
  • Gemini, Qwen, Goose, Grok, LM Studio, OpenClaw and OpenCode report the model on every turn that records it, windowed reads included.
  • cv distill and cv adopt --model default the agent type to general-purpose only when the source names none.
  • A source replaced or deleted mid-read is an error, checked after slow callbacks, per mapped window, at checkpoints and at EOF.
  • Native Codex file-change records, code-mode edits included, feed cv touched, tool histograms and query facts without duplicating patch calls.
  • Qwen checkpoint facts live under the qwen bag, not gemini.
  • Compressed Codex rollouts need the zstd feature; without it they are unreadable, not parsed as JSONL.
  • ZIP uploads over 10,000 entries are refused.
  • cv blame -L says when its commit list was cut and marks an empty message (no message); cv show hints spell sub-agent ids in full.
  • Claude Code 2.1.304 is the verified writer: request-ledger, isolation-latch and unknown records are carried, never read as turns.
  • A Claude fork sub-agent's fork-context-ref sets lineage.forked_from and extra.claude.fork_context; a retried request's api_error renders as an error.
  • Claude fork inference counts only a copied first prompt or boundary, not a SessionStart hook's earlier timestamp.
  • A workflow agent turns stale when its session's tool-results gains spilled outputs.

Titles and affordances.

  • has:subagents matches the forest agents counts: Claude workflow agents and Codex and Devin forests too.
  • Kimi, Kimi Code and Hermes sub-agents join the forest; dataset --subagents reads every harness's forest.
  • Emitted sessions' fallback title is the cv ls title; Cursor CLI titles drop the leading <timestamp>.
  • has:skill and --kind affordances count a Claude skill loaded by slash command, once per activation.
  • Kimi Code: the latest TodoList is a plan/state row; legacy Agent/AgentSwarm calls are spawns, their results returns.
  • Roo: a new_task result beside user text is a subagent_return detail; the turn stays a prompt.
  • Tool-filtered histograms keep edit counts; native edits reconcile by call and resolved path, never guessing relative paths in compound shell commands.

Reshaping.

  • cv pack --excerpt-bytes N (default 1600) bounds each excerpt message; the bundle's Bounds: line names every bound and what it cut.
  • CV_PACK_LLM digests send up to the model's provider-reported context window (was 60K chars), or --context-bytes N; the bundle states bytes sent and the limit.
  • cv port --strict help names the actual ⚠ lossy: output marker for losses the target format cannot hold.
  • prune, rewind and port take --skills keep|drop|drop-stale (default keep), legacy command-file skills included.
  • cv prune, cv rewind, cv adopt and Claude ports check the staged session resumes before publishing; else they refuse and leave nothing.
  • cv prune, cv rewind and adoption refuse a non-JSON-record line; cv prune refuses an empty transcript; minted ids are UUID v7.
  • cv rewind copies to the end of the file (tail records like cost-state were dropped).
  • cv rewind at a cut keeps parallel calls, closes open ones, drops a malformed later line, and asks for a rerun on an unterminated one.
  • cv rewind refuses a bodyless turn only with --thinking portable; a native copy keeps it.
  • cv port to Codex writes the source's cli_version; to OpenClaw and LM Studio, no invented usage.totalTokens or tokenCount: 0.
  • cv port to Gemini derives message ids (UUID v5) from session and turn, so re-emits match; to Continue, a tool turn without result is refused.
  • Gemini, Grok, OpenClaw, Cline, Roo and Continue emits stage their files, publish the transcript or index last, and roll back on failure.
  • Staged emits are not crash-atomic: a crash can leave a published prefix; a failed rollback is reported.
  • OpenClaw port and emit refuse an unreadable or concurrently changed sessions.json; an unwritable Gemini projects.json fails the emit.
  • Hermes and OpenCode exports reject unreadable sources before creating any output; --force restores a replaced sidecar when the transcript fails.
  • Claude, Gemini and Qwen resume hints are one runnable line: cd <dir> && <harness> --resume <id>.
  • Qwen emission keeps absent cache counts absent; OpenCode keeps an unknown cwd empty instead of cv's own.
  • cv splice --generate rejects an empty completion; pack --json returns content, artifact paths and resume hints; cv pack names LMSTUDIO_API_BASE.
  • A refused write names the failed JSONL record, or the OS error behind a refused exclusive rename.

Doctor and hooks.

  • cv doctor adds Writer versions: the newest Claude and Codex versions seen versus the newest verified, plus unknown sessions.
  • cv hooks install codex (user or --scope project) installs Claude's five hooks: compaction recovery, start context, lanes, decisions, edit guard.
  • cv hooks install|show codex and cv doctor report each Codex hook as trusted, untrusted or modified, with Codex's review step.
  • Codex's edit guard denies a conflicting edit (Codex has no ask), but not one over a file the same root thread's agents edited.
  • cv hooks and cv hook --harness accept every --harness spelling (cc, claude-code); cv lanes --recent N reads Codex sessions too.

Waiting commands.

  • Every waiting command says on stderr within a second what it waits for; on a pipe, each exits within 5 s or announces itself.
  • cv workflow --follow takes --for <duration>, then renders the run as it stands.
  • cv hook with a terminal on stdin exits 2; cv mcp and cv task … - say what they read.
  • Followers announce a session unreadable at start once it reads, instead of guessing its message count.
  • cv events keeps every extracted event (the per-message (kind, target) dedup is gone).
  • A follower's byte mark on a compressed Codex rollout is unresolved, not resumed from a decoded prefix.

Removed.

  • cv watch --interval takes seconds like scry; a negative --interval exits 2.
  • An unknown cv pack --format exits 2 naming md, prompt, session.
  • Mentions of a leftover index.sqlite or pre-0.9.12 discover.json are gone; delete either by hand.
  • MCP errors for removed properties name their replacements.

Skips: counted, reported, or warned once.

  • cv index defers a session whose old search baseline cannot be invalidated (catalog unopenable), names it, and completes the pass instead of aborting.
  • A source discovery cannot open (unreadable dir, locked or corrupt database, bad export or sessions.json) is named by cv doctor, not silently empty.
  • cv doctor --json gains skipped_sources; per-file cv: skipping lines become one stderr summary.
  • An unreadable session file errors instead of reading empty: Continue, OpenCode, Cline, Roo, Devin, Hermes, Goose, legacy Codex .json.
  • Undecodable records count as skipped_lines: Claude (trailing partial included), Cursor, Continue, OpenCode, Cline, Roo, Goose, Zed.
  • A catalog, usage-cache, scan-cache or config.toml failure is said once per process and retried; nothing partial is published.
  • A Hermes compression continuation that cannot be queried errors instead of dropping continued_in.
  • Search names a hit whose source cannot be read; --scan skips unreadable sessions and names them.
  • cv formats reports each harness's first parse error (first_error in --json).
  • ls --json --enrich carries enrich_error for an unreadable transcript.
  • cv workflow --revive says when a lane's read stopped early; an unreadable run-state file is named, not claimed as a ghost launch.
  • cv archive, cv pack, cv cat and cv events --subagents name their read failures instead of dropping them.
  • cv serve closes a connection whose body exceeds its Content-Length.

Tooling and CI.

  • The viewing-and-sharing manual links Compare branches to the renamed Splice composer section.
  • cv schema --json lists routes (every cv serve method and path) and the subagent_row and task_row keys.
  • cv index --json reports changed, removed and errors beside indexed.
  • Release gates: 0.17.0 compatibility, 0.16.1 upgrade over every corpus, real Codex 0.162.1 hooks, and macOS nightly and on rc tags.
  • Contributors: tools/size-budget.txt and check-size.py --write are gone (drift is reported); tools/dump-hash.sh is the byte-identity gate.

rc.1 tagged 2026-10-22; rc.2 2026-10-23.

Install clustervision 0.18.0

Install prebuilt binaries via shell script

curl --proto '=https' --tlsv1.2 -LsSf https://github.com/emberian/cv/releases/download/v0.18.0/clustervision-installer.sh | sh

Install prebuilt binaries via powershell script

powershell -ExecutionPolicy Bypass -c "irm https://github.com/emberian/cv/releases/download/v0.18.0/clustervision-installer.ps1 | iex"

Download clustervision 0.18.0

File Platform Checksum
clustervision-aarch64-apple-darwin.tar.xz Apple Silicon macOS checksum
clustervision-x86_64-apple-darwin.tar.xz Intel macOS checksum
clustervision-i686-pc-windows-msvc.zip x86 Windows checksum
clustervision-x86_64-pc-windows-msvc.zip x64 Windows checksum
clustervision-aarch64-unknown-linux-gnu.tar.xz ARM64 Linux checksum
clustervision-i686-unknown-linux-gnu.tar.xz x86 Linux checksum
clustervision-x86_64-unknown-linux-gnu.tar.xz x64 Linux checksum