# Appendix — Paths, Env Vars & Config Where lean-ctx stores everything, every environment variable that changes its behavior, and every config section. Source: `rust/src/core/data_dir.rs`, `rust/src/core/config/`. --- ## 1. Directories (XDG Base Directory layout) Since GH #408 lean-ctx separates its files into the standard XDG categories so the **config dir can be mounted read-only**. Typed resolvers live in `rust/src/core/paths.rs` (`config_dir()`, `data_dir()`, `state_dir()`, `cache_dir()`, `runtime_dir()`). | Category | Default | Override | Contents | |----------|---------|----------|----------| | **Config** | `$XDG_CONFIG_HOME/lean-ctx` (`~/.config/lean-ctx`) | `LEAN_CTX_CONFIG_DIR` | `config.toml`, `env.sh`, `shell-hook.*` — **RO-safe** | | **Data** | `$XDG_DATA_HOME/lean-ctx` (`~/.local/share/lean-ctx`) | `LEAN_CTX_DATA_DIR` | `sessions/`, `vectors/`, `graphs/`, `knowledge/`, `archives/`, `memory/`, `packages/`, `agents/`, `stats.json`, `client-id.json` | | **State** | `$XDG_STATE_HOME/lean-ctx` (`~/.local/state/lean-ctx`) | `LEAN_CTX_STATE_DIR` | `events.jsonl`, `journal.md`, `*.log`, `mcp-live.json`, `heatmap.json`, `pipeline_stats.json`, `cost_attribution.json`, `context_ledger.json`, `cooccurrence/`, `tee/`, `dashboard.token`, `agent_runtime_env.json` (`0600`) | | **Cache** | `$XDG_CACHE_HOME/lean-ctx` (`~/.cache/lean-ctx`) | `LEAN_CTX_CACHE_DIR` | `semantic_cache/`, `models/`, `anomaly_detector.json`, `*_learned.json`, `litm_calibration.json`, `context_ir_v1.json`, `latest-version.json`, `.first_run_wow_done` | | **Runtime** | `dirs::data_local_dir()/lean-ctx` | — | `daemon.pid`, `daemon.sock`, `daemon-*.log`, `*.lock` | Unix dir permissions: `0700`. The **Runtime** dir is the OS data-local dir (`~/.local/share/lean-ctx` on Linux, `~/Library/Application Support/lean-ctx` on macOS); it holds only daemon IPC and is intentionally separate from the data dir. ### Resolution order (per category) Each resolver applies the same three steps: 1. **Explicit override** — `LEAN_CTX__DIR` set & non-empty → wins. 2. **Single-dir backward-compat** — existing installs never split silently. If `LEAN_CTX_DATA_DIR` points at a **non-standard** path, **or** legacy `~/.lean-ctx` holds data, **or** mixed `$XDG_CONFIG_HOME/lean-ctx` holds data (the pre-#408 layout), then **all** categories collapse onto that one directory — byte-for-byte the old behavior. 3. **XDG split default** — a fresh install uses the per-category default above. "Holds data" = contains a data marker (`stats.json`, `sessions/`, `vectors/`, `graphs/`, `knowledge/`). `config.toml`/hooks alone do **not** count, so a config-only dir does not pin the other categories back onto it. > **Data-only pin (GH #594).** A `LEAN_CTX_DATA_DIR` equal to the *standard* > data dir (`$XDG_DATA_HOME/lean-ctx`) is treated as a data pin only and does > **not** collapse config/state/cache. Older versions baked exactly that value > into editor MCP `env` blocks; honoring it as single-dir made the MCP server > read `config.toml` from the data dir while the CLI read it from the config dir. > Now both keep the XDG split, so they always read the same config. > **Don't hardcode `LEAN_CTX_DATA_DIR`** in editor MCP configs — a *custom* path > still forces the legacy single-dir layout. Leave it unset for the clean XDG > split; existing installs are auto-detected and keep working, and `setup` / > `update` strip any stale pin a previous version may have written. ### Migrate an existing install to the split (opt-in) Legacy/mixed installs keep working in single-dir mode. To adopt the four-dir layout on demand: | Command | Effect | |---------|--------| | `lean-ctx doctor` | Reports `XDG layout: N item(s) in single dir` when a split is available | | `lean-ctx doctor --fix` | Moves data/state/cache out of the config dir into their XDG homes | The migration is **all-or-nothing** (partial moves would re-collapse via back-compat), **idempotent/resumable** (existing destinations are skipped, never clobbered) and **crash-safe** (atomic `rename`, copy+remove fallback across filesystems; the source is removed only after a successful copy). An explicit `LEAN_CTX_DATA_DIR` is treated as a deliberate single-dir choice and is never auto-split; runtime files are left in place. ### Read-only config sandbox (the #408 goal) Once split, the config dir holds only `config.toml` + hooks, so it can be mounted read-only while the writable categories live elsewhere: ``` --ro $XDG_CONFIG_HOME/lean-ctx # config.toml, shell hooks --rw $XDG_DATA_HOME/lean-ctx # sessions, vectors, graphs, knowledge --rw $XDG_STATE_HOME/lean-ctx # events, journals, logs, ledgers --tmpfs $XDG_CACHE_HOME/lean-ctx # semantic cache, models (regenerable) # runtime (daemon.pid/sock) lives in the OS data-local dir ``` Project-local lean-ctx data (in the repo, not these dirs): `.lean-ctx.toml` (project config override), `.lean-ctx-id`, `.lean-ctx/`. --- ## 2. Environment variables There are ~120 env vars; the ones you'll actually touch are below. The full list is in `rust/src/core/config/`. Most have a matching `config.toml` key — the env var always wins. ### The ones you'll use | Variable | Purpose | Default | |----------|---------|---------| | `LEAN_CTX_DISABLED=1` | Bypass ALL compression + disable shell hook | unset | | `LEAN_CTX_RAW=1` | Uncompressed output for one command | unset | | `LEAN_CTX_DATA_DIR` | Explicit data dir; a *custom* path also forces legacy single-dir mode (a standard-path pin is **data-only**, see §1) | `$XDG_DATA_HOME/lean-ctx` | | `LEAN_CTX_CONFIG_DIR` | Explicit config dir (`config.toml`, hooks) | `$XDG_CONFIG_HOME/lean-ctx` | | `LEAN_CTX_STATE_DIR` | Explicit state dir (events, logs, ledgers) | `$XDG_STATE_HOME/lean-ctx` | | `LEAN_CTX_CACHE_DIR` | Explicit cache dir (semantic cache, models) | `$XDG_CACHE_HOME/lean-ctx` | | `LEAN_CTX_PROJECT_ROOT` | Explicit project root | auto-detected | | `LEAN_CTX_TOOL_PROFILE` | `minimal\|standard\|power` | config / power | | `LEAN_CTX_PROFILE` | Active context profile | config / `coder` | | `LEAN_CTX_COMPRESSION` | `off\|lite\|standard\|max` | config / `lite` | | `LEAN_CTX_RESEARCH_PROSE_CAP` | Proxy research prose squeeze cap in bytes | `20000` | | `LEAN_CTX_MEMORY_PROFILE` | `low\|balanced\|performance` | `performance` | | `LEAN_CTX_PROXY_PORT` | Proxy port | `4444` | | `LEAN_CTX_NO_UPDATE_CHECK=1` | Disable update check | unset | | `LEAN_CTX_ALLOW_PATH` | Extra PathJail roots (path list; see §5) | unset | | `LEAN_CTX_EXTRA_ROOTS` | Multi-root workspace roots (path list; see §5) | unset | ### Provider tokens (for `ctx_provider`) `GITHUB_TOKEN` / `GH_TOKEN`, `GITLAB_TOKEN` / `CI_JOB_TOKEN`, `JIRA_URL` + `JIRA_EMAIL` + `JIRA_TOKEN`, `DATABASE_URL`. Optional LLM enhance: `OPENROUTER_API_KEY`, `ANTHROPIC_API_KEY`. ### Internal (set by lean-ctx itself — don't set these) `LEAN_CTX_MCP_SERVER`, `LEAN_CTX_ACTIVE`, `LEAN_CTX_HOOK_CHILD`, `LEAN_CTX_HEADLESS`, `LEAN_CTX_PLUGIN_DIR`, etc. --- ## 3. Config file (`config.toml`) Global at `/config.toml` (`$XDG_CONFIG_HOME/lean-ctx/config.toml`, or the single dir for legacy/mixed installs — see §1); per-project override at `/.lean-ctx.toml` (merged, project wins). Manage with `lean-ctx config` (`set`, `schema`, `validate`, `show`). ### Sections | Section | What it controls | |---------|------------------| | (root keys) | compression, cache, shell hook, profiles, memory caps, savings footer, proxy tri-state | | `[tools]` | `profile` (minimal/standard/power), explicit `enabled` list | | `[setup]` | `auto_inject_rules`, `auto_inject_skills`, `auto_update_mcp` | | `[archive]` | Zero-loss tool-output archive: `enabled`, `threshold_chars` (800), `max_age_hours` (48), `max_disk_mb` (500) | | `[search]` | BM25/dense/splade weights + candidate counts | | `[autonomy]` | Auto preload/dedup/consolidate, cognition loop | | `[providers]` | GitHub/GitLab/Jira/Postgres + MCP bridges | | `[loop_detection]` | Per-tool call limits to prevent agent loops | | `[updates]` | `auto_update`, `check_interval_hours` (6), `notify_only` | | `[boundary_policy]` | Cross-project search/import + universal gotchas | | `[secret_detection]` | Secret redaction in output | | `[cloud]` | `contribute_enabled` + sync timestamps | | `[proxy]` | Upstream URLs for Anthropic/OpenAI/Gemini | | `[memory.*]` | Knowledge/episodic/procedural/lifecycle/gotcha/embeddings caps | | `[llm]` | Optional local LLM enhance (Ollama) | Key defaults worth knowing: - `compression_level = "lite"` (root) — light compression on by default. - `savings_footer = "always"` config default, but the **`SavingsFooter` enum default is `Never`** so no inline footer tokens are emitted unless enabled. - `memory_profile = "performance"`, `memory_cleanup = "aggressive"`. - `[memory.knowledge] max_facts = 200` — the source of doctor's "facts at capacity" warning. --- ## 4. Files written outside the lean-ctx dirs | Category | Examples | Written by | |----------|----------|-----------| | Shell hook | `~/.zshenv`, `~/.bashenv`, fish, PowerShell profile | `setup` step 1 / `init --global` | | Agent aliases | `~/.zshrc`, `~/.bashrc` (lean-ctx-on/off/mode/status) | `setup` / `init --global` | | MCP configs | `~/.cursor/mcp.json`, `~/.claude.json`, ~30 editors | `setup` step 3 / `init --agent` | | Agent rules (opt-in) | `~/.cursor/rules/lean-ctx.mdc`, `AGENTS.md` blocks | `setup` step 4 | | Skills (opt-in) | `~/.claude/skills/lean-ctx/`, … | `setup` step 6 | | Proxy env (opt-in) | RC exports, `~/.claude/settings.json`, Codex `config.toml` | `proxy enable` | | Autostart | `~/Library/LaunchAgents/com.leanctx.{proxy,daemon,autoupdate}.plist`; systemd user units on Linux | setup steps 5/9 | | Binary | `~/.local/bin/lean-ctx` | installer / `dev-install` | Every edit to an existing file goes through `config_io::write_atomic`, which writes a `*.lean-ctx.bak` backup first. Rules injection only rewrites content between `` markers — your own content is preserved. `lean-ctx uninstall` reverses all of the above. --- ## 5. Filesystem boundary — `path_jail`, `allow_paths`, `extra_roots` (GH #392) All tool file access (`ctx_read`, `ctx_edit`, `ctx_tree`, …) is jailed under the current `project_root` (**PathJail**). Three knobs widen or remove that boundary — they overlap, so here is exactly what each one does: | Knob | Effect | Use when | |------|--------|----------| | `allow_paths = ["…"]` (root key) | **Adds** directories to PathJail's whitelist. Tools may read/edit under them, but `ctx_tree`/`ctx_search` do **not** scan them. | One extra directory needs to be readable/editable (e.g. a shared skills folder). | | `extra_roots = ["…"]` (root key) | Same whitelist effect as `allow_paths` **plus** multi-root scanning: `ctx_tree`, `ctx_search`, overview treat them as additional project roots. | Multi-repo workspaces. | | `path_jail = false` (root key) | **Disables PathJail entirely** — every absolute path is allowed. | Sandboxed environments (bwrap, containers, VMs) where the OS is the boundary. | | `allow_ide_config_dirs = true` (root key) | **Adds every supported editor's config dir** to the read whitelist — registry-derived (`~/.cursor`, VS Code, Cline/Roo, JetBrains, …). Opt-in; exposes other agents' sessions/credentials. | Letting the agent manage MCP setup across editors. | Env equivalents (path-list syntax, `:` on Unix / `;` on Windows): `LEAN_CTX_ALLOW_PATH` (= `allow_paths`), `LEAN_CTX_EXTRA_ROOTS` (= `extra_roots`). Notes that save debugging time: - **`~`, `$VAR` and `${VAR}` are expanded** in `allow_paths` / `extra_roots` / the env vars (since v3.8.1). On older versions `"$HOME/code"` was matched literally and silently never applied. - `allow_paths = ["/"]` technically whitelists everything; prefer the explicit `path_jail = false` — `lean-ctx doctor` flags the `"/"` pattern. - Config changes are picked up on the next tool call (mtime-based reload); no MCP server restart needed. If a change appears to do nothing, run `lean-ctx doctor`: it reports config parse errors (a broken `config.toml` silently falls back to defaults) and dead `allow_paths` entries (unset `$VAR`, missing directory), plus the effective jail state. - **Compile-time off-switch:** building with the `no-jail` cargo feature removes the jail entirely (for trusted single-user builds). - **Removed:** the `LEAN_CTX_NO_JAIL=1` env var (≤ 3.7.3). It was replaced by the `path_jail = false` config key and the `no-jail` compile feature; setting the old env var has no effect on current versions. - Home-level IDE config dirs are excluded from the jail's whitelist by default. Opt in with `allow_ide_config_dirs = true` (or `LEAN_CTX_ALLOW_IDE_DIRS=1`): the allow-list is **derived from the editor registry**, so it covers every supported editor — including non-dotfile layouts like VS Code (`~/Library/Application Support/Code/User`), Cline/Roo and JetBrains — and never drifts as editors are added. `~/.lean-ctx` is always allowed, and a config file that lives directly in `$HOME` never widens the jail to the whole home directory. `lean-ctx setup` asks once (informed consent) and the relaxation is audited by `lean-ctx doctor`. These dirs expose other agents' sessions and credentials.