CLI tool
zvec-ai/zvec-grep avatar
zvec-ai/zvec-grep

zvec-grep (zg): a local-first search layer that combines ripgrep, BM25 and vector search

Local-first search across your workspace, built for humans and AI agents.

3,848 stars224 forksTypeScriptApache-2.0

At a glance

What is it?
zvec-grep installs as the zg CLI and indexes a workspace into .zvec-grep/, then answers keyword, BM25 and semantic queries from the same index. It is aimed at developers and coding agents that want ranked, source-linked results without shipping files to a hosted service.
Who is it for?
Adopt zvec-grep if you want one index that serves both a terminal query and an agent tool call, and you are comfortable with Node.js 22 or newer and a .zvec-grep/ directory inside each indexed project. Skip it if your search needs are pure regex over a tree that changes every few seconds, or if you cannot accept a local embedding model being required at index time.
Can I use it commercially?
Yes. Apache-2.0 is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository received new commits within the last day.
What is it written in?
Mainly TypeScript, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on September 30, 2026, and from our analysis. They are not legal advice.

Editorial analysis

What zvec-grep actually replaces

The pitch is a single search layer over a workspace that serves two audiences with the same index. Today that usually means two tools: ripgrep for literal and regex matching, plus some separate retrieval stack for anything semantic. zvec-grep sits in front of both. The README describes it as unifying ripgrep, BM25 and vector search behind "one local-first interface", and the package description in package.json calls it "Agent-friendly hybrid workspace search across code and non-code content".

The second audience is the reason the project exists. A coding agent given only ripgrep has to guess the right literal, run several searches, and read a lot of context to find evidence. zvec-grep exposes the same index as a tool the agent calls, returning ranked passages with file and line references. In the README's OpenCode example the agent calls a zvec_grep_search tool with a natural-language query plus a list of full-text terms, and the tool returns a file offset and limit to read. The README notes the prompt does not name a tool; OpenCode picks it.

It is for people who keep their source and documents in one tree and want to ask questions across both. It is not a hosted service and not a database you query over the network.

How the three retrieval modes share one index

The repository layout is a single TypeScript package with a src/ tree, a test/ tree, and docs/ containing a numbered set of documents including 05-architecture.md and 06-server.md. The README links the architecture document as the place where the unification is described, so the mechanism is documented rather than implied by the tagline.

What the README shows directly is the query shape. The agent tool call carries a root, a natural-language query, an fts array of literal terms, and fuse: true. That is the hybrid contract: the semantic side handles the meaning of the question, the fts side pins exact strings, and fusion merges the two rankings before results are returned. The example in the README returns a read instruction with offset and limit into sherlock-holmes.txt, and the answer that follows cites line ranges such as sherlock-holmes.txt:5479-5486. Source locations survive the ranking step, which is what makes the output usable as evidence rather than a summary.

Indexing is a separate step. The README's note states that the index lives in .zvec-grep/ under the indexed project root, so the index is per-project and travels with the tree. The embedding backend is chosen at index time with an --embedding flag; the README's example uses local/potion-retrieval-32m, and the README says files, indexes and local models stay on the machine, with remote embeddings receiving data only with permission.

Installing zvec-grep and running a first hybrid query

The README's walkthrough is the shortest path to a working index. It needs Node.js 22 or newer, which package.json enforces through the engines field, and it installs the CLI globally from npm under the scoped name @zvec/zvec-grep. The binary it puts on your PATH is zg.

bash
npm install -g @zvec/zvec-grep

The README then builds a small corpus from two public-domain texts. This is a demonstration workspace, not a required step.

bash
mkdir zg-mystery && cd zg-mystery
curl --retry 3 --retry-all-errors --progress-bar -fL \
  -o alice-in-wonderland.txt https://raw.githubusercontent.com/GITenberg/Alice-s-Adventures-in-Wonderland_11/master/11.txt \
  -o sherlock-holmes.txt https://raw.githubusercontent.com/GITenberg/The-Memoirs-of-Sherlock-Holmes_834/master/834.txt

Index the directory, naming the embedding model. The README's note says the index is written to .zvec-grep/ under the indexed project root, so you should see that directory appear once the command finishes.

bash
zg index --embedding local/potion-retrieval-32m

Query it the way a human would, with a natural-language question and a result cap.

bash
zg query --human "An unseen creature left a few marks. What did the detective infer?" --limit 3

The README states the result is the relevant passages from sherlock-holmes.txt ranked ahead of alice-in-wonderland.txt. If the command fails, the README's tip is to rerun the same command with --debug, and it points at zg status --mode direct --debug for per-file failures stored in an existing index, and zg status --mode server --debug for recorded server indexing errors.

For the agent path, the README configures OpenCode and then runs a prompt that never names a tool.

