Skip to content

Releases: fkiene/llmtrim

llmtrim 0.11.4

Choose a tag to compare

@github-actions github-actions released this 17 Jul 23:13

Added

  • Status line shows the active /sub plan's rate limits (Codex first). Under a Codex
    reroute the segment now reads the ChatGPT plan's windows (weekly always; 5h when the plan
    reports one) from GET /backend-api/wham/usage, cached at ~/.llmtrim/sub-rate-limits.json by
    the proxy on each throttled turn. A matching snapshot replaces Claude Code's Anthropic blob
    only while the proxy is healthy; until the first poll lands (or if the proxy is down) the
    Claude numbers stay so the segment isn't blank. Kimi/Grok share the cache schema; their usage
    endpoints are not wired yet.

Fixed

  • Codex traffic is compressed and tracked again. Codex CLI 0.144+ sends its request bodies
    with Content-Encoding: zstd, which the interceptor could not parse, so every Codex turn was
    forwarded verbatim and never reached the ledger — llmtrim status showed no Codex activity at
    all (#193). The interceptor now decodes zstd- and gzip-encoded request bodies (capped at
    256 MB) before compression and attribution, and forwards the body as plain JSON. A body it
    cannot decode still passes through verbatim, so a decode problem can never break the call.
  • Codex sessions are labeled codex in the cost breakdown again. Two attribution gaps hid
    them: the fingerprint markers predated Codex 0.144's system prompt (which opens with "You are
    Codex" and no longer says "Codex CLI"), and identity extraction read only the first
    system/developer item of a Responses body — Codex now leads with a non-message
    additional_tools item, so the identity message behind it was skipped. The fingerprint gained
    the current marker and identity extraction concatenates every system/developer message,
    skipping tool registrations (whose schemas would also destabilize the session hash).

llmtrim 0.11.3

Choose a tag to compare

@github-actions github-actions released this 17 Jul 10:48

Fixed

  • /compact redirects to a cheaper model only when the prompt cache is cold. The redirect
    used to run on every /compact. But /compact re-sends the conversation Claude Code has been
    caching against your selected model, so while that cache is warm a cache-read there is cheaper
    than a cold read on a smaller model, so redirecting a warm compact cost more, not less. The
    redirect now stays on your selected model when the session's last turn is within the cache TTL.
    Unknown freshness (no session row yet, or a build without the breakdown feature) still
    redirects, so the feature is never silently disabled.

llmtrim 0.11.2

Choose a tag to compare

@github-actions github-actions released this 16 Jul 13:51

Fixed

  • Window /sub survives Claude Code /clear (and /compact) without the env token.
    Retention used to depend only on LLMTRIM_CLAUDE_WINDOW_TOKEN surviving into the next
    SessionStart hook. Claude Code often drops that env on clear, so /sub on grok was lost and
    the next turn fell back to Anthropic. SessionEnd now keeps the live session map and a
    short-lived cleared backup; SessionStart reattaches via session map, that backup, or the
    env token last (so a stale token from another window cannot override this session).
  • /sub skill bash no longer trips Claude Code permission checks. Session id is read from
    process env (not shell-expanded on the skill line), and Bash(<llmtrim> window-sub slash *) is
    pre-approved via skill allowed-tools + settings.permissions.allow. ensure treats a
    missing/stale allow rule as stale so upgrades self-heal.

llmtrim 0.11.1

Choose a tag to compare

@github-actions github-actions released this 16 Jul 09:10

