github yvgude/lean-ctx v3.7.3

5 hours ago

Compression where the agent actually is — and fidelity where it matters. A
shell MCP tool so the Codex Desktop/Cloud app compresses even without
lifecycle hooks, plus a self-diagnosing, additive shell allowlist so permitting
one command no longer means wiping out the defaults. Navigation output (map/
signatures) now carries line ranges so agents jump straight to a symbol, and
already-compact formats (TOON) pass through untouched instead of being
recompressed away. The proxy also speaks OpenAI's new Responses API.

Supersedes 3.7.2: an automated release misfire published an incomplete 3.7.2 to
crates.io / npm before this work had landed, and those registries permanently
reject re-publishing a version — so 3.7.3 is the first clean release of this work
across every channel (crates.io, npm, GitHub, Homebrew).

Added

  • OpenAI Responses API support in the proxy (#346, thanks @Lctrs): clients that moved to OpenAI's new Responses API (POST /v1/responses) — opencode, the OpenAI Agents SDK — were forwarded untouched because the proxy only understood Chat Completions (messages). The proxy now compresses the Responses-API shape too: each function_call_output.output (the Responses analogue of a role:"tool" message — a string, or an input_text content array) is run through the same pattern pipeline as every other tool result. The conversation input array is intentionally left structurally intact (no history pruning) so a function_call can never be separated from its matching function_call_output and trigger a 400. Retrieve/cancel/delete sub-paths (/v1/responses/{id}/…) pass through cleanly, and /status introspection now reports an accurate token breakdown for Responses requests (instructions → system prompt; input items → user/assistant/tool buckets; input_image counted). Chat Completions remains fully supported.
  • shell MCP tool (#337): the instruction-only fix in 3.7.1 wasn't enough — the Codex Desktop / Cloud app loads the MCP server but its agent ignores ctx_shell and reaches for a native shell/Bash tool, so nothing compressed. lean-ctx now exposes a shell tool (familiar name + model-optimized description) that transparently delegates to the same 95+-pattern compression pipeline as ctx_shell, giving the Desktop/Cloud app the compression the CLI gets via hooks. Registered for all MCP clients.
  • lean-ctx allow <cmd> (#341): permit a binary on the shell allowlist additively through the new shell_allowlist_extra config field — so allowing e.g. acli keeps git/cargo/npm/… intact instead of replacing the whole built-in list. lean-ctx allow --list prints the effective allowlist plus the exact config path in use; --remove reverts. Picked up on the next command — no MCP/daemon restart needed.
  • Line ranges in map / signatures output (#340, thanks @iohansson): every entity in the navigation-focused map and signatures views now carries a compact @Lstart[-end] suffix (e.g. fn ⊛ build() → Config @L42-58), so an agent can jump straight to a symbol instead of issuing a follow-up search. Spans are populated consistently across the tree-sitter extractors (all languages, not just Kotlin) and the regex fallbacks (TS/JS, Rust, Python, Go, generic), with Vue/Svelte SFC spans shifted back to file-absolute lines. Mode-aware by design: the suffix is emitted only in map/signatures (MCP + CLI) where locating code is the point — compression-first paths (aggressive, entropy, full-body reads, and ctx_compress/ctx_outline/ctx_fill/ctx_analyze/repo-graph) stay byte-identical and pay zero extra tokens. The map/signatures compression caches are version-bumped so stale range-less entries are never served.
  • Format-aware passthrough for already-compact output (#342, thanks @pomazanbohdan): ctx_shell / lean-ctx -c no longer recompress output that is already in a compact, token-oriented format. lean-ctx detects TOON (Token-Oriented Object Notation) by its structural markers — the tabular key[N]{f1,f2}: header and the length-prefixed key[N]: array header — and returns it verbatim, because a second pass saves little while rewriting the exact line/field shape an agent needs to validate a CLI output contract. The decision is output-shape based, not command based, so any tool emitting TOON is covered without enumerating it in excluded_commands. Controlled by the new preserve_compact_formats config (default ["toon"]; set to [] to disable) and surfaced as a "Compact-format passthrough" line in lean-ctx doctor.
  • Clearer path to the public leaderboard (community feedback): the lean-ctx gain recap now always shows a one-line, state-aware hint — how to publish to leanctx.com/metrics with --leaderboard, how to claim a display name (--name="…") instead of showing up as "anonymous", and how to --unpublish. The gain --publish output likewise points a private-only publisher to the public board and nudges nameless leaderboard entries toward a handle, so getting on (and managing) the leaderboard is never a guess.
  • VS Code / Cursor extension, now publishable (community feedback): the editor extension is consolidated into a single, marketplace-ready package (vscode-extension) and shipped to the VS Code Marketplace and Open VSX (Cursor, VSCodium, Windsurf) via a dedicated, tag-triggered CI workflow (publish-vscode.yml). It gains binary auto-detection (PATH / ~/.cargo/bin / Homebrew, for GUI editors with a stripped PATH), setup / doctor / gain / heatmap / web-dashboard commands, one-click workspace MCP wiring, plus an Apache-2.0 license and PNG icon. The duplicate scaffold (packages/vscode-lean-ctx) was removed.

Fixed

  • MCP stdio stays protocol-clean (#348): confirmed and regression-guarded that lean-ctx routes all tracing diagnostics to stderr — never the stdout JSON-RPC transport — so a log line can never be interleaved into an MCP client's message stream and break parsing. This has held since ≤3.7.1 (the transport writes only framed JSON-RPC, the auto-started proxy runs as a subprocess with stdout redirected to null, and tool handlers return strings rather than printing); a source-level guard now fails the build if the logging writer is ever switched to stdout.
  • shell_allowlist edits silently ignored in MCP/editor mode (#341): allowlist changes looked like no-ops while lean-ctx -c (CLI, warn-only) still ran the command, due to three compounding traps. (1) A malformed config.toml fell back to the defaults with the warning printed only to stderr — invisible over an MCP/stdio transport; the parse error is now surfaced in the block message and in lean-ctx doctor. (2) Setting shell_allowlist directly replaced the entire default list — the new additive shell_allowlist_extra (written by lean-ctx allow) avoids that footgun. (3) The "not in allowlist" message now names the exact config path the runtime reads plus the precise additive fix, so a config-path/HOME mismatch between the editor's MCP process and your shell is immediately visible. lean-ctx doctor gains a "Shell allowlist" check (effective command count + parse status).
  • Codex instructions no longer claim Desktop "can't" run hooks (#350, thanks @iohansson): the block lean-ctx injected into ~/.codex/AGENTS.md (and LEAN-CTX.md) asserted as fact that "lifecycle hooks do not run" in the Codex Desktop/Cloud app — false (hooks do run there, trust-gated via /hooks since Codex 0.129.0) and traceable to a misread of openai/codex#13019, which is about completion notifications, not lifecycle hooks. A false absolute like that is exactly the kind of thing that confuses the agent. The instructions now make no surface-specific "hooks don't run" claim; they frame the lean-ctx MCP/CLI tools (ctx_shell / ctx_read / ctx_search, or lean-ctx -c) as the path that compresses reliably on every surface regardless of hook status, and lean-ctx doctor's Codex note is corrected to match. A regression test fails the build if the docs ever re-introduce a "hooks do not run" / "no automatic compression" absolute.
  • Proxy no longer mangles file/source reads (#351, external testing feedback): the request-compressing proxy treated every tool result as shell output, so a Read of a large source file was run through command-output truncation (head/tail + "safety" lines) on the very next turn — gutting the file the model was mid-refactor on and forcing an uncounted re-read. The proxy now resolves each tool result's originating tool name (tool_use/tool_calls/function_call/Gemini functionResponse.name) and never lossy-compresses a file read or content that heuristically looks like source code, across all four providers (Anthropic, OpenAI Chat, OpenAI Responses, Gemini). Shell/search/command output still compresses as before. History pruning is likewise code-aware: an older file read is replaced with an honest, actionable "re-read the file if you need it again" stub instead of a misleading 3-line excerpt.
  • Proxy stopped failing large-refactor and long-generation calls (#351, external testing feedback): the request-body ceiling was 10 MiB, so a big-codebase refactor with several files in context hit a hard 400 mid-task — now 64 MiB and configurable via LEAN_CTX_PROXY_MAX_BODY_MB. A single 2-minute total request timeout also aborted long streaming generations (e.g. Opus doing a large refactor) mid-stream; it is replaced by a connect timeout plus a read (idle) timeout (LEAN_CTX_PROXY_CONNECT_TIMEOUT_SECS, LEAN_CTX_PROXY_READ_TIMEOUT_SECS, defaults 15s / 300s), so a slow-but-alive stream is never cut while a genuinely dead upstream still fails.

Changed

  • Identifier α-substitution (§MAP) is now opt-in (#351, external testing feedback): aggressive reads on large projects used to replace long identifiers with short α-codes plus a §MAP: decode table (symbol_map_auto, previously auto-on above 50 source files). A tester found the abbreviated form obscured package/symbol names exactly when editing. It is now off by default — set symbol_map_auto = true (or LEAN_CTX_SYMBOL_MAP=1) to opt back in for maximum exploration savings.
  • Editing intents always read the full file (#351, external testing feedback): when the active task classifies as refactor, fix-bug, or generate, auto-mode reads now resolve to full regardless of model tier — you cannot safely edit a file you can only partially see, and an abbreviated/signatures view just forced a follow-up read. Exploration/review intents still compress as before.
  • Per-model cost breakdown in the proxy (#351, external testing feedback): /status now reports a per_model array (requests, estimated tokens saved, and USD saved priced from the shared model table) instead of a single flat number, and discloses that savings are request-side and do not subtract agent re-reads. Token figures remain explicitly labelled estimates.

Upgrade

lean-ctx update                 # recommended (auto-downloads + refreshes shell hooks)
cargo install lean-ctx          # or
npm update -g lean-ctx-bin      # or
brew upgrade lean-ctx

Note: After upgrading via cargo/npm/brew, run lean-ctx setup to refresh shell aliases. lean-ctx update does this automatically.

Full Changelog: v3.7.3...v3.7.3

Don't miss a new lean-ctx release

NewReleases is sending notifications on new releases.