bash
zg install --target opencode --yes
opencode models
opencode run --model opencode/nemotron-3-ultra-free \
  "An unseen creature left a few marks. What did the detective infer? Cite local evidence."

The README warns that free model availability changes and that you should check opencode models and substitute a model that exists in your environment.

Where zvec-grep is the wrong tool

The index is a materialized artifact. Anything you add after zg index runs is not in it until you index again, and the README does not describe a file watcher or an incremental reindex trigger. If your workflow is "grep a tree that a build process rewrites constantly", plain ripgrep is strictly better: no index, no staleness window, no .zvec-grep/ directory to exclude from version control.

The second boundary is the embedding model. Choosing --embedding local/potion-retrieval-32m means a model artifact has to be available locally, and the README does not document the download size, the cache location, or what happens on a machine without network access at index time. That matters for CI containers and air-gapped hosts, and it is the first thing to test on your own infrastructure rather than assume.

The third is the server mode. The README references a server document and server-specific status and log commands, which implies a long-running mode with its own state and failure surface. If you only ever want one-shot queries from a shell, the direct mode is the simpler path and the server adds an operational component you would have to monitor.

Finally, the README does not document rollback of the index or a schema version for .zvec-grep/. Upgrading the CLI across a release boundary and reusing an old index is not described, so treat the index as disposable and plan to rebuild it.

ripgrep and zvec-grep: different jobs, not competing versions

The honest comparison is with ripgrep itself, because zvec-grep wraps that class of search rather than replacing it. ripgrep is a stateless scanner: you give it a pattern, it walks the tree, it prints matches. There is no index, no model, no setup, and the answer is always current. Its weakness is that the user must already know the literal. Ask ripgrep "what did the detective infer from the marks" and you get nothing useful.

zvec-grep inverts that. You pay an indexing step and a model dependency, and in return you can ask a question in prose and get ranked passages with line references. The fts array in the README's tool call shows the two are meant to be used together inside one request: semantics for recall, literals for precision.

There is also a broader class of retrieval stacks built around a vector database plus a separate pipeline. Those are designed for serving many users over a network with a persistent service. zvec-grep is the opposite shape: a CLI, a per-project index directory, and a tool definition an agent can call. If you already run a retrieval service, zvec-grep is not a drop-in replacement for it, and the README does not claim to be one.

Licence, release cadence and the cost of keeping up

The project is Apache-2.0, stated in the LICENSE file at the repository root and in the license field of package.json. That is a permissive licence with an explicit patent grant, and it imposes no copyleft obligation on your own code. It does not, however, say anything about the embedding model you point --embedding at; the licence of a model artifact is a separate question from the licence of this CLI, and the README does not address it. If you plan to ship an index built with a particular model, check that model's terms independently.

On cadence, the last push to the repository was on 2026-09-10, and the most recent tagged release listed is v0.2.0 from 2026-08-27, preceded by zvec-grep 0.1.5 on 2026-07-16. The version field in package.json reads 0.2.1, ahead of the latest tag. Pre-1.0 versioning means the CLI surface can move between minor releases, so pin the version you install and read the release notes before bumping. The upgrade cost is not just the npm install: an index built by one version may need rebuilding under another, and the README does not promise otherwise.

Editorial conclusion

Adopt zvec-grep if you want one index that serves both a terminal query and an agent tool call, and you are comfortable with Node.js 22 or newer and a .zvec-grep/ directory inside each indexed project. Skip it if your search needs are pure regex over a tree that changes every few seconds, or if you cannot accept a local embedding model being required at index time. Before rolling it out, verify three things: that zg install --target opencode writes the integration you expect, that your chosen --embedding value resolves in your environment, and whether .zvec-grep/ belongs in your .gitignore.

Frequently asked questions

What is Zvec?

In this repository, zvec is the underlying engine that zvec-grep is built on; the README says zg is powered by zvec and links to the zvec project. zvec-grep itself is the CLI and agent-facing search layer distributed as @zvec/zvec-grep.

What is better than grep?

That depends on the query. grep and ripgrep are stateless scanners that are always current and need no setup, while zvec-grep requires an indexing step but can answer a natural-language question and return ranked passages with file and line references. The README's own tool call uses both at once, passing an fts list of literal terms alongside the semantic query.

What is the difference between grep and RAG?

The README does not frame zvec-grep as a RAG pipeline, so the distinction it documents is narrower: grep matches literals, while zvec-grep fuses ripgrep-style matching, BM25 and vector search over a local index and returns source-linked passages. The README states that files, indexes and local models stay on your machine, with remote embeddings receiving data only with your permission.

Official sources

  1. Issues
  2. License: Apache-2.0
  3. README
  4. Releases
  5. zvec-ai/zvec-grep on GitHub
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/zvec-ai-zvec-grep.svg)](https://hysenlabs.com/projects/zvec-ai-zvec-grep)