Changed

  • Overview and non-TTY status dollars match Sessions (frozen proxy bills). KPI "You paid" /
    "Total saved" / today / week / trend / top models, and the piped status hero, read
    breakdown_turns.bill_micros plus a per-turn frozen-rate input counterfactual
    (llmtrim-ledger::money) — not live re-pricing of compressions. Lifetime $ may drop vs
    older builds when breakdown retention is shorter than compressions, or for CLI/MCP-only
    traffic (no session bill). Token % gauge is unchanged. When there is no proxy bill yet, the
    UI shows a billing notice (not $0.00).
  • Sessions columns: savedsaved$ (money) + trim (token size %). Detail bill
    footer uses SUM(bill_micros) (blocks allocate; * when they residual).
  • status --json / MCP llmtrim_stats: additive money object with unavailable +
    null dollars when there is no proxy attribution. Legacy cost remains compressions +
    live list prices with "source": "compressions_live_prices" — prefer money when
    unavailable is false.

Added

  • Money coverage UX on Overview (and doctor empty-case only) when compressions exist but no
    breakdown bills — banner instead of fake $0.00.
  • llmtrim-ledger::money: shared MoneyTotals / coverage / per-day / per-model queries;
    shared saved_micros SQL for Overview and Sessions.
  • Grok remote auth: paste the callback URL or xAI one-time code into
    llmtrim sub auth grok login, or use RFC 8628 llmtrim sub auth grok device for SSH/headless
    hosts (no localhost callback).

llmtrim 0.11.0

Choose a tag to compare

@github-actions github-actions released this 15 Jul 19:45

Breaking

  • SubProvider / StreamReducer gain a Grok variant and are marked #[non_exhaustive] so
    further backends can land without a major bump. External exhaustive matches need a _ arm.
    Workspace version is 0.11.0 (0.x minor = semver-breaking).

Added

  • llmtrim ensure: bring this machine to the recommended state. Installs or refreshes owned
    Claude Code integrations (statusline, cold-cache guard, window-local /sub, default compact
    model chain), tray login when the GUI binary is present, and restarts a version-skewed daemon.
    Opt-outs live in ~/.llmtrim/integrations.json so ensure does not re-enable after an explicit no.
  • llmtrim doctor --fix and status f run the same ensure path.
  • Quiet auto-heal on start and status open when the binary version advanced or owned pieces
    look stale (no prompts; no network tray download; no first-time installs).
  • Linux desktop tray one-shot download during interactive ensure when the tray binary is
    missing (optional; default off when non-interactive).
  • One-time subscription onboarding in the status TUI (s for login steps, n to dismiss)
    when Claude Code is present and sub is not configured.
  • Subscription reroute: Grok (SuperGrok / Grok Build). llmtrim sub auth grok login signs in
    via OAuth against auth.x.ai (browser PKCE); llmtrim sub use grok maps Claude tiers to
    grok-4.5 (opus/sonnet/fable) and grok-composer-2.5-fast (haiku) and routes Claude Code's
    Anthropic /v1/messages traffic to cli-chat-proxy.grok.com/v1/responses. Tokens live at
    ~/.llmtrim/grok/auth.json. Works with sub mode fallback chains (codex,kimi,grok) and the
    window /sub command. Device-code login is not available yet (browser only).
  • Window /sub on <provider>. The Claude Code slash command accepts an explicit backend:
    /sub on codex, /sub on kimi, or /sub on grok. Bare /sub on still re-enables the last
    window provider or the global sub setting.
  • Status line shows window /sub overrides immediately. Mid-session /sub on grok (or any
    provider) now paints →grok-4.5 even when earlier turns were Anthropic and global sub is
    off. Window overrides are treated as always-mode for the arrow (matching the proxy), and a
    policy switch overrides a stale ledger backend until the new one serves a turn.
  • Window /sub no longer inherits another provider's tier map. With global llmtrim sub on codex and a Claude Code /sub on grok, the proxy was already routing to Grok but still applied
    [sub.codex.tiers] (e.g. opus → gpt-5.6-terra) on the Grok request. Tiers are now loaded per
    serving provider, and foreign model ids in overrides are ignored. After upgrading, run
    llmtrim ensure (or f in status) so owned /sub hooks refresh and a version-skewed
    daemon restarts onto the new binary.

