Added
- Jira Cloud OAuth 2.0 (3LO) (#318): authenticate built-in and custom Jira data sources via the standard 3-legged OAuth flow instead of Basic auth + API token. New
lean-ctx provider auth jiraruns the interactive flow (loopback redirect, browser consent, accessible-resource/cloudIddiscovery), persists tokens to~/.lean-ctx/credentials/jira-oauth.json(0600), and auto-refreshes on expiry with refresh-token rotation.lean-ctx provider list/provider logoutround out the surface. The CLI is secret-free: users register their own Atlassian OAuth app and supply the client id/secret via env. Basic auth continues to work unchanged; OAuth is selected automatically when a credential exists orJIRA_AUTH=oauthis set. - Context-pressure triage in the Context Cockpit (#249): the Context Manager moves from observation to triage. The Files in Context table gains sortable Used (re-read count), Last (recency), and Evict columns — the Evict score combines high token cost + long idle + rarely re-read so the best eviction candidate is one click away. A triage banner maps the live pressure band to a concrete next action (Healthy / Elevated → prefer
map+signatures/ High → compress or evict / Critical → evict or handoff pack). The ledger now tracks per-itemaccess_count(backward-compatible via#[serde(default)]). - Offline-first Context Cockpit: Chart.js, D3 and the UI fonts are now self-hosted (no external CDN), so the dashboard renders identically offline and with large sessions; libs degrade gracefully with an inline notice if one fails to load. Added a dashboard-wide ⌘K / Ctrl+K command palette with fuzzy search across every view, quick actions (refresh, theme toggle) and full keyboard navigation, plus an embedded favicon and clearer route labels.
- Friendly first run (UX P0.3): running bare
lean-ctxin an interactive terminal now prints a short quickstart (one obvious next step:lean-ctx setup) instead of silently starting the stdio MCP server and appearing to hang. MCP clients (which pipe stdin, not a TTY) and explicitlean-ctx mcpare unaffected — they still get the server. --helpleads with the essentials (UX P1): aGETTING STARTEDblock (setup/doctor/gain) now sits at the top of the help, above the full reference — newcomers see the 3 commands they need first instead of scanning 150 lines.- Efficiency Epic — resident line-search index:
ctx_searchnow narrows candidate files in memory via a RAM-resident trigram index (core/search_index.rs) before reading them, eliminating the per-call directory walk + full-corpus read. Benchmarked 17×–1000× faster (p50, warm) on a 2000-file corpus with byte-identical recall. Falls back to the walk path when the index is absent/building; opt-out viaLEAN_CTX_DISABLE_SEARCH_INDEX=1. ctx_composetask composer: one call returns extracted keywords, semantically ranked files, exact match locations, and the most relevant symbol's body inline — replacing the typical search→read→outline→read chain.- Benchmark harness (
rust/benches/efficiency.rs+benchmarks/efficiency/): reproducible latency (p50/p95/p99) + token report comparing the walk and resident-index paths, with a recall-parity assertion. - Submodular context packing (
core/context_packing.rs): generic greedy max-coverage selector with a provable1 − 1/eapproximation guarantee (Nemhauser–Wolsey–Fisher).ctx_composenow uses it to inline the non-redundant set of symbol bodies with maximal keyword coverage under a token budget, instead of just the first match. Budget viaLEAN_CTX_COMPOSE_SYMBOL_TOKENS(default 600). - Search index Bloom tier (
core/search_index.rs): monorepos whose trigram postings would exceed the memory budget now build compact per-file Bloom filters (~3× smaller, ~12 bits/trigram) instead of falling back to a full directory walk. Bloom filters have zero false negatives (a superset of true matches thatctx_searchregex-verifies), so recall is identical to the exact tier. TheMAX_FILESceiling rose 20k→200k. Proven by a parity fuzz test (Bloom ⊇ postings for every query) + end-to-end recall test. - Hebbian co-access graph (
core/cooccurrence.rs): a persistent, decaying "files that fire together, wire together" association graph. Files surfaced for the same task strengthen their mutual link (LTP); every update decays all weights (the forgetting curve) and prunes below threshold. Bounded by neighbour/file caps. Becomes an associative retrieval signal over time. - Spreading-activation retrieval (
core/spreading_activation.rs): ACT-R-style associative ranker. Activation seeds at the files a task names and spreads over the project graph (fan-out-normalised, decaying → provably convergent even on cycles), surfacing structurally-close files lexical search misses.ctx_composeruns it over the union of the static import/call graph and the learned co-access graph as a budgeted, additive## Related (associative…)section (LEAN_CTX_COMPOSE_GRAPH_BUDGET_MS, default 1500). - Retrieval eval harness (
tests/retrieval_eval.rs): a labelled benchmark (queries + relevance judgments) measuring recall@k, MRR and R-precision. Gates the associative ranker as regression-free (recall ≥ lexical for every query) with a measured gain (mean recall@3 1.00 vs 0.00 lexical, R-precision 1.00 — it recovers in-cluster files without flooding unrelated ones).
Hardening
ctx_composesemantic ranking is wall-time budgeted (H1): the onlyO(corpus)stage (a cold BM25 build) runs in a cache-sharing worker thread bounded byLEAN_CTX_COMPOSE_BUDGET_MS(default 2500). On overrun the call returns immediately with exact-match + symbol sections and a "warming" note, while the worker finishes warming the resident cache for the next call — the agent loop can no longer stall on a cold index.ctx_composefull-path test coverage (H2): newtests/ctx_compose_scenarios.rsexercises the semantic + exact-match + symbol pipeline on a real mini-corpus and asserts the tight-budget degradation path never stalls.- Instruction token cap is priority-aware (H3): the compression/output-style guidance suffix is now protected from truncation; only the variable session/knowledge/gotcha blocks are shed when the 1200-token cap is exceeded. Previously a large on-disk session could silently drop the agent's output-style contract.
Changed
lean-ctx configpoints to the simpler surface (UX P2): the full config dump now ends with a tip towardconfig show(the 5 high-level knobs) andconfig set <key> <value>, so the 100+ keys no longer feel like the only entry point. The simplified config template (config init) now defaultscompression_level = "lite", matching the new friendly default.- Friendly-by-default output style (UX P0): the default
compression_levelis nowlite(plain-English "concise" guidance — bullets, no filler) instead ofstandard(the symbolic dense style). New users, and anyone opening their generated rules files or inspecting the MCP instructions, now see readable directives rather than the→ ∵ ∴vocabulary orCRP MODE. The denser symbolic "power modes" stay one line away (compression_level = "standard" | "max", orLEAN_CTX_COMPRESSION). This only shapes the model's prose; tool-output compression is governed separately and is unchanged — engine efficiency is unaffected. ctx_readauto-mode delivers task-relevant bodies: inmap/signaturesmode with an active task, the body of the best-matching symbol is inlined, avoiding a follow-up full read. Themapheuristic threshold was raised 3000→6000 tokens, and the redundant double disk read in auto-mode selection was removed (cached token counts are reused).- Alpha/§MAP symbol substitution is now off by default for agent-facing output (it traded per-call bytes for agent decode work). CLI/batch pipelines can opt back in with
LEAN_CTX_SYMBOL_MAP=1. - Resident graph-index cache (
core/graph_cache.rs):try_load_graph_indexreuses a deserializedProjectIndexfrom RAM, instead of re-reading + decompressing + parsing on every graph query. - BM25 + graph caches use a
(mtime, size)content fingerprint instead of mtime alone: coarse (1–2 s) filesystem mtime could miss a same-second background rebuild; pairing it with the file size catches those rewrites without the cost of hashing a multi-MB index on every per-query freshness check. A rebuild is still picked up immediately within the TTL window.
Fixed
- CLI
--helpbanner tool count no longer drifts (UX P0): theN MCP toolsfigure in the banner is now derived from the live registry (server::registry::tool_count()) instead of a hardcoded literal — it read61while the README and feature catalog already said63. A unit test pins the banner to the registry count so the three figures can never diverge again. - Instruction token-cap truncation was O(lines) tokenizations —
truncate_to_token_capre-counted tokens once per line while walking back from the end. On large session/knowledge blocks this is wasteful, and it timed out the coverage job's ptrace-instrumented run. Replaced with a binary search over line boundaries (O(log lines) tokenizations, identical output). - CI:
dropin_install_testsfailed on shell-less runners (regression from #309): the new "is the shell installed?" guard skips writing zsh hooks when nozshbinary is present, but the drop-in install tests assert the hooks are written — so they failed on the zsh-lessubuntu-latestrunner. AddedLEAN_CTX_SHELL_HOOK_FORCE(1/true/allor a comma list likezsh,bash) to force hook installation regardless of detection — useful in minimal containers / custom images, and the seam the tests use to stay host-independent. ctx_editconcurrent-edit timeout under multi-agent load (#320): the global cache write-lock was held across the entire disk I/O of an edit, so a second agent editing a different file could time out waiting on the first. Edits now serialize per file via a sharedcore::path_locksregistry, perform disk I/O with no global lock, and take the global cache lock only briefly to apply the resulting cache effect. Concurrent edits to different files now run in parallel; edits to the same file remain correctly serialized.- Eval harness reported zero recall on Windows:
recall_at_k/mean_reciprocal_rankcompared retrieved paths (OS separator,\on Windows) against expected fixtures (/) withends_with, so every comparison missed and recall/MRR collapsed to 0 on Windows. Both sides are now normalized to/before comparison. - Flaky CI on Windows: made the
ctx_treetoken-savings test deterministic via a synthetic fixture (instead of walking the live repo, whose size + path tokenization varied by platform), and de-flakedspawned_background_task_doesnt_block_callerby polling for completion with a generous deadline instead of a fixed sleep.
Hardening
- Per-file advisory lock registry (
core/path_locks.rs): a process-wideper_file_lock(path)shared byctx_readandctx_editserializes access to the same file without contending on a global lock, with bounded GC of unused entries. Lock-ordering documentation (LOCK_ORDERING.md) updated accordingly.
Refactoring
config/mod.rssplit: extracted the enum surface (TeeMode,TerseAgent,OutputDensity,ResponseVerbosity,CompressionLevel,RulesScope) intoconfig/enums.rs, trimming ~250 lines from the module.- Premium
lean-ctx wrappedartifact: the shareable text summary is now TTY-aware with ANSI colouring, box drawing and a savings sparkline (plain text when piped /NO_COLOR).
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.6.25...v3.6.25