Files
wehub-resource-sync 26382a7ac6
CodeQL / Analyze (javascript-typescript) (push) Waiting to run
JetBrains Plugin / Actionlint (push) Waiting to run
CodeQL / Analyze (actions) (push) Waiting to run
CodeQL / Analyze (rust) (push) Waiting to run
JetBrains Plugin / Validation (push) Waiting to run
JetBrains Plugin / Build (push) Waiting to run
JetBrains Plugin / Test (push) Blocked by required conditions
Security Check / Security Scan (push) Waiting to run
CI / Clippy (push) Failing after 15m13s
CI / Test (ubuntu-latest) (push) Failing after 16m1s
CI / Test (macos-latest) (push) Has been cancelled
CI / Test (windows-latest) (push) Has been cancelled
CI / Build (no embeddings / no ORT) (push) Has been cancelled
CI / Format (push) Has been cancelled
CI / Cookbook (Node) (push) Has been cancelled
CI / Pi Extension (Node) (push) Has been cancelled
CI / Rust SDK (lean-ctx-client) (push) Has been cancelled
CI / Embed SDK (lean-ctx-sdk) (push) Has been cancelled
CI / Python SDK (leanctx) (push) Has been cancelled
CI / Hermes Plugin (Python) (push) Has been cancelled
CI / SDK Conformance Matrix (push) Has been cancelled
CI / Coverage (push) Has been cancelled
CI / cargo-deny (push) Has been cancelled
CI / Adversarial Safety (push) Has been cancelled
CI / Benchmarks (push) Has been cancelled
CI / Output-Quality Gate (eval A/B) (push) Has been cancelled
CI / Documentation (push) Has been cancelled
CI / CI Green (push) Has been cancelled
chore: import upstream snapshot with attribution
2026-07-13 12:35:30 +08:00

4.4 KiB

Embed lean-ctx (Rust SDK)

Build on lean-ctx in-process. The lean-ctx-sdk crate gives you an Engine handle that wraps a shared session cache and dispatches the real engine tools (ctx_read, ctx_search, ctx_symbol, …) directly — no MCP server, no CLI.

This is the path for power-developer tools (the Lean-md use case). If instead you want to ship a tool the agent calls, build an Addon. If you just want drop-in text compression over HTTP, use the compress() client SDKs.

Name disambiguation. The pip/npm lean-ctx-sdk packages are the HTTP compress() clients. The Rust crate described here is the in-process engine façade — same name, different ecosystem and job.

Why embed (the re-read delta)

The Engine owns one SessionCache across calls, so a re-read of an unchanged file collapses to a token-cheap delta — the core reason to embed rather than shell out per call:

use lean_ctx_sdk::{Engine, ReadMode};

let engine = Engine::builder(".").build()?;

let first = engine.read("src/main.rs", ReadMode::Full)?;
println!("read #1: {} tokens, saved {}", first.original_tokens, first.saved_tokens);

let again = engine.read("src/main.rs", ReadMode::Full)?;
println!("read #2: saved {} ({:.0}%)", again.saved_tokens, again.saved_pct());
// read #2 typically saves ~99% — the shared-cache delta.
# Ok::<(), lean_ctx_sdk::Error>(())

Add the dependency

The crate lives in the lean-ctx workspace (rust/crates/lean-ctx-sdk). While it is unpublished, depend on it by path:

[dependencies]
lean-ctx-sdk = { path = "path/to/lean-ctx/rust/crates/lean-ctx-sdk" }

The surface (v1)

You want Call
Read a file (compressed, cached) engine.read(path, ReadMode::Auto)
Search code engine.search("pattern", None)
Find a symbol definition engine.symbol("MyType")
Outline one file engine.outline("src/lib.rs")
Directory tree / repo map engine.tree(None)
Any other tool engine.call("ctx_impact", args)
Count tokens (no engine) lean_ctx_sdk::tokens::count(text)
Hash content (no engine) lean_ctx_sdk::hash::blake3_str(text)
Author + audit an addon lean_ctx_sdk::addon::scaffold/audit

ReadMode mirrors the engine modes: Auto, Full, Raw, Signatures, Map, Diff, Reference, Task, Lines { start, end }.

Engine::call(name, args) reaches every registered tool with a raw JSON arg map — the escape hatch for capabilities without a typed method yet. A string path argument is PathJail-resolved automatically. See the full surface map.

Safe by default

Engine::builder(root).build() is read-mostly and scoped:

  • PathJail on — paths resolve against root; escapes/secret paths error with Error::Path.

  • Scoped state — engine data goes to a throwaway temp dir. Point it at your real lean-ctx data to share session memory with the CLI/MCP:

    let engine = Engine::builder(".")
        .data_dir("/home/me/.local/share/lean-ctx")
        .build()?;
    # Ok::<(), lean_ctx_sdk::Error>(())
    
  • Write/exec gated — mutating tools are denied unless you opt in:

    let engine = Engine::builder(".")
        .allow_write(true)   // ctx_edit, ctx_fill
        .allow_exec(true)    // ctx_shell, ctx_execute
        .build()?;
    # Ok::<(), lean_ctx_sdk::Error>(())
    

The SDK also drops the engine's jemalloc feature, so embedding never forces a #[global_allocator] onto your binary.

Runtime constraint

Engine methods are synchronous and drive their own multi-threaded Tokio runtime. Do not call them from inside another Tokio runtime worker. From async code:

let out = tokio::task::spawn_blocking(move || engine.read("src/main.rs", ReadMode::Full))
    .await
    .unwrap()?;

Distribution stays Addons

The SDK is for building; distribution is still the Addon system. A binary you build with the SDK and ship as an addon runs under the gateway OS sandbox + output redaction + trust/signing — embedding does not weaken end-user security.

Run the example

# from the lean-ctx repo
cargo run -p lean-ctx-sdk --example embed

See also