JuliusBrussee/caveman
tldr.page
Learn

caveman learn

caveman learn shows where your coding agent's tokens go, and what to fix first. It reads the setup files and session history already on your computer. Nothing is sent anywhere.

You get:

  • a Setup Score from 0 to 100 (higher is leaner),
  • a list of findings: places your tokens go, biggest first, each with a suggested fix,
  • a local HTML report and a JSON file.

It never edits your files. Fixes happen inside Claude Code or Codex, through the caveman-learn skill, one edit at a time, and only after you say yes.

Every number is an estimate from your own history (inferred in JSON). No local number is promoted to verified; see Accounting and evidence.

Words used in the report

The report and terminal use plain words. JSON keeps the precise names in the right-hand column; the tables further down use them too.

WordWhat it meansName in JSON
messageOne request your agent sends to the model: your prompt, or one tool step. The agent re-sends its instructions and the whole conversation with every one.turn (tokens_per_turn, turns)
findingOne place your tokens go, with the evidence and a suggested fix.sink (sinks[])
idA finding's name, for commands like caveman learn apply <id>. Shown by --all.sink_id
Setup ScoreHow lean your setup is, 0 to 100, from this computer only. Not money. Caveman Cloud's team score is a different number.cave_score
tokens a day at your usual paceTokens per message times your average messages per day in the period scanned. A rate from now on, not tokens already spent.tokens_per_day_rate
tokens so farWhat a habit already used in the period scanned.tokens_observed
estimateWorked out from local files. Not verified, not a bill.basis: "inferred"
safe fixA mechanical fix exists. It is applied only if it uses fewer tokens overall.class reducible
repeated textThe same text pasted again across sessions. Caveman memory can recall it instead.class recurring_context
habitA measured pattern in how your sessions run. Changing it is up to you.class behavioral
neededSetup you need. Shown so the picture is complete; never changed.class load_bearing
always-loaded setup, instructionsCLAUDE.md, AGENTS.md, skill descriptions, hooks: loaded into every message.config_tax
unused skillsSkills whose descriptions load with every message but were never used in the sessions scanned.dead_load
context windowHow much the model can hold at once.window
overloaded messagesMessages where the conversation filled more than half the context window. A common rule of thumb: answers tend to get worse past that point.dumbzone, context_dumbzone
how full sessions getEach session's peak share of the context window.context_depth, peak_context_pct
first-message sizeWhat a session sends with its first message: your setup plus your first prompt.first_turn_tokens, measured_prefix_tokens
Caveman memory (cavemem)Caveman's local memory store. The agent recalls a short version of the text when it needs it, instead of pasting it again.cavemem_offload
read from cacheShare of input the provider served from its prompt cache, which costs less than list price. How much less varies by model: usually a tenth of list price or less.cache_read_pct
input really costsYour input price per million tokens after caching, and its share of list price.effective_input_usd_per_mtok, effective_input_multiplier
no priceA model missing from Caveman's price list. Its tokens are left out, so the real total is higher.unpriced
pointsThe change in a percentage: 15% to 13% is −2 points.percentage points
week of Sep 21A Monday-to-Sunday week, in UTC.ISO week (2026-W39)
middle sessionThe median: half the sessions are above it, half below.median

Privacy: what it reads and writes

Analysis runs locally. export writes a file for you to inspect and sends nothing.

Reads

