Lynx discovers. Consumers decide.
Install • First repository • MCP • CLI • Platforms • Releases • Limits • Architecture
Lynx answers a single class of question extremely well:
Where, in this repository, does X live — and what is it connected to?
It turns developer intent ("where is token refresh handled?", "who calls
ValidateToken?", auth::AuthService::Login) into stable repository
coordinates — a fully-qualified symbol name, its file, and its exact line
range — plus the structural relations around it and an optional token-bounded
context package.
Lynx is not an agent, a planner, or an editor. It does not reason about what you should do, modify your code, or decide anything. It discovers, and it returns evidence; the consumer decides.
Lynx is standalone. It has no dependency on any particular agent, IDE, or MCP client.
AI agents and developer tools need reliable, fast, structured access to repository knowledge. Without a repository intelligence layer they repeatedly scan, grep, embed, and guess their way through the codebase — every query, every session.
Lynx gives them one persistent, deterministic layer instead:
- Index once, query cheaply.
lx indexwrites a persistent.lynxindex; search/resolve/relations/context hydrate it and never re-index. Queries areO(query), notO(repository). - Coordinates, not text spans. Results are symbols with stable identities, so they survive across runs and processes.
- Deterministic. Bare symbol lookups bypass ranking entirely.
- Bounded. Every query has a candidate cap, a deadline, and a cancellation token. Memory does not scale with repository size.
- Consumer-agnostic. A small CLI and a standard stdio MCP server. No SDK.
Three supported channels — all install the same lx binary and the same
lx mcp server.
1. Installer (fastest; no Rust/Node/Python/Docker runtime required):
curl -fsSL https://raw.githubusercontent.com/PizenLabs/lynx/main/install.sh | sh2. Rust-native (cargo install):
cargo install pizen-lynx # installs the `lx` binary3. Source (contributors):
git clone https://github.com/PizenLabs/lynx
cd lynx && cargo build --release -p pizen-lynx # target/release/lxThen verify whichever channel you used:
lx --version
lx doctorThe installer detects your OS and architecture, downloads the matching prebuilt
archive, verifies its SHA-256 checksum, installs the lx binary atomically
into $HOME/.local/bin, and prints PATH guidance if needed. It needs no sudo.
Inspect or control it without executing:
sh install.sh --help # usage
sh install.sh --download-only=/tmp # download + verify only, install nothing
LYNX_VERSION=v0.2.0 sh install.sh # pin a release
sh install.sh --dir "$HOME/bin" # choose the install directory
sh install.sh --system # explicit /usr/local/bin install (may need sudo)Safety properties: HTTPS-only, checksum verified before unpacking, atomic
replacement (a failed install leaves your existing lx untouched), no shell
startup files modified, no telemetry, no background service. The installer is a
single auditable file: install.sh.
crates.io note.
pizen-lynxis the product package. Its internal implementation crates (pizen-lynx-core,-storage,-parser,-embed,-protocol,-mcp) are published only because Cargo requires them forcargo install; they are not a public API and carry no stability guarantee. Seedocs/architecture/distribution-design.md.
First index note. The embedding model is downloaded once into
$HOME/.cache/lynx/fastembedon the firstlx index. Nothing else is downloaded after install.
From any repository (git not required):
cd /path/to/your/repository
lx doctor # health check: state, index, MCP
lx index # build or incrementally update <repo>/.lynx
lx status # counts, provenance, freshness
lx search "authentication middleware" # ranked symbols
lx resolve ValidateToken # exact coordinates
lx context "token refresh" --token-budget 2048 # bounded context packagelx index only re-parses and re-embeds files that changed since the last pass.
Retrieval commands hydrate <repo>/.lynx; only lx index writes it.
An agent needs only one more step: see below.
Lynx ships one canonical stdio MCP server, usable by any MCP client:
lx mcp # serve the current repository over stdio
lx mcp /path/to/repo # or pin the workspace explicitly
lx mcp --check # fast protocol smoke test (no indexing), then exitPoint your agent at the installed binary with the standard stdio shape:
{
"mcpServers": {
"lynx": { "command": "lx", "args": ["mcp"] }
}
}That is the whole integration: the consumer spawns lx, discovers the tools, and
queries the repository. Per-consumer file locations and snippets (Claude Desktop,
Claude Code, Cursor, VS Code/Copilot, OpenCode, Cline/Windsurf, Zed, Gemini CLI)
are in docs/mcp.md.
| Tool | Returns |
|---|---|
search |
Ranked matches (BM25 + embeddings, RRF-fused) |
resolve / resolve_all |
Deterministic symbol coordinates / ambiguity |
inspect |
Full evidence for one symbol |
relations |
Structural edges incident to a symbol |
similar |
Embedding-similarity neighbors |
context |
Budget-bounded ContextPackage |
index_status |
Counts, provenance, freshness |
Lynx never edits your agent configuration and never modifies unrelated files.
| Command | Purpose |
|---|---|
lx index [PATH] [--include-tests] [--force] |
Build/refresh the persistent index |
lx status [--no-check] |
Counts, provenance, freshness |
lx search <QUERY> [--mode …] [--limit N] [--explain] |
Hybrid search |
lx resolve <NAME> |
Exact symbol coordinates |
lx relations <SYMBOL> |
Structural edges |
lx context <QUERY> [--token-budget N] |
Bounded context package |
lx doctor |
Installation/index/MCP health check |
lx mcp [PATH] [--check] |
stdio MCP server / smoke test |
Full reference: docs/cli.md.
Prebuilt binaries are built natively per target and published with a
SHA256SUMS manifest:
| Platform | Architecture | Artifact | Status |
|---|---|---|---|
| macOS | arm64 (Apple Silicon) | lynx-vX.Y.Z-darwin-arm64.tar.gz |
Validated |
| Linux | x86_64 | lynx-vX.Y.Z-linux-x86_64.tar.gz |
CI-native |
| Linux | arm64 | lynx-vX.Y.Z-linux-arm64.tar.gz |
CI-native |
| macOS | x86_64 (Intel) | — | Unsupported |
| Windows | — | — | Unsupported |
"CI-native" means the target is built and validated on a native runner by the
release workflow. macOS Intel (x86_64) is unsupported because the embedding
engine is backed by ONNX Runtime, which no longer publishes an x86_64 macOS
build; use an Apple Silicon Mac or build from source. See
docs/architecture/release-readiness.md
for the exact status of each target.
Releases are triggered by Git tags, and the tag's shape decides whether
production binaries are published (the rule lives in
scripts/release/classify_tag.sh):
| Tag | Meaning |
|---|---|
v1.0.1 (stable vMAJOR.MINOR.PATCH) |
Stable release — builds production binaries, checksums, and a GitHub Release |
v1.0.1-rc.1, v1.0.1-alpha.1, v1.0.1-beta.1 |
Prerelease — validation only; does not update the stable release surface |
v1, v1.0, v1.0.0foo, release-v1.0.0 |
Invalid — the pipeline fails closed |
A stable release guarantees git tag == Cargo package version == lx --version.
The installer consumes only stable releases: latest resolves to the newest
non-prerelease release, and an explicitly requested prerelease tag is refused
unless LYNX_ALLOW_PRERELEASE=1 is set for testing.
crates.io publication is separate and maintainer-controlled. GitHub Releases
do not trigger a crates.io publish. cargo install pizen-lynx installs the one
product binary lx; the internal crates are published only because Cargo
requires them and carry no stability guarantee.
The full contract — state machine, target policy, installer rules, publication
policy — is docs/architecture/release-contract.md.
Languages. Rust, Go, TypeScript, JavaScript, and Python are parsed to symbols (functions, methods, types, traits, interfaces, enums, modules) and intra-file relations. Markdown, YAML, JSON, TOML, and unknown text files are indexed as bounded file/module documents.
Explicit limitations (not hidden):
- Semantic top-1 is representation-limited. Paraphrase recall is strong (the right symbol is almost always in the top results), but the top result is not always the right one. Lexical and structural lookups are precise.
- Relations are intra-file. Cross-file calls are not linked.
- Context ordering inherits retrieval ordering: the right symbol is usually in the package, not always first.
- Very large repositories are supported up to the measured envelope;
semantic retrieval is an exact
O(symbols)scan (no approximate index). - Resource requirements are dominated by the embedding model (~250 MB
resident). Structural commands (
resolve,relations, lexical-only search,status,doctor,--version) load no model at all.
Honest, measured numbers are in
docs/architecture/final-product-report.md
and docs/architecture/production-readiness.md.
The public product is one binary (lx) with two surfaces (lx and lx mcp).
The implementation is a modular Cargo workspace:
crates/
lynx-protocol/ frozen contracts every consumer depends on (no I/O)
lynx-parser/ source -> SymbolIdentity + intra-file Relation
lynx-embed/ text -> vector (VectorProvider seam; local FastEmbed)
lynx-storage/ DualStorage: SQLite (identity/graph/vectors) + Tantivy (lexical)
lynx-core/ Engine: discovery, indexing, retrieval, ranking, context
lynx-mcp/ stdio JSON-RPC transport + session lifecycle
lynx-cli/ `lx` command-line transport (the product package)
lynx-core owns the product logic; lynx-storage owns persistence; the
transports contain none. Nothing repository-proportional is retained in memory:
queries stream from storage under a bounded candidate budget. See
docs/architecture/final-product-audit.md.
Workspace boundaries are implementation boundaries, not public APIs. Only
pizen-lynx (the product) is a supported, versioned package. The other crates
are published to crates.io only because Cargo requires registry-resolvable
dependencies; they are internal and may change at any time. See
docs/architecture/distribution-design.md
and docs/architecture/distribution-audit.md.
benchmarks/scripts/run_final.sh # writes benchmarks/reports/final_<ts>.txtRuns the grounded retrieval suite, repository scaling, incremental indexing, persistence lifecycle, MCP stress, agent workflows, and a ripgrep baseline.
cargo fmt --all -- --check
cargo check --workspace
cargo test --workspace
cargo clippy --workspace --all-targets --all-features -- -D warningsDistribution tests (installer + clean-machine install → index → query → MCP):
make dist-test
# or
tests/distribution/run.shRelease classification and version guards (the release workflow's own logic):
tests/distribution/release_test.shRegistry / crates.io packaging test (package every crate, install pizen-lynx
from a locally assembled registry, run lx):
tests/distribution/cargo_install_test.shBuild a release binary directly:
cargo build --release -p pizen-lynx # target/release/lxMIT