# Lexa > Fast local code intelligence for humans and AI agents. ## Benchmark Lexa includes a Criterion-based benchmark suite for indexing, search, and snapshot performance. ### Running the suite Full run: ```bash cargo bench --bench engine ``` Faster local smoke run: ```bash cargo bench --bench engine -- --warm-up-time 1 --measurement-time 2 --sample-size 10 ``` ### Baseline (June 3, 2026, generated Rust corpus) | Benchmark | Corpus | Time | | -------------------------------------- | ----------- | --------- | | `project_index/100` | 100 files | \~5.7 ms | | `project_index/500` | 500 files | \~30.8 ms | | `search/exact_word` | 1,000 files | \~57.6 µs | | `search/unique_token` | 1,000 files | \~192 µs | | `search/regex` | 1,000 files | \~54.1 µs | | `search/rich_scoped` | 1,000 files | \~92.9 µs | | `search/symbol_defs` | 1,000 files | \~91.5 ns | | `search/callers` | 1,000 files | \~97.9 µs | | `incremental_edit/single_file_reindex` | 500 files | \~1.1 ms | | `snapshot/write` | 500 files | \~6.4 ms | | `snapshot/load_into_engine` | 500 files | \~7.6 ms | ## Binary Releases GitHub Actions builds Lexa artifacts for four targets on every release tag. ### Target matrix * macOS Apple Silicon (`aarch64-apple-darwin`) * macOS Intel (`x86_64-apple-darwin`) * Linux x86\_64 (`x86_64-unknown-linux-gnu`) * Windows x86\_64 (`x86_64-pc-windows-msvc`) ### Publishing a release Tag the commit and push — the release workflow handles the rest: ```bash git tag v0.5.1 git push origin v0.5.1 ``` The workflow attaches the four binaries to the GitHub Release and updates `CHANGELOG.md` is a manual edit you make before tagging. ### Picking up a release locally ```bash lexa upgrade ``` This replaces the currently running binary with the latest release. Pin a specific version with `lexa upgrade v0.5.1`, or override the install location with `--install-dir` / `LEXA_INSTALL_DIR`. See the [Install](/docs/install) page for details. ## Changelog ### Unreleased No changes yet. ### v0.6.1 — 2026-06-04 #### Fixed * Fixed `clap` argument-id collision causing `lexa upgrade` panic when global `--version` flag and upgrade positional version argument shared the same internal id. ### v0.6.0 — 2026-06-04 #### Added * Top-level `symbol_search` for fuzzy symbol discovery when exact `symbol_defs` is too strict. * `reindex` and `clear_index` MCP tools for explicit graph recovery. * Architecture cycle detection in structural audit output. * `files` filtering by path, glob, language, and line-count bounds. #### Changed * Removed legacy MCP `pipeline.query` argument; pipeline now accepts `pipeline` or `steps`. * Made `brief` explicit about scope as a context bundle for symbols, paths, and scoped keywords — not natural-language QA. * Improved `brief` ranking and body extraction for relevant definitions. * `lexa index` prints a lightweight branded banner in interactive terminals. * Moved CLI upgrade/version-check code into a dedicated module; centralized shared output formatting. #### Fixed * Prevented invalid graph snapshots silently loading as empty index. * `audit` now refuses to run when no files are indexed. * Added header-first snapshot validation so incompatible graph versions fail before payload decoding. * Cleaned `outline` output: kept imports out of symbol list; improved missing-file/config error messages. * Improved JSON outline classification consistency; removed package manifest parser unwrap. * Named `brief` scoring weights to make future ranking changes easier to review. #### Tests * Added regression coverage: snapshot header validation, graph-loading behavior, pipeline schema cleanup, fuzzy symbol search, outline import filtering, parser edge cases. ### v0.5.1 — 2026-06-04 #### Fixed * Resolved local asset imports for SVG/PNG provider logos and known asset files without indexing binary bytes. * Returned clear metadata stubs from `read` for known binary assets instead of "missing". * Normalized TypeScript imports in outlines and dependency data to module specifiers like `./assets/logo.svg`. * Avoided TypeScript outline false positives where exported object/string values were misclassified as imports. * Made Unix upgrades install through a staged binary + atomic move to avoid macOS `Killed: 9` after in-place replacement. #### Improved * `brief` prefers relevant symbol definitions before generic snippets/call sites. * Improved `brief` natural-query handling with identifier, path, and phrase candidates. * Ranked callable definitions above related type aliases for the same concept. * Bounded large `brief` symbol bodies to 120 lines. #### Tests * Coverage for asset import resolution, metadata-only asset reads, TypeScript import normalization, brief definition ranking, phrase/path-based brief lookup, large symbol body truncation. * Verified Unix installer path with temporary install directory. ### v0.5.0 — 2026-06-04 #### Changed * Made MCP structured content opt-in to reduce duplicated tool output by default. ### v0.4.2 — 2026-06-04 #### Changed * Clarified audit verification limits; reinforced that structural audit output does not replace build, typecheck, lint, or test verification. ### v0.4.1 — 2026-06-04 #### Fixed * Detected unresolved local TypeScript imports. * Fixed Windows installer ZIP layout handling. * Read MCP stdin framing as bytes to avoid non-UTF-8 input failures. ### v0.4.0 — 2026-06-03 #### Added * Added MCP graph freshness checks and watcher support. ### v0.3.0 — 2026-06-03 #### Added * First audit command implementation. * Scoped audit strict mode. * Audit configuration. * Dead-code audit candidates. #### Improved * Refined audit reporting and release workflow behavior. ### v0.2.0 — 2026-06-03 #### Added * Lexa binary upgrade command. #### Improved * Improved import dependency resolution. * Restricted release workflow execution on pull requests. ### v0.1.0 — 2026-06-03 #### Fixed * Fixed release publishing without checkout. ## Configuration & Environment Variables Lexa has no global config file. Configuration is split between environment variables, CLI flags, and a few optional per-project files (notably the audit config). ### Environment variables | Variable | Effect | | ------------------------ | ---------------------------------------------------------------------------------------- | | `LEXA_INSTALL_DIR` | Override the directory `lexa upgrade` writes to. Equivalent to `--install-dir`. | | `LEXA_NO_UPDATE_CHECK=1` | Skip the GitHub release check that runs with `lexa --version`. | | `PATH` | Must include the directory Lexa was installed into (`~/.cargo/bin` for `cargo install`). | ### Audit config (TOML) Audit reads an optional TOML file. Auto-discovery looks for `lexa.toml` or `.lexa/audit.toml` in the project root unless `--config ` or `--no-config` is passed. See the [Audit CLI page](/docs/cli/audit) for the full schema and a minimal example. ### MCP client config The MCP server is a stdio subprocess. Configure your client (Claude Code, Cursor, etc.) with: ```json { "mcpServers": { "lexa": { "command": "/path/to/lexa", "args": ["mcp", "/path/to/project"] } } } ``` See the [MCP setup page](/docs/mcp) for the full example and the available flags. ### Graph path The default location is `/.lexa/graph.lexa`. See [Project Graph](/docs/project-graph) for the full resolution order and override flags. ## Development Lexa is a Rust project. The full contribution guide lives in [`CONTRIBUTING.md`](https://github.com/anvia-hq/lexa/blob/main/CONTRIBUTING.md). ### Building ```bash cargo build --release ``` The release binary lives at `./target/release/lexa`. ### Local checks Before opening a PR, run the formatting, lint, and test suite: ```bash cargo fmt -- --check cargo clippy --all-targets --all-features -- -D warnings cargo test ``` For performance-sensitive changes also build in release mode and consider running the [benchmark suite](/docs/benchmark). ### Tests ```bash cargo test ``` Tests live alongside the source files in each module. The audit, snapshot, brief, and pipeline subsystems each have their own focused test files. ### Benchmark See the [Benchmark](/docs/benchmark) page for the canonical baseline and the smoke-test invocation. ### Releases See [Binary Releases](/docs/binary-releases) for the publish flow. ## Getting Started If you already have `lexa` installed, head to the [Quick Start](/docs/quick-start) for the 60-second tour. ### New here? 1. [Install Lexa](/docs/install) for your platform. 2. Run the [Quick Start](/docs/quick-start) walkthrough on any project. 3. Connect an MCP client (Claude Code, Cursor, etc.) using the [MCP setup guide](/docs/mcp). 4. Skim the [CLI Overview](/docs/cli) to learn the command surface. ### Why use Lexa? Lexa is an [index-first code intelligence engine](/docs/why-lexa) — one local graph feeds both a CLI and an MCP server, so humans and AI agents work from the same view of the project. See the [Project Graph](/docs/project-graph) page to understand the model behind every command. ## Global Flags These flags apply to every Lexa subcommand unless noted. | Flag | Description | | ---------------- | --------------------------------------------------------------------- | | `--graph ` | Override the default `.lexa/graph.lexa` location for this invocation. | | `--no-graph` | Run without loading or persisting a graph snapshot. | | `--json` | Emit JSON instead of pretty text. Affects every subcommand. | | `--version` | Print the Lexa version and exit. | ### A note on `--json` The JSON shape mirrors the per-subcommand text output — there is no separate "machine format" with extra fields. The MCP `structuredContent` envelope is also JSON, but it is opt-in (see [Output Formats](/docs/mcp/output)). ### A note on `--no-graph` Use `--no-graph` for ephemeral one-shot inspections on read-only filesystems or in CI when you do not want a graph to land in the project directory. ### See also * [Project Graph](/docs/project-graph) — how the graph path is resolved. * [Configuration & Env Vars](/docs/configuration) — environment variables that influence behavior. ## Install Lexa ships as a single native binary. Pick the path that matches your platform. ### macOS / Linux ```bash curl -fsSL https://raw.githubusercontent.com/anvia-hq/lexa/main/install.sh | sh ``` ### Windows (PowerShell) ```powershell irm https://raw.githubusercontent.com/anvia-hq/lexa/main/install.ps1 | iex ``` ### Pin a specific version Pass the version you want to the installer: ```bash curl -fsSL https://raw.githubusercontent.com/anvia-hq/lexa/main/install.sh | sh -s -- v0.5.1 ``` ### Install from source If you have a Rust toolchain: ```bash cargo install --path . ``` Or build without installing and run from the working tree: ```bash cargo build --release ./target/release/lexa --help ``` ### Upgrading an existing install The `lexa upgrade` command replaces the running binary in place. ```bash lexa upgrade # latest release lexa upgrade v0.5.1 # specific version lexa upgrade --install-dir "$HOME/.local/bin" ``` By default, `lexa upgrade` updates the binary in the directory that contains the currently running `lexa`. Override that with `--install-dir` or the `LEXA_INSTALL_DIR` environment variable. After upgrading, refresh the project graph so it picks up any new metadata: ```bash lexa index . ``` ### Disabling the version check `lexa --version` does a short cached GitHub release check to report whether `lexa upgrade` is available. Set `LEXA_NO_UPDATE_CHECK=1` to skip it: ```bash LEXA_NO_UPDATE_CHECK=1 lexa --version ``` ## Language Support Lexa has two parsing tiers: tree-sitter (full symbol + import extraction) and lightweight (regex-based, symbol-level only). All 33 supported languages get outline, search, and safe-edit coverage; tree-sitter languages additionally get precise imports and dependency resolution. ### Tree-sitter (full) * Zig * Python * Rust * TypeScript * JavaScript * Go * C * C++ * Java * Ruby * PHP ### Lightweight (symbol-level) * HCL, R, Markdown, JSON, TOML, YAML * Dart, Kotlin, Swift * Svelte, Vue, Astro * shell, CSS, SCSS, SQL * protobuf, Fortran, LLVM IR, MLIR, TableGen ### Assets and binaries Binary assets (PNG, SVG, fonts, etc.) are skipped from indexing by the walker. `lexa read` returns a metadata stub for known binary assets instead of "missing" so that agents can follow asset paths without crashing. ### Filter by language ```bash lexa files apps/desktop --language typescript lexa brief "createProjectAgent" --language rust ``` The `Language` enum and `detect_language(path)` helper live in `src/types.rs`. ## Project Graph Every Lexa command operates on a single per-project graph file. ### Where the graph lives The default location is `/.lexa/graph.lexa`. Lexa resolves the graph path in this order: 1. `--graph ` (global flag) — applies to the current invocation. 2. `./.lexa/graph.lexa` relative to the canonicalized project root. 3. `./graph.lexa` relative to the current working directory. If no graph is found and the command allows it, Lexa indexes the project on the fly. Use `--no-graph` to run a command entirely in memory without loading or persisting a snapshot. ### What's in the graph The graph is a single binary snapshot that combines: * **File metadata** — language, line count, byte size, modification time. * **Symbols** — functions, structs, classes, traits, methods, types, etc. * **Imports** — both resolved project-file edges and unresolved local imports. * **Text index** — trigram and word indexes for fast substring, exact-word, and fuzzy search. * **Content cache** — LRU of recent file contents, with FNV-1a 64-bit content hashes in lower-case hex. * **Change log** — session-local, capped at 100 versions per file. ### Change history is session-local `lexa changes [since]` and the MCP `changes` tool return edits made during the current process. Snapshots persisted to `.lexa/graph.lexa` do **not** include the change log — it is rebuilt on every restart. ### Hash format Every hash Lexa emits (CLI and MCP) is the lower-case hex of an FNV-1a 64-bit content hash. Use it as an opaque token; the format may evolve. ### Recreating the graph ```bash lexa reindex . # rebuild the in-memory graph from disk lexa clear-index # remove the persisted snapshot ``` If a snapshot file is unreadable (incompatible version, partial write, etc.) Lexa prints a hint to run `lexa reindex .` or `lexa clear-index`. ## Quick Start Lexa works on any codebase — point it at a directory and it builds a local graph in milliseconds. ### The 60-second tour ```bash lexa index /path/to/project cd /path/to/project lexa files lexa text-search "handle_request" lexa outline src/main.rs lexa symbol-defs Engine lexa read src/main.rs -L 1-80 ``` What this does: * `lexa index` writes the project graph to `.lexa/graph.lexa` (overridable with `--graph`). In an interactive terminal you'll see a short branded banner. * Every later command in the same project root reads that graph automatically. * `text-search` and `symbol-defs` rank results from the index — no grep, no re-walk. * `outline` shows the symbols and imports of a single file. * `read -L 1-80` prints the first 80 lines of a file with its content hash. ### A custom graph path If you want the graph somewhere other than `.lexa/graph.lexa`, pass `--graph` once and it applies to every command: ```bash lexa --graph /tmp/project.graph.lexa index /path/to/project lexa --graph /tmp/project.graph.lexa text-search "Parser" ``` ### Where to go next * Learn the [CLI Overview](/docs/cli). * Connect an [MCP client](/docs/mcp) so agents can query the same graph. * Skim [Safe-Edit Semantics](/docs/safe-edit) before writing any automation that patches files. ## Safe-Edit Semantics Lexa reads, patches, and creates files with hash-aware concurrency control. This page describes the model. For the per-flag reference see the [Read & Edit CLI page](/docs/cli/read-edit). ### The three edit operations `lexa patch ` accepts three operations: | Op | Effect | | --------- | -------------------------------------------------------------------- | | `replace` | Replace the lines in `--line-range` (or `--after`) with `--content`. | | `insert` | Insert `--content` at `--after` (after the given 1-based line). | | `delete` | Remove the lines in `--line-range`. | Atomic file writes go through a temp file + rename (`src/edit.rs`) so a failed edit never leaves the project in a half-written state. ### The hash-aware flow Always read with `--hash` first, then pass the hash to `--if-hash` on the patch. Lexa refuses the patch if the on-disk content has changed since you read it. ```bash lexa read src/main.rs --hash # hash: 4f8a3c1e... lexa patch src/main.rs replace -L 12 --if-hash 4f8a3c1e... --content ' println!("updated");' ``` The hash is an FNV-1a 64-bit digest, lower-case hex. Treat it as an opaque token. ### Verifying without editing Pass `--if-hash` to `lexa read` to short-circuit when the content matches — useful as a cheap "did anything change?" probe in automation. ### Dry runs `lexa patch` and `lexa create` accept `--dry-run` and return a diff-style preview without touching the file. ### Path safety ### Creating files `lexa create ` writes a new file. It refuses to overwrite an existing file unless `--overwrite` is passed. Use `--dry-run` to preview. ### Recording in the change log Every successful `patch` and `create` is recorded in the session-local change log (`src/store.rs`) and bumps the change sequence. See `lexa changes [since]` to enumerate the session's history. The change log is **not** persisted to the graph file — it resets on every process start. ## Why Lexa Lexa is a fast local code intelligence engine for humans and AI agents. ### The pitch Lexa turns a codebase into a portable, queryable graph so every tool can work from the same stable view of the project. Instead of repeatedly scanning files ad hoc, Lexa indexes structure, text, symbols, imports, content hashes, and recent edits into one local graph. That gives agents: * **Compact context** — pull only the relevant symbols, files, and snippets. * **Traceable lookups** — every result points back to a real file path and line range. * **Hash-aware reads** — every read returns a content hash, so edits can be verified against the version that was inspected. * **Atomic line-based patches** — replace, insert, and delete operations reindex the touched file in one step. ### Project info | Project | Info | | --------- | ----------------------------- | | Interface | CLI and MCP server | | Index | `.lexa/graph.lexa` by default | | Runtime | Native Rust binary | | License | MIT | ### The index-first workflow ```mermaid flowchart LR A[1. Build one local graph] --> B[2. Query paths, symbols, text, outlines, imports, context] B --> C[3. Read and patch with content hashes] ``` 1. **Build one local graph for the project** with `lexa index .`. 2. **Query that graph** for paths, symbols, text, outlines, imports, and context — from the CLI or an MCP client. 3. **Read and patch files** with content hashes so edits can be checked against the version that was inspected. That makes Lexa useful as a shared context layer between a developer, a terminal workflow, and an AI agent — one local source of truth, many consumers. ## MCP Setup Lexa ships an MCP server over stdio. It exposes every CLI command as a tool under the same name, plus three recovery tools (`reindex`, `clear_index`, `status`) that the CLI does not have direct equivalents for. ### Start the server ```bash lexa index /path/to/project lexa mcp /path/to/project ``` By default the server refreshes the graph before startup and watches the project for changes while running. External edits are applied to the same in-memory graph before the next MCP request, so tools always see fresh content without a restart. If you want a fully rebuilt graph instead of the cheaper startup freshness check, run `lexa index` first. The MCP server is a stdio subprocess. In every client config below, the `lexa` command runs the MCP server. Pass the project root you want it to serve as the first arg. If `lexa` is not on the client's PATH, replace `"lexa"` with its absolute path (run `which lexa` to find it). ### Flags | Flag | Description | | ---------------------- | ---------------------------------------------------------------------------------- | | `--no-refresh` | Skip the startup graph refresh and the runtime watcher. | | `--debounce ` | Tune the watcher debounce interval (default: 500ms). | | `--no-graph` | Run without loading or persisting a graph (full reindex on every request). | | `--structured-content` | Opt in to JSON `structuredContent` in every tool response. Alias: `--json-output`. | The global `--json` flag also opts in to structured content. ### Client configuration Each section below shows the exact config block to drop in. Replace `/path/to/project` with the directory whose graph you want the server to expose. If `lexa` is not on PATH, swap `"lexa"` for its absolute path (run `which lexa` to find it). #### Claude Code Drop this in a `.mcp.json` at your project root, or in `~/.claude.json` to make it global: ```json { "mcpServers": { "lexa": { "command": "lexa", "args": ["mcp", "/path/to/project"] } } } ``` Or add it from the CLI: ```bash claude mcp add lexa -- lexa mcp /path/to/project ``` #### Claude Desktop Edit `~/Library/Application Support/Claude/claude_desktop_config.json` (macOS) or `%APPDATA%\Claude\claude_desktop_config.json` (Windows): ```json { "mcpServers": { "lexa": { "command": "lexa", "args": ["mcp", "/path/to/project"] } } } ``` #### OpenCode OpenCode reads `opencode.json` from the project root, or `~/.config/opencode/config.json` for global entries: ```json { "mcp": { "lexa": { "type": "local", "command": ["lexa", "mcp", "/path/to/project"] } } } ``` #### Codex (OpenAI CLI) Codex uses TOML. Add a server to `~/.codex/config.toml`: ```toml [mcp_servers.lexa] command = "lexa" args = ["mcp", "/path/to/project"] ``` #### Droid (Factory) Droid reads `~/.factory/mcp.json` (or `.factory/mcp.json` in the project root for project-scoped servers): ```json { "mcpServers": { "lexa": { "command": "lexa", "args": ["mcp", "/path/to/project"] } } } ``` #### Cursor Edit `~/.cursor/mcp.json` (global) or `.cursor/mcp.json` in the project root: ```json { "mcpServers": { "lexa": { "command": "lexa", "args": ["mcp", "/path/to/project"] } } } ``` #### Zed Edit `~/.config/zed/settings.json`. Zed calls MCP servers "context servers": ```json { "context_servers": { "lexa": { "command": "lexa", "args": ["mcp", "/path/to/project"] } } } ``` #### Continue Edit `~/.continue/config.json`: ```json { "mcpServers": [ { "name": "lexa", "command": "lexa", "args": ["mcp", "/path/to/project"] } ] } ``` #### Windsurf Edit `~/.codeium/windsurf/mcp_config.json`: ```json { "mcpServers": { "lexa": { "command": "lexa", "args": ["mcp", "/path/to/project"] } } } ``` #### Cline Edit the Cline MCP settings file (Command Palette → "MCP Settings" opens it). On most platforms it lives at `~/Library/Application Support/Code/User/globalStorage/saoudrizwan.claude-dev/settings/cline_mcp_settings.json` on macOS or `%APPDATA%\Code\User\globalStorage\saoudrizwan.claude-dev\settings\cline_mcp_settings.json` on Windows: ```json { "mcpServers": { "lexa": { "command": "lexa", "args": ["mcp", "/path/to/project"], "disabled": false } } } ``` #### Generic stdio client Any MCP client that speaks stdio can launch Lexa with this shape: ```json { "mcpServers": { "lexa": { "command": "lexa", "args": ["mcp", "/path/to/project"] } } } ``` ### See also * [MCP Tools Reference](/docs/mcp/tools) — every tool, with input schemas and notes. * [MCP Output Formats](/docs/mcp/output) — text vs JSON, the `groups` vs `findings` rule. ## MCP Output Formats Lexa's MCP server emits two response shapes: text only (default) and text-plus-JSON when structured content is opted in. ### Text only (default) By default every tool returns a single text content block with the same human-readable rendering the CLI would print. The JSON envelope is omitted to reduce duplicated tool output and save tokens. ### Opt in to structured content Three ways to enable it: | Surface | How | | -------------- | -------------------------------------- | | MCP-only flag | `lexa mcp --structured-content` | | MCP-only alias | `lexa mcp --json-output` | | Global | `lexa --json mcp ` | When enabled, every tool response includes both a text content block and a `structuredContent` object that mirrors the per-tool JSON shape. ### The `groups` vs `findings` rule for `audit` The `audit` response is the only one with a non-trivial shape. It exposes both a flat `findings` array and a grouped `groups` object: * `groups.primary` — strong `actionable` findings. * `groups.secondary` — lower-priority findings on the same files. * `groups.actionable` — every finding tagged `actionable`. * `groups.candidates` — every `candidate` finding. * `groups.risk_notes` — every `risk_note` finding. * `groups.expected` — every `expected` finding. When summarizing audit output, read from `groups` first and only descend to `findings` when you need the full detail on a specific item. See the [Audit CLI page](/docs/cli/audit) for the full schema. ### Per-tool JSON keys Most tools expose the same fields as their CLI `--json` output. The most notable extras are `path_glob` and `language` filters on `files`, and the full `ContextDetails` shape on `brief` (suggested next steps, relevant symbols, relevant snippets). ## MCP Tools Reference Lexa's MCP server exposes 22 tools. The table below summarizes every one. Use the per-tool headings below for input schemas and notes. ### At a glance | Tool | CLI equivalent | Required input | Notes | | -------------------------------------- | -------------------- | --------------------- | ----------------------------------------------------------------- | | [`files`](#tool-files) | `lexa files` | optional filters | Filters by path / glob / language / line count. | | [`list`](#tool-list) | `lexa list` | optional path | Immediate children of a directory. | | [`glob`](#tool-glob) | `lexa glob` | `pattern` | Glob match against indexed paths. | | [`path_search`](#tool-path_search) | `lexa path-search` | `query` | Fuzzy path search. | | [`outline`](#tool-outline) | `lexa outline` | `path` | Symbols and imports for one file. | | [`symbol_defs`](#tool-symbol_defs) | `lexa symbol-defs` | `name` | Exact symbol definitions. | | [`symbol_search`](#tool-symbol_search) | `lexa symbol-search` | `query` | Fuzzy symbol search. | | [`word_refs`](#tool-word_refs) | `lexa word-refs` | `word` | Exact identifier occurrences (incl. declarations). | | [`text_search`](#tool-text_search) | `lexa text-search` | `query` | Substring or regex text search. | | [`callers`](#tool-callers) | `lexa callers` | `name` | Non-definition call sites / usages. | | [`brief`](#tool-brief) | `lexa brief` | `task` | Compact context bundle for a code task. | | [`trace_deps`](#tool-trace_deps) | `lexa trace-deps` | `path` | Resolved `imported_by` / `depends_on` edges. | | [`read`](#tool-read) | `lexa read` | `path` | Read with optional line range, `compact`, `if_hash`. | | [`patch`](#tool-patch) | `lexa patch` | `path`, `op` | Line-based edit with `if_hash` and `dry_run`. | | [`create`](#tool-create) | `lexa create` | `path` | Create a file; refuses overwrites unless asked. | | [`changes`](#tool-changes) | `lexa changes` | optional `since` | Session-local change history. | | [`recent`](#tool-recent) | `lexa recent` | optional `limit` | Recently modified files. | | [`status`](#tool-status) | `lexa status` | — | Index status. | | [`reindex`](#tool-reindex) | — | — | Rebuild the in-memory index; persist when persistence is enabled. | | [`clear_index`](#tool-clear_index) | `lexa clear-index` | — | Clear in-memory index and remove the graph file. | | [`audit`](#tool-audit) | `lexa audit` | optional `include` | See [Audit CLI page](/docs/cli/audit) for the full schema. | | [`pipeline`](#tool-pipeline) | `lexa pipeline` | `steps` or `pipeline` | Composable query chain. | *** ### tool-files ```json { "name": "files", "arguments": { "path": "apps/desktop", "path_glob": "**/*.{ts,tsx}", "language": "typescript", "min_lines": 50, "max_lines": 500, "max_results": 20 } } ``` `max_results` is canonical; `max` is accepted as a compatibility alias. The response includes `count`, `total`, `limit`, `truncated`, `filters`, and a `files` array. ### tool-list ```json { "name": "list", "arguments": { "path": "apps/desktop" } } ``` Returns `{ path, count, entries[] }` — only the immediate children. ### tool-glob ```json { "name": "glob", "arguments": { "pattern": "**/*.rs" } } ``` Returns `{ pattern, count, total, limit, truncated, paths[] }`. ### tool-path\_search ```json { "name": "path_search", "arguments": { "query": "termnl-sess", "max_results": 5 } } ``` Returns `{ query, count, limit, results: [{ path, score }] }`. ### tool-outline ```json { "name": "outline", "arguments": { "path": "src/main.rs" } } ``` Returns `{ path, language, line_count, byte_size, symbol_count, imports, unresolved_imports, symbols[] }`. Since v0.6.0 imports are kept out of the symbol list. ### tool-symbol\_defs ```json { "name": "symbol_defs", "arguments": { "name": "Engine" } } ``` ### tool-symbol\_search ```json { "name": "symbol_search", "arguments": { "query": "createAgent", "max_results": 10 } } ``` Fuzzy — `createAgent` will also match `createProjectAgent` and friends. ### tool-word\_refs ```json { "name": "word_refs", "arguments": { "word": "Engine" } } ``` Includes declarations and definitions. For non-definition call sites only, use [`callers`](#tool-callers). ### tool-text\_search ```json { "name": "text_search", "arguments": { "query": "useEffect", "max_results": 20, "regex": false, "scope": true, "compact": false, "paths_only": false, "path_glob": "**/*.{ts,tsx}" } } ``` ### tool-callers ```json { "name": "callers", "arguments": { "name": "createProjectAgent", "max_results": 20 } } ``` Narrower than `word_refs` — skips declaration-like occurrences such as type aliases. ### tool-brief ```json { "name": "brief", "arguments": { "task": "createProjectAgent", "max_results": 10, "path_prefix": "packages/agents", "path_glob": null, "language": "typescript" } } ``` Returns a `ContextDetails` object with suggested next steps, relevant symbols, and relevant snippets. `path` is accepted as a `path_prefix` alias. Brief is a context bundler, not natural-language QA — vague queries return low-confidence results with suggested next steps. ### tool-trace\_deps ```json { "name": "trace_deps", "arguments": { "path": "src/main.rs", "direction": "imported_by", "transitive": true } } ``` `direction` is one of `imported_by` (default) or `depends_on`. External packages are not returned as dependency nodes; unresolved local imports are reported separately in the `depends_on` direction. ### tool-read ```json { "name": "read", "arguments": { "path": "src/main.rs", "line_start": 1, "line_end": 80, "compact": false, "if_hash": "4f8a3c1e..." } } ``` Text content is prefixed with `hash:` when not in `if_hash` short-circuit mode. `if_hash` short-circuits when the on-disk hash matches. ### tool-patch ```json { "name": "patch", "arguments": { "path": "src/main.rs", "op": "replace", "content": " println!(\"updated\");", "range_start": 12, "range_end": 12, "if_hash": "4f8a3c1e...", "dry_run": false } } ``` `op` is one of `replace`, `insert`, `delete`. For `insert`, pass `after` instead of a range. Always read with `read` first and pass the resulting `hash` to `if_hash` to detect concurrent changes. ### tool-create ```json { "name": "create", "arguments": { "path": "src/new_file.rs", "content": "pub fn new_file() {}", "overwrite": false, "dry_run": false } } ``` Refuses to overwrite an existing file unless `overwrite: true`. ### tool-changes ```json { "name": "changes", "arguments": { "since": 0 } } ``` `since` is a session-local sequence number, not a git ref. The change log is not persisted to the graph snapshot. ### tool-recent ```json { "name": "recent", "arguments": { "limit": 10 } } ``` ### tool-status ```json { "name": "status" } ``` Returns `{ files_indexed, symbols_indexed, unique_words_indexed, word_indexed_files, seq, change_history_persisted, graph }`. ### tool-reindex ```json { "name": "reindex" } ``` Rebuilds the in-memory index from the MCP project root and persists when persistence is enabled. ### tool-clear\_index ```json { "name": "clear_index" } ``` Clears the in-memory index and removes the graph file. Returns `{ cleared, graph_removed, graph }`. ### tool-audit ```json { "name": "audit", "arguments": { "max_results": 20, "since": "main", "config": "lexa.toml", "no_config": false, "include": ["dead-code"] } } ``` `max_results` is canonical; `max` is a compatibility alias. `config` is a TOML file path, not a named preset. Strict mode is a CLI-only flag. See the [Audit CLI page](/docs/cli/audit) for the full output shape and the `groups` vs `findings` rule. ### tool-pipeline ```json { "name": "pipeline", "arguments": { "steps": ["search AgentRunRequest", "limit 3"] } } ``` Or, if you prefer a single string: ```json { "name": "pipeline", "arguments": { "pipeline": "search AgentRunRequest | limit 3" } } ``` See the [Pipeline CLI page](/docs/cli/pipeline) for the full list of operations. ## Audit The `lexa audit` command runs a read-only review of the project graph and reports architecture findings: import cycles, large files, large symbols, and dependency hotspots. Dead-code candidates are opt-in. ```bash lexa audit lexa --json audit lexa audit --max 50 lexa audit --since main lexa audit --since main --strict lexa audit --config lexa.toml lexa audit --no-config lexa audit --include dead-code ``` ### Flags | Flag | Description | | --------------------- | ------------------------------------------------------------------------------------- | | `-m, --max` | Cap the number of findings returned. | | `--since ` | Scope findings to files changed since a git ref plus their direct dependency context. | | `--strict` | Return a non-zero exit code on high-severity structural findings. | | `--config ` | Path to a TOML config file (not a named preset). | | `--no-config` | Skip auto-discovery of `lexa.toml` / `.lexa/audit.toml`. | | `--include dead-code` | Opt in to dead-code candidate analysis. Repeatable. | ### Actionability classification Every finding is tagged with one of four actionability levels: | Tag | Meaning | | ------------ | ------------------------------------------------------------------- | | `actionable` | Likely refactor target. | | `candidate` | Verify before changing. | | `expected` | Normal dependency shape for a shared primitive or composition root. | | `risk_note` | Edit carefully; no refactor assumption required. | Human-readable output is grouped by actionability. A lower-priority finding on a file with a stronger `actionable` finding is marked `secondary`. ### JSON / MCP output shape The `--json` and MCP responses include both a flat `findings` array and a grouped `groups` object. Buckets: * `primary` — strong `actionable` findings. * `secondary` — lower-priority findings on the same files. * `actionable` — every finding tagged `actionable`. * `candidates` — every `candidate` finding. * `risk_notes` — every `risk_note` finding. * `expected` — every `expected` finding. ### Dead-code candidates Off by default — enable with `--include dead-code` or the config. Scoped to **source-code symbols only** by default. Skipped automatically: * Style sheets (CSS, SCSS) * Data and config files (JSON, YAML, TOML, …) * Package manifests * Framework config files * Tests * Generated artifacts (protobuf/gRPC, Android/Qt/Dart/C# outputs, lockfiles, build output, dependency folders, `worker-configuration.d.ts`, `routeTree.gen.ts`, Drizzle metadata) This avoids reporting tooling keys, CSS tokens, and framework mount selectors as unused. ### MCP audit call ```json { "name": "audit", "arguments": { "max_results": 20, "include": ["dead-code"] } } ``` * `max_results` is the canonical field; `max` is accepted as a compatibility alias and takes lower precedence. * `config` is a TOML file path, not a named preset. * Strict mode is a separate CLI flag and is not exposed on the MCP audit tool. ### Minimal config example (`lexa.toml`) ```toml [audit] max_findings = 100 [audit.thresholds] large_file_warning = 800 large_file_high = 1500 large_symbol_warning = 120 large_symbol_high = 250 fan_in_warning = 15 fan_in_high = 40 fan_out_warning = 20 fan_out_high = 50 [audit.rules] "architecture.cycle" = "high" "file.large" = "warning" "symbol.large" = "warning" "dependency.hotspot" = "warning" "dead_code.candidate" = "off" [audit.ignore] generated = true paths = ["target/**", "vendor/**"] findings = ["dependency.hotspot:src/main.rs"] [audit.dead_code] ignore_symbols = ["main", "handler", "setup"] entrypoint_globs = ["src/main.*", "src/bin/**", "pages/**", "app/**"] ``` ## Code Structure Commands for symbols, dependencies, and task context. ### `outline ` Show imports and symbols for a single file. ```bash lexa outline src/main.rs ``` Output includes the file's language, line count, byte size, the symbol list, the resolved import list, and any unresolved local imports. As of v0.6.0 imports are kept out of the symbol list. ### `trace-deps ` Trace the resolved project-file imports of a single file. ```bash lexa trace-deps src/main.rs lexa trace-deps src/main.rs --reverse lexa trace-deps src/main.rs --transitive ``` | Flag | Description | | ------------------ | ---------------------------------------------------------- | | `-r, --reverse` | Return files that import this one (`imported_by`) instead. | | `-t, --transitive` | Follow the graph through every intermediate file. | ### `brief ` Bundle context for an explicit code task. The task is a free-form description of what you're trying to do; Lexa returns a small, ranked set of relevant symbols, snippets, and next steps. ```bash lexa brief createAgentRuntimeForRun lexa brief "terminal session" --path-prefix apps/desktop lexa brief "createProjectAgent packages/agents" --path-prefix packages/agents --max 8 ``` | Flag | Description | | --------------- | --------------------------------------------------------------------- | | `-m, --max ` | Cap the number of context items (default: 10). | | `--path-prefix` | Restrict to a project-relative path prefix. | | `--path-glob` | Restrict to a glob. | | `--language` | Restrict to one of the [supported languages](/docs/language-support). | ## Discovery Find files and paths in the indexed project. ### `files [path]` Show indexed files, optionally filtered. ```bash lexa files lexa files apps/desktop --language typescript lexa files --path-glob "**/*.{ts,tsx}" --max-lines 200 lexa files packages --min-lines 100 --max-results 20 ``` `path` is treated as a project-relative **prefix** — `lexa files apps/desktop` returns every file under `apps/desktop/`. Use `list` if you want only the immediate children. | Flag | Description | | ----------------------------- | --------------------------------------------------------------------- | | `--path-glob` | Match a glob against the indexed path. | | `--language` | Restrict to one of the [supported languages](/docs/language-support). | | `--min-lines` / `--max-lines` | Filter by line count. | | `-m, --max-results` | Cap the number of results (`--max` is an alias). | ### `list [path]` Return only the **immediate** children of a directory — useful for navigating a tree without descending. ```bash lexa list lexa list apps/desktop ``` ### `glob ` Match indexed paths against a glob pattern. Supports `*`, `**`, `?`, and `{a,b}`. ```bash lexa glob "**/*.rs" lexa glob "apps/**/index.{ts,tsx}" ``` ### `path-search ` Fuzzy path search. Useful when you only remember part of a path. ```bash lexa path-search "termnl-sess" lexa path-search "create-project-agent" --max 5 ``` | Flag | Description | | --------------- | ---------------------------------------- | | `-m, --max ` | Cap the number of results (default: 20). | ## CLI Overview Lexa is a CLI plus an MCP server backed by a single indexed graph. Every command reads from the same per-project graph, and every command is also exposed as an MCP tool under the same name. ### Sibling pages * [Indexing](/docs/cli/indexing) — `index`, `reindex`, `clear-index`, `status`, `watch` * [Discovery](/docs/cli/discovery) — `files`, `list`, `glob`, `path-search` * [Search](/docs/cli/search) — `text-search`, `symbol-defs`, `symbol-search`, `word-refs`, `callers` * [Code Structure](/docs/cli/code-structure) — `outline`, `trace-deps`, `brief` * [Read & Edit](/docs/cli/read-edit) — `read`, `patch`, `create` * [Audit](/docs/cli/audit) — `audit` (architecture review) * [Pipeline](/docs/cli/pipeline) — `pipeline` (composable query chains) * [Maintenance](/docs/cli/maintenance) — `upgrade`, `changes`, `recent` ### Common flags and output modes Two output formats: * **Pretty text** (default) — human-friendly, colored in interactive terminals. * **JSON** — pass `--json` to switch every command's output to JSON via `serde_json::to_string_pretty`. Common command-line options: * `-m, --max ` — cap the number of results (most commands accept this). * `-L, --line-range ` — `START-END`, `START-`, or a single line number. * `--path-glob` — match a glob pattern against indexed paths. * `--language` — restrict to one of the [supported languages](/docs/language-support). ### CLI ↔ MCP parity Every CLI command has an MCP tool with the same name and (mostly) the same flags. Differences: * MCP accepts a JSON object; the CLI accepts positional args and flags. * MCP supports a `steps` array form for the [pipeline](/docs/cli/pipeline). * MCP `structuredContent` is opt-in (see [Output Formats](/docs/mcp/output)). ## Indexing These commands build, rebuild, and inspect the per-project graph. ### `index ` Index a project and write the graph. ```bash lexa index . lexa index /path/to/project lexa index . -o /tmp/custom.lexa ``` | Flag | Description | | --------------------- | ----------------------------------- | | `-o, --output ` | Override the output graph location. | In an interactive terminal, `lexa index` prints a short branded banner. ### `reindex [path]` Rebuild the in-memory graph from the on-disk tree. Useful when a snapshot is incompatible or stale. ```bash lexa reindex . lexa reindex /path/to/project ``` ### `clear-index` Remove the persisted graph snapshot (`.lexa/graph.lexa` by default). ```bash lexa clear-index ``` ### `status` Show index status without rebuilding. ```bash lexa status ``` Output includes `files_indexed`, `symbols_indexed`, `unique_words_indexed`, the current `seq`, and `change_history_persisted`. ### `watch [path]` Watch the project for changes and refresh the graph in place. The graph is persisted to disk on each refresh. ```bash lexa watch . lexa watch . --debounce 250 ``` | Flag | Description | | --------------------- | --------------------------------------------------- | | `-d, --debounce ` | Debounce interval for the watcher (default: 500ms). | ### See also * [Project Graph](/docs/project-graph) — how the graph is persisted and resolved. ## Maintenance Commands for keeping Lexa and the project graph in shape. ### `upgrade [version]` Upgrade the Lexa binary, not the project index. By default `lexa upgrade` updates the binary in the directory that contains the currently running `lexa`. ```bash lexa upgrade lexa upgrade v0.5.1 lexa upgrade --install-dir "$HOME/.local/bin" ``` | Flag | Description | | ---------------------- | --------------------------------------------- | | `--install-dir ` | Override the install directory for this call. | `LEXA_INSTALL_DIR` (env var) has the same effect. After upgrading, refresh the project graph so it picks up any new metadata: ```bash lexa index . ``` ### `changes [since]` Show files changed since the given session sequence number (default: 0). The argument is a session-local counter, **not** a git ref. ```bash lexa changes lexa changes 42 ``` ### `recent` Show recently modified files. ```bash lexa recent lexa recent --limit 5 ``` | Flag | Description | | ----------------- | ---------------------------------------- | | `-l, --limit ` | Cap the number of results (default: 10). | ## Pipeline The `lexa pipeline` command chains query operations into a single invocation. Use it to express multi-step lookups without scripting bash. ### Supported operations | Operation | Effect | | ------------------------ | ----------------------------------------- | | `find` / `glob` | Match indexed paths. | | `fuzzy` / `path_search` | Fuzzy path search. | | `search` / `text_search` | Text search. | | `filter` | Restrict the prior step's output. | | `outline` | Switch each path to its outline. | | `deps` | Switch each path to its dependency edges. | | `read` | Read the file. | | `sort` | Sort the prior step's output. | | `limit` | Cap the number of results. | | `count` | Print the count and stop. | ### Pipe string form ```bash lexa pipeline "search AgentRunRequest | limit 3" lexa pipeline "glob **/*.ts | filter --language typescript | limit 10" ``` Steps are split on `|`, trimmed, and dispatched in order. The output of one step becomes the input of the next. ### MCP `steps` array form When calling the MCP `pipeline` tool, prefer the `steps` array form over a single pipe string: ```json { "name": "pipeline", "arguments": { "steps": ["search AgentRunRequest", "limit 3"] } } ``` Both forms are accepted; the legacy `pipeline.query` argument has been removed (v0.6.0). The pipe string is still available as the `pipeline` field for clients that prefer it. ### Tips * Use `count` as the final step when you only need a number (e.g. for progress reporting). * Use `outline` after `glob` to get a one-shot file list with imports and symbols. * Combine `filter --language` and `filter --path-glob` for tight scopes. ## Read & Edit Read files, apply line-based patches, and create new files. For the conceptual model — hash-aware flow, edit ops, path safety — see [Safe-Edit Semantics](/docs/safe-edit). ### `read ` Read a file or a line range. ```bash lexa read src/main.rs lexa read src/main.rs -L 1-80 lexa read src/main.rs -L 1-80 --compact lexa read src/main.rs --hash ``` | Flag | Description | | -------------------------- | -------------------------------------------------------------------- | | `-L, --line-range ` | `START-END`, `START-`, or a single line number. | | `-c, --compact` | Suppress blank lines between code blocks. | | `--hash` | Prefix the content with its content hash. | | `--if-hash ` | Short-circuit if the on-disk hash matches; otherwise print an error. | ### `patch ` Apply a line-based edit. Always read with `--hash` first and pass it to `--if-hash` to detect concurrent changes. ```bash lexa patch src/main.rs replace -L 12 --if-hash 4f8a3c1e... --content ' println!("updated");' lexa patch src/main.rs insert --after 8 --if-hash 4f8a3c1e... --content '// new comment' lexa patch src/main.rs delete -L 12-14 --if-hash 4f8a3c1e... ``` | Flag | Description | | ----------------------- | -------------------------------------------------- | | `-L, --line-range` | Range to replace or delete. | | `--after ` | Insert after the given 1-based line. | | `--content ` | Inline replacement content. | | `--content-file ` | Read replacement content from a file. | | `--if-hash ` | Refuse the edit if the on-disk hash doesn't match. | | `--dry-run` | Preview the diff without writing. | The three operations are `replace`, `insert`, and `delete`. See [Safe-Edit Semantics](/docs/safe-edit) for the model. ### `create ` Create a new file. Refuses to overwrite an existing file unless `--overwrite` is passed. ```bash lexa create src/new_file.rs --content 'pub fn new_file() {}' lexa create src/new_file.rs --content-file /tmp/body.txt lexa create src/existing.rs --content 'replacement' --overwrite lexa create src/preview.rs --content '...' --dry-run ``` | Flag | Description | | ----------------------- | ----------------------------------- | | `--content ` | Inline file content. | | `--content-file ` | Read content from a file. | | `--overwrite` | Allow overwriting an existing file. | | `--dry-run` | Preview without writing. | ### Atomic writes Both `patch` and `create` write through a temp file and rename, so an interrupted edit never leaves the project in a half-written state. The touched file is reindexed in place and the change is recorded in the session-local change log. ## Search Text and symbol search over the indexed graph. ### `text-search ` Substring search by default; opt into regex with `--regex`. ```bash lexa text-search "render" lexa text-search "handle_request" --scope lexa text-search --regex "render[A-Z]\\w+" lexa text-search "useEffect" --path-glob "**/*.{ts,tsx}" lexa text-search "TODO" --compact --paths-only ``` | Flag | Description | | --------------- | ------------------------------------------------ | | `-m, --max ` | Cap the number of results (default: 20). | | `-r, --regex` | Treat `` as a regular expression. | | `--scope` | Include the enclosing symbol range for each hit. | | `-c, --compact` | Print compact one-line results. | | `--paths-only` | Print only file paths. | | `--path-glob` | Restrict to a glob. | The default result format is ` path:line: text`. With `--scope` the format becomes ` path:line: text [kind name:line_start-line_end]`. ### `symbol-defs ` Exact symbol definitions. ```bash lexa symbol-defs Engine lexa symbol-defs createProjectAgent ``` ### `symbol-search ` Fuzzy symbol discovery when `symbol-defs` is too strict. Use this when you only remember part of a name (`createAgent` → `createProjectAgent`). ```bash lexa symbol-search createAgent lexa symbol-search termnl --max 10 ``` | Flag | Description | | --------------- | ---------------------------------------- | | `-m, --max ` | Cap the number of results (default: 20). | ### `word-refs ` Find exact identifier occurrences **including** declarations and definitions. Useful for "where is this symbol used or defined?". ```bash lexa word-refs Engine ``` ### `callers ` Find non-definition call sites and usages. Narrower than `word-refs` — skips declaration-like occurrences such as type aliases. ```bash lexa callers createProjectAgent lexa callers handle_request --max 50 ``` | Flag | Description | | --------------- | ---------------------------------------- | | `-m, --max ` | Cap the number of results (default: 20). | ### Useful search flags ```bash lexa text-search "render" --scope lexa text-search --regex "render[A-Z]\\w+" lexa text-search "useEffect" --path-glob "**/*.{ts,tsx}" lexa text-search "TODO" --compact --paths-only lexa symbol-search createAgent ```