Added
- CodeBuddy AI platform support (#423) — CodeBuddy joins Claude Code / Codex
as a first-class agent: detection,init/setup/uninstall, MCP wiring
at~/.codebuddy/mcp.json, dedicated rules injection, and the same path-jail
protection as.claude/.codex(~/.codebuddyinIDE_CONFIG_DIRS, the
broad-root guard, and the home/agent-dir checks). Thanks @studyzy. - Structure-first cold reads (
structure_first, #361) — an opt-in bias (off
by default; envLEAN_CTX_STRUCTURE_FIRST) forautoto prefermapon a
cold read of a medium-sized source file. It is the one read saving that
survives a phase-isolated harness (no warm-session re-read to amortise a full
read) and is capability-safe: the active-diagnostic / edit-fail / small-file
guards still forcefull. gainnow reports net-of-injection bill impact (#361) —lean-ctx gain
(andgain --json) surface the observed proxy turns, the total injected
overhead (per-turn tax × turns) andnet_tokens_saved(which can go negative
and says so), so the meter reconciles to the provider bill instead of a
tool-local ratio. The proxy persists its request count to make this honest.- Faithful benchmark arm config (#361) —
bench/agent-task/r2/ships a
zero-injection, capability-safe lean-ctx arm (rules_injection=off, minimal
tool profile,structure_first, proxy on with cache-aware pruning) plus the pi
extension config and proxy env wiring, so an independent benchmark runs
lean-ctx "installed = running as designed".
Changed
- Suspect files are never compressed away on a fix task (#361) — when the
task text explicitly names a file (e.g. "fix the sort in versioncmp.c"),auto
now forcesfullfor that file ahead of any compression-favouring intent, so
the agent always gets the body it needs to localise and edit the defect. - The proxy protects build/test fidelity and foreign tools (#361) — a
generic/foreign shelltool_resultthat looks like a build failure or test run
is preserved verbatim at the wire (compiler errors, panics and test summaries
kept intact), and vendor-prefixed tools (forge_read,pi.shell, …) are now
classified by name segment so a foreign source read is protected and a foreign
shell log is compressed. Request-body compression is deterministic, keeping the
provider prompt-cache prefix byte-stable. - The pi extension can route shell through
ctx_shell(#361) — a new
routeShellopt-in (envLEAN_CTX_PI_ROUTE_SHELL, implied byreplacemode)
suppresses the nativebashbuiltin so build/test/log output is compressed and
metered (lossless for signal), while the read/list/search builtins stay
available alongsidectx_*.
Fixed
[archive]could exhaust host RAM and force a reboot (#417) — archived
tool outputs (.txt+.meta.json+ SQLite FTS) were written on every large
call, but the configuredmax_disk_mb/max_age_hourslimits were never
enforced:archive::cleanup()had no production caller and the FTS cap deleted
only DB rows, orphaning the (much larger).txtblobs. The store therefore
grew unbounded on disk and starved the host of RAM via the page cache.
cleanup()now enforces both the age TTL and the on-disk size budget, prunes
the content files and FTS index together (no more orphans), runs at MCP start
and periodically off the hot path, andlean-ctx cache prunereclaims the
archive too.doctorreported the proxy as broken on Windows (#416) — proxy autostart
has no backend on Windows, sodoctortreated its absence as a hard failure
(a permanent 27/28). The proxy check is now platform-aware: a reachable proxy
is green, an unreachable proxy on a platform without autostart is a warning
(runlean-ctx proxy start), and "running but autostart not installed" is a
warning rather than a failure on macOS/Linux.setupreported compression settings it never saved (#415) — the wizard
printed "✓ Compression: …" before writing and swallowed the write error, so a
failed save still looked successful. Success (and the rules-prompt injection)
is now reported only after the config is actually persisted.doctoralso
displayed "power" for an unpinned install; it now correctly reports
"lean (default)".- A data dir split across two trees could not be merged (#414) — when both a
legacy (~/.lean-ctx) and an XDG tree held astats.json, the old migration
bailed anddoctorpointed atlean-ctx setupinstead ofdoctor --fix.
doctor --fixnow consolidates every non-canonical data tree into the
canonical one (newer file wins, never clobbering a newer copy) before the XDG
split, the hint points to the right command, and$XDG_DATA_HOME/lean-ctxis
included in split detection. - JetBrains plugin now ships as a downloadable GitHub Release asset (#418) —
the plugin.zipis built and attached to every release. It was missing from
v3.8.5 because the plugin'sRelease Assetjob only ran onreleaseevents,
which aGITHUB_TOKEN-created release never triggers. The plugin version is now
single-sourced ingradle.propertiesand mirrors the engine release via
-Pversion=<tag>, so it can no longer drift (it had been stuck at 3.8.3). - The wake-up briefing listed dead and foreign agents (#419) —
ctx_overview
read the rawAgentRegistry, so it showed peers from crashed or exited MCP
processes (and from other projects). It now prunes stale entries
(cleanup_stale) and scopes the list to the current project root, matching
whatctx_agent listand the dashboard already do. ctx_readmap/signatures served pre-rebuild output (#420) —lean-ctx graph build --forceandlean-ctx index build-fullonly dropped the in-process graph
cache, but a running daemon kept serving stalemap/signaturesfrom its
long-livedSessionCachein another process. Both commands now also flush the
daemon's read cache over IPC (never auto-starting one), so derivations
re-derive on the next read.ctx_multi_readignoredautomode (#421) — batch reads forced
auto→full, so every file came back fully expanded regardless of the active
profile.ctx_multi_readnow honoursautolike a singlectx_read, resolving
the optimal mode per file. Tool descriptions, schemas and the injected rules
(bumped to v12) now steer agents to omitmode(=auto) and reservefull
for the read immediately before an edit.ctx_semantic_searchwas hidden in the default profile (#422) — the
meaning-based search tool was categorised underMemoryand absent from the
lean core set, so it never appeared in the default ("lean") gate. It is now a
Core tool and part of the advertised core surface; the setup/doctor tool counts
are derived dynamically instead of a hard-coded "13".- A cold read could cost more tokens than the raw file (#361) — an
independent benchmark measuredctx_readauto-mode payloads up to +21.6%
larger than the source on a small codebase: on a tiny file the one-line
framing header (file ref + deps/exports summary) is net overhead that only
amortises across re-reads, and the CLI one-shot path used a divergent resolver
that lacked the small-file guard.ctx_readnow enforces a hard anti-inflation
invariant — a read never returns more tokens than the raw file. When
framing would exceed the bare content (auto-resolved orfullreads) the file
is shipped verbatim, so a read is break-even at worst and a win whenever a
compressed mode or cached re-read applies; an explicitly requested view
(map/signatures/lines:) is always honoured untouched. The same guarantee
now covers the additive one-shot CLI path, which also routes through the
unified auto-mode resolver. Re-reads are unaffected (the cache keys on path and
re-derives the file ref). Follow-up:mapmode no longer repeats exports the
API:section already lists with full signatures — the same symbols were
emitted twice (once as a bareexports:line, once inAPI:). A shared
exports_not_in_signatureshelper now drives the MCP, CLI and benchmark map
renderers, so every export is shown exactly once (re-exports/const aliases the
API can't capture still surface) and the scorecard measures the deduped output
agents actually receive. - A knowledge store could grow to 2× its fact cap on import (#417) —
remember()hard-caps a project's facts atmax_facts, but the bulk
import_facts()path still used the oldmax_facts * 2guard, so a
merge/import could inflate a store to twice its budget before any eviction
fired (observed live as adoctorcapacityCRIT, e.g. facts 232/200). The
import path now runs the memory lifecycle as soon as it exceedsmax_facts,
draining the excess by importance (archived, not lost). The eviction invariant
now holds on every write path (remember,import, persist-merge). - Knowledge stores for deleted projects accumulated forever (#615) — a store
atknowledge/<hash>/is keyed to aproject_root; when that root is deleted
(a removed git worktree, a thrown-away project) the store can never be written
again, so its eviction cap can never self-heal and it lingers as pure disk
bloat (one such store surfaced live as a permanentdoctorcapacityCRIT).
lean-ctx doctornow reports orphaned stores and the reclaimable size,
lean-ctx cache prunereclaims them (alongside BM25/graph/archive), and
doctor --fixprunes them as part of a repair. Detection is conservative — a
store with an empty (legacy/global) root or a still-existing root is never
touched, and only the explicit prune commands delete (never the background
lifecycle), so a temporarily-unmounted drive can't trigger data loss. auto_update_mcp = falsewas ignored by the hooks-layer MCP writers (#281)
— the hooks integration still registered and rewrote MCP server entries even
whenauto_update_mcpwas disabled, contradicting the setting's contract. The
hooks-layer writers now honour the flag on every path, so a user who opts out
of automatic MCP registration is respected (the proxy/daemon paths already
did).
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-ctxNote: After upgrading via cargo/npm/brew, run
lean-ctx setupto refresh shell aliases.lean-ctx updatedoes this automatically.
Full Changelog: v3.8.6...v3.8.6