next-plaid

Library Listed

CPU-based PLAID implementation for multi-vector search using ndarray

Checked · Sources

Downloads
256
Dependents
1
Stars
610
Forks
67
Contributors
21
Commits
765
Latest release
1.8.5 ·

About

From the project README ·

NextPlaid & ColGREP

NextPlaid is a multi-vector search engine. ColGREP is semantic code search, built on it.

ColGREP · NextPlaid · Models

ColGREP demo


ColGREP

Semantic code search for your terminal and your coding agents. Searches combine regex filtering with semantic ranking. All local, your code never leaves your machine.

Quick start

Install with Homebrew (macOS / Linux):

brew install lightonai/tap/colgrep && colgrep --install-agent

or with the shell installer:

curl --proto '=https' --tlsv1.2 -LsSf https://github.com/lightonai/next-plaid/releases/latest/download/colgrep-installer.sh | sh && "${CARGO_HOME:-$HOME/.cargo}/bin/colgrep" --install-agent

colgrep --install-agent downloads the local model behind agent mode (one-time, 2.5 GB): a small model that explores your codebase like a sub-agent and returns the code locations that answer a question. To install colgrep alone, drop the && … part; you can run colgrep --install-agent later.

Build the index:

colgrep init /path/to/project  # specific project
colgrep init                   # current directory

Search:

colgrep "database connection pooling"
Read the full README

Or ask the agent: it searches with colgrep, reads the candidates, and returns the exact lines that answer the question (after colgrep --install-agent):

colgrep --agent "where is the database connection pool configured"

That's it. No server, no API, no dependencies. ColGREP is a single Rust binary with everything baked in. colgrep init builds the index for the first time. After that, every search detects file changes and updates the index automatically before returning results.

Regex meets semantics:

colgrep -e "async.*await" "error handling"
Change the model

The default is lightonai/LateOn-Code-edge. Switch to any other ColBERT-style model on HuggingFace:

# Persist as the default (existing indexes for other models are kept)
colgrep set-model lightonai/LateOn-Code

# One-shot override for a single query or init
colgrep --model lightonai/LateOn-Code "database connection pooling"

# See which model an index was built with
colgrep status

# Private HuggingFace model
HF_TOKEN=hf_xxx colgrep set-model myorg/private-model

Each (project, model) pair has its own index directory, so switching models never corrupts existing indexes and you can flip back and forth without re-indexing. colgrep clear scopes to the active model; colgrep clear --all wipes every index.

Agent integrations
ToolInstall
Claude Codecolgrep --install-claude-code
OpenCodecolgrep --install-opencode
Codexcolgrep --install-codex
Hermescolgrep --install-hermes

Restart your agent after installing. Claude Code has full hooks support. OpenCode, Codex, and Hermes integrations are basic for now, PRs welcome.

