Capability matrix
Downshift by Tiago Vilas Boas. Updated . Source on GitHub
Downshift by Tiago Vilas Boas · https://github.com/tiagovilasboas/downshift
Audit date: 2026-10-17. Source of truth for writers: every row below was read from code, tests or a dated evidence file in this repository, not from existing marketing text. When a public doc says more than a row supports, the doc is listed in Contradictions and overclaims found.
Status vocabulary (one of five): Implemented means code, tests and at least one dated observation on a real harness. Implemented, not validated everywhere means the code is shared but the effect was observed on some harnesses or plans only. Experimental means shipped behind a flag or a maintainer command, with no production claim. Planned means documented intent with no code path. Not supported means the harness or design cannot do it.
Harness status words (Completed, Functional, Beta, Experimental) are a different scale and are defined in harness-matrix.md; they appear only in section 4.
Shorthand: core is internal/core, cmd is cmd/downshift, "matrix" is docs/reference/harness-matrix.md, "A/B" is docs/evidence/subagent-routing-ab-2026-10-15.md, "audit" is docs/evidence/hardening-audit-2026-10-15.md.
1. Model selection and routing
| Capability | Status | Where (package/command) | Evidence (file, date or test name) | Limits | Docs that describe it |
|---|---|---|---|---|---|
| Deterministic task classification (TRIVIAL/SIMPLE/MEDIUM/COMPLEX) from regex signals, English and Portuguese | Implemented | core/classifier.go, core/signals.go |
classifier_edge_test.go, classifier_ptbr_test.go; benchmark/report.md (2026-10-17): seed 73.5% tier accuracy (67.0–79.1%; superseded 69.0% at be1054ac per baseline-freeze-2026-10-17.md), fresh 50.0% then 53.0%, heldout2 40.0% then 41.7% |
Scores only the first 32 KB; most misses on blind splits are abstentions (model kept); no other language | docs/reference/complexity-weights.md, docs/contrib/classifier.md |
| Semantic boost (nearest-centroid, raise-only, never COMPLEX alone, never on a no-signal prompt) | Implemented | core/semantic_fuse.go, internal/semantic |
semantic_test.go (TestAugmentWith_NeverDowngrades, TestMaybeAugment_EnabledWithHashOnSeedComplex); reason code SEMANTIC_BOOST |
In-process FNV word hash only (hashembed.go); DOWNSHIFT_MINILM=0 opts out; a lift clears confidence |
docs/design/minilm-semantic.md |
Tier to model selection from the session list (catalog-tier path, position fallback, explicit_only skipped) |
Implemented | core/session_select.go, core/policy.go, core/capabilities.go (PlanForSession) |
upshift_tier_test.go (TestUpshiftTier_UpshiftNeverWritesLowerCatalogTier), audit 2026-10-15 |
Unknown session never rewrites; upshift lands on the least model at the needed tier when confident, on the strongest tier on a guessed baseline or explicit_upshift (open question in the audit) |
docs/reference/session-models.md |
| Reasoning effort per tier | Implemented, not validated everywhere | core/policy.go (EffortFor), Codex adapter effort_map |
TestHandle_HeldUpshiftLeavesSpawnUnchanged, TestHandle_UnconfidentKeepsRequestedEffort (audit) |
Only Codex has CanApplyEffort; Claude Code, Cursor, Antigravity have no effort field; Grok is config only; effort changes only alongside a model rewrite or a confident decision |
docs/guides/install.md (Codex) |
| Session inferred from the current model (catalog ladder below it) | Implemented | core/session_inferred.go (InferSession capability) |
TestInferSessionFromCurrent_LadderEndsAtCurrent, TestPlanSession_InferenceIsACapability; examples/claude-code-pretooluse-task.json |
Claude Code only; downshift only, never above the current model; DOWNSHIFT_INFER_SESSION=off |
docs/reference/session-models.md step 5 |
Session discovery (downshift models discover, discovered.json, 24 h TTL) |
Implemented, not validated everywhere | internal/discovery, cmd/discover.go, core/session_discovered.go |
discovery_test.go; Codex models_cache.json and Kiro CLI listing read; Cursor returned "Authentication required" 2026-10-09 |
Claude Code needs ANTHROPIC_API_KEY; Antigravity has no routing-namespace source; a listed model is not proof of credit |
docs/reference/session-discovery.md |
Baseline (current model) resolution: payload model, CLAUDE_CODE_SUBAGENT_MODEL, parent transcript tail (400 ms bounded wait), configured settings (BASELINE_FROM_SETTINGS) |
Implemented, not validated everywhere | internal/adapters/claudecode/sessionmodel.go, configuredmodel.go; Codex sessionmodel.go (turn_context); Cursor model_id |
TestHookE2E_ClaudeCodeBaselineFromSettings, TestHookE2E_ClaudeCodeTranscriptModelSkipsSettingsFallback; matrix 2026-10-12/15 |
--model and /model invisible to a hook; Explore under Fable stays unknown; Antigravity inherit unknown; parallel Agent calls in a first message |
matrix "Decision linkage", docs/guides/claude-code.md |
Model catalog: tiers, list prices, cache prices, aliases, family prefix, native_name, explicit_only, OpenRouter prefix strip |
Implemented | internal/catalog/catalog.json (version 2, updated 2026-10-16), catalog.go |
catalog_test.go (TestLookupByID_OpenRouter* and the other prefix-normalisation tests); Claude Code small = claude-haiku-4-5 1/5, Sonnet 2/10, Opus 4/20, Fable 10/50 per 1M |
Prices are a dated snapshot (Anthropic 2026-10-08, OpenRouter 2026-10-12); gpt-6.1-sol has no price; user override under the state dir |
docs/contrib/agent-reference.md, llms.txt |
Quota and credit gate (hook marks, native snapshots, DOWNSHIFT_QUOTA_MODE=required, stale grace 1 h) |
Implemented, not validated everywhere | internal/quota, core/session_quota*.go, cmd/quota.go |
quota_test.go; Codex transcript replay 2026-10-09 (docs/evidence/native-quota-routing-2026-10-09.md) |
Live Codex consumer not proven to send transcript_path (GAP-CODEX-HOOK); Claude statusline rate_limits not observed live (GAP-CLAUDE-QUOTA); Cursor export blocked on 3.24.9; Antigravity and KiroCrew have no source |
docs/guides/quota.md |
explicit_only models never chosen automatically; explicit_upshift opt-in |
Implemented | catalog.json (gpt-6-astra, claude-fable-5-1-thinking-high), core/session_select.go |
TestCanWriteSessionID* in core, install_test.go |
claude-fable-5-1 on Claude Code is opt-in by listing, not explicit_only |
docs/reference/session-models.md |
2. Conservative choice under uncertainty
| Capability | Status | Where | Evidence | Limits | Docs |
|---|---|---|---|---|---|
| Guardrails R1 (unconfident downshift), R6/R9/R7 (unconfident small/mid/frontier with no baseline), R8 (unconfident upshift): held, spawn unchanged | Implemented | core/selfcheck.go (Check) |
cost_safety_invariants_test.go (TestCostTruthTable, TestCostPropertySweep, TestCostNoInferenceNeverRewrites), selfcheck_abstain_test.go |
A confident decision with no baseline may write any tier (designed); an upshift on a settings-guessed baseline is still written (audit) | docs/reference/session-models.md "Payload without a model field" |
Guessed baseline downshifts only to the small tier (HELD_GUESSED_BASELINE) |
Implemented | Claude Code and Cursor adapters | TestHandle_SettingsBaselineHoldsMidTierDownshift, TestHandle_ParentModelIDHoldsMidTierDownshift (audit) |
Applies to downshifts only | matrix, docs/reference/stats-export.md |
Language guard (UNSUPPORTED_LANGUAGE): foreign function words or non-Latin script clear confidence |
Implemented | core/lang_guard.go |
lang_guard_test.go, TestHookE2E_MultilangGuardAcrossHarnesses; docs/evidence/multilang-codex-2026-10-16.md (wire response only) |
Heuristic (ES/FR/DE word list, script check); no recognition guarantee | docs/reference/complexity-weights.md#language-coverage |
| Risk abstention: confident MEDIUM/SIMPLE with a risk category loses confidence without a tier change | Implemented | core/risk.go (applyRiskAbstention) |
TestCheck_RiskAbstainDoesNotCoverSemanticLift; CHANGELOG M3 "unsafe confident recommendations are 0" on a 170-row private set |
Counts as a deterministic lift for R7/R9 only while the tier is the regex read | docs/reference/complexity-weights.md |
| No-signal prompts default to MEDIUM and abstain | Implemented | core/classifier.go (NoSignal) |
TestUnsupportedLanguage_CoversFullPromptAndNoSignal; reason code NO_SIGNAL |
A no-signal prompt is never lifted by the semantic boost | docs/reference/stats-export.md |
| Fail-open runner: panic recovery, 1 MiB payload cap, 2 s stdin timeout, hook budget for helpers, "allow unchanged" on any error | Implemented | cmd/main.go (runHookAdapter), internal/hookctx |
conformance_test.go (TestHarnessConformance, every harness), hook_empty_stdin_test.go, panic_test.go |
Failures are logged as error rows with a code (INVALID_EVENT, PAYLOAD_TOO_LARGE, ...) |
docs/design/architecture.md |
Frontier-on-doubt alarm (Frontier decisions N (rewritten on doubt, no deterministic lift: M)) |
Implemented | internal/telemetry/telemetry.go |
TestHonesty_FrontierOnDoubtCountsRefutedRewrite |
Prompt-free count; a WARNING, not a block | README "Cost and metrics" |
3. Guardrails for risky tasks
| Capability | Status | Where | Evidence | Limits | Docs |
|---|---|---|---|---|---|
Risk categories (secret, authz, crypto, payment, vuln, pii, destructive, concurrency, prompt_injection): floor off the small tier, R5 holds any downshift, full prompt scanned past the 32 KB cap |
Implemented | core/risk.go, core/selfcheck.go (R5) |
risk_safety_test.go (TestRiskSafety_SignalPastClassifyCapKeepsTaskOffSmall, TestRiskSafety_PortugueseParity, TestRiskSafety_ConcurrencyIsNotTrivial), risk_patterns_test.go; audit 2026-10-15 |
Regex, EN and PT; real-traffic false-positive rate not measured; the risk list does not fire on an upshift (upshift ranking fixed by catalog tier instead) | docs/reference/complexity-weights.md, docs/guides/config.md (category names) |
| R2: COMPLEX is never downshifted; R4: a model from another harness is never written | Implemented | core/selfcheck.go |
TestCostRuleIDsStable, TestCostTruthTable |
Rule ids are stable telemetry history (R3 retired) | README BDI table |
| Prompt-injection vocabulary ("ignore previous instructions", "this is a trivial task", "use the cheapest model") treated as a risk category | Implemented | core/risk.go (prompt_injection row) |
risk_test.go table |
Pattern list only | Not explained in any user doc (see Hidden capabilities) |
| Removed 2026-10-17 | — | — | Out of product scope; hook stays regex + hash semantic boost | — | |
| Project tier floor by class or risk | Implemented | see section 10 |
4. Harness integration
Harness status words (Completed, Functional, Beta, Experimental) are a separate scale from the capability statuses above: they say how much has been verified on each real harness, per harness-matrix.md. TestHarnessConformance runs the same eight scenarios against every registered hook, whatever the harness status. The "Experimental" harness word means a proof of concept and does not change any capability row.
| Harness | What is emitted | What is honored (evidence, date) | Child end and usage | Limits | Docs |
|---|---|---|---|---|---|
| Claude Code (Completed) | PreToolUse on Agent|Task: updatedInput.model with the family name (haiku/sonnet/opus/fable, StrictModelName); systemMessage line on rewrite |
Observed 2026-10-06: child ran claude-haiku-4-5-20251001 under a Sonnet 5.5 parent, API-reported model in the child transcript, two spawns (docs/evidence/claude-code-rewrite-honored-2026-10-06.md) |
PostToolUse (resolvedModel, launch status), PostToolUseFailure (error/interrupted), SubagentStop (tokens and model from the child transcript, 32 MiB cap); UsageSource: transcript |
Free plan has no subagents; Workflow-created agents never reach PreToolUse (2026-10-11 evidence); PostToolUseFailure payload unverified (GAP-CHILD-FAILURE); "API (direct)" plan row has no evidence file; child-end systemMessage not observed live |
matrix, docs/guides/claude-code.md, docs/guides/install.md |
| Codex (Functional) | PreToolUse on (^Agent$|.*spawn_agent$): updatedInput.model and reasoning_effort |
Inferred, not observed, 2026-10-02: the next spawn in the same hashed session asked for the written model (docs/evidence/codex-rewrite-honored-2026-10-02.md) |
PostToolUse end parser exists, unverified (assumed field names); UsageSource: none; rollout token_count parser stays off |
Payload over 1 MiB fails open; schema evolving; hook must be trusted in /hooks; gpt-6.1-sol routes but is unpriced; 2026-10-09 recheck found no hook stdin sample |
matrix, docs/guides/install.md |
| Cursor (Functional) | preToolUse on Task: updated_input.model; inherit and missing model use parent model_id as baseline |
Unconfirmed: one spawn 2026-10-10 on Cursor 3.24.9 emitted muse-spark-1.3-max, child executor model not present in the transcript (docs/evidence/cursor-rewrite-honored-2026-10-10.md); discarded on Free and legacy Pro |
subagentStop end parser exists, unverified; no usage field read; linked only when the payload names the tool call |
No session id in the payload (not groupable, not pausable); 144 captured payloads had empty top-level model; native quota export blocked (built-in-only API) |
matrix, docs/evidence/cursor-gap-diagnostic.md |
| Antigravity (Experimental) | PreToolUse on invoke_subagent: overwrite of Subagents[].Model with the alias flash_lite/flash/pro for the last subagent that has a Prompt |
Observed 2026-10-09, desktop 2.21.1, one child: requested pro, executed gemini-3.5-flash-lite per native executor and generation metadata (docs/evidence/antigravity-executor-ack.md) |
None (ChildEndEvent empty); nothing recorded |
overwrite is not in the vendor's documented hook output (docs/evidence/vendor-hook-docs-2026-10-11.md): build-specific sensor, not a contract; inherit has no baseline; quota and alias mapping unresolved (GAP-AG-MAPPING); no session id |
matrix, docs/evidence/antigravity-runtime-source.md |
| KiroCrew (Experimental) | Native preToolUse policy via wrapper script: exit 0 allow, exit 2 block with a message naming the model to respawn with |
Block and retry observed 2026-10-10, Kiro CLI 2.29.0: native state.json recorded resolved_model=claude-haiku-4.5 after the retry (docs/evidence/kirocrew-native-hook-2026-10-10.md). Not an in-place rewrite |
None; nothing recorded | Only spawn_run with an explicit task and model is covered; native use_subagent without a model passes through; ~/.kiro/crew/hooks.json entries are informational; no session id; setup only reports it |
matrix, docs/guides/install.md, docs/guides/kirocrew-routing-guide.md |
| Grok CLI (Config only) | Nothing: no hook adapter; downshift try "<task>" grok prints the effort to pin in config.toml |
Not supported (allow/deny hook, one model) | None | Config only; not in AllHarnessCaps |
docs/guides/install.md |
Shared runner and layering (one runHookAdapter, rewrite and policy wires, capabilities as data) |
Implemented | cmd/main.go, cmd/harnesses.go, core/capabilities.go |
TestHarnessConformance (eight scenarios, every harness), TestPluginHooksMatchSetupTarget, TestSetupTargetsWireEveryChildEndEvent |
Project dir comes from cwd (vendor-documented for Claude Code only) |
docs/contrib/layering.md, docs/guides/config.md |
5. Observability
| Capability | Status | Where | Evidence | Limits | Docs |
|---|---|---|---|---|---|
stderr line per spawn (downshift: correlation_id=<id> TRIVIAL task → downshift to <model> (~N% cheaper)), plus honor=unobserved quota=<status> usage=unobserved and a feedback id line |
Implemented | cmd/main.go (spawnFate.stderrLine), core/policy.go (Summary) |
spawn_surface_stderr_test.go |
Shown only where the harness surfaces hook stderr; the second line is not explained outside docs/guides/daily-truth.md |
README, docs/guides/daily-truth.md |
Statusline (Claude Code): 5 h / 7 d quota windows, session routing summary, · quota stale |
Implemented, not validated everywhere | cmd/quota.go (quota claude-statusline), internal/telemetry/surface.go |
statusline_test.go (4 tests) |
Claude Code only; written by setup only when no statusline exists; live rate_limits not yet observed (GAP-CLAUDE-QUOTA) |
README, docs/guides/quota.md |
Session tree, --why, --pause/--resume (12 h TTL), --json; /downshift:status plugin command |
Implemented | cmd/session.go, internal/telemetry/session_tree.go, why.go, pause.go, commands/status.md |
session_test.go (TestSessionPause_IsAControlGroupThroughTheSharedRunner) |
Session id only on Claude Code and Codex; Cursor, Antigravity, KiroCrew not groupable or pausable; "running" turns to "?" after 2 h | docs/guides/session-view.md |
downshift watch (live tree, 200 ms minimum interval, --once) |
Implemented | cmd/watch.go |
watch_test.go |
Reads a bounded tail of the log | docs/guides/session-view.md |
downshift doctor (--json, a fix per check: version, binary, state dirs, catalog, scores, context, E5 shadow, model-override env, per harness hooks wired, hook binary, session list, quota snapshot, last hook event, completion, rewrite honored, main session, plugin, companion) |
Implemented | cmd/doctor.go, doctor_hooks.go |
doctor_test.go, doctor_env_test.go, doctor_quota_test.go |
The "rewrite honored" row counts inferred honor (later same-session spawn) as "seen" | docs/guides/install.md, skills |
downshift config (every effective setting with its source) |
Implemented | cmd/config.go |
config_test.go |
Read-only | docs/guides/config.md |
downshift try (--detail, assumed harness default when no model is given) |
Implemented | cmd/try.go |
main_test.go, help_test.go |
No project directory, so a project floor is not applied | README |
Child-end line inside the harness (↳ downshift: finished on haiku · N tokens (work N, cache N) · saved from opus) |
Implemented, not validated everywhere | internal/telemetry/liveline.go (ChildEndLine), CanShowChildLine |
computed for every harness; DOWNSHIFT_QUIET=1 |
True for Claude Code only, "pending a live check" (matrix U2); false elsewhere | docs/reference/session-models.md |
dsmon, dsmon-hook |
Experimental | cmd/dsmon* |
none | Listed under "Experimental" in help --all; downshift watch is the supported live view |
docs/guides/install.md (dsmon) |
downshift probe <event> (field names and hashes of real payloads) |
Implemented (maintainer) | cmd/probe.go |
probe_test.go |
Never records prompts or paths | docs/guides/probe.md |
6. Execution telemetry
| Capability | Status | Where | Evidence | Limits | Docs |
|---|---|---|---|---|---|
Prompt-free event log (events.jsonl): hashed session, agent and tool-use ids, reason codes, corrections, multi-process lock, rotation |
Implemented | internal/telemetry/telemetry.go, locking*.go, rotation.go |
TestPostHooks_PostHooksTelemetryPrivacy, locking_test.go, rotation_test.go |
DOWNSHIFT_LOG_MAX_MB / DOWNSHIFT_LOG_MAX_BACKUPS are undocumented |
docs/reference/stats-export.md |
OpenRouter allowlist shadow telemetry (openrouter.json): records gateway_would slug and tier; stats --detail shows the would-route count |
Implemented, shadow only (#352) | internal/core/gateway_shadow.go, internal/telemetry/telemetry.go, internal/telemetry/stats_print.go |
gateway_shadow_test.go, gateway_would_test.go |
Never changes the live route or model; only a listed row supplies the tier; gateway fields contain no prompt, task, path, tokens or USD | docs/guides/config.md#openrouter-allowlist-optional |
| Permission-mode attribution on routing decisions | Implemented | Claude Code permission_mode payload; telemetry.PermissionModeLabel, session --why, report |
TestHookE2E_ClaudeCodeRecordsPermissionMode, TestPermissionModeLabel, TestCountPermissionModesAndReport |
Claude Code only when the payload supplies it; stores built-in labels or other, omits absent values; display/count only, no routing effect |
docs/guides/claude-code.md, docs/guides/report.md |
| Usage per subagent (input, output, cache read and write tokens) | Implemented, not validated everywhere | internal/childend, internal/adapters/claudecode/subagentstop.go, telemetry/cost.go |
TestSubagentStop_PricesFromTranscriptAndLinksToTheDecision; docs/evidence/billing-gap-audit.md 2026-10-09: 5 of 5 linked records matched native tokens and model |
Claude Code transcript only; 5 of 50 linked records (P3.4 open); Codex, Cursor UsageSource: none; Antigravity, KiroCrew nothing |
docs/reference/session-models.md#claude-code-real-usage |
resolved record with rewrite_honored (harness-reported child model); a refuted rewrite saves nothing |
Implemented, not validated everywhere | childend/record.go, telemetry/honor.go |
TestAggregate_RefutedRewriteSavesNothing, TestCountInferredHonored_RefutedBeatsLaterSpawn (audit) |
Claude Code tool_response.resolvedModel only; rewrite_honored_inferred is correlation |
matrix, docs/evidence/closeout-recheck-2026-10-09.md |
Child end status (completed, launched, interrupted, error, stopped, unknown), completion "measurable" per harness |
Implemented, not validated everywhere | telemetry/child_outcome.go, completion.go, cmd/end.go |
TestChildEnd_StatusesFromDocumentedFields, TestBuildTasks_UsageMarksBackgroundChildCompleted |
Claude Code documented fields; Codex and Cursor parsers unverified; a launch is not an end; error text never stored | matrix "Child end (N5)" |
| Respawn after failure (same session, 10 min window) as a rework hint | Implemented | telemetry/respawn.go, tasks.go |
respawn_test.go |
Needs a session id; never becomes a tier label | README "Cost and metrics", docs/guides/report.md |
Verification sensor: did the child run a recognised test or lint command and did it pass (verification on usage records; downshift verification-report) |
Implemented | internal/adapters/claudecode/verification.go, cmd/verification.go |
TestSubagentStop_RecordsVerificationOutcome, verification_test.go |
Claude Code transcript only; short command allowlist; absent on old events ("unrecorded", not "none"); not in help --all |
CHANGELOG only (see Hidden capabilities) |
Built-in control group: about 1 in 10 spawns left unrouted by hashing the routing id (CONTROL); DOWNSHIFT_NO_ROUTE and session pause excluded as non-random |
Implemented | cmd/main.go, telemetry/control.go |
control_group_test.go, TestInControlGroup_ShareAccuracy |
Costs about the share of the saving by design; DOWNSHIFT_CONTROL_SHARE |
docs/guides/report.md, docs/guides/pilot.md |
Agent-type label on decisions (built-in names, unspecified, custom) and "Baseline by agent type" |
Implemented | telemetry/agent_type.go |
agent_type_e2e_test.go |
Claude Code reports a type; stats --detail and export only |
docs/reference/stats-export.md |
| Decision-intelligence shadow recommendation on every decision event | Experimental | internal/decisionintelligence, cmd/main.go |
decisionintelligence_test.go |
Apply: false always; structured signals only |
docs/design/decision-intelligence.md |
Feedback loop (loop-events.jsonl, features only; downshift feedback <id> success|retry|failed [--required-tier]) |
Implemented | internal/routingv2/training/events.go, cmd/main.go |
events_test.go; RecordRoutedDecision discards the prompt |
success never creates a tier label |
docs/design/classifier-shadow.md |
7. Token reporting and baseline comparison
| Capability | Status | Where | Evidence | Limits | Docs |
|---|---|---|---|---|---|
downshift stats (--days, --detail, --export, --by-harness): token counts and dimensionless normalised units |
Implemented | internal/telemetry/telemetry.go, stats_headline.go, export.go, curation.go, cost_groups.go |
TestHookE2E_RewriteEventStats, TestPrintStats_MarksInferredBaseline, stats_footer_test.go |
Current stats output shows observed token counts, coverage and dimensionless normalized units, not dollars. Schema 3 export has no USD keys. The 19.3% in one operator's log was a historical list-price estimate, not an A/B result. |
docs/reference/stats-export.md, README |
downshift report: routed versus control tokens per completed task, rework rate, token check (a point percentage; no interval printed), not enough data under 20 tasks per group |
Implemented | cmd/report.go, telemetry/report.go, tasks.go |
report_test.go (TestBuildReport_SavingsAndDeterministicCI, TestBuildReport_NoSavingsIntervalIncludesZero) |
Needs measurable completion (Claude Code today); no filled period report exists (P3.7 open, docs/evidence/score-gaps-2026-10-10.md); no price or dollar output |
docs/guides/report.md, docs/guides/pilot.md |
| Cost per session and per subagent (counts, mean, max, three costliest hashed sessions) | Implemented | telemetry/cost_groups.go |
cost_groups_test.go |
Reporting only; a hook cannot enforce a budget | README "Cost and metrics" |
Baseline provenance (baseline_source: requested or inferred) |
Implemented | telemetry/cost.go, childend |
TestBuildUsageEvent_InferredBaselineSource (audit) |
inferred is Claude Code settings only |
docs/reference/stats-export.md |
| Billing comparison for one period (provider dashboard versus export) | Planned | docs/guides/billing-comparison-template.md |
Placeholders empty as of 2026-10-10 | No filled report | docs/reference/beta-exit.md P3.7 |
8. Cost-reduction diagnosis
| Capability | Status | Where | Evidence | Limits | Docs |
|---|---|---|---|---|---|
Skills downshift-setup, downshift-audit (read-only), cost-reducer (fixed order: routing, fixed context, tool output, project policy, misroutes) |
Implemented as agent guidance | skills/*/SKILL.md, skills/*/references/*.md |
Plain SKILL.md, any harness; plugin ships them | No measurement of the skills' own effect; each description costs context in every session | docs/README.md, docs/design/architecture.md packaging table |
Fixed-context measurement (wc -c on always-loaded files, bytes/4 as a token estimate) |
Implemented as guidance | skills/downshift-audit/SKILL.md section 3 |
none (procedure) | An estimate the skill says is an estimate | skills/cost-reducer/references/context-diet.md |
Misroute triage (session --why, try, feedback, misroute: issue) |
Implemented | cmd/session.go, cmd/try.go, cmd/main.go |
classifier_edge_test.go is where accepted misroutes land |
Prompt stays on the machine | CONTRIBUTING.md, skills/cost-reducer/references/misroute-triage.md |
Claude Code main-session policy: model: opusplan, permissions.defaultMode: plan, enabledPlugins["cc-plugin-you-should-know@builtin"]: true, set only when unset |
Implemented, not validated everywhere | cmd/setup_targets.go (optional defaults), setup.go |
setup_test.go; doctor "main session" rows |
Claude Code only; saving estimated, not measured; plan-mode spawn baseline not observed live (session-models.md:103); plugin install does not set them |
docs/reference/session-models.md#main-session-policy-plan-mode-and-opusplan-claude-code, docs/guides/claude-code.md |
More docs
- Install Downshift: Claude Code, Codex and Cursor hook setupGuide
- Downshift configuration: state directory and local settingsGuide
- Downshift and Claude Code subagents: when routing can actGuide
- Downshift session view: subagent tree, reasons and pauseGuide
- Downshift report: routed versus control tokens per completed taskGuide
- Downshift evidence ladder: what each saving figure meansGuide
- Downshift companions: Headroom and Claude Code mods to pairGuide
- Downshift capability matrix, part 2: context and packagingReference
- Downshift harness matrix: Claude Code, Codex, Cursor statusReference
- Downshift value per harness: observed tokens vs list priceReference
- Downshift spawn state: switched, held or only observedReference
- Downshift offline simulation: routing without model callsGuide
- Downshift session models: which model IDs a hook may writeReference
- Downshift complexity weights: how a task becomes a modelReference
- Downshift architecture: deterministic hook and offline CLIDesign
- Downshift routed vs control: first Claude Code A/B resultsEvidence
- Downshift real usage: a Claude Code day and the last 30 daysEvidence
- Downshift Code Intelligence MVP: evidence for Claude CodeEvidence