# 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
```