# Monorepo guide This guide shows how to run lean-ctx in a monorepo without letting one package's cache, index, or agent activity spill into another. ## When you need this Use this setup if your repo has multiple apps or packages, for example: - `apps/web` + `apps/api` in a pnpm or Turborepo workspace - `crates/*` in a Cargo workspace - `services/*` managed by Bazel or Buck2 The goal is simple: - keep config local to the package an agent is working on - avoid indexing build artifacts and vendor trees - keep concurrent agents from stepping on each other - preserve fast search and cache behavior in large trees ## 1. Put `.lean-ctx.toml` at the workspace you want to tune lean-ctx auto-merges a project-local `.lean-ctx.toml` with your global config. That means each package can keep its own ignore rules and performance settings. ### Example: pnpm / Turborepo ```text repo/ ├─ .git/ ├─ apps/ │ ├─ web/ │ │ └─ .lean-ctx.toml │ └─ api/ │ └─ .lean-ctx.toml ├─ packages/ │ ├─ ui/ │ └─ config/ └─ pnpm-workspace.yaml ``` `apps/web/.lean-ctx.toml` ```toml extra_ignore_patterns = [ "dist/**", ".next/**", "coverage/**", "playwright-report/**" ] memory_profile = "balanced" memory_cleanup = "shared" graph_index_max_files = 12000 ``` `apps/api/.lean-ctx.toml` ```toml extra_ignore_patterns = [ "dist/**", "tmp/**", "coverage/**", "generated/**" ] memory_profile = "balanced" memory_cleanup = "shared" ``` ### Example: Cargo workspace ```text repo/ ├─ Cargo.toml ├─ crates/ │ ├─ gateway/ │ │ └─ .lean-ctx.toml │ └─ worker/ │ └─ .lean-ctx.toml └─ target/ ``` ```toml extra_ignore_patterns = ["target/**", "coverage/**"] graph_index_max_files = 15000 ``` ### Example: Bazel / Buck2 ```toml extra_ignore_patterns = [ "bazel-bin/**", "bazel-out/**", "bazel-testlogs/**", "buck-out/**" ] memory_profile = "low" ``` ## 2. Scope BM25 and graph indexing aggressively Large monorepos get slow when indexes include generated output, vendored code, or build caches. `extra_ignore_patterns` is the main lever. Good candidates to ignore: - JS: `node_modules/**`, `dist/**`, `.next/**`, `coverage/**` - Rust: `target/**` - Python: `.venv/**`, `__pycache__/**` - Bazel/Buck2: `bazel-*/**`, `buck-out/**` - Generic generated output: `generated/**`, `vendor/**`, `.cache/**` A solid starting point for a mixed monorepo: ```toml extra_ignore_patterns = [ "node_modules/**", "dist/**", ".next/**", "coverage/**", "target/**", "vendor/**", "generated/**", "bazel-bin/**", "bazel-out/**", "buck-out/**" ] ``` If `lean-ctx doctor` warns about large BM25 indexes, tighten these patterns before increasing limits. ## 3. Let different agents work on different packages The easiest pattern is one agent per package root. Examples: - Cursor on `apps/web` - Claude Code on `apps/api` - Codex on `crates/gateway` That keeps read caches, session history, and search results naturally scoped to the folder each agent opened. When you do need cross-package awareness, prefer explicit scoping over opening the whole repo and hoping for the best: - run tools from the package root the agent owns - use tool `path` parameters to narrow searches to one service or package - keep package-specific `.lean-ctx.toml` files small and boring If you intentionally want one workspace to see sibling projects, add a `.lean-ctx.json` file with `linkedProjects`: ```json { "linkedProjects": ["../packages/ui", "../packages/config"] } ``` Use this sparingly. It is useful for shared libraries, but it also widens the search surface. ## 4. Use `.lean-ctx-id` when paths are reused This matters most in Docker, devcontainers, Codespaces, and remote sandboxes where multiple repos all mount at the same path such as `/workspace`. Create a `.lean-ctx-id` file at the project root: ```text my-monorepo-web ``` or: ```text my-monorepo-api ``` lean-ctx uses this as an explicit project identity, which prevents cache and knowledge collisions between unrelated projects that happen to share the same mount path. Use a different `.lean-ctx-id` for each logical project root that may appear at the same filesystem path. ## 5. Performance defaults for 1000+ files For large repos, start with: ```toml extra_ignore_patterns = [ "node_modules/**", "dist/**", ".next/**", "coverage/**", "target/**", "vendor/**", "generated/**" ] graph_index_max_files = 12000 memory_profile = "balanced" memory_cleanup = "shared" ``` Then adjust from symptoms: - **Index too large:** add more ignore patterns first - **Several IDEs/agents share the repo:** keep `memory_cleanup = "shared"` - **Machine is RAM-constrained:** switch `memory_profile = "low"` - **Graph coverage feels too shallow:** raise `graph_index_max_files` ## Recommended layouts ### Turborepo / pnpm workspaces - keep one `.lean-ctx.toml` per app or service - ignore `.next`, `dist`, coverage, generated client code - only link shared packages if the agent truly needs them ### Cargo workspaces - ignore `target/**` - keep service-specific config in `crates//.lean-ctx.toml` - open the crate you are editing when possible instead of the full repo root ### Bazel / Buck2 polyglot repos - ignore `bazel-*` / `buck-out` - prefer one agent per subsystem - use explicit `path` scoping for search-heavy workflows ## A practical default If you are not sure where to start, do this: 1. add `.lean-ctx.toml` in each active package 2. fill `extra_ignore_patterns` first 3. set `memory_cleanup = "shared"` if multiple tools touch the repo 4. add `.lean-ctx-id` for containerized `/workspace` setups 5. only add `linkedProjects` when cross-package search is genuinely useful That gets most monorepos into the fast and predictable zone without much tuning.