Cross-package release notes for relayburn. Package changelogs contain package-level detail.
summarynow reports context tokens per generated output token and p50/p95/max context size for the ten highest-ratio sessions; context is input + cache-read + cache-creation tokens, while the denominator includes reasoning whether a harness folds it into output (Codex) or reports it separately.hotspots --findingsnow flags high-volume sessions at or above a configurable context-to-output ratio (default 382:1 inclusive, with a configurable 1M-context-token floor), independently of dollar cost. The default is an inspection signal, not a length-normalized anomaly score.
- BREAKING (
relayburn-sdk): the published Rust SDK no longer re-exports its low-levelanalyze-layer internals (detector/aggregator functions and helper types such asPricingTable,CompareTable,CompareCell) — these were never the intended embedding surface. Embed through the verb layer instead:LedgerHandlemethods /summary_report/hotspots/compare. CLI, MCP, and@relayburn/sdkbehavior is unchanged. burn comparecost figures now use canonical decimal rounding ({:.N}/toFixedsemantics) instead of float-multiply rounding, so cells/totals/buckets can shift by one in the last reported digit at exact ties; affects thecompareverb's JSON for all consumers (CLI, MCP,@relayburn/sdk).- Fidelity summaries (
fidelityblock insummary/compareJSON) now emitbyClass/byGranularity/missingCoveragekeys in a stable order instead of a randomized per-run order, so output is reproducible across runs (diff-, cache-, and snapshot-friendly). burnsubagent-tree views now require a re-ingest to render pre-Root-emission event logs (legacy reconstruction path removed).
burn summaryandburn compareaccept--bucket <DURATION>to emit a per-bucket time-series across the--sincewindow instead of a single total ({ "bucketSeconds": N, "buckets": [...] }in JSON). Bucket units:30s/5m/1h/12h/1d/7d— notemis minutes here, unlike--sincewheremis months.summary --bucketsupports only the default grouped (byModel/--by-provider) modes;hotspots/overheadare unchanged.
burn summaryandburn hotspotsno longer run a pre-query ingest sweep by default — both return in well under 100ms instead of seconds on large ledgers (hotspotswas ~3s). Pass--ingestfor a one-off freshen; keep the ledger current out of band withburn ingest --watchor the Claude Stop hook.- Faster reads on large ledgers: time-windowed turn queries (
--since/--untilwithout a--session) now seek thetsindex instead of scanning the wholeturnstable, cuttingsummary/hotspots/overhead/comparequery time by roughly 3-4x. Output is unchanged.
burn summarynow reports turns whose model has no pricing entry (unpricedTurns/unpricedModelsin JSON output, warning footer in human output) instead of silently counting them at $0.
- Pricing: added
claude-fable-5to the vendored models.dev snapshot ($10/$50 per Mtok input/output, $1 cache-read, $12.5 cache-write, 1M context, 128K output) so cost reporting recognizes Claude Fable 5.
@relayburn/sdkhotspots({ groupBy: "findings" })now returns the exported findings result instead of rejecting the option.
ingest()is near-instant when nothing upstream changed: a no-op sweep returns{ ingested: 0 }in roughly source-walk time (~0.2s) instead of ~0.7s. Addsarchive_state.source_fingerprint(schema v6, auto-migrated).
- Pricing: added
claude-opus-4-8to the vendored models.dev snapshot ($5/$25 per Mtok input/output, $0.5 cache-read, $6.25 cache-write, 1M context) so cost reporting recognizes Claude Opus 4.8.
burn update: upgrade to the latest release through whichever package manager installed the binary (npm or cargo);--checkreports availability without installing.- On-launch update check: interactive
burninvocations offer to install a newer release and restart, throttled to one network probe per 24h and suppressed once a version is declined. burn update toggle-auto-update [--on|--off]: enable or disable the on-launch update check (state stored in$RELAYBURN_HOME/update.json).
burn overhead deltas: per-inference context-window attribution. New--session,--top,--min-delta,--owner,--explain,--jsonflags surface "what blew up my context between inference N and inference N+1?" — pairs same-railInferencespans, attributes the delta ininput + cache_read + cache_writeto interveningToolResult/UserPrompt/SystemReminderleaves, surfaces compaction events as their own row (never a negative delta), and isolates main-rail deltas from subagent rails. SDK entry point:LedgerHandle::context_delta(opts). (#432)burn flow --session <id>: inference-flow DAG over a session's span trees. One column per turn on the main rail; dispatched subagents branch onto their own rails inheriting the dispatching inference's Y, withdispatch/returnedges between rails andunattachededges for orphan subagents. Renders Mermaid (default), SVG (--output flow.svg), and JSON (--json).--max-turnsdefaults to 50. New SDK surface:LedgerHandle::flow_graph(session, opts)and free-functionflow_graph_from_trees. (#431)relayburn-sdk: per-turn span tree as derived analytical primitive. NewLedgerHandle::turn_span_tree(session_id, turn_id)andsession_span_trees(session_id)verbs projectTurnRecord+tool_result_eventrows + Claude subagent sidecars into an OTel-styleTurnSpanTree { Turn -> { UserPrompt, Inference -> ToolUse -> { ToolResult, Subagent } } }. Pure projection — no schema change, no caching. Orphan subagents surface as siblingSubagentspans withunattached=true. Locked attribute keys (tokens.*,model,request_id,tool_use_id,agent_id,stop_reason) for downstream consumers (inference-flow DAG, context-delta attribution). (#430)relayburn-sdk:ingest_claude_transcript_path(ledger, path, opts)— per-transcript Claude fast-path used byburn ingest --hook claudeso the hook ingests only the one JSONL the payload points at instead of a full sweep.
relayburn-cli:burn ingest --hook claudenow drives the new single-transcript fast-path, bounding per-hook cost to one JSONL parse.relayburn-cli:burn ingest --quietis now accepted in default (one-shot) and--watchmodes (no longer hook-only). Suppresses the progress spinner, watch banner, and per-tick summaries; one-shot mode still writes its final summary line to stdout for pipeline capture.relayburn-sdk:Inferenceaggregate keys per-API-call rollups by(source, session_id, request_id)with merged usage andkind(reasoning/message/tool-use/mixed). Read viaLedgerHandle::inferences(opts)(free functioninferences()too); persisted at ingest into the newinferencestable. Falls back tomessage_idfor harnesses without arequestId(Codex, opencode, older Claude). (#434)burn summary: one-lineTurn outcomes: …breakdown of assistantstop_reasoncounts, plus astopReasonsblock in--json. (#437)- Ledger fingerprint primitive (
{count}:{maxMtimeUnix}:{totalBytes}) for cheap "did anything change" polling. Exposed asLedgerHandle::fingerprinton the Rust SDK,sdk.fingerprint()on@relayburn/sdk,burn state fingerprint [--session | --project]on the CLI, andburn__fingerprinton the MCP server. OptionalSession(id)/Project(path)scopes; all-sessions is the default. (#440) burn hotspots: newBytescolumn on the per-tool tables and--rank-by bytesmode rank tools by raw output payload size, so a 4 MB Bash result that got truncated to a small token count still surfaces alongside small-bytes / large-tokens reads. JSON output gainstotalOutputBytes,maxOutputBytes, andtruncatedCounton every aggregation row. (#436)relayburn-sdk:ToolResultEventRecordcarries newoutputBytesandoutputTruncatedfields populated at ingest fromcontent.as_bytes().len()plus Claude truncation-marker detection;ToolAttribution/FileAggregation/BashAggregation/BashVerbAggregation/SubagentAggregationexpose the rolled-uptotal_output_bytes,max_output_bytes, andtruncated_count. (#436)relayburn-sdk: Claude Task subagent sidecar discovery + pairing. Newdiscover_subagents/pair_to_main/count_subagents_underhelpers undercrate::reader::claude::subagentswalk<sessionId>/subagents/agent-*.jsonl, pair each sidecar against the parent'stoolUseResult.agentId, and surface unpaired sidecars (slash-command synthetic dispatches and crash-mid-dispatch) as theUnattachedGroupbucket. Discovery is lazy — the directory is only stat'd when something asks for it. (#435)burn summary: newsubagents: X paired, Y orphanline (and matchingsubagentskey in--json) populated by a lazy walk over~/.claude/projects/. Skipped entirely when no sidecars exist anywhere reachable so pre-#435 outputs stay byte-identical. HonorsBURN_CLAUDE_PROJECTS_DIRfor test sandboxing. (#435)- Ledger schema bumped to v4 — new nullable
turns.subagent_id TEXTcolumn denormalizesTurnRecord.subagent.agent_idso subagent rows are queryable without re-deserializingrecord_json. Migrated in place byALTER TABLE … ADD COLUMN; pre-v4 rows stayNULLand are backfilled byburn state rebuild. (#435) relayburn-sdk: Claude slash-command triads (/review,/init, custom skills) now collapse into one syntheticSkillactivity instead of inflating the activity count three rows at a time. Detection pins on the caveat → invocation → stdout parent-UUID chain shape with<command-name>/<local-command-stdout>purpose checks, so real user prompts that happen to look structurally similar are not misdetected. Token attribution stays on the underlying assistant rows —Skillis a view, not a billing reattribution. NewActivityCategory::Skillvariant anddetect_slash_triadshelper. (#438)relayburn-sdk: Claude Code parser now skips harness-injected<task-notification>rows when emittingUserTurnRecords. The detector matches shape AND purpose across three envelope variants (type: "queue-operation"+ content prefix,origin.kind, andqueued_commandattachment withcommandMode), so a real prompt that literally types<task-notification>is not filtered. Drops user-turn inflation from background Bash completions.relayburn-sdk: Claude Code activity classifier now associates each assistant turn with its user prompt by walking theparentUuidchain to the nearest user-prompt ancestor, instead of file order. Fixes mis-classification of late-arriving assistant rows under out-of-order JSONL flushes and interrupt + resume sessions. Falls back to the previous file-order map for legacy/malformed rows without UUIDs. Codex and opencode readers are unaffected — their rollouts don't carry an equivalent chain field. (#433)- BREAKING
relayburn-sdk:TurnRecord.stop_reasonis now anOption<StopReason>enum (kebab-case wire form); deserialization is lenient so pre-3.0 ledgers replay cleanly. (#437) relayburn-sdkledger schema bumps to v3:turnsgains astop_reason TEXTcolumn (#437) andtool_result_eventsgains nullableoutput_bytes/output_truncatedcolumns (#436). Both are migrated in place onLedger::open; existing rows leave the new columnsNULL. Runburn state rebuildto backfill an older ledger.relayburn-sdkledger schema bumps to v5: adds theinferencesderived table for per-API-call aggregates. Created idempotently on open; rebuilt byburn state rebuild. Pre-v5 ledgers stay empty until rebuild or the next ingest run. (#434)relayburn-sdk: Claude Code parser now correctly mergesusagefrom the carrier row of a multi-block assistant message. Previously, if the row carrying theusageblock was not the first row for a givenmessage_id, its tokens were dropped. The new merge adopts the carrier row's usage values whichever row owns them. (#434)
burn hotspots: new MCP-server rollup that collapses everymcp__<server>__<tool>tool call into one row per server, so a chatty MCP server (e.g. relaycast) shows up as a single line instead of 50+. Surfaced in the human renderer (when non-empty) and asmcpServersin--json. (#424)
@relayburn/sdk:writeStamp({ sessionId | messageId, enrichment })for launchers that know the session id up front (e.g. preallocated Claude--session-id), bypassing the sidecarwritePendingStampmatching path.
relayburn-sdk: dedupe ingest filesystem walks (list_dirs,list_jsonl_files,walk_jsonl) intoingest::walk, fix thewalk_jsonlfilter to match.JSONLcase-insensitively, and collapse the per-harness append boilerplate (apply_parsed_extras) and the three single-harness verb skeletons (run_single_harness). No behavior change beyond the case-sensitivity fix. (#343)
relayburn-sdk: analyze hot paths (overhead,hotspots,quality,compare) now aggregate per-session/per-file groups by reference instead of cloningTurnRecords, cutting working-set memory on the most expensive verbs. Behavior is unchanged.
relayburn-cli:burn compare --sincenow uses the same normalization path asburn summaryandburn hotspots, keeping date-filter behavior consistent across commands.relayburn-sdk:normalize_sincenow canonicalizes outputs to UTCYYYY-MM-DDTHH:MM:SS.mmmZ. Relative ranges (7d,24h) emit.000Zinstead ofZ, and ISO inputs with offsets (e.g....-07:00) are converted to UTC. This fixesburn summary/burn hotspots/burn compare --sincesilently dropping same-second turns and misordering offset cutoffs against the ledger'sts >= ?lex compare.
relayburn-sdk: ingest verbs are now synchronous; async callers should run them viatokio::task::spawn_blocking.relayburn-sdk: lower per-record allocations in reader hashing, tool-result sizing, relationship dedup, and project resolution. Cuts overhead during large session imports and concurrentresolve_projectcalls.relayburn-sdk:parse_claude_sessionnow delegates to the incremental parser withstart_offset = 0, dropping the duplicateParseStatecodepath. Behavior is unchanged — trailing in-progress turns and final JSON lines lacking a trailing newline still surface in the single-shot output.
relayburn-sdk: removedrun_ingest_tick.
relayburn-cli:burn comparenow applies--provider,--workflow, and--agentfilters at runtime. It still reads the current ledger snapshot (no pre-query ingest); runburn ingestfirst for freshest data.
relayburn-cli: stdout-write failures in--jsonmode now surface as a non-zero exit instead of being silently dropped.relayburn-sdk: ledger query verbs (query_turns,query_compactions,query_relationships,query_tool_result_events,query_user_turns) now pushsince/until/session_id/source/projectfilters into SQL and reuse compiled statements viaprepare_cached. Cuts the per-call cost ofburn ingest --watchand any verb that drives a filtered query against a multi-month ledger.
relayburn-cli:--no-archiveonburn compareandburn summaryis now an explicit no-op (accepted for TS CLI flag parity).
relayburn-cli:burn sessions listhuman output now keeps full session ids, shows a single human-readable last-seen date column, and truncates long project paths from the beginning.relayburn-sdk/relayburn-cli:burn ingest --watchnow wakes on filesystem events (with burst coalescing and a 30s polling backstop), reducing steady-state polling; pass--no-fseventsto force polling.
relayburn-cli:burn state rebuild classifynow exits 0 and runs the rebuild instead of erroring with "not yet implemented".
relayburn-cli: dropped the no-op flagsburn state prune --force,burn state rebuild archive --full/--vacuum(and the legacyvacuumpositional),burn state rebuild all --force, andburn state rebuild classify --force. They had no effect against the SQLite layout; passing them now fails at parse time.
relayburn-cli:burn summarypartial-coverage footers now name the token field with the largest gap and clarify that totals still include all matched turns.relayburn-sdk:ingest::pending_stampsandquery_verbsnow use thetimecrate for ISO-8601 formatting/parsing (format_iso_8601,format_iso_z,parse_iso_ms). Output and the pending-stamp on-disk wire format are unchanged.
relayburn-cli: newburn sessions listsubcommand that enumerates recent sessions (most-recent first) so callers can find a session id without dropping into raw SQLite. Flags:--since(defaults to7d),--project,--grep(case-insensitive substring against session id + project),--limit(defaults to 20), and the global--json. Pipes cleanly intoburn summary --session <id>for drill-down.relayburn-sdk: newsessions_listquery verb (LedgerHandle::sessions_list- free-function form) returning
SessionsListResult { sessions, limit, truncated }. Derived from theturnstable so older ledgers with an emptysessionstable still enumerate correctly.
- free-function form) returning
relayburn-sdk: price Codexcodex-auto-reviewjudge turns using the GPT-5.2 Codex tariff so auto-approval review spend is no longer reported as zero-cost.
relayburn-sdk(Rust): refresh the bundledmodels.devpricing snapshot so GPT-5.5 and current model metadata are available for cost lookups.
relayburn-cli:burn hotspotsaccepts--session <id>,--workflow <id>,--provider <csv>,--patterns [csv], and--findings. The per-session aggregate view (--sessionwith no id) and--explain-driftremain explicit stubs that exit 2.relayburn-sdk:HotspotsOptionsgainsworkflowandproviderfilter fields, matching the shapecompare()already exposes.relayburn-cli/relayburn-sdk:burn state resetis now a real presenter over the new SDKLedger::reset()verb. Without flags it dry-runs (counts derivable rows, stamps, and content rows that would drop, exits 0);--forceactually wipes both DBs and blanks the ingest cursors so a follow-upburn ingestwalks every upstream file from offset 0;--force --reingestruns that ingest sweep in the same invocation. Replaces the prior "not yet implemented" stub. (#341)
relayburn-sdk(Rust): reduced hot-path CPU/alloc overhead in pricing and classifier parsing by caching the bundled pricing snapshot and reusing compiled regexes. Breaking (Rust SDK):CostBreakdown::modelis nowCow<'static, str>; struct-literal construction must pass aCow(for example,model: value.into()).
relayburn-sdk(Rust):summary_reportnow exposes the richer summary result used byburn summary, so presenters can render one SDK-owned aggregate shape.relayburn-cli/relayburn-sdk:burn summarynow accepts repeatable--tag k=vfilters and--group-by-tag <key>to report cost/tokens by generic folded enrichment tags; Claude, Codex, and OpenCode pending stamps can now be written by external launchers.relayburn-sdk(Rust): reader hot loops inclaude.rsandcodex.rsnow stream JSONL line-by-line viaBufReader::read_untilinstead of pre-allocating a(size - start_offset)-byte buffer up front; only the longest single line stays resident.memchr_newlinein the codex parser now actually uses thememchrcrate for SIMD-accelerated newline scanning. The mainparse_claude_sessionloop also dropsBufReader::lines()in favor ofread_lineinto a reusedString. (#323)
relayburn-cli: removed theburn runlauncher wrapper from the CLI surface. Launchers should write attribution withwritePendingStamp()and ingest throughburn ingest/ SDKingest().- Removed the old TypeScript implementation packages from the workspace. The Rust crates now own the SDK and CLI implementation, with npm packages kept for the Node SDK facade, MCP server, and prebuilt CLI wrappers.
relayburn-sdk(Rust): default ledger home moves from~/.relayburnto~/.agentworkforce/burnso the Rust 2.0 port and the TS 1.x package can coexist on disk during the #249 cutover.RELAYBURN_HOME(and the per-DB path overrides) continue to override the path; TS 1.x users on~/.relayburnare unaffected. Rust-port testers with data under the old path canmv ~/.relayburn ~/.agentworkforce/burnto carry it over (formats are not compatible — Rust treats any non-2.0 layout as empty and requires aburn ingestre-population).relayburn-cli(Rust): wire opencodeHarnessAdapterviapending_stamp::adapter_staticfactory; registered inRUNTIME_ADAPTERS. (#248 D7)relayburn-cli(Rust): wireburn run <harness>driver + claude adapter (eager unit-struct inEAGER_ADAPTERS);afterExitingest folds into[burn] claude ingest: ...summary line. (#248 D5)relayburn-cli(Rust): wireburn ingest(no-flag scan,--watchpoll loop,--hook claude --quiet) andburn mcp-serverstdio subcommand exposingburn__sessionCost; closes #210. (#248 D8)relayburn-cli(Rust): wire codexHarnessAdapterviapending_stamp::adapter_staticfactory; registered inRUNTIME_ADAPTERS. (#248 D6)relayburn-cli(Rust): wireburn compareas a presenter overrelayburn_sdk::analyze::comparebuilding blocks (build_compare_table+ the per-turn fidelity gate), matching the TS CLI flag set (positional comma-separated model list,--include-partial/--fidelity/--since/--project/--session/--min-sample/--csv/--no-archive) and producing byte-equivalent stdout for the cli-goldencompare/compare-jsoninvocations. (#248 D3)relayburn-cli(Rust): portburn overheadandburn overhead trimas thin presenters overrelayburn_sdk::overhead/::overhead_trim. Output (human +--json) is byte-equivalent with the TS CLI. (#248 D2)relayburn-cli(Rust): wireburn stateas a typed clap subcommand withstatus(default),rebuild,prune, andresetverbs overrelayburn-sdk.state statusreports per-table row counts inburn.sqlite, the row count incontent.sqlite, thearchive_stateschema/last-built/last-rebuild fields, and the resolved retention config;--jsonemits the structuredStateStatuspayload.state rebuild {index,content,archive,all}drivesLedger::rebuild_derivable;state prunedrivesLedger::prune_content_older_than.state resetand standalonestate rebuild classifyare stubbed pending a follow-up. (#248 D4)relayburn-cli(Rust): wireburn summaryandburn hotspotsas thin presenters overrelayburn-sdk, matching the TS CLI's flag set and stdout byte-for-byte (default +--json). Un-ignores the four matching golden invocations. (#248 D1)relayburn-sdk-node(Rust): napi-rs bindings skeleton —#[napi]shims for every public verb inrelayburn-sdk(summary,sessionCost,overhead,overheadTrim,hotspots,search,exportLedger,exportStamps, asyncingest, plusledgerOpen), with u64 token counts surfaced as JSBigInt, ISO-8601 timestamps asString, async verbs returningPromise<T>, and a typedBurnErrormapping for SDK failures. (#247)relayburn-cli(Rust): introduce the harness substrate —HarnessAdaptertrait, lazy compile-timephfregistry (lookup/list_harness_names), and the sharedpending_stamp::adapterfactory codex + opencode will reuse. Adapter slots in the registry are reserved but empty pending the Wave 2 PRs (#248-d/e/f).relayburn-sdkre-exportsstart_watch_loop,WatchController,write_pending_stamp,PendingStampHarness, and friends so the CLI doesn't have to reach into private SDK modules. (#248)relayburn-cli(Rust): scaffold the clap v4 derive root with global--json/--ledger-path/--no-colorflags, eight stub subcommands (summary,hotspots,overhead,compare,run,state,ingest,mcp-server), and sharedrender::{table,json,error}helpers. Stubs exit1with anot yet implementedmessage (or a{"error": …}envelope under--json); Wave 2 fan-out PRs replace each stub with a thin presenter overrelayburn-sdk. (#248 part a)relayburn-cli(Rust): add the CLI golden-output test rig — synthetic fixture ledger undertests/fixtures/cli-golden/, a node script that captures TS-CLI stdout/stderr across 16 invocations (summary / hotspots / overhead / overhead-trim / compare / state-status in TTY +--json, plus help text for ingest / run / mcp-server / top-level), andcrates/relayburn-cli/tests/golden.rs— aBURN_GOLDEN=1-gated diff runner Wave 2 PRs flip on per-command viaenabled: trueininvocations.json. (#248)@relayburn/sdk(npm 2.x): scaffold thepackages/sdk-node/umbrella + four per-platform packages (@relayburn/sdk-{darwin-arm64,darwin-x64,linux-arm64-gnu,linux-x64-gnu}) resolved viaoptionalDependencies. Adds the napi-rs build matrix in.github/workflows/napi-build.yml, an esbuild bundle smoke test, and a deep-equal conformance test gate against the TS 1.x SDK across the six verbs (ingest,summary,sessionCost,overhead,overheadTrim,hotspots). Conformance test is skipped untilcrates/relayburn-sdk-nodelands its bindings (#247 part a). (#247 part b)relayburn-ingest(Rust): port the per-process gap-warning state machine (gapmodule —record_session_gap,emit_gap_warning,count_tool_call_gaps,reset_ingest_gap_warnings,set_ingest_gap_writer) andreingest_missing_content(reingestmodule). Suppression mirrors the TS surface: one warning per fresh affected session, silent on steady-state, re-fires after the affected set decays back to empty.relayburn-ledgeraddsLedger::list_user_turn_session_idsto power thereingest_missing_contentskip filter alongsidelist_content_session_ids. (#278)relayburn-analyze(Rust): port the behavioral-pattern detectors (patternsmodule).detect_patternsruns retry-loop, failure-run, cancellation-run, compaction-loss, edit-revert, OpenCode skill-recall-dup, OpenCode skill-pruning-protection, OpenCode system-prompt-tax, and edit-heavy detectors against an ordered turn stream, with optional content-sidecar / tool-result-event / user-turn enrichment. Public surface:detect_patterns,DetectPatternsOptions; per-pattern result structs are re-exported fromfindings(RetryLoop,FailureRun,CancellationRun,CompactionLoss,EditRevertCycle,SkillRecallDup,SkillPruningProtection,SystemPromptTax,EditHeavySession,SessionPatternSummary,PatternsResult,PatternEventSource). (#275)relayburn-analyze(Rust): port the tool-output-bloat detector — Signal A'sBASH_MAX_OUTPUT_LENGTHstatic-config check (with~/.claude/settings.json+<cwd>/.claude/settings.jsonloader) and Signal B's cross-harness observed-bloat aggregation, plus theWasteFindingadapter. Public surface mirrors@relayburn/analyze:BASH_MAX_OUTPUT_ENV_KEY,DEFAULT_BLOAT_TOKEN_THRESHOLD,detect_observed_bloat,detect_static_config_bloat,detect_tool_output_bloat,load_claude_settings,project_claude_settings_path,user_claude_settings_path,tool_output_bloat_to_finding. (#271)relayburn-ingest(Rust): port the standalone primitives —pending_stamps(binary-compatible with the TS@relayburn/ingestwire format),walk(walk_jsonl/walk_opencode_sessions),watch_loop(tokio::time::interval-drivenWatchControllerwith graceful stop), and the typedcursorsmodule layered on the SQLite ledger's cursor blob. Public verb surface (ingest_all, per-harness verbs,reingest_missing_content) is wired; per-harness orchestration follow-ups deferred to dedicated sub-issues. (#245)relayburn-analyze(Rust): port the ghost-surface detector —ghost_surfaceandghost_surface_inputsmodules with Claude / Codex / OpenCode adapters, slash-command miners, the per-source-scoped orchestrator, and theWasteFindingenvelope adapter. Findings sort deterministically by(cost desc, sizeTokens desc, path)and dedup against the OpenCode catalog-bloat detector viacountedByCatalogBloat. (#273)relayburn-analyze(Rust): port thecompareaggregator —build_compare_tablefor the in-memory(model, activity)rollup with per-cell turn / edit / one-shot / priced / cost / cache-hit / median-retries metrics, pluscompare_from_archivesourced from the SQLite ledger viaLedger::query_turns. Public surface:CompareCell,CompareTable,CompareTotals,CompareOptions,CompareCategory,DEFAULT_MIN_SAMPLE,compare_from_archive,CompareFromArchiveResult. (#269)relayburn-analyze(Rust): portsubagent_treeandclaude_mdmodules.build_subagent_tree/aggregate_subagent_type_statswalk per-session subagent invocations (relationship-row substrate with legacysubagentfallback) and roll up self/cumulative cost.parse_claude_md/attribute_claude_md/build_trim_recommendations/render_unified_diff_for_recommendationproduce CLAUDE.md section attribution and trim diffs whose unified-diff format stays byte-aligned with the TS implementation. (#272)relayburn-analyze(Rust): port thehotspotsaggregator —attribute_hotspotscomposes the per-tool sized / even-split attribution loop (paying-turn rate, sibling-cap on initial cost, proportional cacheRead allocation on persistence, source-aware reasoning viacost_for_turn) with theaggregate_by_file/aggregate_by_bash/aggregate_by_bash_verb/aggregate_by_subagentrollups. Public surface mirrors@relayburn/analyze:attribute_hotspots,aggregate_by_file,aggregate_by_bash,aggregate_by_bash_verb,aggregate_by_subagent,AttributionMethod,BashAggregation,BashVerbAggregation,FileAggregation,HotspotsOptions,HotspotsResult,SessionTotals,SubagentAggregation,ToolAttribution. Per-row USD totals match the TS implementation within 1e-9. (#274)
- Architecture:
@relayburn/sdkis now the canonical in-process query surface. Dependency order moves from… → mcp → cli → sdk → relayburnto… → sdk → mcp → cli → relayburn;@relayburn/mcpnow depends on@relayburn/sdkand rewritesburn__sessionCostas a thin wrapper over the SDK's newsessionCost()function. New read verbs should land in the SDK first; MCP and CLI become presenters (tool definitions / table rendering) over the same SDK calls so query logic stops drifting between them. burn comparejoinssummary/sessionCost/overhead/overheadTrimas a thin presenter over@relayburn/sdk's newcompare()function. The archive-vs-ledger branching and fidelity-gate logic move into the SDK so a futureburn__compareMCP tool (and embedders) can wrap the same call without re-implementing them.
@relayburn/sdkhotspots()now returns a discriminated union ({ kind: 'attribution' | 'bash' | 'bash-verb' | 'file' | 'subagent' | 'findings' }) instead of either a raw attribution blob or a flat findings array. CLI / MCP / embedded callers must branch onkind. Mirrors the shapeburn hotspots --jsonemits and adds four narrowgroupByviews for single-axis consumers.
- Recognise
_meta.replaces/_meta.collapsedCallsannotations on Claudetool_resultblocks across reader → analyze → CLI, so replacement tools (e.g. relaywash) get attributed estimated tokens saved inburn summaryandburn summary --by-tool.
burn hotspots --patterns=tool-call-patternflags vanilla call patterns with consolidatable overhead (Glob → Grep → Read sequences, single-file edit clusters,git status/pnpm test/gh prBash calls), with per-occurrence counts and token-overhead estimates. Vendor-neutral — downstream tools map patterns to specific consolidations.@relayburn/sdkhotspots()now also surfacestool-output-bloat,ghost-surface, andtool-call-patternfindings (previously only the coredetectPatternsset).- New
@relayburn/ingestpackage owns session-store discovery, parse-and-append orchestration, pending-stamp resolution, and watch-loop primitives extracted from@relayburn/cli. CLI commands and harness adapters now consume ingest from@relayburn/ingest;@relayburn/sdkdrops its@relayburn/clidependency and importsingest()from the new package andbuildGhostSurfaceInputsfrom@relayburn/analyze.
RELAYBURN_STORAGE=sqliteselects a new single-file SQLite backend (default path~/.relayburn/burn.sqlite, override viaRELAYBURN_SQLITE_PATH). Replaces JSONL ledger + sidecars +.idxfiles with one DB; ingest paths use nativeINSERT OR IGNOREon content-addressed dedup hashes so multi-writer setups converge without external indexes.
- Removed Burn's budget and quota tracking surfaces:
burn budget, monthly plan config APIs, and the MCPburn__currentBlocktool are no longer shipped.
- Publish workflow now always targets all lockstep packages and no longer exposes per-package release choices.
burn overhead trim --jsonnow emits structured trim recommendations for programmatic review while preserving the existing unified diff text output.
- Publish workflow now creates one GitHub Release per lockstep publish, anchored to
relayburn, with all package versions listed in the release body.
burn ingest --watch --opencode-streamnow ingests stream-owned OpenCode sessions directly at completed tool-call grain while keeping file ingest as the fallback.
- Renamed the attribution surface:
burn hotspotsreplacesburn wasteandburn diagnose, whileburn overheadreplacesburn context. burn summary --subagent-treenow renders persisted session relationship graphs while preserving legacy subagent-tree output for older data.
- OpenCode stream cursor progress now survives concurrent file-ingest fallback saves.
- Defaulted user-turn block sizing to cl100k, with a measurement script that reports token-count and tool-attribution drift against the bytes/4 heuristic fallback.
burn rebuild --contentnow fast-skips renamed Codex rollout files using their embedded session metadata.
burn waste --patternsnow bases retry and failure findings on persisted tool-result chronology when available, while preserving legacy fallback behavior.- Spawn-env and native sidechain attribution now share session relationship records, and
burn diagnose --explain-driftsurfaces sessions where they disagree. - Provider-aware CLI rendering now uses shared analyze helpers for effective-provider resolution and aggregation.
- Per-tool cost attribution now uses persisted user-turn block sizes in summary and hotspots reports, with rebuild backfill for historical sessions.
- OpenCode passive ingest now records compaction events, so compaction waste analysis covers Claude, Codex, and OpenCode.
- Waste detectors now share a structured
WasteFindingoutput.burn waste --patterns --findingsrenders all findings in one severity-ranked table and includes the same list in JSON.
burn comparenow requires a comma-separated model list as its first argument. The old--modelsflag was removed; filters and output schemas are unchanged.
burn waste --patterns edit-heavyflags sessions with many edits and too few reads across Claude, Codex, and OpenCode.
- Codex passive ingest now records compaction events.
burn waste --patternsadds OpenCode skill-recall, skill-pruning, and system-prompt tax detectors.
burn run <claude|codex|opencode>replaces the separate harness wrappers with one adapter-backed command.
- Removed
burn claude,burn codex, andburn opencode. Useburn run <name>. - Removed
burn rebuild-index. Useburn rebuild --index.
burn comparenow excludes low-fidelity turns by default, with--fidelityand--include-partialfor overrides.
burn plansnow reports per-cycle fidelity so partial data is marked as a lower-confidence estimate.
- User-turn block sizes are now persisted for Claude, Codex, and OpenCode, giving
burn wastea better fallback when full content is unavailable.
- Added execution-graph records for session relationships and tool-result events.
- Claude ingest now writes the new graph records alongside turns and content.
- Fixed reasoning-token pricing. Codex reasoning is no longer double-billed, and distinct reasoning tariffs from pricing data are honored.
- Added the rebuildable
archive.sqliteanalytics read model andburn archive build | rebuild | status. - Added
@relayburn/mcpandburn mcp-serverso agents can query their own session cost and quota state.
- Added monthly plan tracking with built-in Claude and Cursor presets, projections, runway, reset-day support, and
burn limitsintegration.
- Added Claude subagent tree reconstruction plus
burn summary --subagent-treeand--by-subagent-type.
- Added Claude Code hook-based ingest without mutating global Claude settings.
- Codex and OpenCode parsers now capture content sidecars.
- Added
burn rebuild --contentandlistContentSessionIds()for sidecar backfills.
- Added quality signals: inferred session outcome, one-shot edit rate, and retry volume.
- Added waste-pattern detectors for retry loops, failure runs, compaction loss, and edit reverts.
- Moved earlier unreleased changelog notes into their release sections. No package behavior changed.
- Added
burn wastefor per-tool, per-file, Bash, and subagent cost attribution.
- Added
burn contextfor context-file cost attribution. - Added
burn context advisefor read-only trim recommendations.
- Added
burn comparefor model-by-activity cost and quality comparison. - Added
burn rebuild --reclassifyand--index. - Activity classification now covers Claude, Codex, and OpenCode, with normalized tool names and six new categories.
- Ledger appends now lock against reclassification rewrites, preventing lost rows.
- Tightened deploy/build classifier patterns.
burn comparenow rejects--jsonand--csvtogether.
- Initial release of
@relayburn/reader,@relayburn/ledger,@relayburn/analyze, and@relayburn/cli.