Changed

  • setup and binary-channel update call ensure. First install wires
    statusline/guard//sub/compact. Binary update restarts the daemon and runs ensure -q on the
    new binary (never in-process after a self-replace). Package-manager channels print the package
    command then a single llmtrim ensure follow-up.
  • Owned Claude Code hooks and statusline rewrite in place when the binary path or payload
    (e.g. refreshInterval) changes. Quiet auto-heal only refreshes stale owned pieces and daemon
    skew; it never first-installs integrations or enables tray login.
  • Top-level help leads with setup / update / ensure / doctor. Power-user
    statusline / guard / compact stay available but are hidden from the main command list.
  • Opt-outs stick: statusline / guard / window-sub / compact off write
    integrations.json opt-outs; corrupt state refuses auto-apply instead of resetting them.
  • Safer hooks and tray install: shell-quoted hook paths, atomic settings.json writes,
    shared CLAUDE_CONFIG_DIR, arch-aware tray download via path-filtered tar into a temp dir,
    then promote.

llmtrim 0.10.2

Choose a tag to compare

@github-actions github-actions released this 15 Jul 13:37

Added

  • Ordered model fallback for Claude Code /compact. Configure [compact] models = ["haiku", "sonnet"] or run llmtrim compact models haiku sonnet to try cheaper models for compaction.
    Each candidate is admitted against its known context window after candidate-specific compression;
    failures before any output advance to the next candidate, and Claude Code's selected model remains
    the implicit final fallback. The same chain works through subscription tier mappings, while
    preserving the original model identity in the response. llmtrim setup proposes the default
    chain on Claude Code installations that have not made a choice.
  • llmtrim guard — stop paying for a cold cache without being told. Resume a session that has
    been idle past the prompt-cache TTL and the next turn silently re-writes the entire context,
    billed at the cache-write rate (2× base input for the 1h TTL Claude Code asks for). On a 225k
    context — the median across my own idle gaps — that is a few dollars before any work happens, and
    nothing at the prompt says so. guard is a Claude Code UserPromptSubmit hook: on the first
    submit after a long gap on a big context it prints the idle time, the context size and what the
    cold write costs, then exits 2, which blocks the prompt with no API call. A resend goes straight
    through, and the blocked message is saved to disk since Claude Code does not restore it. llmtrim setup offers to wire it in; guard install / guard uninstall do it directly, merging into
    ~/.claude/settings.json rather than clobbering hooks you already have. It reads Claude Code's
    transcript, not llmtrim's ledger — the ledger keys sessions by a hash of the system prompt, so a
    subagent turn would mask a stale main conversation — and every failure path exits 0: a bug in the
    guard must never block a prompt.

Changed

  • The status line now refreshes while a session sits idle. It already reddened the cache segment
    once the prompt cache expired, but Claude Code only re-renders on conversation events, so an
    abandoned session kept the line drawn at its last turn — green and warm — straight through the TTL
    expiring. The warning only appeared after the turn that paid for it. It now sets
    refreshInterval, so the state is on screen before you type. Re-run llmtrim statusline install
    to pick it up.
  • The cold-cache segment no longer suggests /compact. It read ♻ cold · /compact, which sold
    compaction as the thrifty move. It isn't: /compact re-reads the same cold context to summarise
    it — paying the charge it appears to avoid — and the next turn then writes a fresh cache for the
    summary. Resending pays once. The segment now just reports the state: ♻ cache cold.

llmtrim 0.10.1

Choose a tag to compare

@github-actions github-actions released this 13 Jul 11:34

