Skip to content

Releases: fkiene/llmtrim

llmtrim 0.11.9

Choose a tag to compare

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

Fixed

  • Claude Code under always-sub skip-login actually hits the MITM. Node 20.18+/22 undici
    ignores HTTPS_PROXY unless NODE_USE_ENV_PROXY=1, so the dummy ANTHROPIC_AUTH_TOKEN
    was reaching real Anthropic and returning 401 Invalid bearer token. Setup now exports
    the flag in the managed env block, Windows registry, and settings.json next to the dummy
    token, and heals older profile blocks that lack it.

  • llmtrim ensure no longer re-asks about cheaper /compact models after they are configured.
    compact_models_configured() used str::parse::<toml::Value>(), which in toml 1.x only accepts
    a single value — a real multi-key config.toml failed the parse, the error was swallowed, and
    ensure/doctor always reported compact as missing. It now uses toml::from_str like every other
    config reader.

  • Cold-cache guard shows the blocked draft on the TTY again. suppressOriginalPrompt stopped
    Claude Code nesting Original prompt: into the warning, but also hid the draft entirely once
    the input box was cleared — next-turn additionalContext only helped if you typed something
    else. The block reason now carries the draft under our own label, so a cold session still shows
    what was not sent; the disk stash + next-turn reinject path is unchanged.

llmtrim 0.11.8

Choose a tag to compare

@github-actions github-actions released this 22 Jul 14:31

Added

  • Always-sub can skip Anthropic /login. With global sub in always mode, llmtrim
    injects a dummy ANTHROPIC_AUTH_TOKEN into ~/.claude/settings.json (same idea as
    claude-code-proxy) so Claude Code does not need a live Anthropic OAuth session. The MITM
    strips the dummy credential, injects the real Grok/Codex/Kimi token, and answers non-messages
    Anthropic probes locally (with request-body drain so keep-alive stays healthy). Trade-off:
    Claude Code disables claude.ai connectors while any API-key auth is set. Opt out with
    llmtrim sub anthropic-login keep (connectors work again; Anthropic /login required when
    OAuth expires). Window /sub off under skip-login returns a clear error instead of a bare
    Anthropic 401.

Fixed

  • Guard no longer echoes nested prompts and reinjects blocked drafts. Nested Claude Code
    prompt echoes are suppressed; a blocked draft is reinjected so the user does not lose the
    text they were about to send.

llmtrim 0.11.7

Choose a tag to compare

@github-actions github-actions released this 22 Jul 11:36

Fixed

  • Grok full-body ghost turns are classified and greppable. After the 0.11.6 transport-reset
    hardening, some Grok sub turns still landed in the ledger as anonymous out=0 / zero usage rows
    with no outcome and no serve.log transport line: the stream had accepted (HTTP 2xx) then died
    with only synthetic Anthropic message_start zeros (or nothing at all), and Finalize treated
    those zeros as a real completion. Finalize now blanks all-zero / missing usage, tags
    outcome=empty_stream (no client-visible content) or outcome=incomplete_stream (content
    without positive usage — client abort / truncate), and logs
    llmtrim: stream <outcome> model=… sub=… session=… on stderr. On the reroute path, a quiet EOF
    before any content also triggers one buffered replay when the body is still available — same
    safety rule as the handle_error retry (never after the client has seen bytes).

  • Grok reasoning history is replayed for prompt-cache continuity. cli-chat-proxy returns
    Responses reasoning items (summary always; encrypted_content when
    include: ["reasoning.encrypted_content"] is set). llmtrim previously dropped Anthropic
    thinking / redacted_thinking blocks when building Grok input[], which is the top
    documented cause of cache misses on reasoning models. The reducer now tunnels Grok
    encrypted_content out as a marked thinking signature (same pattern as Codex), requests the
    encrypted include on every turn, and rebuilds reasoning items on the next request — encrypted
    when the signature is ours, summary-only plaintext as a best-effort fallback for history that
    never received a Grok blob. Also dual-sends x-grok-conv-id from the Claude Code session id
    alongside prompt_cache_key. Still uses store: false (no previous_response_id continuation).