How it works
flowchart TD
    A["Your codebase"] --> B["Tree-sitter"]
    B --> C["Structured representation"]
    C --> D["LateOn-Code-edge · 17M"]
    D --> E["NextPlaid"]
    E --> F["Search"]

    B -.- B1["Parse functions, methods, classes"]
    C -.- C1["Signature, params, calls, docstring, code"]
    D -.- D1["Multi-vector embedding per code unit · runs on CPU"]
    E -.- E1["Rust index binary · quantized · memory-mapped · incremental"]
    F -.- F1["grep-compatible flags · SQLite filtering · semantic ranking
100% local, your code never leaves your machine"]

    style A fill:#4a90d9,stroke:#357abd,color:#fff
    style B fill:#50b86c,stroke:#3d9956,color:#fff
    style C fill:#50b86c,stroke:#3d9956,color:#fff
    style D fill:#e8913a,stroke:#d07a2e,color:#fff
    style E fill:#e8913a,stroke:#d07a2e,color:#fff
    style F fill:#9b59b6,stroke:#8445a0,color:#fff
    style B1 fill:none,stroke:#888,stroke-dasharray:5 5,color:#888
    style C1 fill:none,stroke:#888,stroke-dasharray:5 5,color:#888
    style D1 fill:none,stroke:#888,stroke-dasharray:5 5,color:#888
    style E1 fill:none,stroke:#888,stroke-dasharray:5 5,color:#888
    style F1 fill:none,stroke:#888,stroke-dasharray:5 5,color:#888

Agent mode. Your coding agent (Claude, GPT, Gemini, …) can call colgrep itself, or hand the whole question to colgrep --agent: a small search model that runs on your machine, calls colgrep as many times as it needs, reads the candidates, and returns only the lines that answer. The large model gets the answer without spending its context on the search.

flowchart TD
    L["Coding agent · Claude, GPT, Gemini, …"]
    A["colgrep --agent · 2B search model"]
    S["colgrep"]
    M["LateOn-Code-edge · 17M"]
    I["NextPlaid index"]

    L -->|"delegates a question"| A
    L -->|"or searches directly"| S
    A -->|"many searches and reads"| S
    S --> M
    M --> I
    A -. "file:line locations" .-> L

    L -.- L1["Plans, edits, reviews · large model, any provider"]
    A -.- A1["Searches, reads files read-only, picks the exact lines
runs locally on GPU or CPU"]
    M -.- M1["Multi-vector embedding per code unit · runs on CPU"]

    style L fill:#4a90d9,stroke:#357abd,color:#fff
    style A fill:#9b59b6,stroke:#8445a0,color:#fff
    style S fill:#50b86c,stroke:#3d9956,color:#fff
    style M fill:#e8913a,stroke:#d07a2e,color:#fff
    style I fill:#e8913a,stroke:#d07a2e,color:#fff
    style L1 fill:none,stroke:#888,stroke-dasharray:5 5,color:#888
    style A1 fill:none,stroke:#888,stroke-dasharray:5 5,color:#888
    style M1 fill:none,stroke:#888,stroke-dasharray:5 5,color:#888

What the model sees. Each code unit is converted to structured text before embedding:

# Function: fetch_with_retry
# Signature: def fetch_with_retry(url: str, max_retries: int = 3) -> Response
# Description: Fetches data from a URL with retry logic.
# Parameters: url, max_retries
# Returns: Response
# Calls: range, client.get
# Variables: i, e
# Uses: client, RequestError
# File: src/utils/http_client.py

def fetch_with_retry(url: str, max_retries: int = 3) -> Response:
    """Fetches data from a URL with retry logic."""
    for i in range(max_retries):
        try:
            return client.get(url)
        except RequestError as e:
            if i == max_retries - 1:
                raise e

This structured input gives the model richer signal than raw code alone.

Documentation: install variants, performance tuning, all flags and options → ColGREP documentation

Benchmark

NDCG@10 on the Semble code-search benchmark — ColGREP LateOn-Code 0.859, semble potion-code-16M 0.853, ColGREP LateOn-Code-edge 0.846

ColGREP against Semble public bench: 1,251 queries × 63 repos × 19 languages (FP32).


Why multi-vector?

Standard vector search collapses an entire document into one embedding. That's a lossy summary. Fine for short text, bad for code where a single function has a name, parameters, a docstring, control flow, and dependencies.

Multi-vector keeps ~300 embeddings of dimension 128 per document instead of one. At query time, each query token finds its best match across all document tokens (MaxSim). More storage upfront. That's what NextPlaid solves with quantization and memory-mapped indexing.


NextPlaid

A local-first multi-vector database with a REST API. It's what powers ColGREP under the hood, but it's a general-purpose engine you can use for any retrieval workload.

  • Built-in encoding. Pass text, get results. Ships with ONNX Runtime for ColBERT models, no external inference server needed.
  • Memory-mapped indices. Low RAM footprint, indices live on disk and are paged in on demand.
  • Product quantization. 2-bit or 4-bit compression. A million documents fit in memory.
  • Incremental updates. Add and delete documents without rebuilding the index.
  • Metadata pre-filtering. SQL WHERE clauses on a built-in SQLite store. Filter before search so only matching documents are scored.
  • CPU-optimized. Designed to run fast on CPU. CUDA supported when you need it.

NextPlaid vs FastPlaid. FastPlaid is a GPU batch indexer built for large-scale, single-pass workloads. NextPlaid wraps the same FastPlaid algorithm into a production API that handles documents as they arrive: incremental updates, concurrent reads/writes, deletions, and built-in encoding. Use FastPlaid for bulk offline indexing and experiments, NextPlaid for serving and streaming ingestion.

Quick start

Run the server (Docker):

# CPU
docker pull ghcr.io/lightonai/next-plaid:cpu-1.8.5
docker run -p 8080:8080 -v ~/.local/share/next-plaid:/data/indices \
  ghcr.io/lightonai/next-plaid:cpu-1.8.5 \
  --host 0.0.0.0 --port 8080 --index-dir /data/indices \
  --model lightonai/answerai-colbert-small-v1-onnx --int8
# GPU
docker pull ghcr.io/lightonai/next-plaid:cuda-1.8.5
docker run --gpus all -p 8080:8080 -v ~/.local/share/next-plaid:/data/indices \
  ghcr.io/lightonai/next-plaid:cuda-1.8.5 \
  --host 0.0.0.0 --port 8080 --index-dir /data/indices \
  --model lightonai/GTE-ModernColBERT-v1 --cuda

Query from Python:

pip install next-plaid-client
from next_plaid_client import NextPlaidClient, IndexConfig

client = NextPlaidClient("http://localhost:8080")

# Create index
client.create_index("docs", IndexConfig(nbits=4))

# Add documents, text is encoded server-side
client.add(
    "docs",
    documents=[
        "next-plaid is a multi-vector database",
        "colgrep is a code search tool based on NextPlaid",
    ],
    metadata=[{"id": "doc_1"}, {"id": "doc_2"}],
)

# Search
results = client.search("docs", ["coding agent tool"])

# Search with metadata filtering
results = client.search(
    "docs",
    ["vector-database"],
    filter_condition="id = ?",
    filter_parameters=["doc_1"],
)

# Delete by predicate
client.delete("docs", "id = ?", ["doc_1"])

Or via the CLI (pip install "next-plaid-client[cli]"):

next-plaid index create docs
next-plaid document add docs --text "hello world"
next-plaid search docs "hello"

Once the server is running: Swagger UI · OpenAPI spec

Documentation: REST API reference, Docker Compose, environment variables → NextPlaid documentation


API Benchmarks

End-to-end benchmarks against the NextPlaid API on BEIR datasets. Documents are uploaded as raw text in parallel batches of 64. Search queries are sent as raw text, one at a time, with 16 concurrent workers to simulate real user traffic. All throughput numbers (docs/s, QPS) include encoding time — the model runs inside the API, so every document and query is embedded on the fly within the API.

Setup: lightonai/GTE-ModernColBERT-v1 on NVIDIA H100 80GB, top_k=100, n_ivf_probe=8, n_full_scores=4096. CPU search uses INT8-quantized ONNX encoding on the same machine.

DatasetDocumentsMAPNDCG@10NDCG@100Recall@10Recall@100Indexing (docs/s)GPU QPSGPU P95 (ms)CPU QPSCPU P95 (ms)
arguana8,6740.24570.34990.39950.71260.933777.113.6170.117.4454.7
fiqa57,6380.38710.45060.51290.51840.745941.318.2170.617.6259.1
nfcorpus3,6330.18700.38280.34270.18280.322886.76.6262.116.9219.4
quora522,9310.81700.85190.86440.93090.9730105.520.9126.217.7235.1
scidocs25,6570.13520.19140.27320.20200.441846.917.5139.316.5281.7
scifact5,1830.71860.75930.77750.88290.963353.17.9169.516.9305.4

Models

Any HuggingFace ColBERT-style model can be exported to ONNX. By default, both FP32 and INT8 quantized versions are created. INT8 quantization reduces size (~4x smaller) and improves speed with minimal quality loss.

pip install pylate-onnx-export

# Export model (creates model.onnx and model_int8.onnx)
pylate-onnx-export lightonai/GTE-ModernColBERT-v1 -o ./my-models

# Export + push to HuggingFace Hub
pylate-onnx-export lightonai/GTE-ModernColBERT-v1 -o ./my-models --push-to-hub myorg/my-onnx-model
Ready-to-use models

These can be served with NextPlaid and used with ColGREP without export:

ModelUse case
lightonai/LateOn-Code-edgeCode search, lightweight
lightonai/LateOn-CodeCode search, accurate
lightonai/mxbai-edge-colbert-v0-32m-onnxText retrieval, lightweight
lightonai/answerai-colbert-small-v1-onnxText retrieval, lightweight
lightonai/GTE-ModernColBERT-v1Text retrieval, accurate

Any PyLate-compatible ColBERT model from HuggingFace can be used when converted to ONNX.


License

Apache-2.0

Citation

@software{next-plaid,
  title        = {NextPlaid, ColGREP: Multi-vector search, from database to coding agents.},
  url          = {https://github.com/lightonai/next-plaid},
  author       = {Sourty, Rapha\"{e}l},
  contributors = {Dinaburg, Artem and Oruc, Omer Faruk and Tripathi, Abhishek and Carron, Igor and Hsu, Chao-Chun (Joe) and Ellis, Jonathan and NickSdot and Weitekamp, Raymond and R\k{a}czka, Szymon and Motliuk, Mark and Chechenev, Ivan},
  year         = {2026},
}

@misc{LateOn-Code,
  title  = {LateOn-Code: a Family of State-Of-The-Art Late Interaction Code Retrieval Models},
  author = {Chaffin, Antoine},
  url    = {https://huggingface.co/collections/lightonai/lateon-code},
  year   = {2026}
}
Runs on
CUDA
What shows it
  • CUDA: next-plaid feature cuda (dependency cudarc), colgrep feature cuda, next-plaid-cli feature cuda, next-plaid-onnx feature cuda
Native code
Required
  • Binds native code: tree-sitter, libsqlite3-sys, ort-sys, tree-sitter-language, zstd-sys and 4 more
Python bindings
Has Python bindings
  • next-plaid-onnx needs Python only with feature python
License
Apache-2.0

Compare with similar projects

Order: strongest tier first, then most downloads, then name, with unmeasured values last. A library counts downloads over 30 days. An app counts binary downloads per release. An app with none counts its crate downloads over 30 days. ML Rust runs this catalogue, so its closest project always gets a row.

next-plaid beside the projects that share a topic with it
ProjectDownloadsDependentsStarsLatest releaseRuns on (GPU)Native codeLicense
next-plaid This page Listed

CPU-based PLAID implementation for multi-vector search using ndarray

Python bindings

256 downloads over 30 days 1 610 1.8.5 CUDA Binds native code: tree-sitter, libsqlite3-sys, ort-sys, tree-sitter-language, zstd-sys and 4 more Apache-2.0
lancedb Featured

LanceDB: A serverless, low-latency vector database for AI applications

615,090 downloads over 30 days 102 11,863 0.41.0 GPU support unknown No native code found Apache-2.0
qdrant App Featured

Qdrant - High-performance, massive-scale Vector Database and Vector Search Engine for the next generation of AI. Also available in the cloud https://cloud.qdrant.io/

34,017 binary downloads per release Not applicable 35,478 Not measured Not measured Apache-2.0
pgvectorscale App Listed

Postgres extension for vector search (DiskANN), complements pgvector for performance and scale. Postgres OSS licensed.

33,328 binary downloads per release Not applicable 3,161 Not measured Not measured PostgreSQL
faiss-rs Listed

High-level bindings for Faiss, the vector similarity search engine

19,449 downloads over 30 days 5 250 0.13.0 GPU support unknown Binds native code: faiss-sys, faiss_c. Build uses a native toolchain: cmake (feature static) Apache-2.0 OR MIT
splintr Listed

Tokenizer for Rust and Python: pure Rust by default, with 18 bundled vocabularies and four backends covering BPE, SentencePiece and WordPiece. Its output matches Hugging Face tokenizers id for id on 14 model families, including GPT-2, Qwen, Whisper, T5 and BERT.

Python bindings

8,204 downloads over 30 days 7 63 0.22.2 GPU support unknown Binds native code: pcre2-sys (feature pcre2) MIT
vpsearch Listed Dormant

Vantage Point Tree search algorithm for fast nearest neighbour search in multi-dimensional metric spaces.

919 downloads over 30 days 2 32 2.1.0 GPU support unknown No native code found BSD-2-Clause
Why ListedNo archive, New or Featured rule places it, so it is Listed.

What it lacks for Featured

  • It has 1 active dependents and 1 new dependents in 365 days. Featured needs 11 active dependents or 9 new dependents in 365 days. The repository route reads 610 stars, 67 forks and 21 contributors. It needs 4,539 stars, 434 forks and 79 contributors together.

What else the check found

  • The last activity is on 10 Oct 2026, 30 days ago. The rules expect an update within 700 days. Dormancy rule

Exact rules: Listed, Featured library. The check on applied thresholds version 9.

Every rule outcome, as the check records it
  • expected-interval: version 1.8.5 base 700: E = 700 days
  • dormancy: last activity 2026-10-10, 30 days ago, E = 700: active
  • featured: not featured: active_users 1 < 11 and new_adopters 1 < 9 and repository route stars 610 (needs 4539), forks 67 (needs 434), contributors 21 (needs 79)
  • listed: listed: no archive, new or featured rule applies
Crates5 crates

Measurements and sources

Each signal row shows the raw value, its source and the fetch date. The Sources list gathers every distinct source on this page. Movement needs more history.

Sources6 sources
Adoption1 active dependents, 1 new dependents in 365 days1 not measured
Adoption measurements
SignalValueSourceFetchedCounts
Active dependents1crates.io database dumpYes
New dependents (365 days)1crates.io database dumpYes
Peak active dependents1crates.io database dumpYes
Active dependents as a share of the peak1crates.io database dumpYes
Binary downloads per releaseNot measuredYes
MaintenanceLatest human commit: 30 days ago3 not measured
Maintenance measurements
SignalValueSourceFetchedCounts
Latest human commit2026-10-10GitHub repositoryYes
Latest release2026-10-10crates.io database dumpYes
First release2026-01-12crates.io database dumpYes
Latest version1.8.5crates.io database dumpYes
Days the oldest outside issue waits for a reply251GitHub repositoryYes
Maintainer replies over 365 days0GitHub repositoryYes
Repository archivedfalseGitHub repositoryYes
Repository gonefalseGitHub repositoryYes
Release commit or manifest in the repotruecrates.io packageYes
Published docstruecrates.io database dumpYes
Latest release fails cargo checkNot measuredYes
Build check dateNot measuredYes
Build check toolchainNot measuredYes
SecurityUnpatched vulnerabilities: none
Security measurements
SignalValueSourceFetchedCounts
Unpatched vulnerabilities past the grace windownoneRustSec advisory databaseYes
RustSec unmaintained advisorynoneRustSec advisory databaseYes
Deprecation noticenonecrates.io database dumpYes
Deprecated requirementnonecrates.io database dumpYes
Distribution53 releases, 256 downloads over 30 days5 not measured
Distribution measurements
SignalValueSourceFetchedCounts
Releases53crates.io database dumpYes
Downloads over 30 days256crates.io database dumpYes
Binary downloads over the last 3 releasesNot measuredYes
Homebrew installs on request over 365 daysNot measuredYes
Repology repository familiesNot measuredYes
Docker pull growth over 90 daysNot measuredYes
Docker pulls at the growth baselineNot measuredYes
Every version a prereleasefalsecrates.io database dumpYes
Every version 0.0.xfalsecrates.io database dumpYes
Every version yankedfalsecrates.io database dumpYes
Crate deleted from crates.iofalsecrates.io database dumpYes
Repository610 stars, 67 forks, 21 contributors, 765 commits. Stars alone never qualify a project.
Repository measurements
SignalValueSourceFetchedCounts
GitHub stars610GitHub repositoryYes — one part of the repository route
GitHub forks67GitHub repositoryYes — one part of the repository route
Contributors with a GitHub account21GitHub contributorsYes — one part of the repository route
Commits on the default branch765GitHub repositoryNo
Repository's main crate left out of the entrynonecrates.io database dumpYes
Facts that never count
Facts that never count measurements
SignalValueSourceFetchedCounts
LicenseApache-2.0crates.io database dumpNo
Runs on, from listed crates and their direct dependenciesCUDAcrates.io database dumpNo
What shows each backendCUDA: next-plaid feature cuda (dependency cudarc), colgrep feature cuda, next-plaid-cli feature cuda, next-plaid-onnx feature cudacrates.io database dumpNo
Native code, from listed crates and their dependenciesBinds native code: tree-sitter, libsqlite3-sys, ort-sys, tree-sitter-language, zstd-sys and 4 morecrates.io database dumpNo
Python bindings, from direct dependencies of listed cratesHas Python bindings: next-plaid-onnx needs Python only with feature pythoncrates.io database dumpNo
Crates that depend on a listed crate directly1crates.io database dumpNo

Corrections and review history

Report a correction

No correction applies to this entry.

Judgments

A judgment enters only through an approved issue and a merged pull request.

No judgment applies to this entry.