@zvec/zvec-grep
v0.1.5
Published
Agent-friendly hybrid code search with indexed context and managed ripgrep.
Readme
zvec-grep is an agent-friendly hybrid code search tool built on Zvec. It gives repositories a root-local semantic index, combines vector search with full-text search, and keeps CLI output compact enough for AI agents while still offering rich terminal output for humans.
The command is intentionally short:
zg query "where query auto update happens"[!IMPORTANT] Command interface
- Hybrid Code Search: Query code with natural language, exact terms, or both in one command.
- Explicit Index Lifecycle: New repositories require
zg index --embedding <model>; agents do not silently create indexes.- Automatic Refresh: Existing anonymous indexes are checked and incrementally updated before normal queries.
- Token-Efficient Output: Agent output defaults to
--preview none;--humandefaults to full source previews.- No-Index Lexical Search:
zg query --rgprovides managed ripgrep search without requiring an index.
💫 Features
- Semantic + Lexical Retrieval: Blend vector search and full-text search for code, docs, tests, scripts, and configuration.
- Root-Local Indexes: Anonymous indexes live under
<repo>/.zvec-grep/, so repository state stays with the repository. - Agent-Ready Output: Default output is grouped by file and keeps previews small to save tokens.
- Human Output Mode: Add
--humanfor a terminal-friendly summary with full previews by default. - Managed ripgrep Route:
zg query --rgsupports commonrgflags and works even before a repository is indexed. - Explicit Model Choice: The first index build requires a model such as
local/embeddinggemma-300m,local/qwen3-embedding-0.6b, orqwen/text-embedding-v4. - Schema Reuse: Re-running
zg indexon an existing index reuses the stored embedding schema unless you explicitly change it. - MCP Server: Run
zg serve --mcpto expose indexed and no-index lexical search tools to MCP clients. Indexing and status remain CLI-only operations. - Library API: Use
createZvecGrep()directly from Node.js tools, agents, or MCP servers.
📦 Installation
Install the CLI from npm:
npm install -g @zvec/zvec-grep
zg versionOr run it without a global install:
npx @zvec/zvec-grep helpInstall the latest source checkout as a global zg command:
git clone https://github.com/zvec-ai/zvec-grep.git
cd zvec-grep
npm ci
npm run build
npm install -g .
zg versionRun the stdio MCP server:
zg serve --mcpInstall the Codex MCP integration:
zg install --target codex --yesCodex MCP tool calls default to a 600-second timeout. Override it during installation with --mcp-tool-timeout <seconds>.
✅ Requirements
- Node.js 22 or newer
- macOS, Linux, or Windows
- A supported embedding model for indexed search
zg query --rg works without any embedding model or index.
⚡ Quickstart
Index a repository with an explicit embedding model:
zg index \
--embedding local/embeddinggemma-300m \
-g "src/**" \
-g "docs/**" \
-g "test/**" \
-g "!dist/**" \
-g "!node_modules/**" \
-g "!coverage/**"Check index state:
zg statusSearch with natural language:
zg query "where query auto update happens"Combine semantic intent with exact anchors:
zg query "GPU fallback" --fts "usingCpuFallback" -g "src/**" -t ts --limit 5Use exhaustive lexical search without an index:
zg query --rg -F "ZVEC_GREP_HOME" srcSwitch to human-readable output:
zg query --human "root local index discovery" --limit 3Use from an MCP client with zvec_grep_search and zvec_grep_rg. MCP inputs use JSON-friendly fields such as include: ["src/**"]; use the CLI for zg status and zg index. The Codex installer writes managed zvec-grep blocks to ${CODEX_HOME:-$HOME/.codex}/config.toml and ${CODEX_HOME:-$HOME/.codex}/AGENTS.md.
🧠 Models
Local models run through node-llama-cpp and keep code search private to your machine:
zg index --embedding local/embeddinggemma-300m
zg index --embedding local/qwen3-embedding-0.6bOn Apple Silicon, local builds use quiet llama.cpp CMake defaults to avoid harmless OpenMP and ARM native-detection warnings. Override any llama.cpp CMake option with NODE_LLAMA_CPP_CMAKE_OPTION_<name>, for example NODE_LLAMA_CPP_CMAKE_OPTION_GGML_NATIVE=ON to opt back into native CPU tuning.
Remote Qwen embeddings are useful when you prefer a managed embedding service or want to avoid local model setup:
zg index \
--embedding qwen/text-embedding-v4 \
--api-key "$DASHSCOPE_API_KEY"After a successful index, explicitly passed global model and provider options are saved to ~/.zvec-grep/config.json with user-only permissions. This lets an already-running zg MCP server load a newly configured remote API key on its next model request without restarting Codex. Values read only from environment variables are not persisted.
{
"version": 1,
"defaults": {
"embedding": "qwen/text-embedding-v4"
},
"providers": {
"qwen": {
"apiKey": "...",
"endpoint": "https://dashscope.aliyuncs.com/compatible-mode/v1/embeddings"
}
}
}Resolution order is explicit CLI or library options, then environment variables, then global config, then built-in defaults. Repository roots and file-selection settings remain in each repository's .zvec-grep metadata rather than global config.
For existing indexes, zg index without --embedding reuses the stored schema. Use --rebuild --embedding <model> only when you intentionally want to rebuild with a different model:
zg index --rebuild --embedding local/qwen3-embedding-0.6b🔎 Query Patterns
Multiple quoted queries are treated as separate search groups:
zg query "request validation" "error handling" --limit 5Route options each consume one query and can be repeated. Add --fuse when
you want all groups combined into one ranked result list:
zg query \
--hybrid "authentication flow" \
--fts "AuthService" \
--vector "where credentials are validated" \
--fuse \
--limit 10Use ripgrep-style path and file-type filters early to keep results focused.
Positive globs include paths and globs beginning with ! exclude them:
zg query "cache invalidation" \
-g "src/**" \
-g "!test/**" \
-g "!tests/**" \
-g "!fixtures/**" \
-g "!dist/**" \
-t tsFile-type filters are applied in addition to glob filters. For example,
-g "docs/**" -t ts selects TypeScript files under docs, not every file in
that directory.
Use --preview to control indexed source previews:
zg query "plugin lifecycle" --preview none
zg query "plugin lifecycle" --preview short --limit 5
zg query "plugin lifecycle" --preview full --limit 2For exact text, symbols, flags, or error codes, use --fts or --rg:
zg query "authentication flow" --fts "AuthService" --fts "ForbiddenError"
zg query --rg -i -C 2 -g "*.ts" "needle text" srcManaged rg mode accepts common ripgrep matching, context, type, glob, ignore,
depth, size, symlink, encoding, and regex-engine options. Zvec-grep owns the
result format, so output-changing modes such as --json, --count, --files,
-l, -o, --replace, and --vimgrep are rejected. .git/** and
.zvec-grep/** remain excluded.
🛠️ Library API
import { createZvecGrep } from "@zvec/zvec-grep";
const zvecGrep = await createZvecGrep({
root: process.cwd(),
});
const result = await zvecGrep.context({
query: "ranking implementation",
limit: 5,
});
for (const item of result.items) {
const location =
item.range.kind === "text"
? `${item.file.relativePath}:${item.range.startLine}`
: item.file.relativePath;
console.log(location);
}
await zvecGrep.close();For explicit no-index lexical search:
const result = await zvecGrep.context({
query: "ZVEC_GREP_HOME",
rg: true,
});🤝 Join the Zvec Community
| 💬 DingTalk | 📱 WeChat | 🎮 Discord | X (Twitter) |
| :-----------------------------------------------------------------------------------------------------------: | :-----------------------------------------------------------------------------------------------------------: | :-----------------------------------------------------------------------------------------------------------------------------------------------------: | :--------------------------------------------------------------------------------------------------: |
| | | |
|
| Scan to join | Scan to join | Click to join | Click to follow |
❤️ Contributing
Issues and pull requests are welcome. Please keep changes focused, add tests for behavior changes, and run:
npm run checkPull request titles use Conventional Commits syntax.