Fixed

  • Codex reroute failed every turn after the first. The ChatGPT backend accepts
    previous_response_id only over its WebSocket transport; on the HTTP /responses path llmtrim
    uses, it answers 400 Unsupported parameter: previous_response_id. Server-side continuation
    defaulted to on, so from the second turn onward every rerouted request died — and it was
    incoherent with the store: false llmtrim sends anyway, since there is no stored response to
    continue from. Continuation now defaults to off (still available via
    LLMTRIM_CODEX_PREVIOUS_RESPONSE_ID or [sub.codex] previous_response_id, for a transport that
    accepts it), and prefix caching via prompt_cache_key carries the cache instead. A rejected
    continuation now also heals itself: the request is re-issued in full rather than surfacing the
    400, so an enabled-by-config continuation degrades instead of breaking the session.

  • Compression could rewrite the system prompt. The compressible set came solely from the cache
    zone, so a request with no cache_control markers had nothing frozen and the text-mutating
    stages were free to fold n-grams through the instructions. On Claude Code's title-generation
    call — which carries no markers — this rewrote the few-shot examples, deleting the conditional
    that gave them meaning. Instructions are what the model conditions on rather than reads as data,
    so a fold that is harmless in a tool result can invert a directive. system, instructions and
    system-role messages are now excluded from compression unconditionally, cached or not. This
    costs nothing on real traffic (593 of 594 captured requests already had cache_control on
    system; replaying 58 of them produces byte-identical output) and closes the gap for the small
    utility calls that carry no markers.

  • Status line blanked out mid-turn. The cache percentage and context gauge were read only from
    Claude Code's blob, which fills current_usage and total_input_tokens from the last
    response. Claude Code re-runs the status line on every render, so while a turn was in flight both
    were absent: the cache segment vanished and the gauge emptied, then both snapped back when the
    turn landed — which reads like the prompt cache collapsing on every message. The proxy measures
    the same quantities on the wire, so the last completed turn now stands in across the gap. The
    blob still wins whenever it carries a figure, and a fresh session with no recorded turn renders
    empty rather than inventing a value.

Added

  • Reroute request capture. With capture_dir set, the body actually sent to a reroute backend
    is recorded alongside the existing before/after pair. The capture previously stopped at llmtrim's
    own pipeline output, leaving the translated payload — the thing the upstream prompt cache keys
    on — unobservable, which made cache behaviour under sub impossible to diagnose from evidence.

llmtrim 0.10.0

Choose a tag to compare

@github-actions github-actions released this 12 Jul 22:15

Fixed

  • Status line claimed a reroute that never happened in sub fallback mode. The reroute arrow
    and the context gauge were derived from config: if sub was set, the line rendered
    ◆ Opus→gpt-5.6-terra on every turn. But in fallback mode Anthropic serves the turn and the
    chain fires only when Anthropic fails — so the arrow named a backend that hadn't answered, and
    the gauge rescaled to that backend's context window, under-reporting how full the real (Claude)
    window was. The serving backend is now recorded per turn in the ledger (new sub_provider
    column, added to existing ledgers on open) and the status line reads that: the arrow appears
    only on a turn a backend genuinely served, and shows the model it ran. In always mode, where
    every turn reroutes, config still seeds the arrow before the first turn lands, so nothing
    changes there.

Added

  • Ordered subscription fallback chains. llmtrim sub mode fallback now tries a list of
    providers in order instead of a single one: llmtrim sub chain codex,kimi (or
    LLMTRIM_SUB_CHAIN=codex,kimi, or [sub] chain = ["codex", "kimi"]). When Anthropic cannot
    serve a turn — quota, payment, throttling, overload, or a transient server failure — Anthropic is
    retried once, and if it still fails each provider in the chain is tried in turn (with bounded
    backoff, honoring Retry-After) until one answers. A failure reported inside an HTTP 200
    stream counts as a failure too, and is caught before any of it reaches the client. With no chain
    configured, the active sub provider is the chain, so existing setups behave as before.

Changed

  • Breaking (config): sub mode on-error is now sub mode fallback. The old name still works —
    llmtrim sub mode on-error, LLMTRIM_SUB_MODE=on_error, and [sub] mode = "on_error" all keep
    meaning fallback, and print a one-line notice — but the new spelling is what gets persisted.
  • Breaking (library): llmtrim-core's RuntimeConfig::sub_on_error is now sub_fallback, and
    RuntimeConfig gained a sub_chain field. Hence the 0.10 minor bump.

