# Workspace root. The SDK (Track A) is an opt-in member; `default-members` keeps # every existing `cargo build`/`test`/`clippy`/`publish` scoped to the engine # crate exactly as before — build the SDK explicitly with `-p lean-ctx-sdk` or # the whole workspace with `--workspace`. [workspace] members = [ ".", "crates/lean-ctx-sdk", # Grammar-addon cdylibs (#690, Phase 1c) — one crate per long-tail # tree-sitter grammar, built per-platform by grammar-addons.yml and # dlopen'd at runtime by core::signatures_ts::grammar_loader. Add a new # `crates/grammar-addons/` member (mirroring lua/) plus a matrix # entry in the workflow when tiering another grammar out (scope item 1). "crates/grammar-addons/lua", # Standalone manual-verification harness the grammar-addon design proved # out against (Phase 0 spike, #693) — not part of the release pipeline. "experiments/grammar-dlopen-spike/host", ] default-members = ["."] [package] name = "lean-ctx" version = "3.9.8" edition = "2024" autobins = false description = "Context Runtime for AI Agents with CCP. 71 MCP tools, 10 read modes, 95+ compression patterns, cross-session memory (CCP), persistent AI knowledge with temporal facts + contradiction detection, multi-agent context sharing, LITM-aware positioning, AAAK compact format, adaptive compression with Thompson Sampling bandits. Supports 24+ AI tools. Reduces LLM token consumption by up to 99%." license = "Apache-2.0" repository = "https://github.com/yvgude/lean-ctx" homepage = "https://leanctx.com" readme = "README.md" keywords = ["mcp", "llm", "tokens", "compression", "ai"] categories = ["command-line-utilities", "development-tools"] exclude = ["examples/", "tests/", "crates/"] [package.metadata.binstall] bin-dir = "{ bin }{ binary-ext }" pkg-url = "{ repo }/releases/download/v{ version }/{ name }-{ target }.tar.gz" [package.metadata.binstall.overrides.x86_64-pc-windows-msvc] pkg-fmt = "zip" pkg-url = "{ repo }/releases/download/v{ version }/{ name }-{ target }.zip" [lib] name = "lean_ctx" path = "src/lib.rs" [[bin]] name = "lean-ctx" path = "src/main.rs" [[example]] name = "lean-ctx-cloud-api" path = "src/cloud_server_main.rs" required-features = ["cloud-server"] [[example]] name = "gen_mcp_manifest" path = "src/bin/gen_mcp_manifest.rs" required-features = ["dev-tools"] [[example]] name = "gen_tdd_schema" path = "src/bin/gen_tdd_schema.rs" required-features = ["dev-tools"] [[example]] name = "gen_docs" path = "src/bin/gen_docs.rs" required-features = ["dev-tools"] [[example]] name = "gen_registry" path = "src/bin/gen_registry.rs" required-features = ["dev-tools"] [[example]] name = "gen_rules" path = "src/bin/gen_rules.rs" required-features = ["dev-tools"] [[example]] name = "gen_testbench_recording" path = "src/bin/gen_testbench_recording.rs" required-features = ["dev-tools"] [[example]] name = "locomo_bench" path = "src/bin/locomo_bench.rs" required-features = ["dev-tools"] [[example]] name = "seed_observatory" path = "src/bin/seed_observatory.rs" required-features = ["dev-tools"] [features] default = [ "tree-sitter", "embeddings", "http-server", "team-server", # Self-hosted org gateway (`lean-ctx gateway init|serve|doctor`): ships by # default like team-server so the documented pilot path works with the # standard binary (Local-Free Invariant — free, no license gate). "gateway-server", # Cross-shape routing Anthropic→OpenAI (enterprise#16): org model aliases # (`acme/fast` → Foundry/vLLM/Ollama) must work from Claude-shaped clients # with the shipped binary, so the pilot path needs no custom build # (enterprise#63; Local-Free Invariant — compile-gated only, no license gate). "shape-xlat", "secure-update", "jemalloc", # Remote dense backends ship in release binaries so LEANCTX_QDRANT_URL / # LEANCTX_PGVECTOR_URL work out of the box (both are env-gated at runtime). "qdrant", "pgvector", ] jemalloc = ["dep:tikv-jemallocator", "dep:tikv-jemalloc-ctl"] dev-tools = [] no-jail = [] neural = ["dep:ort", "dep:ndarray", "dep:libloading"] embeddings = ["dep:ort", "dep:ndarray", "dep:libloading"] ort-cuda = ["ort?/cuda"] ort-webgpu = ["ort?/webgpu"] ort-rocm = ["ort?/rocm"] ort-directml = ["ort?/directml"] ort-coreml = ["ort?/coreml"] http-server = [ "dep:axum", "dep:tower-http", "dep:reqwest", "dep:tokio-tungstenite", "dep:rustls", ] qdrant = ["embeddings"] pgvector = ["embeddings"] team-server = ["http-server"] # Self-hostable org gateway (proxy remote-bind + usage store + admin API). # LOCAL_OPTIONAL: free, gated by compilation only — never by account/license/plan # (Local-Free Invariant; enforcement lives in lean-ctx-enterprise, not here). gateway-server = [ "http-server", "dep:deadpool-postgres", "dep:tokio-postgres", "dep:tokio-postgres-rustls", "dep:webpki-roots", "dep:hex", ] # N×M shape translation (enterprise#16): Claude clients on OpenAI-shape # upstreams (Foundry, vLLM, Ollama…). LOCAL_OPTIONAL: compile-gated only. shape-xlat = ["http-server"] secure-update = [] cloud-server = [ "http-server", "dep:deadpool-postgres", "dep:tokio-postgres", "dep:lettre", "dep:jsonwebtoken", "dep:uuid", "dep:hex", "dep:rand", "dep:argon2", "dep:resvg", ] tree-sitter = [ "dep:tree-sitter", "dep:tree-sitter-rust", "dep:tree-sitter-typescript", "dep:tree-sitter-javascript", "dep:tree-sitter-python", "dep:tree-sitter-go", "dep:tree-sitter-java", "dep:tree-sitter-c", "dep:tree-sitter-cpp", "dep:tree-sitter-ruby", "dep:tree-sitter-c-sharp", "dep:tree-sitter-kotlin-ng", "dep:tree-sitter-swift", "dep:tree-sitter-php", "dep:tree-sitter-bash", "dep:tree-sitter-dart", "dep:tree-sitter-scala", "dep:tree-sitter-elixir", "dep:tree-sitter-zig", "dep:tree-sitter-gdscript", "dep:tree-sitter-lua", "dep:tree-sitter-luau", "dep:tree-sitter-ocaml", "dep:tree-sitter-haskell", "dep:tree-sitter-julia", "dep:tree-sitter-solidity", "dep:tree-sitter-nix", "dep:tree-sitter-powershell", "dep:tree-sitter-language", "dep:libloading", ] wasm = ["dep:wasmi"] [dependencies] rmcp = { version = "2", features = [ "server", "client", "transport-io", "transport-streamable-http-server", "transport-child-process", "transport-streamable-http-client-reqwest", ] } # Header types for the gateway's downstream HTTP MCP client (already in the tree via rmcp/reqwest). http = "1.4" tiktoken-rs = "0.12" tokio = { version = "1.52", features = [ "rt", "rt-multi-thread", "macros", "io-std", "io-util", "net", "sync", "time", "signal", "process", ] } serde = { version = "1.0", features = ["derive"] } serde_json = "1.0" subtle = "2.6" md-5 = "0.11" anyhow = "1.0" regex = "1.12" walkdir = "2.5" ignore = "0.4" tracing = "0.1" tracing-subscriber = { version = "0.3", features = ["env-filter"] } thiserror = "2.0" futures = "0.3" tokio-util = { version = "0.7", features = ["codec"] } dirs = "6.0" chrono = { version = "0.4", features = ["serde"] } toml = "1.1" toml_edit = "0.25" similar = "3.1" flate2 = "1.1" rusqlite = { version = "0.39", features = ["bundled"] } tree-sitter = { version = "0.26", optional = true } tree-sitter-rust = { version = "0.24", optional = true } tree-sitter-typescript = { version = "0.23", optional = true } tree-sitter-javascript = { version = "0.25", optional = true } tree-sitter-python = { version = "0.25", optional = true } tree-sitter-go = { version = "0.25", optional = true } tree-sitter-java = { version = "0.23", optional = true } tree-sitter-c = { version = "0.24", optional = true } tree-sitter-cpp = { version = "0.23", optional = true } tree-sitter-ruby = { version = "0.23", optional = true } tree-sitter-c-sharp = { version = "0.23", optional = true } # tree-sitter-kotlin (fwcd) caps tree-sitter at <0.23; kotlin-ng matches tree-sitter 0.26. tree-sitter-kotlin-ng = { version = "1.1", optional = true } tree-sitter-swift = { version = "0.7", optional = true } tree-sitter-php = { version = "0.24", optional = true } # platform-verifier: validate TLS against the OS trust store (corp proxy CAs), # not just compiled-in webpki-roots. Opt-in per-agent via RootCerts::PlatformVerifier. ureq = { version = "3.3", features = ["platform-verifier"] } # PDF → text extraction for ctx_url_read (research context layer). # 0.12 pulls lopdf >=0.42 (RUSTSEC-2026-0187: stack overflow on deeply nested PDFs). pdf-extract = "0.12" tar = "0.4" zip = "8.6" tree-sitter-bash = { version = "0.25", optional = true } tree-sitter-scala = { version = "0.26", optional = true } tree-sitter-elixir = { version = "0.3", optional = true } tree-sitter-zig = { version = "1.1", optional = true } tree-sitter-dart = { version = "0.2", optional = true } tree-sitter-gdscript = { version = "6.1", optional = true } tree-sitter-lua = { version = "0.5", optional = true } tree-sitter-luau = { version = "1.2", optional = true } # All five below expose the modern `LANGUAGE*: LanguageFn` const (tree-sitter-language # crate), so they bind to tree-sitter 0.26 via `.into()` like the grammars above. tree-sitter-ocaml = { version = "0.25", optional = true } tree-sitter-haskell = { version = "0.23", optional = true } tree-sitter-julia = { version = "0.23", optional = true } tree-sitter-solidity = { version = "1.2", optional = true } tree-sitter-nix = { version = "0.3", optional = true } tree-sitter-powershell = { version = "0.26", optional = true } # Grammar-addon loader (#690, Phase 1b): dlopen a per-platform grammar cdylib # and reconstruct a tree_sitter::Language from its exported LanguageFn, same # as the Phase 0 spike (experiments/grammar-dlopen-spike). tree-sitter-language = { version = "0.1", optional = true } libloading = { version = "0.8", optional = true } # Exact pin: `ort` 2.0 is still in its release-candidate phase (no stable 2.0.0 # yet; rc.12 is the upstream-recommended production build). RCs can carry breaking # API changes between candidates, so `=` prevents `cargo update` from silently # pulling an unvetted rc.13+ (`ort-sys` is already `=`-pinned transitively). # Revisit when ort 2.0.0 stable ships. # # `load-dynamic` loads `libonnxruntime` at runtime (see `core::ort_environment`) # rather than linking it at build time. This is deliberate: ort's static # `download-binaries` has no `x86_64-pc-windows-gnu` artifact (our CI's Windows # target) and would statically bloat every test binary. Runtime loading keeps # builds portable; the shared library is provided by the platform package # (`onnxruntime` on Arch/Homebrew/Nix), `pip install onnxruntime`, or # `ORT_DYLIB_PATH`. ort = { version = "=2.0.0-rc.12", optional = true, default-features = false, features = [ "api-24", "std", "ndarray", "tls-rustls", "tracing", "load-dynamic", ] } ndarray = { version = "0.17", optional = true } axum = { version = "0.8", optional = true, features = ["ws"] } # Upstream WebSocket client for the Codex ChatGPT remote-control passthrough # (#597): tunnels `/backend-api` WS upgrades through to wss://chatgpt.com so # Codex Desktop remote-control pairing works while the subscription opt-in routes # model turns through the proxy. Already in the tree via axum's `ws` feature. tokio-tungstenite = { version = "0.29", default-features = false, features = [ "connect", "rustls-tls-webpki-roots", ], optional = true } # tokio-tungstenite's rustls connector relies on the process-default # CryptoProvider. The tree pulls both aws-lc-rs (reqwest) and ring (lettre/ureq), # so rustls can't auto-pick one; we install aws-lc-rs explicitly at proxy start # (#597). Default features keep the aws_lc_rs provider available. rustls = { version = "0.23", optional = true } tower-http = { version = "0.7", features = ["cors", "auth"], optional = true } deadpool-postgres = { version = "0.14", optional = true } tokio-postgres = { version = "0.7", features = [ "with-chrono-0_4", "with-uuid-1", # Evidence/GDPR exports read aggregated rows as jsonb (enterprise#36/#39). "with-serde_json-1", ], optional = true } # Postgres TLS (#54/#58): Azure Database for PostgreSQL enforces TLS — the # usage store must speak sslmode=require. Reuses the process rustls provider. tokio-postgres-rustls = { version = "0.14", optional = true } webpki-roots = { version = "1.0", optional = true } lettre = { version = "0.11", default-features = false, features = [ "tokio1-rustls-tls", "smtp-transport", "builder", ], optional = true } jsonwebtoken = { version = "10.4", optional = true } # Non-optional since GH #727: `kind=skills` document blobs (featureless # context_package core) encode zstd bodies as base64 inside the pack JSON. base64 = "0.22" uuid = { version = "1.23", features = ["v4", "serde"], optional = true } hex = { version = "0.4", optional = true } hmac = "0.13" sha2 = "0.11" hkdf = "0.13" chacha20poly1305 = "0.10" rand = { version = "0.10", optional = true } argon2 = { version = "0.5", optional = true } glob = "0.3" urlencoding = "2.1" ratatui = "0.30" crossterm = "0.29" rpassword = "7.5" ed25519-dalek = { version = "2.2", features = ["rand_core"] } getrandom = "0.4" tempfile = "3.27" reqwest = { version = "0.13", default-features = false, features = [ "rustls", "stream", "json", "cookies", ], optional = true } bytecount = "0.6" libc = "0.2" blake3 = "1.8" rayon = "1.12" moka = { version = "0.12", features = ["sync"] } postcard = { version = "1.1", features = ["use-std"] } zstd = "0.13" memmap2 = "0.9" lsp-types = "0.97" fs2 = "0.4" unicode-width = "0.2" resvg = { version = "0.47", optional = true } wasmi = { version = "1.1", optional = true } gethostname = "1.1" yaml_serde = "0.10.4" semver = "1.0.28" [lints.rust] unreachable_pub = "warn" # CI coverage (cargo-tarpaulin) injects `--cfg tarpaulin`; declare it to avoid # `-D unexpected_cfgs` failures when using `cfg_attr(tarpaulin, ...)`. unexpected_cfgs = { level = "warn", check-cfg = ["cfg(tarpaulin)"] } [lints.clippy] pedantic = { level = "warn", priority = -1 } # --- Style preferences (not quality issues) --- too_many_lines = "allow" module_name_repetitions = "allow" must_use_candidate = "allow" return_self_not_must_use = "allow" similar_names = "allow" unreadable_literal = "allow" # --- Documentation: covered by separate doc-coverage tooling --- missing_errors_doc = "allow" missing_panics_doc = "allow" doc_markdown = "allow" # --- Casts: intentional numeric conversions for token counting, stats, sizing --- cast_possible_truncation = "allow" cast_precision_loss = "allow" cast_sign_loss = "allow" cast_possible_wrap = "allow" cast_lossless = "allow" # --- Performance: format_push_string would require 276 refactors for minimal gain --- format_push_string = "allow" # --- Struct design: Config/StatsStore legitimately use many bools --- struct_excessive_bools = "allow" # --- Float: intentional comparisons in stats/benchmarks --- float_cmp = "allow" # --- Style: constants placed near usage for readability --- items_after_statements = "allow" # --- Underscore bindings: intentionally named for clarity then used --- used_underscore_binding = "allow" no_effect_underscore_binding = "allow" # --- Micro-optimization: &bool vs bool, readability preferred --- trivially_copy_pass_by_ref = "allow" # --- HashMap: we always use default hasher --- implicit_hasher = "allow" # Debug info is the bulk of `target/debug` size, and `target/` never GCs — a # heavily-rebuilt worktree can reach tens of GB. Line-table debuginfo keeps # `file:line` in panics and backtraces while dropping full variable-level data. # Set `debug = 2` in a local profile override if you need to step-debug. [profile.dev] debug = "line-tables-only" # Keeps DWARF in per-object files instead of merging into the linked binary # on every rebuild — cuts incremental link time on Linux. split-debuginfo = "unpacked" [profile.release] opt-level = "z" lto = true codegen-units = 1 strip = true panic = "unwind" [target.'cfg(windows)'.dependencies] windows-sys = { version = "0.61", features = [ "Win32_Foundation", "Win32_System_Threading", "Win32_Security", "Win32_System_Pipes", ] } [target.'cfg(not(windows))'.dependencies] tikv-jemallocator = { version = "0.7", optional = true } tikv-jemalloc-ctl = { version = "0.7", optional = true } [dev-dependencies] criterion = { version = "0.8", features = ["html_reports"] } filetime = "0.2" insta = "1.48" jsonschema = { version = "0.46", default-features = false } proptest = "1.11" serial_test = "3.5" tempfile = "3.27" tower = "0.5" wat = "1.252" [[bench]] name = "compression" harness = false [[bench]] name = "graph_export" harness = false [[bench]] name = "efficiency" harness = false # rmcp 2.2.0 on crates.io calls SseStream::from_bytes_stream but sse-stream 0.2.x # only has from_byte_stream (singular). The upstream git rev has the fix; pin to it # until rmcp publishes a corrected version. [patch.crates-io] rmcp = { git = "https://github.com/modelcontextprotocol/rust-sdk.git", rev = "67a3085", package = "rmcp" } rmcp-macros = { git = "https://github.com/modelcontextprotocol/rust-sdk.git", rev = "67a3085", package = "rmcp-macros" }