lean-ctx-sdk — in-process embedding façade (Rust)
Embed the lean-ctx context engine in-process behind a small, stable Rust API. This is the substrate for power-developer tools (e.g. Lean-md) that want to call lean-ctx directly — a shared session cache, compressed reads, code search and symbol lookup — instead of going through the MCP server or CLI.
Not the
compress()client. The pip/npm packages also namedlean-ctx-sdkare thin HTTP clients for the daemon's/v1/compressendpoint. This crate is the Rust in-process engine façade — different artifact, different job. Seedocs/guides/compress-sdk.mdfor the client SDKs.
The headline: a shared-cache Engine
use lean_ctx_sdk::{Engine, ReadMode};
let engine = Engine::builder(".").build()?;
let first = engine.read("src/main.rs", ReadMode::Full)?;
let again = engine.read("src/main.rs", ReadMode::Full)?; // re-read collapses to a delta
assert!(again.saved_tokens >= first.saved_tokens);
# Ok::<(), lean_ctx_sdk::Error>(())
Because the Engine owns a shared SessionCache, a read followed by a
re-read of an unchanged file collapses to a token-cheap delta — the property
that makes lean-ctx worth embedding. The engine dispatches the real registered
tools (ctx_read, ctx_search, ctx_symbol, …), exactly as the MCP server
does.
Safe by default
EngineBuilder::build() is read-mostly and scoped:
- PathJail on — every path is resolved against the project root; escapes and secret paths are rejected.
- Scoped state — engine data goes to a throwaway temp dir unless you call
.data_dir(…); your real~/.lean-ctxis never touched silently. - Auto-update off for the embedded process.
- Write/exec gated —
ctx_edit/ctx_fillneed.allow_write(true);ctx_shell/ctx_executeneed.allow_exec(true).
It also drops the engine's jemalloc feature, so embedding the SDK never forces
a #[global_allocator] onto your binary.
Surface (v1)
| Group | API | Backed by |
|---|---|---|
| Read | Engine::read(path, ReadMode) |
ctx_read |
| Search | Engine::search(pattern, subdir) |
ctx_search |
| Symbol | Engine::symbol(name) |
ctx_symbol |
| Outline | Engine::outline(path) |
ctx_outline |
| Tree | Engine::tree(subdir) |
ctx_tree |
| Any tool | Engine::call(name, json_args) |
the registry (write/exec gated) |
| Hashing | hash::blake3_hex/str |
engine hash |
| Tokens | tokens::count |
engine tokenizer |
| Compression | compress::shell_output(…) |
shell pattern engine |
| Addon authoring | addon::scaffold/audit/slugify |
addon scaffold + audit gate |
See docs/rfcs/sdk-embedding-v1.md for
the full surface map and roadmap, and
docs/guides/embed-sdk.md for the guide.
Runtime note
Engine methods are synchronous and drive their own multi-threaded Tokio runtime,
so they must not be called from inside another Tokio runtime worker. From
async code, wrap calls in tokio::task::spawn_blocking.
Build & test
# from rust/
cargo test -p lean-ctx-sdk
cargo run -p lean-ctx-sdk --example embed
cargo clippy -p lean-ctx-sdk --all-targets -- -D warnings
The crate is a workspace member but excluded from default-members, so the
engine's own cargo build/test/clippy are unchanged — build it explicitly
with -p lean-ctx-sdk.
License
Apache-2.0, same as lean-ctx.