Files
wehub-resource-sync 26382a7ac6
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
JetBrains Plugin / Actionlint (push) Has been cancelled
CodeQL / Analyze (actions) (push) Has been cancelled
CodeQL / Analyze (javascript-typescript) (push) Has been cancelled
CodeQL / Analyze (rust) (push) Has been cancelled
JetBrains Plugin / Validation (push) Has been cancelled
JetBrains Plugin / Build (push) Has been cancelled
JetBrains Plugin / Test (push) Has been cancelled
Security Check / Security Scan (push) Has been cancelled
chore: import upstream snapshot with attribution
2026-07-13 12:35:30 +08:00

8.4 KiB

Extending lean-ctx — one decision, one trust model

lean-ctx can be extended in several ways. They look similar from the outside (they all "add capabilities"), but each targets a different job and a different trust model. This guide is the single entry point: pick the right mechanism in one decision, then follow its dedicated guide.

TL;DR — building a tool or integration (in any language)? Build an Addon. Everything else is for a narrower job below.

Pick your extension type

flowchart TD
  Q0{What are you adding?}
  Q0 -->|Data: knowledge, graph, patterns to share/sell| PACK[ctxpkg Pack]
  Q0 -->|A tool / integration callable by the agent| ADDON[Addon · flagship]
  Q0 -->|An external context source feeding search/knowledge| PROV[Context Provider]
  Q0 -->|In-process compression / compute| WASM[WASM Extension]
  Q0 -->|Deep in-process build on the engine, in Rust| SDK[Embedding SDK]
  Q0 -->|A reusable config bundle| PERSONA[Persona / Policy Pack]
  Q0 -->|Local hooks on agent lifecycle events| PLUGIN[Plugin]
  • Share or sell data (knowledge, graph edges, session, patterns, gotchas) → ctxpkg Pack
  • A tool / integration the agent can call (any language, via MCP) → Addon — the flagship path
  • An external context source (issues, tickets, DB rows, a REST API, another MCP server's resources) that should flow into search + knowledge → Context Provider
  • In-process compression / computeWASM Extension (WASM ABI)
  • Deep, in-process build on the engine, in RustEmbedding SDK (lean-ctx-sdk)
  • A reusable configuration bundlePersona / Policy Pack
  • Local hooks on agent lifecycle events (pre/post tool, plus local tools) → Plugin (extension trust)

The mechanisms at a glance

Mechanism Job Lives where Distribution Trust model
Addon Expose tools to the agent External MCP server (stdio/http) Registry (lean-ctx addon) Declared [capabilities] → per-addon OS sandbox + env scrub + install consent
Context Provider Feed an external data source into the pipeline [providers.*] / ~/.config/lean-ctx/providers/ Config (+ tokens) Token-scoped; data redacted on ingest
Plugin Hooks on lifecycle events + local tools Local subprocess Local install [trust] permissions → env scrub + cwd jail + timeout
WASM Extension In-process compressor/provider Sandboxed WASM in the engine Extension registry WASM sandbox (no ambient host access)
ctxpkg Pack Ship/sell data Signed archive Hosted registry (lean-ctx pack) Ed25519 signing + publisher identity
Persona / Policy Pack Reusable config TOML bundle File / registry Inherits engine config trust (global-only floors)
Embedding SDK In-process build in Rust Your binary links the crate crates.io Runs in your process — you own the trust boundary

Resolving the common overlaps

Four mechanisms can all involve "an external MCP server" or "extra tools", which is the usual source of confusion. Disambiguation:

Addon vs [[gateway.servers]]

Same runtime, two layers. [[gateway.servers]] is the raw config primitive: a downstream MCP server the gateway aggregates. An Addon is the packaged, distributable, capability-governed form of exactly that — a lean-ctx-addon.toml manifest + registry entry + install consent + per-addon sandbox. lean-ctx addon add writes a [[gateway.servers]] entry for you and records the granted capabilities. Hand-editing [[gateway.servers]] is the escape hatch; an Addon is the supported, shareable artifact.

Addon vs [providers.mcp_bridges.<name>]

Both connect to an external MCP server, but for opposite purposes:

  • Addon exposes the server's tools so the agent can call them (ctx_tools find / call). Use it for actions.
  • MCP Bridge (a Context Provider) pulls the server's resources into the consolidation pipeline — BM25 index, graph, knowledge, session — so they become context (searchable via ctx_semantic_search, recallable via ctx_knowledge). Use it for data.

If you want the agent to do something, build an Addon. If you want lean-ctx to know something, configure a Provider/MCP Bridge.

The line is softer than it used to be: an Addon's output can also flow into the consolidation pipeline when you enable the gateway's deep-integration flags (index_output, and category adapters), so a tool's results become searchable

  • graphable too. The split is now about intent (a callable action vs a standing data source), not capability — see Why an addon goes deeper.

Addon vs Plugin

  • Addon = an MCP server whose tools plug into the gateway. Cross-language (anything that speaks MCP), distributed via the registry. This is the path for third-party tools/integrations.
  • Plugin = a local subprocess that runs on lifecycle hooks (pre/post tool call, etc.) and may register a few local manifest tools. Use it to react to agent activity locally, not to ship a distributable tool.

Naming: @ns/name

Distributable artifacts (Addons and Packs) use a namespaced identity so the same short name from two authors never collides:

@<publisher>/<name>
  • <publisher> is your registry namespace (your verified publisher handle or org).
  • <name> is the artifact slug — lowercase [a-z0-9-], no leading/trailing dash.
  • The bare <name> (no @ns/) refers to a built-in/first-party entry.

Examples: @dastholo/lean-md, @acme/jira-tools, @acme/payments-knowledge. Local-only mechanisms (Plugins, Providers, Personas) are addressed by their local id and are not namespaced.

Start building (scaffolds)

Each executable mechanism has a one-command scaffold so you start from a valid, secure-by-default artifact:

You want Command Then
An addon (tool/integration) lean-ctx addon init [name] [--http] lean-ctx addon audit ./lean-ctx-addon.tomladdon add ./…
A config provider (REST source) lean-ctx provider init <id> edit .lean-ctx/providers/<id>.toml; auto-discovered

Validate before you publish: lean-ctx addon audit runs the capability + malware gate on a single manifest, and lean-ctx addon registry validate [path] runs the full security + quality bar over a registry file (the dry-run CI uses).

One trust model

All executable extensions converge on declared, least-privilege capabilities rather than ambient trust:

  • Addons declare [capabilities] (network, filesystem, env, exec). The declaration drives a per-addon OS sandbox (sandbox-exec on macOS, bwrap on Linux) for network + filesystem — inherited by any child process — plus an environment allowlist at the single gateway spawn point, so host secrets never reach a child unless the addon lists the variable name. exec is a declared + audited capability (disclosure, not OS-enforced — child processes are already bound by the inherited net/fs sandbox). You see exactly what you grant at install. See addon-manifest-v1.
  • Plugins declare [trust] permissions (network, fs_write, env_passthrough) and share the same environment allowlist; subprocesses get a scrubbed env + cwd jail + per-call timeout.
  • WASM Extensions run in a WASM sandbox with no ambient host access.
  • Packs carry no executable code; they are Ed25519-signed and bound to a publisher identity.

Secure-by-default: an Addon that declares a [capabilities] block but omits a field gets the most restrictive value (no network, read-only filesystem, scrubbed env). An Addon with no block keeps the legacy global addons.sandbox behaviour.

See also