10 KiB
Contributing to lean-ctx
Thanks for your interest in lean-ctx — contributions are welcome.
Spec-driven workflow (non-trivial changes)
lean-ctx develops non-trivial features spec-anchored (review-gated SDD):
spec → plan → tasks → implement (impact-first) → verify → evidence
- Spec —
specs/NNN-<slug>/spec.md(copyspecs/_template/);NNN= tracking issue iid, acceptance criteria in EARS. One feature = one dir. - Plan — draft in your agent's plan mode (e.g. Cursor Plan Mode
Shift+Tab), then distill the approved approach intospecs/NNN-<slug>/plan.md. Review before coding. - Tasks —
specs/NNN-<slug>/tasks.md: atomic, individually testable. - Implement — impact-first: run
ctx_impact(orlean-ctx graph impact <file>) before editingrust/src/**and verify the affected tests. - Verify —
scripts/preflight.sh fast+ the affected tests. - Evidence — cite the spec in commits (
refs specs/NNN-<slug>), link issue #NNN.
Skip the full loop for trivial fixes; use it for features, contracts, and anything
touching the tool/CLI surface. See specs/README.md.
Quick start (core Rust binary)
Prerequisites
- Rust (stable) via rustup
- Git
- A C toolchain (
cc, pluscmakeforaws-lc) — several dependencies (jemalloc,aws-lc, …) build from source
Setup
git clone https://github.com/yvgude/lean-ctx.git
cd lean-ctx/rust
cargo build
cargo test
Quality bar (required)
cargo fmt --check
cargo clippy --all-targets --all-features -- -D warnings
cargo test --all-features
cargo test --release
Pre-push gate (CI parity)
make setup-hooks wires a pre-push hook that runs scripts/preflight.sh fast —
the deterministic CI jobs (fmt, clippy, rustdoc, generated-docs drift, Windows
cross-compile) mirrored locally so you catch them in seconds, not after a 50-min
matrix. It is change-aware: a docs-only push (README, CHANGELOG, *.md,
website, …) skips the Rust gates entirely, while CI still runs every job as the
source of truth. Run the full gate (everything + cargo test --lib, ignoring the
diff) with make preflight. Bypass once with SKIP_PREFLIGHT=1 git push.
A change to contract code (proxy/, tools/, config/schema/) that ships no
test signal triggers a no-test advisory; export
LEAN_CTX_PREFLIGHT_STRICT_TESTS=1 to make it blocking.
Building across worktrees & disk usage
lean-ctx pulls in a heavy native-dependency tree (jemalloc, an aws-lc
crypto build, tree-sitter grammars, …), so a debug build is larger than the Rust
source alone suggests. A couple of things worth knowing so it doesn't surprise
your disk:
- Each
git worktreegets its owntarget/. Keep several PR checkouts open and Cargo compiles the full native tree per worktree, sharing nothing between them. target/debugnever garbage-collects. Stale incremental units and old dependency versions accumulate, so one heavily-rebuilttarget/can reach tens of GB (vs. ~2 GB for a clean build).
A shared compilation cache (recommended)
sccache deduplicates dependency compiles
across worktrees and branches, without the build-lock contention a shared
CARGO_TARGET_DIR introduces:
cargo install sccache
export RUSTC_WRAPPER=sccache # add to your shell profile
A single shared
CARGO_TARGET_DIRalso dedups, but Cargo holds a per-target build lock, so concurrent builds across worktrees serialize.
Prune stale artifacts
cargo-sweep drops build artifacts past
a cutoff so target/ can't grow without bound:
cargo install cargo-sweep
cargo sweep --time 7 # remove artifacts unused for > 7 days
Reclaim space fast
target/ is always safe to delete — it's pure build output and regenerates on
the next build:
cargo clean # this checkout's target/
du -sh target # check current size
Debug info is the bulk of that size: this repo sets
[profile.dev] debug = "line-tables-only", which 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.
Cookbook / SDK / extensions (optional)
If you contribute to cookbook/ or packages/, you’ll also need:
- Node.js (>= 22.12.0)
- npm
cd cookbook
npm ci
npm test
Repo structure
lean-ctx/
├─ rust/ # core binary (CLI + MCP server + shell hook)
│ ├─ src/
│ │ ├─ main.rs # CLI entry point
│ │ ├─ lib.rs # library entry point (shared core)
│ │ ├─ mcp_stdio.rs # MCP stdio transport
│ │ ├─ server/ # MCP server state + dispatch
│ │ ├─ tools/ # MCP tool handlers (ctx_read, ctx_shell, ...)
│ │ ├─ core/ # cache, compression, patterns/, memory, graphs, ...
│ │ ├─ cli/ # CLI subcommands (setup, init, read, ...)
│ │ └─ hooks/ # editor/agent installers (Cursor, Claude Code, ...)
│ └─ tests/ # integration/e2e/adversarial tests
├─ cookbook/ # real examples + lean-ctx-client
├─ packages/ # editor integrations (VSCode, Chrome, JetBrains, ...)
├─ docs/ # repo docs (developer-facing)
└─ website/generated/ # generated schemas (tool + TDD schema)
Common contribution types
Add a shell compression pattern
- Add a new module in
rust/src/core/patterns/<tool>.rs - Implement:
pub fn compress(command: &str, output: &str) -> Option<String>
- Register the module + routing in
rust/src/core/patterns/mod.rs(try_specific_pattern) - Add tests (unit tests in the module or integration tests in
rust/tests/) - Run the quality checks above
Tip: open a ticket via the New Compression Pattern template and include raw output + expected compressed output.
Add or update an MCP tool
- Core handler logic lives in
rust/src/tools/ctx_*.rs— keep it pure and deterministic (#498). Seectx_explore.rsfor the citation-returning exploration pattern (BM25 + static graph + AST, bounded turns, no session writes). - The MCP adapter (implements
McpTool) lives inrust/src/tools/registered/ctx_*.rs: schema viatool_def, arg parsing,ToolOutput. Register it inrust/src/server/registry.rsand bump the count SSOT inrust/src/server/mod.rs(test_registry_tool_count_ssot). - For a CLI surface, add
rust/src/cli/<name>_cmd.rsand route it inrust/src/cli/dispatch/mod.rs(+dispatch/help.rs). - Regenerate and commit the SSOT artifacts:
cargo run --example gen_mcp_manifest --features dev-toolsandcargo run --example gen_docs --features dev-tools. - If you change the public tool surface, also update
LEANCTX_FEATURE_CATALOG.md(SSOT snapshot). Theentrypoints_wired,mcp_manifest_up_to_dateandreference_docs_drifttests gate the wiring end to end.
Add an addon to the registry
An addon entry in rust/data/addon_registry.json ships executable trust to
every user (a stdio addon runs code on their machine; an http addon receives
their context). Registry submissions are therefore reviewed like a security
change, not a docs change. See the
addon manifest contract.
Your submission must:
- Use a unique slug
[a-z0-9-]and fillauthor,homepage,license,description(the CI validator rejects installable entries that don't). - Pin the upstream. No
latest, nonpx/uvx-without-a-version. The exact command + version must be reproducible. - Not shell out (
sh -c,bash -c), fetch-and-exec (curl,wget), or use a non-HTTPSurl. The validator flags all of these. - Point
homepageat public, inspectable source for the MCP server. - Default to the community tier (
verifiedstaysfalse) — verification is conferred by review, never self-asserted.
Run the validator locally — it runs in CI on every change to the registry:
cd rust && cargo test --lib addons::registry
Maintainer review checklist (binding):
- Source is public and the MCP server's behaviour matches its description.
- Command/args/url are pinned and reproducible; no shell/fetch primitives.
env/headerscarry no embedded secrets; any required secret is the user's to supply, documented on the homepage.- License is a real SPDX id and compatible with redistribution of the entry.
verified = truerequires two maintainer approvals and a clean run with nowarn/dangerfinding. Otherwise it stays community-tier.- When in doubt, merge as a listed entry (no
[mcp]block) first.
Docs & examples
- Prefer real, runnable examples (no mock data)
- If you add a new example app, add it under
cookbook/examples/and ensure it talks to a reallean-ctx serveinstance
Issues
- If your issue was closed but the problem persists, comment
/reopenon it — as the original author, this reopens the issue automatically (GitHub itself does not let authors reopen maintainer-closed issues). The command is matched anywhere in your comment, so "Please/reopen" works too; issues closed as not planned stay a maintainer call - Issues closed as not planned are maintainer decisions and are not reopened automatically; a comment is still welcome
Pull requests
- Keep PRs focused (one theme per PR)
- Include a short test plan (commands you ran)
- If relevant, include a small “before/after” token-savings snippet
Contributor License Agreement (CLA)
Before your first pull request can be merged, you need to sign our Contributor License Agreement. It is a one-time, automated step: the CLA Assistant bot comments on your PR, and you sign by replying:
I have read the CLA Document and I hereby sign the CLA
The CLA keeps lean-ctx Apache-2.0 for everyone while allowing the maintainer to relicense (e.g. for the hosted/commercial offering). The free, open-source runtime for individual developers stays free — that commitment is written into the CLA itself (§8).
License
lean-ctx is distributed under the Apache License 2.0; by contributing, your contributions are licensed to the public under the same terms (see the CLA for the full grant).