Skip to content

Releases

v3.12.5

Choose a tag to compare

@github-actions github-actions released this 14 Nov 20:23
415131f

Added

  • Configurable multi-repo root limit (#2237). ctx_multi_repo still admits 16 roots by
    default; max_roots in multi-repo.toml or LEAN_CTX_MAX_ROOTS (which wins) raises it,
    up to a hard ceiling of 256. An invalid value is ignored. Roots a saved multi-repo.toml
    or --root lists always load (up to the ceiling), so a process without the env cannot
    drop them and then overwrite the file. The add_root error names both
    settings, list_roots shows the limit, and save_config keeps max_roots and rrf_k
    that are already in the file.

Fixed

  • A knowledge category can be listed whole through recall (#2248). ctx_knowledge action=recall category=<c> showed at most recall_facts_limit facts (showing 10/41) with
    no way to reach the rest, and only listed facts are refreshed against decay. The call now
    takes limit (up to a hard ceiling of 200) and offset; the header names the window
    (showing 11-20/41) and, while facts remain, the next offset. lean-ctx knowledge recall --category <c> takes --limit and --offset. Every fact a window returns counts as
    recalled, as before. memory.knowledge.recall_facts_limit in a project's .lean-ctx.toml
    sets that project's default window; a regression test now covers it. Query and bare recall
    are unchanged. Reported by @antojk.

  • ctx_multi_repo search across several roots (#2244). With two or more roots every
    search failed with "search source authority changed or is unavailable": one source view
    was held for the whole search while each root's index re-bound the request to its own
    project. Each root is now searched under its own project's view and content policy; a root
    withheld by its policy, or whose authority cannot be resolved, is named in a warning and
    the others still answer. A requesting project under an active policy still refuses the
    whole search, checked before and again after the roots are read. list_roots says "index loads on first search" instead of
    "pending".

  • Cockpit starts on Windows with a shared %TEMP% (#2203). The Cockpit's private copy
    was staged under %TEMP%\leanctx-runtime-private; when %TEMP% or a folder above it grants
    other users write access (C:\Temp, managed profiles) the private-directory check refused
    it ("DACL grants an untrusted principal write or ownership access") and lean-ctx cockpit
    answered 503. The copy is now staged beside the installed runtime, whose private ACL the
    install already established; %TEMP% is no longer used.

  • Shell gate reads config.toml for directory-service accounts on musl (#2236). The
    static x86_64-unknown-linux-musl build has no NSS, so an account served by SSSD, LDAP,
    NIS or winbind had no home in the account database: the release gate never read the
    user's config.toml and ran on the built-in defaults. When getpwuid_r finds nothing,
    Linux builds now ask getent passwd <uid> (only /usr/bin/getent or /bin/getent,
    root-owned and not group/world-writable, empty environment, 3 s timeout) and accept the
    home only when the line names this uid and an absolute directory. $HOME is still never
    consulted. The lookup is resolved once per process, a failed or timed-out one included: a
    restart retries it. When no home can be found, the block
    message says that no config location exists instead of naming ~/.lean-ctx/config.toml,
    and lean-ctx doctor reports the shell allowlist as running on defaults.

  • ctx_glob walks only as far as the pattern reaches (#2250, thanks @dkiaulakis). A
    pattern with a / and no ** (src/*.rs, .tmp/prefix*) now descends only through its
    literal leading directories and no deeper than its own component count; a leading ./
    anchors a name to the directory's own entries (./prefix*). Recursive walks (**, or a
    slash-free name, which still matches at any depth) stop after 200,000 visited entries and
    say complete=false (walk budget 200000 entries reached); a walk cut short by
    max_results says complete=false (result cap N reached). Ignore rules, confinement and
    secret-path redaction are unchanged.

Security

  • Rule-file backups and the replace_symbol temp file no longer follow a planted symlink
    (GHSA-x992-2945-crwx).
    lean-ctx init --agent and doctor --fix wrote the backups
    AGENTS.md.bak, .cursorrules.bak and .claude/rules/lean-ctx.bak with a plain copy, so a
    cloned repository that shipped such a name as a symlink had the repository's own rule file
    written outside the project (for example to ~/.bash_aliases). The backups now go through
    the confined write, which refuses a symlinked component, and keep the source's permission
    bits. lean-ctx uninstall now writes its <file>.lean-ctx.bak backups of the project's
    AGENTS.md and .hermes.md the same way. The headless ctx_patch replace_symbol path
    staged its edit in a fixed-name temp file and now uses the shared atomic writer with a
    fresh, unpredictable temp file. Reported and fixed by @kasparovabi.

  • quinn-udp 0.5.16 (RUSTSEC-2026-0538). The indirect dependency quinn-udp moves from
    0.5.15 to the patched 0.5.16; its receive loop could spin after a truncated datagram.

  • hono 4.13.18 and @hono/node-server 2.1.8 in the pi-lean-ctx package lockfile
    (from 4.13.13 and 2.1.5; Dependabot #2246, #2243).

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.12.4...v3.12.5

v3.12.4

Choose a tag to compare

@github-actions github-actions released this 13 Nov 01:45
b6de365

Added

  • Policy enforcement acknowledged to Hive (D4). The bus hello now names the features
    policy_advanced and policy_applied, so Hive delivers its policy.advanced nudge (it
    sends that nudge only to Instances that name the feature). Once per version and digest of a
    verified policy that is in force and that Hive acknowledged, the Instance sends one
    policy.applied frame: version, digest, key_id, applied_at and sessions (the live
    app sessions enforcing it). It sends the frame only when Hive's hello.ack.features names
    policy_applied. An expired, outdated or unverified policy is never reported. Local Read
    policy.sessions adds installed.enforcement (applied_version, acknowledged_at,
    sessions, reported_at), additively.

  • ECCP L/I/G change classifier (task 156). scripts/change-class <base> <head>
    prints L (no public Rust item changed), I (public items only added) or G
    (public item changed or removed, Cargo features or dependency tables,
    Cargo.lock, build.rs, Cargo config, toolchain pin, CI configuration or a
    generated registry) from the git objects alone, without a build or network,
    and serves as $ECCP_CLASSIFIER for scripts/eccp-envelope.

  • ECCP change envelope in git notes (task 157). scripts/eccp-envelope writes,
    shows and verifies a leanctx.change-envelope/v1 JSON note under
    refs/notes/eccp on a merge request head: intent, base, class, read set,
    derivations and check evidence (docs/contracts/change-envelope-v1.md).

  • Audit entries v2 bind each tool call to its session (ent3-1). Every new
    audit-trail entry carries v: 2 and a chained v2_hash over its timestamp
    and, for a call of an MCP session, the session_id, a per-session seq,
    the decision and an output digest, so an edited timestamp, seq or fact fails
    verify_chain and verify_chain_full at that entry. Input and output digests
    are HMAC-SHA256 under the engine-local key (hive/receipts.hmac-key, never
    uploaded). The v1 entry_hash is unchanged: older engines and
    leanctx-verify still verify a mixed trail, and an entry of a newer version
    counts as forward-compatible, not as tampering.

  • Managed configuration for MDM-provisioned machines (task 169). An organisation can
    preconfigure an Instance through a macOS configuration profile, the Windows policy key
    HKLM\SOFTWARE\Policies\LeanCTX\Managed or /etc/lean-ctx/managed.toml
    (leanctx.managed-config/v1, docs/contracts/managed-config-v1.md). Managed
    hive.url and hive.root_key win over [hive] and config set on them is refused;
    hive.org refuses an enrollment for another org; hive.require makes tools refuse
    until the machine is signed in and has a policy floor. A carrier that is malformed,
    a symlink, or not root-owned (it or its directory) fails closed; it is checked and
    read through one open handle. hive status and the cockpit hive status --json
    (managed, since 1.7) show the carrier and each member.

  • Unit claims warn before two agents edit the same code. A ctx_patch or ctx_edit
    write claims the functions, types and Markdown sections it touches for the editing agent
    (10-minute lease, renewed on each edit). When another agent holds a claim on a touched
    unit, the write goes ahead and the result names the holder (LEAN_CTX_CLAIM_MODE=warn,
    the default). strict refuses the write before anything is written, and off turns the
    check off. ctx_agent action=claims lists the live claims. action=plan_claims plans a
    task against them, through an optional local planner (LEAN_CTX_CLAIM_PLANNER) or a
    built-in fallback without network, and claims the free units. Claims are released when
    the agent reports status=finished and when the server shuts down.

Security

The first five fixes below were reported by @dkiaulakis.

  • A redirection written another way cannot write past the gate (GHSA-4gm5-2mgw-9r9r). A
    redirection with a file-descriptor prefix, an &>/>|/<> operator, a quoted or escaped
    target, or no space before its target was missed, so an agent shell could write lean-ctx's
    own state or an unlisted file. The gate now reads every redirection in its canonical form
    before any other check.

  • A command inside ( … ) or { …; } is checked like any other (GHSA-9jrf-q94p-frhr). A
    subshell or group was one segment to the gate, whose first word ((eval, (rm) matched no
    rule, and a redirection after the group was dropped. Every group is now opened into its
    commands for the checks, and a redirection after it is checked too; a command in a case
    arm or after then, do, else or coproc is judged as its own command. The line that
    runs is unchanged.

  • The state guard follows the working directory and the values a line builds
    (GHSA-cfmv-qg29-3rvp).
    Repeated or conditional cd .., a cd in a loop, function or trap,
    CDPATH/HOME/OLDPWD assignments, variables assigned or read at run time (also
    ${d:=…} and set -- arguments, also inside a longer word), the shell's own
    $PWD/$OLDPWD/$_ and ~+/~-/~N, brace and parameter expansions, function
    arguments, alias bodies, GIT_DIR-style variables, versioned interpreter names
    (python3.12, node@20), deno eval/bun -e, awk system()/pipes/output redirection
    (also in -e/--source programs; a program read from stdin with -f - or -f /dev/stdin
    is refused) and in-place writers (sed, perl -i, sort -o, gzip,
    patch, split, tar/unzip extraction) could reach lean-ctx's own state unseen. A write
    whose target cannot be placed is now refused (fail closed); read-only commands are unchanged.

  • A read-only git subcommand cannot write lean-ctx's state or run a program
    (GHSA-fv44-pm58-9c8p).
    When git runs at or above lean-ctx's state, log/diff/show/grep
    and the other read subcommands were allowed whatever their options, so --output=…,
    --ext-diff with -c diff.external=…, a -c/--config-env pager, fsmonitor or alias,
    --paginate, --textconv or grep -O could write a file or run a program. Those options are
    now refused there; plain reads such as log --oneline and diff --stat still pass.

  • Context admission never delivers a value the secret detector flagged
    (GHSA-xmx8-69qv-7f86).
    The detector and the redactor read different spans of one
    comparison or key/value expression: the operand with or without the rest of its operator
    (==, :=), with or without a trailing ) or :. The redactor could judge a flagged value
    benign and leave it unchanged, and admission then delivered it as AllowRedacted, because it
    only re-checked text it had rewritten. Both layers now judge the same operand, so a
    comparison operand is masked exactly when its key=<value> form is. Unchanged text is
    re-checked after a reported value too and is withheld (redaction.incomplete) when the value
    is still there. A benign comparison such as if (token==unit_reference): is no longer withheld.

  • Memory compaction, context bundles and rule exports do not write through a symlink
    (GHSA-mq5c-rjv9-2fc3).
    Reported by @kasparovabi. ctx_compress_memory wrote its backup
    (<name>.original.md) and the compacted file, and ctx_pack / lean-ctx pack wrote the
    bundle file, with a plain write after the path jail check. The jail leaves a dangling link
    unresolved, so a symlink a cloned repository shipped could redirect the write to a file
    outside the project. These writes now go through the confined write, which refuses a
    symlinked component below the project root, and a memory file that is itself a symlink is
    refused before it is read. The compacted file and its backup keep the original's permissions.
    The same applies to lean-ctx export-rules (AGENTS.md, CLAUDE.md, CODEBUDDY.md,
    .cursor/rules/…) and to the artifact registry that ctx_artifacts action=remove rewrites.
    A rule file that links to another file, such as CLAUDE.md → AGENTS.md, is now refused
    with an error instead of written through, and a new bundle file is readable only by its
    owner (0600).

Changed

  • Library crates carry new versions. lean-ctx-protocol 0.7.0 adds the Hive model catalog,
    three routing members of the security policy and the models.subscription right, which
    changes its public types; lean-ctx-ocla 7.0.0, lean-ctx-workgraph 0.3.0 and
    lean-ctx-tasks 0.2.0 expose those types and move with it.

Fixed

  • A PowerShell-shaped command with a non-ASCII character no longer panics the shell gate.
    The verb-prefix check sliced the command name at a byte that could fall inside a
    multi-byte character (A-bᲳ); it now compares bytes, so such a name is no match.
  • The cockpit's proof no longer pins a core per session on a large audit trail (#2240).
    lean-ctx value --session read the whole segmented trail into memory and the savings
    ledger twice; it now streams both once, skips segments sealed before the session began
    and lines that cannot name the session. The cockpit proves only in a session whose
    sidebar was drawn (background spare sessions never draw one), backs off up to an hour
    after a failed or timed-out proof, and /cockpit still proves at once. Thanks
    @jenseinar for the report.

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.12.3...v3.12.4

v3.12.3

Choose a tag to compare

@github-actions github-actions released this 11 Nov 22:06
013ddb1

Added

  • Process v1 G6 and checker ≠ author on Hive tasks. Submitting a task that carries
    process now runs the G6 gate in the Instance: the locked tests must be unchanged against
    spec_commit and must actually run and pass in a clean rerun, else the submit is refused
    with the rule and the paths, and nothing is sent. A verify is refused for the session that
    claimed or submitted the result. Tasks without process keep today's path, and no Hive
    serves process tasks yet. Known gap: code under test runs as the agent's Unix user and
    could forge a passing report; details and the planned fix are in the module documentation
    of rust/crates/lean-ctx-hive/src/tasks/process.rs.
    G6 also asks the compiler which locked tests exist at spec_commit (one extra build in a
    private copy; no test of spec_commit runs), so a locked test the parser cannot name
    (macro-generated, #[cfg_attr(test, test)]) must still pass in the judged run. This can
    roughly double a G6 run's time.
    G6 runs on Linux, macOS and Windows. On macOS a kqueue watch notices a renamed or removed
    ancestor of the run tree (as inotify does on Linux). On Windows the run uses Git for
    Windows' sh, an environment built from the known folders and a job object; there the
    tree's ancestors have no rename protection and locked files are pinned by content,
    attributes and write time (details in tasks/gate_run.rs).

  • P4 tripwires: new crate lean-ctx-tripwires. A pure, deterministic diff analyzer that flags the documented reward-hacking tricks (touched tests or graders, removed or weakened asserts, new skips, a falling test count, fixture constants, branches on test inputs, time/hash/assert overrides, swallowed errors, mock-only tests, edit cycles, plus unparsable) and returns a leanctx.process.tripwires/v1 report; a hit routes to a person, never to automatic acceptance. Not wired into the gate yet.

  • Each app session is its own Hive worker (E48). An agent registered with
    LEAN_CTX_SESSION_ID set gets the role <role>-s<tag>, where the tag is 8 base32
    characters of a blake3 hash of the session id. It is stable across MCP restarts, so every Hive
    Desktop session appears on Hive and in the roster as its own worker (coder-s…). A reviewer
    session on the same Instance can now pass Hive's self_verify, while a subagent of the same
    session is still the same worker and is refused. Without a session id the shared
    (host, role) worker is kept as before. One key (attach::agent_worker_key) now drives task
    links, attach, roster, friction and worker accounting. The session id comes from the
    environment, so this separates sessions as hygiene, not as a trust boundary: the boundary
    stays the Instance. Upgrade note: a claim taken before the upgrade by the shared worker
    belongs to a different wkr_, so let it expire or release it and claim again.

  • Meta Muse Code agent target (#2198). lean-ctx init --agent muse and setup register the
    lean-ctx MCP server in $XDG_CONFIG_HOME/muse/settings.json (default
    ~/.config/muse/settings.json). The writer adds the mandatory "schema_version": 1 when it is
    missing, keeps every other key and server, and merges into the root the file already uses —
    canonical mcpServers or legacy mcp_servers — because Muse disables MCP when both appear;
    a file that already mixes them is left untouched with an error. Re-runs are no-ops, uninstall
    removes only the lean-ctx entry, and doctor checks the entry. Muse Code is MCP-only: its
    PreToolUse output schema is closed and an allow never skips approval, so shell rewrites would
    add prompts. Guidance reaches it through the project AGENTS.md it auto-loads.

  • Task priority: the boards carry the order of work. A task's priority (high |
    normal) and labels (up to 16 of [a-z0-9-]{1,32}) are set with
    lean-ctx hive tasks priority <n> high|normal / labels <n> a,b|--clear (C0 2.2 E47
    PATCH at the task's fields_version, read again and resent once on stale_base), from
    Hive Desktop over /v1/local/hive/tasks/{n}/priority|labels (tasks.ack), and by a Queen
    session with ctx_tasks action=prioritize. Local tasks take the same verbs
    (lean-ctx tasks priority|labels, /v1/local/tasks/{n}/priority|labels, event
    fields). Lists show high first, then by number, an older high task included (the high
    tasks are fetched beside Hive's newest-100 page); a list a full Hive answer may have cut
    is marked partial (JSON partial: true, a (partial: …) line in text). JSON
    rows carry priority, labels and fields_version. A wrong value is refused before any
    request. Only a person (the app, the person's own CLI) and Queen sessions the app
    registered over the local socket (/v1/local/queens, socket only) set them; workers read
    them. A self-declared bus role is never enough.

  • The bus refuses approvals in a person's name (process v1 §7). ctx_agent post and
    send refuse an agent's message, with a named rule and nothing rewritten, when it
    speaks for a person (on_behalf_of, 400 invalid_field: the on_behalf_of field or
    "on behalf of …" / "in the name of …" in its text), states or hands off a person's
    decision (approval_on_behalf, 403 forbidden_right: decision fields with a person as
    decider, a handoff of an Inbox item, consent, G2/G9/G10 approval, release, deploy,
    secret or rights decision, or a sentence such as "the owner approved …"; questions,
    negations and "waiting for" never match), or passes on what was refused for the sender
    (denied_forwarded, 403 forbidden_right: a place Hive denied, a publish Hive refused,
    a vetoed lock or handoff). These three are always enforced. The checks cover questions,
    answers, offers and handoffs; status, progress and finding posts are not checked.
    The relay applies the same rules to older queued posts and keeps a post that breaks
    them local (counted as withheld). Publishes the Hive refuses are remembered per sender
    in the new bus/refused.json (7 days, at most 1000), so no agent passes them on. Only a
    registered Queen session appears as the Queen: under the new [hive] queen_identity
    (warn | enforce, env LEAN_CTX_HIVE_QUEEN_IDENTITY, which wins) the default warn
    passes a sender presenting as the Queen (role queen, the name "Queen", a "From the
    Queen:" label) that is no registered Queen session, puts
    [unverified Queen sender: <name>, agent <id>, role <role>] in front of its text and
    logs it in the new bus/queen-warnings.json; enforce refuses it, and any other value
    counts as enforce. Switch to enforce only once queen-sessions.json lists every
    Queen session: Queens on another machine are not registered with the host yet. Not
    covered yet: app session messages (hive_message_session, an app tool, not the bus).

  • Rights per session (process v1 §9). The launcher (Hive Desktop) writes one rights file
    per session (leanctx.session-rights/v1) and starts the session with the new
    LEAN_CTX_RIGHTS_FILE=<absolute path>. It narrows what that session may write, below the
    Instance's own path jail: writes only inside the role's write scopes, such as its own
    worktree (write_scope); after G2 no role, the Spec Writer included, writes a locked path
    (the feature list, a locked test, a directory or hard link holding one;
    feature_list_locked); a deny_write class refuses (deny_write:<class>); the rights
    file itself is never written (rights_file); denied_tools refuses a tool, aliases
    included (denied_tools). It applies to ctx_shell/shell (a command whose writes
    cannot be judged is refused: unanalysable), ctx_execute, LeanCTX's own writes, the new
    lean-ctx hook rights for native Edit/Write/MultiEdit/NotebookEdit/Bash/
    apply_patch (an unknown native tool is refused: unknown_tool), and calls forwarded to
    the daemon, which carry the file as the new /v1/tools/call field rightsFile (local
    socket only, else 400 rights_file_refused; a profiled session may not use the daemon
    socket itself: daemon_socket). Every refusal names its rule. Reads are not narrowed. A
    rights file that is set but missing, unreadable, insecure or invalid refuses every tool
    call and every write; it never falls back to the Instance's rules. No rights file set
    means no change:
    the Instance's rules apply as before. This is a best-effort first line;
    the guarantee is the G6 locked-path check, and the known limits are listed in the module
    doc (rust/src/core/session_rights.rs).

  • Local Read / Local Service contract for LeanCTX | Hive Desktop. Every Local Read kind
    is a versioned JSON document on the CLI and a /v1/local route of the daemon socket,
    released with one receipt for the bytes sent, and listed in one capabilities document
    with every verb and the transports that answer it (docs/contracts/local-read-v1.md,
    local-service-v1.md): session stats and cost per LEAN_CTX_SESSION_ID, gain/spend
    rollups (daily and per project), the agent bus (bus list|read|post|leases|claim|release),
    presence list, knowledge writes, evidence verification and export, providers, effective
    policies with the organization policy's signature state, agents, and the new
    lean-ctx daemon status --json (running, pid, socket, autostart, service_name).

  • Sync and policy evidence on the local service. hive.sync, policy.sessions and
    policy.session, CLI-only before, are served on the daemon socket at /v1/local/hive/sync,
    /v1/local/hive/policy/sessions and /v1/local/hive/policy/sessions/{id}, released through
    the same release point (one receipt) and listed in capabilities. policy.sessions
    installed adds vaults: one row per vault the installed policy reaches on this machine
    (vault_id, ns, name, linked roots) and which policy applies (vault, default, or
    `unver...

Read more

v3.12.2

Choose a tag to compare

@github-actions github-actions released this 05 Nov 07:05
ffe6e95

Added

  • LeanCTX | Hive is open. lean-ctx hive connect and hive link connect an instance to
    hive.leanctx.com (or a self-hosted Hive), and hive is back in help, suggestions and
    completions; 3.12.0 and 3.12.1 shipped the connector switched off.

Security

  • Write destinations stay inside the project without a Workspace (GHSA-483j-9vcj-2gxx).
    ctx_package save, ctx_pack export, the ctx_edit/ctx_patch backups, ctx_checkpoint restore and the ctx_knowledge export wrote to the path the model passed, so an absolute or
    ../ path left the project in the default configuration. A write destination now goes
    through the path jail with or without a Workspace; reads are unchanged. Reported by
    kasparovabi.

Fixed

  • A directory granted with lean-ctx allow-path is walkable (#2190). ctx_search,
    ctx_tree and ctx_glob refused a granted folder below a protected home location such as
    ~/Library although ctx_read read its files. A walk inside a granted directory now runs;
    a grant never makes home, a filesystem root or a privacy-guarded home folder walkable.
  • A dogfood or release-candidate build updates to its release. The update check read
    3.12.1-dogfood.9 as 3.12.9 and answered "already up to date"; a prerelease now sorts
    before its release, as in SemVer.
  • Updates no longer switch an existing setup to the governor, and 3.12.1's switch is
    undone.
    The 3.12.1 update moved every unpinned Claude Code, CodeBuddy, Cursor, Codex,
    Gemini and Copilot CLI setup to the governor without the lean-ctx MCP server. An update or
    setup refresh now keeps the MCP, hybrid or replace setup it finds. A host that 3.12.1 switched
    automatically (a *.pre-governor-<version>.bak backup or an interrupted migration, and no
    governor pin) gets its previous mode back on the next lean-ctx setup, lean-ctx update or
    init --agent <host>. The mode is read from the backup and pinned. init --agent <host> --mode governor|governor-mcp now pins that choice too, so the repair leaves it alone.
  • New Claude Code installs get governor-mcp. Governor hooks plus the lean-ctx MCP server
    with deferred tools, so Hive, the agent bus and knowledge work from the first session. New
    installs of the other hosts get the standard MCP setup.
  • Claude Code always keeps a search tool. The standard setup denied native Grep/Glob even
    when ~/.claude.json had no lean-ctx MCP server. That happened after the 3.12.1 migration,
    when a server or daemon of the previous build re-rendered the standard hooks, and sessions
    then had neither native search nor ctx_search. The deny is now written only together with
    the MCP entry, and a refresh removes it when the entry is missing. lean-ctx doctor reports
    a pinned standard mode or a native-tool deny without the MCP server, with the repair command.
  • An older binary no longer overwrites a newer setup. Every explicit setup and init records
    its version. The silent hook refresh of a server or daemon still running from before an update
    leaves the setup alone when a newer build wrote it.
  • A host pin selects the mode of later refreshes. [governor] pinned.<host> (written by
    init --agent <host> --mode <m>) is honoured by every setup and refresh path, not only by the
    governor default.
  • gain and the cockpit count the governor's applied savings. Applied R1.bash, R2 and R4
    decisions are recorded as governor:<rule> savings; shadow decisions still count nothing.
    R1.read already did.
  • Test processes of every LeanCTX crate stay off production endpoints. The guard that
    sends test traffic to a loopback sink recognised only the Engine's own unit tests and
    processes cargo launched for the Engine or lean-ctx package. Since the crate split, the
    unit tests of the server, Hive, hooks and proxy crates, and the binaries they spawn, sent
    telemetry to production, each as a new installation. Any process of a lean-ctx… or
    leanctx… package, and every sandboxed unit-test harness, now gets the loopback sink; an
    installed binary keeps its configured endpoint.

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.12.1...v3.12.2

v3.12.1

Choose a tag to compare

@github-actions github-actions released this 04 Nov 10:08
0f0297e

LeanCTX | OSS 3.12.1

A security and governance release. Shell, file and Hive paths now fail closed: the shell gate checks every command it lets through, its policy can no longer be changed from an agent's own environment, and native Read/Grep follow the secret-path rule. LeanCTX on a machine is now an instance, and it speaks Hive-Protocol 2.2 with LeanCTX | Hive.

Full list: CHANGELOG.md.

Highlights

  • Governor setup by default on Claude Code. New installs get native tools plus two hooks (hook govern, hook rewrite-enforce) and no MCP server: about 86 tokens of fixed prefix per turn instead of ~2,950. Measured ×0.88 against native Claude Code on long conversations. Existing setups switch once on update, with backups. lean-ctx init --agent claude --mode hybrid keeps the ctx_* tools, and that choice is pinned. CodeBuddy, Cursor, Codex CLI, Gemini CLI and Copilot CLI get the same default.
  • Governor rule R4 groups large Bash output whose lines differ only in numbers, timestamps or ids. The exact original stays in the archive (ctx_expand). Errors, tracebacks and diffs stay verbatim. Shadow by default.
  • ctx_read symbol="name" reads one function or class. A read without a range returns files up to 300 lines whole and larger files as an outline capped at ~1,500 tokens.
  • ctx_shell asks before refusing an unlisted program: allow once, for the session, always, or deny, in your AI tool's approval dialog.
  • Opt-in: long-session elision in the proxy. Once a Claude Code conversation passes ~180 kB (~50k tokens), the proxy can replace old tool outputs (over 2 KB, older than the last 8 messages) with a short note that names the archived full text. It is off by default: measured on Claude Code with Haiku 5.5 over three runs (44 long tasks per arm), it cut cost to ×0.67–0.92 against native but solved 37 of 44 tasks against 42 of 44, when the model answered without reading back an elided early output. Turn it on with [proxy] long_session_elide = true or LEAN_CTX_PROXY_LONG_SESSION_ELIDE=on.
  • lean-ctx hive docs import --markdown turns docs into LeanCTX | Hive pages, one section per heading, re-revising only what changed.
  • Hive-Protocol 2.2. Agents check each other's task results (ctx_tasks action=verify). A connected instance now carries corrections, supersedes and withdrawals of its facts to the vault.
  • emspace spaces work without setup. ctx_read names the page that documents a file, and ctx_provider reads one page section.
  • Knowledge has no fact limit. Facts leave memory only by quality. The knowledge store keeps a change journal (ctx_knowledge action=changes).

Security

  • Shell gate: every command the hooks let run without the lean-ctx -c wrap is now checked: heredocs, lean-ctx … prefixes, && chains with reads, Mistral Vibe, Codex, Copilot and PowerShell. Release builds take shell-security settings only from the built-in defaults and ~/…/config.toml, never from LEAN_CTX_SHELL_*, HOME or XDG_* set by the agent. lean-ctx calls from an agent's shell follow an allowlist. Over-long or too deeply nested commands are refused instead of crashing the hook.
  • Approvals mirror your AI tool. The hooks no longer answer "allow" for every call. They allow only what the host's own permission settings would have run without asking.
  • Native Read and Grep follow the secret-path rule on Claude Code, CodeBuddy, Cursor, Copilot CLI and Gemini CLI.
  • PathJail writes stay in the active project by default (path_jail_scope = projects). ctx_multi_repo add_root passes the jail. Project policies can no longer drop the built-in exclusions for .env*, keys and credentials.
  • Signatures are verified against a trusted key: context capsules, every signed audit-trail entry, context packages, addons and compliance verify. --allow-untrusted-signer restores the old check where it applies.
  • Hive: hive connect sends nothing before your yes and lists exactly what it shares. A broken screening rule pauses Hive content instead of letting it through. Fencing tokens are no longer printed.
  • Installers: the skill's curl | bash installer verifies SHA256SUMS. A Cockpit bundle with two checksum entries is refused. npm install lean-ctx-bin@X installs engine X. The Hermes plugin pins lean-ctx-client.
  • Secrets off command lines: serve --auth-token-file, serve --a2a-signing-key-file, cockpit --auth-token-file. The signing keychain password goes over stdin.
  • Local surfaces: dashboard requests that name a project are answered for that project or refused. The Windows daemon pipe and the daemon socket are owner-only. report-issue redacts secrets. Role, policy and workflow refusals are tool errors (isError: true).

Upgrade notes

  • Behaviour changes: native reads of secret-like files (for example *.pem test certificates, .npmrc) are denied under the default role. Allow them through io.allow_secret_paths. Shell-security options belong in config.toml, because LEAN_CTX_SHELL_* and LEAN_CTX_PROFILE=… lean-ctx … from an agent's shell are ignored or refused. lean-ctx config set path_jail_scope home restores the 3.11 jail. See the upgrade guide: docs/guides/upgrade-3.12.md.
  • Claude Code switches to the governor setup on the next update, once per version, after backing up settings.json, ~/.claude.json, CLAUDE.md and the config. Pin another mode with lean-ctx init --agent claude --mode hybrid|replace|mcp.
  • LeanCTX | Hive: this release speaks only the instance naming (C0 2.2), and no earlier release connects to Hive. Hive's TOML org policy is no longer read.
  • New crates on crates.io: the engine is split into lean-ctx-engine, lean-ctx-hooks, lean-ctx-hive, lean-ctx-server and lean-ctx-proxy, with the CLI crate lean-ctx on top (all 3.12.1). Also new: lean-ctx-compress, lean-ctx-fs, lean-ctx-patterns, lean-ctx-syntax, lean-ctx-workgraph and lean-ctx-doc (behind ctx_doc), all 0.1.0. leanctx-native-storage stays unchanged at 0.1.1. Breaking for direct users: lean-ctx-protocol 0.5.0 and lean-ctx-ocla 5.0.0. cargo install lean-ctx works as before.
  • Removed: Hive swarms and Task Compute, sealed vaults, human review of Hive knowledge, episodic and procedural memory, the optional LLM enhancement layer and learned auto modes. lean-ctx autopilot policy and autopilot evidence --learn are deprecated no-ops. Details are in the changelog under Removed and Deprecated.

v3.12.0

Choose a tag to compare

@github-actions github-actions released this 29 Oct 15:52
e8afaec

🚀 LeanCTX 3.12.0: meet the Cockpit

The LeanCTX Cockpit: Savings view
The new Cockpit, Savings view. Our own dogfooding numbers since Oct 17: every figure is measured from the signed savings ledger on this machine.

3.12.0 brings the LeanCTX Cockpit: one local place for everything LeanCTX does for your agents. What it kept out of the context, what it cost, what it protected and what it can prove. It is free for everyone, runs only on 127.0.0.1, needs no account, and installs itself.

lean-ctx update      # then start any agent session; the Cockpit installs itself
lean-ctx cockpit     # opens it in your browser

✨ The Cockpit

  • One place for savings, spend and proof. lean-ctx cockpit (or lean-ctx dashboard) starts in the background, reuses a running instance, picks a free port and stops with lean-ctx cockpit stop.
  • Your familiar commands open it. On a terminal, lean-ctx gain, gain --web, gain --live, watch, wrapped and cockpit --export open the matching view. Scripts, CI, --json and --terminal keep their text output exactly as before.
  • Every page, free, no plan checks.
    • Cockpit shows protection and open findings side by side.
    • Savings, Spend and the Ledger of every call.
    • Report.
    • Numbers explained, with every formula and price source.
    • Security, Context, Sources, Agents, Proof, Decisions.
    • Memory, Packages, Inbox and Improvements.
  • Honest numbers. Every figure carries a trust label: measured, estimated, evidenced or derived.
  • Installs itself, signed and verified.
    • A fresh install with install.sh, PowerShell, npm or Homebrew ships it.
    • An update from 3.11 and AUR's lean-ctx-bin get it at the next agent session, without a command.
    • Every package is checked against the LeanCTX signing keys before it runs.
    • Opt out with LEAN_CTX_NO_COCKPIT=1.
  • Light and dark, desktop to phone.

📚 Knowledge from your repository

  • lean-ctx import docs turns AGENTS.md, CLAUDE.md, .cursorrules, .cursor/rules and docs/ into project facts, each anchored to its file and section.
  • lean-ctx import git learns decisions, fixes and dead ends from your commit history. It reads no diffs and no authors.
  • Every fact passes the same secret and personal-data screening as any other import.
  • lean-ctx knowledge export-agents-md --write writes them back as a marked section of AGENTS.md.

🔒 Security: eight advisories fixed

Thank you to everyone who reported them responsibly.

🧭 Focus

3.12.0 keeps what selects, controls and proves context, and drops what measured no benefit.

  • 36 rarely used MCP tools are removed. Calling one names its successor.
  • The hosted services that needed an account close. Personal Cloud ended today: its routes answer 410 personal_cloud_ended, your local data is unaffected, and the stored data is deleted 30 days after release. Existing hosted team servers keep running until their teams move to LeanCTX Hive with 3.12.1.
  • The local Engine and the whole Cockpit stay free.
  • LeanCTX Hive, shared knowledge for teams and your own machines, follows with 3.12.1.
  • Upgrade guide: docs/guides/upgrade-3.12.md. Focus changes: docs/migration/focus-2026-10.md.

🪟 Also in this release

  • Windows: checkpoint packages, imports and source re-checks work again, and so do file locks and atomic file replacement.
  • Semantic search without ONNX Runtime: the new built-in potion-code model runs in pure Rust.
  • Pi and Oh My Pi are recognised as AI clients.
  • You choose which AI tools setup configures, and updates stay inside that choice (--dry-run shows the plan).
  • Dependencies: zip 9.0.5 (critical advisory GHSA-m665-v7pm-7grj), rustls 0.23.46 and @hono/node-server 2.1.5.

Full changelog (every change, breaking changes, removed features)

Focus release. The local Engine and the whole Cockpit are free and local, with no
account and no plan checks; the hosted services that needed an account close. LeanCTX
Hive (shared knowledge for teams and your own machines) follows with 3.12.1. LeanCTX also keeps what
selects, controls and proves context and drops what measured no benefit. 3.12.0 includes
every change prepared for 3.11.5, which is not released separately. Upgrade notes:
docs/guides/upgrade-3.12.md (retired services) and
docs/migration/focus-2026-10.md (focus changes,
successor tools and restore lines).

Breaking changes at a glance: Personal Cloud, the ctxpkg.com registry and the hosted
per-customer team servers close on the 3.12.0 release day (writes stop, the services answer
410) and their stored data is deleted 30 days after release, without migration; the
engine's cloud client, the login, register, account, sync, cloud, team and
enterprise commands, remote pack install|update|publish and addon add ns/name are
removed; hosted Wrapped publication, the leaderboard, the README badge and the billing CLI
are gone; the capability registry is schema 3 (price classes hive and retired); the
built-in personal-data detectors are email, phone and payment cards. From the focus work:
36 MCP tools are removed (34 retired plus ctx_intent and ctx_task; a call names the
successor); the Autonomy Drivers, Workflow Evidence Ledger, Intent Route,
invocation-context-binding, invocation-evidence-manifest and tokenizer-translation-driver
contracts are withdrawn; ctx_work_graph action="execute" and lean-ctx pair are removed
(the host starts agents with action="start"); cognitive_mode and the read-path autonomy
drivers are retired; role budgets, SLOs and anomaly detection are gone; domain and
compliance packs moved to Pro/Enterprise; .lean-ctx.toml write and read-only keys apply
only in a trusted workspace; decision receipts are schema_version: 2 with keyed object
digests, so SDKs before 3.12.0 reject them (engine and SDK ship together); the engine's
built-in dashboard UI is replaced by the Cockpit. The SDK Agent Tools v1 contract is
unchanged. Telemetry is unchanged. lean-ctx-protocol renames hive::project to
hive::vault (VaultV1, VaultRefV1, vault_id); the published crates need Rust 1.87.

Added

  • ctx_execute code needs your approval (GHSA-rxv5-4c3x-g4q6). Code in any language other
    than shell runs only after approval in the same dialog as ctx_shell — once, for this
    session, always (global execute_allowed_languages) or deny, per language; a batch asks once
    per language and runs nothing if one is denied. Without the dialog (client without
    elicitation, shell_approval=off) the code is refused — list the language in
    execute_allowed_languages to run it without asking.

  • Knowledge from the repository itself. lean-ctx import docs [<file|dir>…] turns
    AGENTS.md, CLAUDE.md, .cursorrules, .cursor/rules and docs/ into project facts:
    each bullet or paragraph is one fact, categorised by its nearest heading (conventions,
    procedures, decisions, architecture, gotchas, dead ends, experiences) and anchored to its file
    and section. lean-ctx import git [--limit N] mines the local history: reverts become dead
    ends, fixes experiences, and commits that decide, switch or replace something decisions, each
    anchored to its commit; trailers and lines naming a person by email are dropped first, and no
    diff or author is read. Every file and every fact passes the same admission as any other import
    (path rules, project policy, secret and PII detection): a masked value stays masked, a withheld
    one yields nothing and is counted. A re-import updates the fact at the same anchor instead of
    adding a second one. Each fact under a heading carries a code anchor on its section, so an edit
    there marks it to verify; a fact whose section (or file) is gone on re-import is marked to
    verify
    (source_removed) and becomes current again when the section returns.
    lean-ctx knowledge export-agents-md [--write] writes these categories as a marked section of
    AGENTS.md (only public facts; the rest of the file is kept), and importing that section yields
    the same facts again.

  • The whole Cockpit is free and ships with official installs. Improvements, Spend
    history, Ledger filters and export, Report, Delivery insights, Memory Care, Package
    Studio, recipes and compar...

Read more

v3.11.4 — LeanCTX Engine: more reliable agent tool calls

Choose a tag to compare

@github-actions github-actions released this 11 Oct 21:31
3afe2bb

A bugfix release: tool calls that an agent gets almost right are now served instead of refused, edits survive indentation slips, and the Claude Code plugin wakes the agent only once per finished background job. Agent Tools protocol and data formats are unchanged.

Fixed

  • Searching a broad directory searches the project instead of failing. ctx_search, ctx_glob and ctx_tree called on ~, / or another directory that contains the session's project now walk the project and say so in the first line of the result. Before, they answered "refusing to scan" and agents repeated the same call. Without a bound project the refusal now names the fix: pass the project directory as path.
  • Agents can read their own instruction files. Skills, commands, sub-agent definitions, rules and plans under ~/.claude, ~/.codex/skills and ~/.codex/prompts, ~/.agents/skills, ~/.cursor, ~/.gemini/commands and OpenCode's ~/.config/opencode, plus the global CLAUDE.md, AGENTS.md and GEMINI.md, open read-only on first use. Credentials and settings beside them, such as ~/.codex/auth.json or ~/.claude/.credentials.json, stay closed, and LeanCTX tools cannot write there. A skill linked in from elsewhere below ~ is followed read-only; a link into a protected location or outside ~ is not, and links inside dependency folders such as node_modules are never followed.
  • A missing file comes with the file that was meant. ctx_read, ctx_search, ctx_glob and ctx_tree name the existing path when the requested one has a typo, another extension, or was written relative to the wrong directory (src/x.rs for rust/src/x.rs).
  • Paths with spaces work when written shell-style. On macOS and Linux a path such as My\ Project/notes.md or '/Users/me/My Project' turned into My/ Project and was reported as missing. Backslash escapes and surrounding quotes are now removed.
  • Common argument spellings are accepted. file_path, filePath, file and filename work as path, cmd as command (for MCP calls and lean-ctx call), a path inside a ctx_search queries[] entry scopes that one query, ctx_glob accepts glob for pattern, and ctx_patch replace_all accepts old_string/new_string. A replacement must still be named explicitly, so a missing one is never taken as "delete every match"; two spellings with different values are rejected.
  • An edit whose indentation is off still applies. When old_string matches exactly one place in the file at a uniformly different indentation, ctx_edit and ctx_patch (replace_unique) apply it there and shift new_string by the same amount, and say so. Uneven or ambiguous matches still fail with the exact-match error.
  • Read modes and glob patterns with small typos work. lines:72:92, lines:72..92, lines 72-92 and a capitalised Full are read as the mode they spell; **.rs and src** are read as **/*.rs and src*/**.
  • ctx_read no longer fails with "per-file lock contention". When an earlier read of the same file holds its lock for more than 10 seconds, the read proceeds without it.
  • No more "Retry the read" after LeanCTX opened a dependency folder. When a path in a dependency cache or an agent folder is still refused after it was opened read-only, the error now gives the actual reason. lean-ctx call resolves these paths the same way as the MCP server.
  • The Claude Code plugin wakes the agent once per finished job. When the agent itself had already read a finished background job with ctx_shell (background_action="status" or "cancel"), the plugin announced the same result again on the next turn, costing a whole extra turn.

Changed

  • The token-saving curve in the Claude Code cockpit is drawn true to time and to scale. The x axis now runs from the session's first lean-ctx call to now, the y axis starts at zero, the raw total sits behind "kept out" as a dim envelope, moments in which tokens were kept out are lit, and an axis line shows the session span and the gain of the last ten minutes. Before, one column per sample scaled from the window's lowest value made a single saving look like a cliff.

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.11.3...v3.11.4

v3.11.3

Choose a tag to compare

@github-actions github-actions released this 11 Oct 14:01
a6a2040

PathJail opens the home directory by default, the gateway keeps downstream MCP sessions alive between calls, Windows updates and CUDA 13 GPU embeddings work, and Claude Code gets a gateway cockpit. Agent Tools protocol and data formats are unchanged.

Changed

  • PathJail opens your whole home directory by default. The default path_jail_scope = home now admits everything below ~ for reading and writing; before, it admitted only paths inside a project, read-only outside the session's project. Protected locations stay closed: every top-level dot entry (~/.ssh, ~/.aws, ~/.config, shell rc files, other agents' ~/.claude, ~/.codex, …), ~/Library, ~/AppData and ~/snap, and everything outside ~. The previous behaviour is the new scope projects (lean-ctx config set path_jail_scope projects), the strictest one stays project. A scope you set yourself is kept; home set explicitly now means the wider scope too. Every installation without its own setting shows a one-time notice on its next interactive command.

Fixed

  • Windows: a second update or enable-gpu no longer fails (#2048). Each update moves the running lean-ctx.exe aside to lean-ctx.old.exe. The process that does this is still running from that file, so it cannot delete it, and the next update refused to start with stale Windows rollback binary exists. The next update now deletes the leftover file. If an old lean-ctx process (an editor's MCP server, a daemon) still runs from it, the file is renamed aside and removed by a later update once that process has exited; only when even that rename fails does the update stop and say which process to close. lean-ctx dev-install uses the same cleanup.
  • lean-ctx enable-gpu on the CUDA build it would install says so (#2048) instead of downloading and reinstalling the same binary. lean-ctx enable-gpu --force still reinstalls it.
  • GPU embeddings work with CUDA 13 runtimes (#2049). onnxruntime-gpu on PyPI is built for CUDA 13 since 1.27, and pip install "onnxruntime-gpu[cuda,cudnn]" installs the CUDA 13 wheels, which put the DLLs into site-packages\nvidia\cu13\bin\x86_64 (Linux: nvidia/cu13/lib). LeanCTX looked only for CUDA 12 libraries (cudart64_12.dll, libcudart.so.12) in the CUDA 12 wheel directories, so lean-ctx embeddings status reported CUDA runtime: not loadable although everything was installed. LeanCTX now reads which CUDA major the selected ONNX Runtime's CUDA provider was built for from the provider's import table and searches and preloads the matching CUDA 12 or CUDA 13 libraries, including the new wheel layout and CUDA_PATH_V13_* toolkits.
  • Windows: the CUDA check no longer fails on every machine (#2049). The check loads onnxruntime_providers_cuda.dll directly; outside ONNX Runtime its initialisation refuses to run, which Windows reports as error 1114 after every dependency has already loaded (Linux reports the same case as a missing Provider_GetHost, which was already handled). embeddings status therefore said not loadable and indexing warned about a CPU fallback while ONNX Runtime was in fact using the GPU, and GPU-sized embedding batches were never used. Error 1114 now counts as loaded; other loader errors show their Windows error code and meaning instead of a bare LoadLibraryExW failed.
  • CUDA runtime: OK means the GPU is really used (#2049). ONNX Runtime loads cudart and cuDNN by name only when a session starts, so a provider DLL that loads (for example through a CUDA toolkit on PATH) could still fall back to CPU without a word. embeddings status now also requires the CUDA runtime and cuDNN to resolve, preloads them before the provider is registered, and names the library that is missing otherwise.
  • Clearer CUDA diagnostics on Windows (#2048, #2049). Instead of a bare LoadLibraryExW failed, lean-ctx embeddings status lists the missing DLLs and every directory it searched, says when no NVIDIA driver (nvcuda.dll) is installed, and states the CUDA major the provider needs instead of the CUDA version of the ONNX Runtime LeanCTX was compiled against.
  • ONNX Runtime and CUDA libraries from more Windows Python installs are found (#2048): every python.exe on PATH, system-wide installs under %ProgramFiles%\Python3* and C:\Python3*, the Python install manager's %LOCALAPPDATA%\Python\pythoncore-* (the default for Python 3.14) and the Microsoft Store Python, in addition to the per-user installs and active virtual or conda environments.
  • lean-ctx embeddings status says which setting chose the embedding model (#2049): LEAN_CTX_EMBEDDING_MODEL (which overrides the config), [embedding] model in the named config.toml, or the default, plus how to change it.
  • Every second gateway call no longer fails with Transport closed (#2040, reported by @smollgreymouse). ctx_tools (find, list, call) and gateway compression addons each built their own Tokio runtime per call and dropped it afterwards. A pooled downstream MCP session's transport lives on the runtime that opened it, so the next call got a session whose connection was already gone. All gateway I/O now runs on one runtime that lives as long as the process, so a downstream server is started once and reused across calls.
  • The status line shows this conversation's numbers. When several agents run LeanCTX in the same project, the Claude Code status line showed whichever session had written last, so its figures jumped between conversations or stood still. Each session now records the process of the AI client it serves, and the status line reads the session that belongs to its own client.
  • Polling a background shell job no longer inflates the session counts. Every ctx_shell status or cancel call for a background job counted as one more tool call and one more command in the session statistics; a single long build polled by an agent could add hundreds. These polls no longer count.

Tool calls that failed although the agent's request was sound, found in the usage telemetry of 3.11.1 and 3.11.2:

  • ctx_read answers an empty file, an SVG and a directory. An empty file returned File is empty as an error; it now reads as <path>: empty file (0 bytes). SVG files were rejected as binary; they are XML text and read like source (a real binary behind any extension is still caught by its content). A directory failed with the OS error Is a directory; it now lists its entries.
  • ctx_search searches an invalid regex literally. Code text such as foo(, items[0 or fn run(&self is not valid regex and failed the call; it is now searched verbatim, with a one-line note. action=symbol also takes the symbol name from symbol, query or pattern when name is missing.
  • ctx_patch infers replace_unique. An edit with old and new text but no op failed with missing 'op'; such an edit can only be replace_unique, at the top level and inside ops[].
  • An edit whose result already holds is not an error. ctx_edit (and ctx_patch replace_unique) with identical old and new text, where that text is in the file, reports No change: instead of failing. Text that is absent still fails.
  • Dependency source reads on the first call. Reading a file in a language cache registered the cache as a read-only root but still failed the call with "Retry the read"; it now resolves in the same call. The Rust toolchain source (~/.rustup/toolchains), Cargo git dependencies (~/.cargo/git/checkouts) and the Bun, Dart pub and Ruby gem caches are recognized alongside the existing ones. Credential and configuration directories (~/.claude, ~/.codex, ~/.config, ~/.cargo/credentials.toml) stay jailed, and writes into any cache stay denied.
  • Usage telemetry counts each tool call once. The daily total of tool calls and failures, and the latency histogram, counted every call twice: once where the call is dispatched and again when its lifecycle finished. The per-tool counts were already right; the totals now match them.
  • A failed inline shell command is one error, filed as a failed command. The shell worker also recorded every non-zero exit of a command that finished in the foreground as a LeanCTX-internal error, next to the pipeline's own command entry, and did so even for exit 1 with output (grep, diff, test), which is not an error. The worker now records only background jobs, as command or timeout; inline runs are classified once by the call pipeline.
  • Telemetry opt-outs and CI detection reach MCP servers started by Codex. Codex starts MCP servers with only HOME, PATH, USER, LANG and a few more variables, so a server it started could not see DO_NOT_TRACK=1, LEAN_CTX_TELEMETRY=off or the CI markers set in the shell or job around it: an opt-out did not reach the server, and a CI job counted as a local machine. On Linux the server now also reads these few keys, and the runtime-environment markers, from its nearest ancestor processes. Nothing else from their environment is read or kept.
  • Containers under cgroup v2 report as container. A container that has no /.dockerenv (containerd, Kubernetes, Podman) and runs under cgroup v2 reported as a local machine. Its overlay root filesystem, the container variable and the Kubernetes service-account directory now mark it too.

Added

  • Notices from the LeanCTX team reach the installations they concern. The acknowledgement of a telemetry send can carry up to three short notices, for example "the fix for this ctx_read failure is in 3.11.3". The server picks them by what the batch already reports (version, AI client, OS, runtime environment, a tool that failed), so nothing extra is sent and nobody needs to know who you are. A notice is shown once, on the terminal of the next interactive lean-ctx command, and never in an MCP response: text from a server does not reach the AI model. Only plain text up to 280 characters ...
Read more

v3.11.2

Choose a tag to compare

@github-actions github-actions released this 09 Oct 21:50
93f5268

Updater and security hotfix for 3.11.1. Agent Tools protocol, configuration and data formats are unchanged.

Upgrade notes

  • Updating from 3.11.0 or 3.11.1 needs one manual step. Their built-in updater stops after downloading and verifying a release with Failed to complete durable update transaction: prepared transaction is missing its integrity digest, and scheduled automatic updates fail the same way. Nothing is changed or damaged: the installed binary keeps running. Install this release once through the channel you installed with — curl -fsSL https://leanctx.com/install.sh | sh, brew upgrade lean-ctx, npm i -g lean-ctx-bin@latest, cargo install lean-ctx --force or your AUR helper — and lean-ctx update and automatic updates work again from then on.
  • Windows on 3.11.0 (#2039): the 3.11.0 updater also needs the external cosign tool and looks for it under that exact name; installing cosign does not help, because its update then stops at the error above. Extract the Windows ZIP of this release over your lean-ctx.exe, or update through npm. From 3.11.1 on, no external tool is needed.

Security

  • The home jail scope opens projects, not your home directory. 3.11.1 admitted every path below ~ for reading, so a prompt-injected agent could pull loose personal files (~/Documents/taxes.pdf, ~/Downloads, ~/Desktop) into the model context. A path is now admitted only when a folder between it and ~ holds a project marker (.git, Cargo.toml, package.json, go.mod, pyproject.toml, Makefile, …). Every repository below ~ stays readable; anything else needs lean-ctx allow-path <dir>, and the refusal says so.
  • redirect_exclude from an untrusted workspace is withheld (#2034). Paths in redirect_exclude skip the native-read hook redirect and with it the redaction that path applies. In 3.11.1 a repository's own .lean-ctx.toml could extend the list even when the workspace was not trusted, so a cloned repository could opt its reads out (for example with ["**"]) on hosts where the read redirect is active. Such a list is now ignored with a [SECURITY] warning until you run lean-ctx trust; the global config and LEAN_CTX_HOOK_EXCLUDE still apply.

Fixed

  • Codex threads recorded while ChatGPT routing was on stay resumable. Codex stamps model_provider = "leanctx-chatgpt" into every such thread and refuses to resume it once that provider is missing (Model provider 'leanctx-chatgpt' not found). lean-ctx doctor --fix, proxy runs and stale-proxy cleanup deleted the [model_providers.leanctx-chatgpt] block by name, including the direct one users restored by hand. Cleanup now only touches a block that targets the local proxy, and repoints it at https://chatgpt.com/backend-api/codex instead of deleting it; a block aimed anywhere else is kept verbatim and no longer reported as routed or broken.
  • ctx_multi_repo action=search without a query says so. While a content policy was active, the call was refused with the cross-project policy message instead of query is required for search.
  • No downgrade as "update". Without an explicit version, lean-ctx update and scheduled updates only install a release newer than the running build; a build ahead of GitHub's latest release was offered, and on a schedule installed, the older release. lean-ctx update <version> and --pin still install any version on purpose.
  • GitHub API rate limit (#2037): the updater now sends GITHUB_TOKEN, GH_TOKEN or LEAN_CTX_GITHUB_TOKEN when set (only to api.github.com, without following redirects), raising GitHub's limit from 60 requests per hour per IP address to 5000. An exhausted quota now says so, with the reset time and the fix, instead of http status: 403; a rejected token reports 401 Bad credentials. The background version check uses the same client.
  • lean-ctx update and lean-ctx update --rollback complete again. The updater sealed each prepared transaction with its integrity digest when writing it to disk, but then executed the unsealed copy, which the integrity check rejected every time. The updater now executes exactly the sealed transaction it persisted. A new test runs the real prepare → execute → recover path on a stand-in binary.
  • macOS: the update signature is applied before the swap. The updater re-signed the installed binary after moving it into place (#356, so the TCC grant survives), which changed its bytes after the transaction had recorded them; the update then stopped with "active binary does not match prepared target". The staged binary is now signed first, and the receipt records exactly the bytes that are installed; the release manifest and archive digests still record its provenance.
  • A reinstall no longer blocks later updates. A failed 3.11.0/3.11.1 run leaves a prepared transaction behind; after a manual reinstall the updater refused every update with "active binary matches neither prepared state". Recovery now recognizes a transaction that a build at least as new as its target has superseded and removes its staged files without touching the binary. Likewise, an update receipt from a different, earlier version no longer refuses updates ("current binary differs from the active receipt"); the updater starts a new receipt from the running binary. A binary that differs from a receipt of the same version is still refused.

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.11.1...v3.11.2

v3.11.1

Choose a tag to compare

@github-actions github-actions released this 09 Oct 10:28
b4fd337

Highlights

  • Agents can read across all your projects at once: the path jail now admits every project below your home directory for reading by default, while writes stay in the session's own project and ~/.ssh, ~/.aws, ~/.config, other top-level dot directories, ~/Library, ~/AppData and ~/snap stay closed.
  • Each agent session binds to the project it was started in. Setup no longer pins one project into an agent's global MCP config, and existing pins are removed.

Upgrade notes

  • Path jail scope: the new path_jail_scope setting defaults to "home": reads anywhere below your home directory outside the protected zones; writes only in the session's project, host-declared roots and allow entries. Set lean-ctx config set path_jail_scope project to keep the previous single-project boundary. The setting is global-only; a project-local .lean-ctx.toml cannot change it. With an implausible $HOME (/, a single path component, not owned by you) the scope falls back to project. path_jail = false still disables the jail.
  • Protected zones are a hard deny in both scopes: a project root or allow entry that only contains a zone (for example a dotfiles repository at ~) no longer opens ~/.ssh and the like; add an entry inside the zone (lean-ctx allow-path ~/.config/myapp) if a tool must reach it.
  • Project pins: earlier lean-ctx setup / doctor --fix runs and MCP-start hook refreshes copied the installing session's LEAN_CTX_PROJECT_ROOT and LEAN_CTX_EXTRA_ROOTS into user-global agent configs (~/.codex/config.toml, ~/.grok/config.toml, global JSON MCP entries), so every later session of that agent opened the same project. The Codex and Grok entries are cleaned on the next agent refresh; lean-ctx doctor reports remaining pins under "Project binding" and lean-ctx doctor --fix removes them line by line, keeping key order and comments (a pin that shares a line with other keys is listed for a manual edit). LEAN_CTX_EXTRA_ROOTS values move into extra_roots; per-project entries in ~/.claude.json are left alone. Restart the agent once afterwards.
  • Telemetry: the daily aggregates report more (see Changed), and setup no longer asks: setup and the first interactive command after this update print a three-line notice instead. Turn telemetry off any time with lean-ctx telemetry off, DO_NOT_TRACK=1 or LEAN_CTX_TELEMETRY=off; an explicit opt-out made since 3.11.0 stays in effect, and lean-ctx telemetry show prints the exact payload. What the server keeps, including a keyed network hash and the network operator's public name derived from the connection (never the IP address), and how long, is described at leanctx.com/privacy.

Security

  • Agent shells can no longer loosen lean-ctx itself. lean-ctx is on the default shell allowlist, so an agent could run lean-ctx yolo --yes, lean-ctx allow <cmd>, lean-ctx allow-path <dir>, lean-ctx trust, lean-ctx security open, lean-ctx security secrets off or lean-ctx config set <security key> through ctx_shell (or a hook-rewritten Bash call) and then do what the jail or the allowlist had just refused. Those subcommands are now blocked in agent shells with a message to ask the user; listing (--list, status, config show), narrowing (--remove) and tightening (secure, untrust, security secrets on) still run. Run the blocked commands in your own terminal.
  • Path jail writes: the new home scope opens other projects for reading only; writes outside the session's project need an explicit lean-ctx allow-path, so an agent in one repository cannot plant another repository's Git hooks or a binary on your PATH.

Added

  • lean-ctx allow-path <dir> admits one directory for reading and writing — outside your home directory, a sibling project to edit, or one protected location — effective on the next tool call without a restart. --list shows the jail scope and added directories; --remove takes one out. It refuses /, the home directory and any directory containing it.
  • lean-ctx security status shows the active jail scope, and lean-ctx doctor reports global project pins.

Changed

  • A refused path names the one command that admits it (lean-ctx allow-path <dir>, offered for the enclosing project) for the user to run in their terminal. The previous hints to open a new IDE window or set an env var that the running server cannot see are gone.
  • When a stale LEAN_CTX_PROJECT_ROOT pin is still set and the MCP server starts inside a different real project, the session binds to that project and logs a warning. Host-specific roots (CLAUDE_PROJECT_DIR, workspace folders) keep their precedence.
  • Telemetry reports where and how long LeanCTX runs, as coarse ranges. The daily heartbeat adds the runtime environment (local, container, Codespaces, Gitpod, Replit, cloud agent, CI), the installation age (under an hour … 30+ days) and the number of active days in the last 30 (1 … 15+), each as a closed value. They let usage numbers separate people from short-lived agent sandboxes. No machine, account, network or path information is sent. The disclosure lists the new category, so every installation sees the one-time notice again; DO_NOT_TRACK=1, LEAN_CTX_TELEMETRY=off and lean-ctx telemetry off still turn telemetry off.
  • The install channel is detected. It was unknown for every installation because no build set it; it now follows the location of the running executable (npm, Homebrew, cargo, PyPI, AUR, release binary). Only the channel name is sent.
  • Telemetry reports token savings and per-tool latency. The daily tool aggregate adds the day's total tool-output tokens before and after compression, and each built-in tool's summed latency. Counts only; no content.
  • Telemetry includes the daily usage record and why tools fail. The batch carries the last 90 days of the installation's own lean-ctx gain record (operations and tokens before/after compression per day, lifetime totals, month of first use), so usage through shell hooks and before telemetry is counted. Failed tool calls are reported by class (invalid input, not found, permission, policy, timeout, edit conflict, too large, unavailable), together with the five most frequent error messages per tool and day as templates: the client replaces every quoted text, path, file name, number, identifier, URL and e-mail address with a placeholder before anything is sent, and drops a message entirely when no safe wording remains. Shell commands that exit non-zero are now reported as command instead of internal.
  • Upgrades turn on telemetry that was only off by the old default. Before 3.11 telemetry was opt-in, so telemetry.enabled = false without a recorded choice is re-enabled once on upgrade, and the one-time notice explains it. An opt-out made since 3.11 (lean-ctx telemetry off, declining in setup, and now also lean-ctx config set telemetry.enabled false) is recorded as explicit and never overridden; DO_NOT_TRACK=1 and LEAN_CTX_TELEMETRY=off always win, and a read-only config is left untouched.
  • Telemetry counts which LeanCTX features are used. A daily feature_aggregate reports how often each CLI command runs (lean-ctx pack export → cli.pack.export, graph build, index build-full, telemetry off …) and every graph, BM25 and semantic index build with its failures. Commands and verbs come from a fixed registry; arguments, paths and queries never become part of a code, and hot-path commands (shell hooks, -c, read, grep, statusline) are not counted.
  • Telemetry names 21 more AI clients. Cline, Roo Code, Kilo Code, Continue, OpenCode, Goose, Amp, Augment, JetBrains, Warp, Trae, Qwen Code, Crush, Claude Desktop, ChatGPT, LM Studio, Copilot CLI, Visual Studio, Neovim, Emacs and Factory are reported as their own family, and none separates installations used only through the CLI and shell hooks from an unrecognised MCP client (other). The client's name is never sent, and what LeanCTX offers each client over MCP is unchanged.
  • Setup no longer asks about telemetry. Setup and the first interactive command after an install or update show a three-line notice instead: telemetry is on, how to turn it off (lean-ctx telemetry off, or enabled = false under [telemetry] in the config.toml it names) and where to see what is sent. The full list stays on lean-ctx telemetry on|off and the payload on lean-ctx telemetry show. An earlier explicit choice is kept.

Fixed

  • ctx_shell output capture works in your project. Redirects and tee (> build.log, >> notes.txt, | tee out.txt) were refused everywhere except /tmp, $TMPDIR and write_allow_paths; the project root stayed refused even when listed, and allow_paths / extra_roots were not consulted. Capture may now also go to the session's project and the jail's allow entries. /, ~, its ancestors and read_only_roots are never capture targets; downloads (curl -o, wget, dd of=) keep the scratch-only rule.
  • ctx_shell no longer relocates, queues or throttles your builds. Three multi-agent build settings were on by default: agents.shared_cargo_target pointed every cargo build/test run through ctx_shell at <data dir>/build-cache/cargo-target, so ./target kept a stale binary; agents.serialize_build_commands made each build wait for builds from other sessions on the machine; agents.cargo_build_jobs = 3 capped cargo at three jobs. All three are now opt-in (false, false, 0) and documented in the config reference under [agents]. Set them again in config.toml if you relied on the shared cache.
  • ctx_shell walk hint judges each invocation on its own (#2027). A scoped grep -r … tariff followed by a stdin-reading grep in the same command line (…; echo x | grep -c x, | grep -v _test) was treated as a recursive walk of the working directory, so the hint named `.claude/work...
Read more