Skip to main content
Lettuce runs fully local-first. You index a repo into a single SQLite file on disk, then point your coding agent at a stdio MCP server that reads that file. Nothing is uploaded — source, graph, and embeddings all stay on your machine, and there’s no API key or network call at query time.
Prefer a hosted endpoint with no local setup? See the Quickstart for lettuce cloud instead. The tools your agent calls (understand, read_snippet, …) are the same either way.

1. Install

Lettuce is a Python package managed with uv.
This exposes two commands you’ll use: codewaze (the CLI) and codewaze-mcp (the stdio MCP server).

2. Index a codebase

Point index at a repo. Lettuce walks the tree, parses each source file with tree-sitter into a graph of symbols (files, classes, functions, methods, variables) and relationships (contains, imports, calls, inherits, references), and builds semantic embeddings so understand and search can match by meaning.
The graph is written to <repo>/.lettuce/graph.db by default. Re-running index refreshes it.
The first index downloads a small embedding model (BAAI/bge-small-en-v1.5, ~130 MB, runs on CPU via ONNX) and loads it once — budget ~30–60s of one-time startup. Subsequent indexes are fast.

Options

Where to write the graph DB. Defaults to <first-repo>/.lettuce/graph.db. Pass an explicit path to put it elsewhere or to share one map across repos.
Build semantic embeddings (on by default). --no-embed is faster but leaves understand/search lexical-only — they’ll work, but match on names and text rather than meaning.
Scope the graph to a branch. Defaults to the repo’s current git branch. Re-indexing a different branch never clobbers a previously indexed one, so you can keep several branches mapped in the same DB.

Multiple repos in one map

Pass several paths plus a shared --db to build a single cross-repo graph — calls and imports resolve across repo boundaries, so an agent can follow a reference from a service into the library it depends on:

3. Query from the CLI (optional)

You can drive the graph directly to sanity-check an index:
Each --repo resolves to that repo’s .lettuce/graph.db; pass --db to point at a shared map instead.

4. Connect your agent

The local server speaks MCP over stdio — your agent launches it as a subprocess, no port or auth.

Claude Code

Cursor / Windsurf / Cline

Add a stdio server to the agent’s MCP config (e.g. .cursor/mcp.json):
By default the local server exposes a minimal two-tool surfaceunderstand and read_snippet — which is all most agents need. Set CODEWAZE_MCP_FULL=1 in the server’s environment to expose the full navigation surface (search, find_symbol, callers, callees, find_path, transitive, subgraph, …); see MCP tools.
Each tool takes an optional repo (a path) or db argument so the server knows which graph to read. You can also set LETTUCE_DB in the server’s environment to pin it to a single graph and drop the argument entirely.

5. Tell the agent to use it

Agents won’t reach for a new tool unprompted. Drop this into the repo’s CLAUDE.md (or your agent’s equivalent):
Now ask “Who calls process_payment, and what would break if I rename it?” — the agent should answer from a single understand call instead of grepping and reading whole files.

Languages

Python, TypeScript, JavaScript, Go, Rust, Java, Ruby, C, C++, .NET (C#), PHP, Kotlin, Scala, Swift, Bash, and Lua. Python and TS/JS use hand-written tree-sitter walkers; the rest go through a shared generic extractor.

Where things live

The graph DB is portable — copy it to another machine and the MCP server reads it as-is. No daemon, no server, no external service.