AgentSession transcriptsConfig and memory filesRoot override
Claude Code~/.claude/projects/**/*.jsonl~/.claude/CLAUDE.md, ~/.claude/skills/*, hook count from ~/.claude/settings.json, plugin count from ~/.claude/plugins/installed_plugins.json, MCP servers from ~/.claude.json and .mcp.json, every CLAUDE.md from the current directory up to /CAVEMAN_CLAUDE_ROOT, then CLAUDE_CONFIG_DIR (global config then at $CLAUDE_CONFIG_DIR/.claude.json)
Codex~/.codex/sessions/**/rollout-*.jsonl, ~/.codex/archived_sessions/~/.codex/AGENTS.md, ./AGENTS.mdCAVEMAN_CODEX_ROOT, then CODEX_HOME
Gemini CLI~/.gemini/tmp/*/chats/session-*.json~/.gemini/GEMINI.md, GEMINI.md from repo root to cwdCAVEMAN_GEMINI_ROOT
opencode~/.local/share/opencode/storage/{session,message,part}noneCAVEMAN_OPENCODE_ROOT
aider.aider.chat.history.md files under the rootnoneCAVEMAN_AIDER_ROOT (required; off without it)

The memory and rules doctor also reads .claude/CLAUDE.md, CLAUDE.local.md, .claude/rules/*.md and ~/.claude/rules/*.md (path-scoped rules with a paths: frontmatter are skipped because they load on demand), and Claude Code auto memory at <claude root>/projects/<repo-key>/memory/MEMORY.md plus its topic files, honoring CLAUDE_CODE_PROJECT_DIR_NAME.

Two other inputs: the session_outcomes finding reads commit timestamps with git in up to 12 repositories (3 s per call, budgeted overall), and the wrap_measured block reads rows the Caveman proxy already recorded in caveman.db.

Writes

All paths are under $CAVEMAN_HOME (default ~/.caveman) unless noted. CAVEMAN_DB overrides the database path.

WhenWhat is written
Any command that builds a plan (default run, scan, report, apply, applied, simulate, savings, export, experiment report)caveman.db tables config_snapshots, config_snapshot_history, learn_sinks
caveman learn and learn scan (not with --no-remember, which autopilot always passes)Also: one cavemem memory per reducible sink (title plus suggestion) in mem/mem.db, and a matching row in the learnings table
caveman learn, learn scan --write-report, learn reportreports/caveman-learn.html, reports/caveman-learn.json, reports/caveman-learn.YYYY-MM-DD.json (last 8 dated snapshots kept)
learn apply <sink> without --dry-runcandidates/learn-<sink>.json
learn appliedrow in applied_fixes
learn experiment start/arm/stoprows in experiments, experiment_arms
learn exportreports/caveman-learn-digest.json (or --out <path>)
Autopilotruntime/learn-autopilot.json, .lock, -nudge.json, -nudge.inflight.json, -announced.json, and its own report, snapshots and trend history under runtime/learn-autopilot/reports/
learn autopilot on/offkey learnAutopilot in ~/.caveman-cloud/config.json
learn implementthe skill file, only if missing: ./.claude/skills/caveman-learn/SKILL.md (Claude Code) or $CODEX_HOME/skills/caveman-learn/SKILL.md (Codex)

Report files are created with mode 0600.

Quick start

caveman learn             # read your sessions, score them, show the top findings
caveman learn implement   # open Claude Code or Codex to review and fix, with consent
caveman learn savings     # later: what the applied fixes returned

Commands and flags

The default window is --since 30d. The scan times out after 120 s (CAVE_LEARN_TIMEOUT, seconds).

CommandWhat it does
caveman learnIn an interactive terminal: progress, Setup Score, top findings, then a menu (implement, show all findings, open report, done). Otherwise compact text.
--plainCompact text; no animation or menu. CAVEMAN_PLAIN=1 or TERM=dumb has the same effect.
--allEvery finding with internal id, basis, evidence and suggestion; confirmed outcomes; per-repository rows.
--jsonThe caveman.learn.v1 plan on stdout.
--mdDetailed Markdown.
--since <Nd>Window, e.g. 7d.
--sources <list>Any of claude,codex,gemini,opencode,aider. Default: all.
--repo <substring>Keep only sessions whose repository matches, before any detector runs. Config is still read from the current directory.
--retroAdds the "would have saved" replay block (retro). Budgets: --behavior-budget-ms, --retro-budget-ms. Omitted when --repo is set.
implement [claude|codex] [--prompt "<focus>"]Opens the agent with the caveman-learn skill and the current report.
apply <sink_id> [--dry-run]Materializes a candidate for a reducible or recurring_context sink. Edits nothing.
applied <sink_id> [--fix-kind <k>] [--note <t>]Records an approved, re-measured fix in the outcome ledger.
simulate <sink_id...>Token counterfactual over scanned history only.
savingsAttributed savings ledger, grouped by measurement method.
experiment start|arm|report|list|stopOn/off holdout over your own sessions.
export [--out <path>]Privacy-reduced digest file.
reconcile --usage-export <csv>Measured tokens vs a provider usage export.
autopilot [status|on|off]Background refresh after sessions end.
scan, reportLower-level passthroughs to the proxy. report --json prints the plan and rewrites the report files.

Examples:

caveman learn --plain --since 7d --sources claude,codex
caveman learn --repo my-service --all
caveman learn --json > plan.json
caveman learn implement codex --prompt "only config trims"
caveman learn apply claude_md_weight:project --dry-run
caveman learn applied claude_md_weight:project --note "trimmed setup section"
caveman learn simulate claude_md_weight:project recurring_context:repaste:<fingerprint>
caveman learn savings --json
caveman learn experiment start deploy-skill --sink procedure_repeat:<key> --fix-kind skill_distillation
caveman learn experiment arm deploy-skill off
caveman learn experiment report deploy-skill
caveman learn experiment list
caveman learn experiment stop deploy-skill
caveman learn export --out ./learn-digest.json
caveman learn reconcile --usage-export ~/Downloads/usage.csv
caveman learn autopilot off

Notes per command:

  • apply on a behavioral or load_bearing sink returns applied: false with a reason; there is no mechanical fix. A recurring_context candidate carries locators (file, JSONL line, block index, SHA-256), never the block text.
  • applied needs a fix kind. It is taken from the sink's evidence or a default (claude_md_weight, claude_md_sections, config_tax, dead_load, dumbzone_advice); otherwise pass --fix-kind. The "before" value comes from the newest report snapshot older than the current scan, so a scan run after your edit is not used as the baseline. The edited file is fingerprinted at record time.
  • simulate accepts only claude_md_weight:*, claude_md_sections:*, dead_load:skills and recurring_context:repaste:*. Config sinks are tokens per turn times scanned provider-counted turns; recurring blocks are occurrence sums minus the largest occurrence and one pointer per occurrence. Overlapping selections on the same file are counted once. No dollars, no forward projection.
  • experiment report defaults its window to the experiment's start.
  • export carries sink ids, classes, magnitudes, the score, spend totals and per-model rows. It carries no paths, locators, evidence maps, repository names or session text.
  • reconcile matches CSV columns by header name only and fails on any ambiguous header. Coverage is a token comparison, not a saving.

Autopilot

Autopilot rescans in the background and tells you about new findings without you running learn. It keeps its own report under runtime/learn-autopilot/reports/: its scans run with whatever working directory and environment the last session-end hook had, so they never overwrite the canonical report, dated snapshots or trend history your own caveman learn writes.

AspectBehavior
TriggerThe Caveman native hook's SessionEnd event (Claude Code, Codex, Gemini CLI; opencode and Hermes bridges forward it). The hook spawns a detached, idle-priority caveman learn autopilot run and returns immediately.
ThrottleAt most one scan per 6 hours. CAVEMAN_LEARN_AUTOPILOT_HOURS changes it. One scan at a time (lock file; stale after timeout + 60 s).
Scanlearn scan --write-report --no-remember --reports-home $CAVEMAN_HOME/runtime/learn-autopilot with the default window and sources, killed at CAVE_LEARN_TIMEOUT.
Proxy checkBefore scanning, the detached child runs caveman-proxy learn capabilities and needs no_remember, reports_home and memory_health. An older proxy would ignore those flags and write cavemem and the canonical report, so it never scans: last_error becomes "proxy too old for autopilot (needs learn capabilities)" and learn autopilot status shows it. The result is cached per proxy path, mtime and size, so an upgrade re-probes. The SessionEnd hook itself never probes.
WritesIts own report files, the caveman.db plan tables every scan updates, and its own runtime/learn-autopilot* state. Never cavemem memories or learnings rows: --no-remember skips them, because sink titles carry changing counts and each unattended run would add a near-duplicate.
Enable precedenceCAVEMAN_LEARN_AUTOPILOT env (0, false, off, no disable; anything else enables) → learnAutopilot in ~/.caveman-cloud/config.json → off when CI is set (not 0/false) or under NODE_TEST_CONTEXT → on.
Opt outcaveman learn autopilot off, or CAVEMAN_LEARN_AUTOPILOT=0.
State$CAVEMAN_HOME/runtime/learn-autopilot*.json. Writes are temp-file + rename and refuse symlinked parents.
Statuscaveman learn autopilot status: on/off and why, last scan, next scan, last error, last line shown, and a line waiting to show.

Session-start nudge

After a background scan, autopilot may show one line at the next session start, for example:

caveman learn: new finding — <title> (~2.4k tokens in every message, estimate). Run `caveman learn` to review.

Rules:

  • Sinks of class reducible or recurring_context with tokens_per_turn ≥ 2000 qualify. This includes memory_health:duplicate_rules and memory_health:memory_orphans when they are reducible and above the threshold.
  • memory_health:broken_imports and memory_health:memory_truncation qualify with no token threshold: they break what the agent loads. When they are all that is new they lead the line (caveman learn: memory files (<repo>) — <title>. Run \caveman learn --all` to review.`); otherwise they are appended as ", plus N memory-file findings".
  • Only sinks not seen by an earlier autopilot scan. The first scan records a baseline and announces nothing.
  • While a nudge is still unclaimed, newer sinks stay unseen and are announced after it.
  • Shown only on Claude Code, Codex and Gemini CLI SessionStart with source startup or clear; never on resume, compact or fork. It is delivered as a user-visible systemMessage, not model context.
  • Claimed with one atomic rename, so concurrent sessions announce it once. The claim parks it in runtime/learn-autopilot-nudge.inflight.json with the claimer's token; it counts as announced only when that claimer confirms, after the line was written to the host (the fast hook owns the token and confirms after relaying the delegated output). At most one nudge is in flight: a newer nudge waits behind an unconfirmed one. An unconfirmed nudge, for example after the delegate hit its 3 s timeout, is shown once more after 10 minutes, never twice.
  • Suppressed when autopilot is disabled.

Setup Score

The Setup Score (cave_score in JSON) grades how lean your local setup is. It starts at 100 and subtracts four capped penalties. The caps sum to 100.

ComponentPenaltyCapMeasured when
config_tax50 × (config tokens/turn + recurring re-paste tokens/turn) ÷ median turn context35config tax > 0 and transcripts with usage exist
dumbzone50 × share of turns over 50% of the model window25any usage-bearing turn
dead_load40 × skill-description tokens with no detected use ÷ config tokens20sessions scanned and config tax > 0
subagent_pressure20 × min(1, subagent spawns per session ÷ 5)20any session scanned

Config tokens per turn = user CLAUDE.md + every CLAUDE.md from cwd to / + Claude skill descriptions. AGENTS.md has its own finding and is not in this sum. A component that cannot be measured has penalty 0, measured: false, and a detail string saying why.

What it is not:

  • Not money. It carries no currency and is not derived from spend.
  • Not billed usage. It is transcript and file arithmetic.
  • Not the Caveman Cloud Cave Score, which scores organization traffic on a different scale. The two will not match.

The terminal and TUI show the score only once at least one block has recurred across three or more sessions (a recurring_context sink exists). Before that, learn prints the session count and top findings without a score. --json always includes it.

Sink reference

Sinks are ranked: forward-rate sinks first by tokens per day, then historical sinks by observed tokens.

Classes (the report's label in brackets):

  • reducible ("safe fix"): a mechanical fix exists and must pass the net-token-negative gate.
  • recurring_context ("repeated text"): content re-established across sessions; fix is a cavemem offload.
  • behavioral ("habit"): a measured habit. Numbers are stated; suggestions are soft.
  • load_bearing ("needed"): measured config you need. Listed so the score stays honest; never edited.
Sink idClassMeasuresFix kindAuto-fixable
config_tax:baselineload_bearingConfig tokens loaded every turn (see score); measured turn-1 prefix when available. Plugin tokens are not measured.noneNo
claude_md_weight:{user,project,codex}reducibleA CLAUDE.md (or ~/.codex/AGENTS.md for codex) over 150 lines or 2000 tokensclaude_md_weightYes, via skill
claude_md_sections:{user,project}reducibleCLAUDE.md sections with no distinctive-line echo in ≥5 sessions. Emitted only if at least one other section did echo.claude_md_sectionsYes, via skill
dead_load:skillsreducibleSkills whose descriptions load every turn with no use detected in the windowdead_loadYes, via skill
recurring_context:repaste:<fingerprint>recurring_contextA block of ≥180 tokens re-established in ≥3 sessions. Top 24 listed; the rest still count in the score.cavemem_offloadYes, via skill
context_dumbzonebehavioralTurns over 50% of the model window, if ≥10% of turnsdumbzone_adviceNo
subagent_overusebehavioralSubagent spawn countsnoneNo
subagent_spendbehavioralShare of provider-counted context in subagent sidechains (≥100k tokens, ≥3 sessions). Visibility only.noneNo
config_surfacebehavioralHooks + plugins ≥ 10noneNo
mcp_surfacebehavioral≥3 configured MCP servers whose schemas load each turnnoneNo
cross_provider:depthbehavioralMedian session peak depth compared across agents (needs ≥2 sources; skips assumed windows)noneNo
cross_provider:repastebehavioralOne recurring block seen in two or more agentsnoneNo
learning_loop:error_loop:<session>:<hash>behavioralSame tool call ≥3 times in one session, at least half failingnoneNo
learning_loop:refetch_loop:<session>:<hash>behavioralSame call ≥3 times with only pagination/limit variants, no errorsnoneNo
cache_churnbehavioral≥2 sessions with ≥3 turns that each re-wrote >10k tokens and >25% of context to cachenoneNo
cache_efficiencyload_bearing, or behavioral when multiplier ≥ 0.6Effective input cost per million tokens after cache reuse (needs ≥200k input tokens). A rate, not a volume.noneNo
reread_wastebehavioralRepeated full reads of the same file (≥5k tokens)noneNo
compaction_churnbehavioralFiles re-fetched after compaction (≥2k tokens). May overlap reread_waste; never sum them.noneNo
tool_output_portfoliobehavioralTool-output tokens grouped by call shape (local estimate)noneNo
session_outcomesbehavioralShare of tokens in sessions with no commit between session start and 45 min after its end (≥8 sessions, ≥50k tokens). Correlational.noneNo
procedure_repeat:<key>behavioralA 3–6 step tool-signature sequence repeated in ≥3 sessions (≥15k tokens)skill_distillationNo; holdout only
config_growthbehavioralGrowth (≥400 tokens and ≥20%) in always-loaded config versus this machine's snapshot historynoneNo
memory_health:duplicate_rules:{claude,codex,gemini}reducibleRules (≥6 words) loaded from more than one file per agent sessiondedupe_rulesYes, via skill
memory_health:memory_orphans:<memory-dir hash>reducible when index links to missing files load tokens, else behavioralMemory files MEMORY.md never links; index links to missing filesmemory_index_repairVia skill, per item
memory_health:memory_truncation:<memory-dir hash>behavioralMEMORY.md lines past the session-start cutoffmemory_index_condenseVia skill, per item
memory_health:broken_imports:<file-hash>behavioral@import paths that resolve to missing filesnoneVia skill, per item
memory_health:stale_references:<file-hash>behavioralBackticked repo paths in project instruction files that no longer existnoneVia skill, per item
memory_health:buried_rules:<file-hash>behavioral≥3 NEVER/ALWAYS/MUST/IMPORTANT/CRITICAL lines in the middle 30–70% of a file over 150 lines. Heuristic.noneVia skill, per item

The memory_truncation cutoff follows the Claude Code memory docs (https://code.claude.com/docs/en/memory, checked 2026-09-27): "The first 200 lines of MEMORY.md, or the first 25KB, whichever comes first, are loaded at the start of every conversation."

<file-hash> is the first 8 hex characters of a hash of the file path.

Some sinks carry spend_usd_per_day or spend_usd_observed. That is what the context cost at your measured effective input rate over the window. It is not what removing it would return.

Trends

The trends block compares your own sessions week over week.

AspectRule
BucketsUTC ISO weeks (2026-W39), up to 8, inside the window. Sessions are bucketed by start time; undated sessions are counted in undated_sessions and left out.
Compared weekThe last complete week (current_week). The week in progress is shown (in_progress: true) but never drives the comparison. No trends block when the window holds no complete week.
PriorSessions of up to 4 weeks before the compared week, pooled.
MinimumA bucket with fewer than 5 sessions has a null value and insufficient_data.
Directionimproved, worse, flat or insufficient_data. Flat when the relative change is under 10%, or, for percent and per-100 metrics, the absolute change is ≤1 point.
Partial weekspartial: true marks a week cut by the window start or still in progress.

Metrics:

KeyStatisticBetter
tokens_per_sessionmedianlower
peak_context_pctmedianlower
dumbzone_turn_pctpooled share of turnslower
first_turn_tokensmedianlower
cache_read_pctpooled share of contexthigher
tool_errors_per_100_turnspooled ratelower
score_session_penaltyrecomputed dumbzone + subagent penaltylower

Only the session-derived score components are recomputed per week; config_tax and dead_load depend on today's config and are not replayed. Full score history comes from the dated report snapshots (score.history). movers lists up to three sinks that grew and three that shrank by ≥10 tokens/turn versus the newest snapshot at least 7 days old (else the newest one).

A trend is not a saving and does not show what caused the change.

Fixing

The consent loop

caveman learn implement (or the TUI's "Implement with agent") opens Claude Code or Codex with the caveman-learn skill, installing it if missing. The skill:

  1. Reads caveman learn report --json and shows the score, components and ranked sinks.
  2. For each sink you choose, proposes one concrete diff with before and after tokens per turn, and asks yes or no.
  3. Applies only approved edits, with the agent's own file tools.
  4. Re-measures. Net-token-negative gate: if tokens per turn did not drop, the edit is reverted.
  5. For a cavemem offload, also checks that caveman mem recall returns the content and a pointer is in place; otherwise it reverts (caveman mem forget <id> and restores the source).
  6. After an edit passes its gate, runs caveman learn applied <sink_id>.

load_bearing sinks are never edited. procedure_repeat candidates skip the gate and go to an experiment instead, because a skill adds prefix tokens every session and pays back only on some.

You can install the skill directly: caveman tools skills install caveman-learn (add --user for all repos, --agent codex for Codex).

Applied ledger and verdicts

Each later scan compares sessions after applied_at with the recorded before-value and reports a row in confirmed:

FixAfter-valueVerdict rule (needs ≥3 sessions after)Method
claude_md_weight, claude_md_sections, dead_load, config_taxCurrent token count of the same file, sections or skillslower = improved, higher = regressed, equal = unchangeddeterministic_remeasure
cavemem_offloadWhether the block's fingerprint recurs after the fixabsent = improved, present = unchangedinterrupted_time_series
dumbzone_adviceShare of turns over 50% of the window≥5 points lower = improved, ≥5 higher = regressedinterrupted_time_series
Anything elsenonealways insufficient_dataunattributed

Provenance compares the file's SHA-256 with the fingerprint taken at applied time: intact, changed_since (someone edited past the fix), target_missing, or not_fingerprinted. changed_since and target_missing force confidence to low.

Savings

caveman learn savings lists every recorded fix, including regressions, grouped by measurement method (rung), strongest first:

RungMethodConfidence
4deterministic_remeasure: the edited file was re-countedhigh
3controlled_holdout: change on vs off on this machinehigh
2counterfactual_replay: scanned history re-run with the changemedium
1interrupted_time_series: before vs after sessions, no controllow

Rungs are never summed together, and there is no blended headline. Each row carries standing confounders for its method. Only positive savings are priced, as a per-day rate over the scanned window at your measured effective input rate, when the plan has a spend block. total_saved_usd_by_rung sums within one rung only. Nothing is projected to a month or labeled verified.

Experiments

A holdout compares arms over your own sessions:

  1. experiment start <label> [--sink <id>] [--fix-kind <kind>] [--note <t>] opens the on arm.
  2. experiment arm <label> off (later on again) switches arms. Switching to the running arm is a no-op.
  3. experiment report <label> assigns each session to the arm active at its start and compares median tokens per session.
  4. experiment stop <label> closes it.
VerdictCondition
insufficient_dataEither arm has fewer than 5 sessions (method drops to unattributed)
improvedon-arm median ≥10% below off-arm
regressedon-arm median ≥10% above off-arm
unchangedotherwise

When the on-arm has more than 1.25× the off-arm's tool errors per turn, the report says so. Arms run at different times on different work, so the result is still inferred.

Reverting

Every edit is made by the skill and reported exactly, so it can be undone with your own tools or version control. An offload reverts with caveman mem forget <id> plus restoring the trimmed text. A regressed verdict is shown with no dollar figure; the skill offers the revert path.

Output files and JSON

caveman learn --json and caveman learn report --json print one document with schema: "caveman.learn.v1" and basis: "inferred". The same plan, plus moves, generated_at and generation, is saved as reports/caveman-learn.json. The Go types are in proxy/internal/store/learn_types.go.

BlockPresentContent
windowalwaysfrom, to, since
cave_scorealwaysscore, scope: local_setup, four components
sessions_scanned, sessions_by_sourcealwayscounts
sinksalwaysranked sinks: sink_id, class, basis, framing (forward_rate or historical), token fields, evidence, suggestion
caveatsalwaysplain-language limits for this run
spendusage for a cataloged model existswindow cost at dated catalog rates, per-component and per-model rows, unpriced models, effective input rate and multiplier
confirmeda fix was recordedledger rows with verdict and attribution
trendsa complete week with dated sessions existssee Trends
context_depthusage-bearing sessions existpeak-depth histogram in 10% buckets
wrap_measuredthe proxy recorded savings in the windowtokens only, proxy-counted
retro--retro and something to reportreplay totals by family
portfoliosinks share a fix familygrouping of existing sinks, no new estimate
repos≥2 repositories with ≥2 sessions eachper-repository summary

Other subcommands print their own schemas: caveman.learn.savings.v1, caveman.learn.simulate.v1, caveman.learn.experiment.v1, caveman.learn.digest.v1, caveman.learn.reconcile.v1.

spend is what the scanned window cost at published rates. It is a floor when unpriced is non-empty, it is not an invoice, and on a subscription plan the marginal cost is zero. The compact plain view folds several unpriced models into one line; --all, --md, JSON and the HTML report list each model.

Limits and known gaps

  • Headless sessions can consume the nudge. A scripted claude -p or codex exec fires SessionStart with source startup, so it can claim and confirm the nudge where no one sees it.
  • Unsupported agents. Only the five sources above are scanned. Cursor, Windsurf, Hermes, Pi and other agents are not read.
  • aider is off unless CAVEMAN_AIDER_ROOT points at a directory to walk. aider history has no provider usage, so it adds nothing to depth, dumbzone, spend or trends.
  • Context windows. A window comes from the shared model catalog. For un-cataloged models learn assumes 1M if the model id contains 1m, 400k for OpenAI, 1,048,576 for Gemini, and 200k otherwise. If a session's context grows past the assumed window, that whole session is re-measured against 1M (then 2M). A 1M-window session that never exceeds 200k is still measured against 200k. Assumed windows add a caveat and are excluded from the excess token floor and from cross_provider:depth.
  • Turn-1 prefix includes the first user prompt, so the measured prefix is an upper bound.
  • Plugins are counted but their tokens are not measured.
  • claude_md_sections sees only visible transcript text. Claude Code injects CLAUDE.md into the system prompt, so the finding is emitted only when at least one section echoes (a positive control).
  • --repo drops Gemini sessions (their transcripts have no working directory) and omits retro.
  • Auto memory location ignores a custom autoMemoryDirectory setting.
  • Time budget. With --retro, a scan that hits its budget covers partial history; repository, section-echo, trend and applied-fix blocks are omitted rather than zero-filled.
  • Ledger coverage. memory_health fixes can be recorded with applied but have no after-value measurement yet, so they stay insufficient_data. simulate does not accept memory_health sinks.
  • Savings rungs. Confirmed ledger rows are currently produced only at the deterministic_remeasure and interrupted_time_series rungs. controlled_holdout results appear in experiment report, not in savings, and no command yet produces counterfactual_replay rows.