Fixed

  • Upstream connection failures are reported instead of swallowed (#157).
    A request that failed before the upstream answered (a TLS error, a reset, a dropped
    keep-alive) fell through to the proxy library's default handler: an empty-bodied 502, with
    the cause logged only through a tracing subscriber llmtrim never installs. Claude Code could
    not parse the reply, so the turn died — and nothing anywhere recorded why. A transport failure
    is now reported in the shape the client is reading (an SSE error frame on a streaming call, a
    retryable overloaded_error otherwise), and the underlying cause is named on stderr, so
    llmtrim serve in the foreground shows what actually broke.

  • Subscription reroute: the Codex prompt cache no longer goes cold every turn. Claude Code
    prepends a billing-header system block whose hash changes on every turn, and the Codex translator
    forwarded it at the head of the Responses instructions — the very front of the cached prefix —
    so each turn re-sent a different prefix and paid a full cold cache. The block is now dropped for
    both Codex and Kimi. On a 4-turn session, cached input read back rose from 4.6k to 34.3k tokens.

  • Subscription reroute: the status line shows trim again. Rerouted turns never recorded their
    Claude Code session, so the trim segment sat at ✂ – even though compression was running
    normally. It now reports the session's real savings (✂ 39.8% on the run above).

  • GPT-5.6 Codex reroutes. Claude model requests keep the standard Responses shape and use the
    official Codex originator and user-agent identity required by the backend.

  • Subscription reroute: Claude Code thinking no longer 502s on Codex. The Codex
    reducer streamed thinking_delta summaries but never forwarded the upstream
    encrypted_content as Anthropic signature_delta, so Claude Code rejected the SSE
    stream (502 / dropped connection) and follow-up turns could not replay thinking blocks.
    Signatures now map both ways (encrypted_contentsignature), text waits for a late
    signature when needed, and adaptive thinking without an explicit output_config.effort
    still enables Codex reasoning.

  • Claude Code statuslines survive package upgrades. llmtrim statusline install now keeps
    a stable executable path when the active binary is also reachable through a symlink on PATH
    (as with Homebrew's versioned Cellar layout), and llmtrim update re-points an existing
    llmtrim-owned entry before the upgrade runs, so the statusline no longer ends up pointing at
    a removed binary.

llmtrim 0.9.4

Choose a tag to compare

@github-actions github-actions released this 12 Jul 02:53

Fixed

  • Low cache reuse on sub codex / sub kimi. Follow-up turns now reuse backend state via previous_response_id + output transcript, producing the expected high cache hit rates instead of full resends.

  • Status line stayed red after /compact. The cold-cache segment (♻ cold · /compact) and
    context gauge keyed only on the interceptor ledger's last_ts. /compact runs inside Claude
    Code and does not update that timestamp, so the line kept warning after a successful compact.
    The renderer now clears the cold state when Claude Code reports a post-compact reset (empty
    context, no current_usage yet).

Changed

  • Status line shows the resolved upstream model on sub reroutes. Codex reroutes now render
    the concrete backend model (e.g. →gpt-5.6-terra) instead of the provider shortname (→codex);
    Kimi still shows →kimi.

llmtrim 0.9.3

Choose a tag to compare

@github-actions github-actions released this 11 Jul 09:13

Fixed

  • The desktop tray popover rendered blank. Every installed tray (macOS, Linux, Windows) showed
    an empty white box under the tray icon instead of the stats UI. The shipped binaries were built
    with plain cargo rather than cargo tauri build, which left Tauri's custom-protocol feature
    off, so the webview ran in dev mode and tried to load a Vite dev server that does not exist on a
    user's machine. custom-protocol is now a default feature, so release builds embed and serve the
    real UI. (#149)