llmtrim 0.11.6

Choose a tag to compare

@github-actions github-actions released this 22 Jul 08:52

Added

  • Grok reroute pins prompt_cache_key to the Claude Code session id. Codex and Kimi already
    set Responses prompt_cache_key from x-claude-code-session-id; Grok did not, so multi-session
    concurrency (and any server-side routing change) could drop cached_tokens to 0/128 on an
    otherwise append-only conversation. cli-chat-proxy accepts the field (HTTP 200) and reports
    input_tokens_details.cached_tokens on hits.

  • Grok upstream usage capture under LLMTRIM_CAPTURE_DIR. When the capture corpus is on, each
    completed Grok turn also writes *-upstream-usage.json with the raw response.completed.usage
    object and the mapped ledger fields, so a cache-collapse audit can compare Grok's wire usage
    against the Anthropic-shaped ledger without re-running the turn.

Fixed

  • Upstream transport resets are retried and recorded instead of becoming silent zero-output rows.
    Stale keep-alive connections to subscription backends (especially Grok) used to surface as hyper
    SendRequest: connection reset and land in the ledger as anonymous out=0 rows. The outbound
    client now expires idle pool sockets after a short timeout (with hyper-util's pool_timer wired
    so the timeout actually fires), retries once when the request body is still available to replay,
    logs session/model on every transport failure, and records outcome=transport_reset rather than
    a silent zero-output row.

llmtrim 0.11.5

Choose a tag to compare

@github-actions github-actions released this 20 Jul 15:58

Added

  • llmtrim setup --env creates CA files (if needed) and prints envvars When this option is
    used, setup ensures the local CA (and, on POSIX, the combined OS-trust bundle) exist, then
    prints an evaluatable snippet — export lines on POSIX, $env: assignments on Windows — to
    wire the interceptor into your current shell.

Fixed

  • The managed shell-profile block now single-quotes its values. setup interpolated the proxy
    URL and CA paths into bare double quotes, so a home directory or CA path containing ", $, a
    backtick or a backslash produced a profile line that broke or expanded at shell start. Values
    are now emitted as inert single-quoted literals on both the POSIX and PowerShell paths, matching
    the quoting setup --env already used. Re-run llmtrim setup to rewrite an existing block.

  • A legacy sub value keeps its formatting when migrated to a [sub] table. Coercing
    sub = "codex" or an inline sub = { … } emitted the header as [sub ], leaking the space
    that sat before the old =, and dropped a trailing comment on the line. The header is now
    clean and the comment moves to its own line above it.

  • The config writers now preserve comments and key order, and no longer corrupt the file.
    All three (compact.models, theme, and the sub reroute editors) go through toml_edit,
    a format-preserving TOML editor, instead of hand-rolled line edits and a full re-serialize.
    Three bugs go with it: compact.models = [...] written in TOML's dotted top-level form was
    invisible to the writer, which appended a second [compact] section and left the key defined
    twice so the file stopped parsing; llmtrim sub re-serialized the whole document and silently
    deleted every comment while reordering keys; and theme was matched anywhere in the file
    rather than only at the top level. A writer handed a file that doesn't parse now reports it
    and leaves the file untouched, rather than editing it blind and producing plausible-looking
    output from an already-broken config.

  • compact.models no longer corrupts the config when it was written as a multi-line array.
    The writer replaced the single models = [ line and left the array's continuation lines
    behind, stranding "haiku", / ] after the new value and producing a config.toml that
    llmtrim could no longer parse. It now consumes the whole array. A file already damaged this
    way still needs a manual edit: once the tail is orphaned nothing distinguishes it from real
    config, so repairing it automatically would risk deleting keys.

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.