Mengenal zvec-grep (zg): Satu Lapisan Pencarian Hybrid untuk Manusia dan AI Agent
Review zvec-grep (zg): CLI pencarian lokal yang menggabungkan ripgrep, BM25, dan vector search, plus MCP endpoint untuk agent. Termasuk hasil uji langsung, tabel model embedding, dan catatan versi.
Masalahnya
Agent coding hari ini punya dua cara mencari di repositori, dan keduanya punya lubang.
grep/rg cepat dan eksak, tapi tidak tahu arti. Pertanyaan seperti “di mana preferensi tema dipulihkan saat startup” harus diterjemahkan manual oleh model menjadi pola teks yang tepat. Kalau tebakan polanya salah, hasilnya kosong — dan agent biasanya langsung berpindah strategi, bukan mencari ulang.
Sebaliknya, RAG/semantic search mengerti arti, tapi sering dipasang sebagai layanan terpisah: butuh embedding API, vector database, indexer, dan biasanya mengirim isi workspace ke server orang lain. Untuk pertanyaan yang jawabannya cuma sebuah nama fungsi, cara ini mahal dan lambat.
Yang dibutuhkan agent sebenarnya satu pintu saja: cari berdasarkan makna, rangking berdasarkan relevansi, verifikasi dengan teks eksak — semuanya lokal.
Apa itu zvec-grep
zvec-grep (perintahnya zg, singkatan zvec-grep) adalah CLI pencarian local-first yang menyatukan tiga mode pencarian di belakang satu interface:
| Mode | Untuk apa | Butuh index |
|---|---|---|
| Hybrid (vector + BM25, digabung RRF) | Query bahasa natural, konsep, sinonim | Ya |
| FTS/BM25 ranked | Kata kunci dan simbol yang dikenal | Ya |
| Managed ripgrep | Teks eksak dan regex, harus lengkap | Tidak |
Dibangun di atas zvec, vector database in-process. Sama seperti ripgrep tidak butuh server, zg tidak butuh daemon terpisah untuk dipakai — server hanya opsional agar MCP client bisa berbagi satu index.
Angka repo per 27 September 2026:
| Metrik | Nilai |
|---|---|
| Stars / forks | 3.792 / 222 |
| Lisensi | Apache-2.0 |
| Rilis npm | @zvec/zvec-grep 0.2.2 (bin: zg) |
| Kebutuhan runtime | Node.js 22+ |
| Dibuat | 10 Juli 2026 |
| Endpoint MCP | http://127.0.0.1:7999/mcp (loopback saja) |
README dan dokumentasi menjelaskan implementasi TypeScript/Node.js; implementasi Rust dikembangkan terpisah di direktori rust/.
Cara kerjanya
workspace files
│
├── scan + extract (symbol / heading / chunk)
│ │
│ └── embed ──► .zvec-grep/index.zvec
│
└── managed ripgrep (tanpa index, eksak)
query ─► router (direct | server | auto)
│
├── indexed: BM25 + vector ─► RRF ─► hasil teranking
└── --rg: exhaustive scan
Poin desain yang membedakan dari “RAG di atas repo”:
- Index per-workspace, bukan per-mesin. Index hidup di
<root>/.zvec-grep/, berisimanifest.json,files.zvec, danindex.zvec. Konfigurasi global dan state daemon ada di~/.zvec-grep/. - Ekstraksi sadar struktur. Kode C/C++, Go, Java, JS/TS, Python, dan Rust diekstrak per simbol, signature, dan breadcrumb. Markdown diekstrak per heading.
<script>di.vue/.svelteikut terbaca. Format lain jatuh ke chunk teks biasa. - Fusion, bukan salah satu. Vector search menemukan kandidat berdasarkan makna, BM25 mengunci identifier eksak, lalu ranking keduanya digabung dengan reciprocal rank fusion.
- Output dua mode. Di terminal, output manusiawi dengan preview source. Saat stdout di-pipe, output otomatis ringkas dan dikelompokkan — inilah yang dipakai agent supaya konteks tidak bengkak.
Yang dibuang tanpa perlu konfigurasi: .git, .zvec-grep, direktori dependency/build/generated/cache, file yang di-ignore git, dan semua binary termasuk .pdf, .docx, .xlsx, archive, media, serta .sqlite. Batas ukuran default juga sadar tipe: 1 MiB untuk kode, 256 MiB untuk teks/Markdown, 16 MiB untuk data terstruktur.
Install dan uji pertama
Empat perintah, dan salah satunya untuk memilih model:
# Node.js 22+
npm install -g @zvec/zvec-grep
cd your-repository
zg index --embedding local/potion-code-16m-v2
zg query "where authentication is validated" --limit 5
Kalau dijalankan tanpa index, zg membuat index sendiri dengan model lokal sebelum pencarian pertama selesai. Model remote tidak pernah dipakai implisit — itu keputusan Anda lewat zg index berikut otorisasinya.
Saya uji langsung di workspace kecil (dua file: satu TypeScript, satu Markdown) di macOS dengan Node 22.22.3:
$ zg index --embedding local/potion-code-16m-v2
Scanning files...
Preparing local/potion-code-16m-v2
Downloading local/potion-code-16m-v2 · 0% · 0 B/32 MiB
Indexing complete
$ zg status
✓ Workspace index is ready
Coverage ████████████████████ 100% 2 / 2 files
Entities 5
Truncated 0 fragments
Embedding local/potion-code-16m-v2 (256 dimensions · cosine)
Storage .zvec-grep/index.zvec
$ zg query "di mana preferensi tema dipulihkan" --limit 3
hits: 3
#1 matchedBy=fts+vector docs/catatan.md:8-11
heading: Preferensi Tema
#2 matchedBy=fts+vector docs/catatan.md:3-7
heading: Autentikasi
#3 matchedBy=fts+vector src/use-theme.ts:1-5
matchedBy=fts+vector itu bukti hybrid-nya jalan: satu hit mendapat skor dari dua jalur sekaligus. Perlu jujur soal query bahasa Indonesia: hit teratas di situ juga cocok secara leksikal (kata “tema” dan “preferensi” ada di dokumennya), jadi hasil ini bukan bukti kemampuan lintas bahasa. Untuk korpus berbahasa Indonesia, pilih model multilingual seperti local/potion-multilingual-128m dan bandingkan hasilnya dengan model kecil ini.
Perhatikan juga bahwa output default zg query adalah Markdown ringkas untuk agent (matchedBy, rentang baris, preview none). Kalau dijalankan di terminal dan ingin output manusiawi penuh, tambahkan --human.
Model diunduh dari Hugging Face pada pemakaian pertama (32 MiB untuk model di atas), di-cache di ~/.zvec-grep/models, dan ada fallback otomatis ke salinan ModelScope kalau artefak Hugging Face gagal diunduh.
Memilih model embedding
Model menentukan cakupan bahasa, ukuran index, dan kecepatan. Ini tabel ringkas dari katalog resmi:
| Model | Runtime | Max input | Dim |
|---|---|---|---|
local/potion-code-16m-v2 |
Model2Vec FP16 | 1.024 | 256 |
local/potion-retrieval-32m |
Model2Vec FP32 | 1.024 | 512 |
local/potion-multilingual-128m |
Model2Vec FP32 | 1.024 | 256 |
local/multilingual-e5-small |
ONNX Q8 | 512 | 384 |
local/jina-embeddings-v2-base-code |
ONNX Q8 | 8.192 | 768 |
local/gte-modernbert-base |
ONNX Q4 | 8.192 | 768 |
local/embeddinggemma-300m |
GGUF Q8_0 | 2.048 | 768 |
local/qwen3-embedding-0.6b |
GGUF Q8_0 | 8.192 | 1.024 |
qwen/qwen3.7-text-embedding |
Remote text | 128.000 | 1.024 |
Aturan praktisnya: mulai dari model terkecil yang menutup bahasa dan panjang input yang dibutuhkan, bandingkan hasil pada beberapa query nyata, baru naik kelas. Model Model2Vec seperti Potion memakai static vector lookup, jadi memilih GPU tidak mempercepatnya — kalau mau hemat waktu, di situ letak hematnya.
Ganti model berarti rebuild. Ruang vektor dari dua model berbeda tidak kompatibel meski dimensinya sama:
zg index --rebuild --embedding local/jina-embeddings-v2-base-code
Data Anda di mana
Lokal secara default, dan itu bukan sekadar tagline:
- Scanning, managed ripgrep, index, dan model lokal semuanya di mesin Anda.
- Server MCP hanya listen di
127.0.0.1, dan Bearer token opsional melindungi endpoint lokal itu. - Satu-satunya jalur yang bisa mengirim data keluar adalah Remote Embedding, dan itu butuh otorisasi eksplisit:
--allow-remoteuntuk satu perintah, atau grant permanen per workspace.
zg auth grant --capability embedding --scope workspace \
--embedding qwen/text-embedding-v4
zg auth status
zg auth revoke
Grant disimpan di .zvec-grep/authorization.json. Kredensial provider dan izin transfer data adalah dua hal terpisah — punya API key tidak otomatis berarti data boleh dikirim.
Integrasi ke agent
zg install --target claude # claude, codex, qwen, qoder, opencode, cursor, all, auto
zg install --target codex --mcp-transport stdio --yes
Installer mendeteksi agent yang terpasang, menulis konfigurasi MCP (default stdio), menambahkan guidance cara memakai tool-nya, dan menyalakan daemon bersama. Toolset default agent sengaja hanya mengekspos satu tool — zvec_grep_search — karena lifecycle index tetap milik CLI. Kalau butuh administrasi dari agent, daemon bisa dijalankan ulang dengan --mcp-toolset full yang membuka enam tool (search, rg, index, index_drop, index_status, server_status).
Keputusan “pakai zg atau pakai rg” diserahkan ke agent, bukan dipaksa oleh aturan. Ini pilihan yang menarik secara desain: benchmark mereka sendiri mencatat bahwa aturan “selalu pakai zvec-grep” bisa melebih-lebihkan manfaatnya, sementara melarangnya justru merugikan tugas yang butuh identifier eksak.
Soal benchmark
Repo ini punya dua suite benchmark A/B berpasangan, dijalankan dengan agent, model, prompt, environment, dan limit yang sama — satu profil pakai tool standar, satu profil lagi ditambah index dan tool zg. Yang diukur: kualitas jawaban (judge), input token, jumlah tool call, dan wall time.
| Suite | Agent | Cakupan |
|---|---|---|
| SWE-QA-Bench | Claude Code 2.1.212 + Claude Opus 5 (high) | 20 task repositori, 11 repo, 3 trial publik (5 trial per profil di CI, 200 trial untuk run penuh) |
| BrowseComp-Plus | Codex + gpt-5.6-sol (medium) | 100 kasus multi-dokumen |
Saya tidak menyalin angka agregatnya di sini karena hasil lengkapnya disajikan sebagai chart di repo, dan mereka sendiri mengingatkan bahwa hasil antar-run bervariasi. Contoh variasi yang mereka publikasikan di subset reproduksi 3 task:
| Task | Baseline skor / tool call | zg skor / tool call |
|---|---|---|
reflex:6 |
87–96 / 7–12 | 84–92 / 3–5 |
requests:16 |
68–97 / 2–6 | 75–99 / 7–10 |
conan:39 |
5–92 / 2–24 | 5–100 / 3–19 |
Angka itu mereka sebut sendiri sebagai strata deskriptif dari run historis, bukan signifikansi statistik. Yang paling jujur dari dokumentasi benchmark-nya juga dicatat: kualitas jawaban cenderung stabil antar-run, sementara token dan tool call berfluktuasi karena trajektori agent bercabang.
Catatan praktis
Beberapa hal yang saya temukan saat mencobanya, dan yang tidak kelihatan dari halaman depan repo:
- Dokumentasi
mainlebih baru dari rilis npm. Docs di branchmainmemakai gaya flag (zg --index,zg --install), sementara@zvec/zvec-grep0.2.2 masih memakai subcommand. Di 0.2.2,zg --indexdijawabError: Unknown command: --index. Selalu cekzg --helpdanzg <command> --helpdari versi yang terpasang, bukan dari README. - Target
zg installikut versi. 0.2.2 mengenalcodex,claude,qwen,qoder,opencode,cursor,auto,all. Targetvscodedancopilotmuncul di dokumentasimain. - Install script npm bisa diblokir. Saat saya
npm install, npm 12 memblokir install script@zvec/zvec,node-llama-cpp,onnxruntime-node,sharp, danprotobufjs(allowScripts). Untuk model Model2Vec/Potion tidak masalah — indexing jalan normal. Tapi kalau Anda butuh model ONNX (Transformers.js) atau GGUF (llama.cpp), runtime native itu perlu disetujui lebih dulu. zg --rgbukanrg. zg yang memiliki format output, jadi opsi pengubah output seperti--json,--count,-l,-o, dan--vimgrepditolak. Pakai-A/-B/-Cuntuk konteks.- Index boleh dibatasi sejak awal. Untuk repo besar, lebih murah membatasi scope saat build daripada memperbaiki index yang bengkak:
zg index -g "src/**" -t ts. --debuguntuk diagnosa. Ada di mode direct maupun server. Di 0.2.2,zg status --debugmenambahkan detail kegagalan unduhan model.
Kapan pakai, kapan tidak
| Situasi | Saran |
|---|---|
| Agent perlu menjawab pertanyaan lintas file / arsitektur | Pasang zg, ini kasus terbaiknya |
| Cari identifier, config key, atau regex yang sudah diketahui | rg native sudah cukup, zg --rg kalau ingin format seragam |
| Repositori besar, indexing berulang | Batasi scope + --refresh background |
| Tim tidak boleh mengirim kode keluar | Pakai model lokal saja, jangan grant Remote Embedding |
| Dokumentasi, buku, notes, hasil export knowledge base | Ikut terindeks — bukan cuma kode |
| Butuh pencarian antar-bahasa pemrograman yang eksotis | Ekstraksi struktural masih terbatas pada bahasa besar; sisanya jatuh ke chunk teks |
Penutup
zg menarik karena dua hal yang jarang digabung: ia tidak memaksa Anda membangun infrastruktur RAG (tidak ada vector DB terpisah, tidak ada API key wajib), dan ia juga tidak memaksa agent memilih hanya satu gaya pencarian. Index lokal, tiga jalur retrieval, satu format output ringkas, dan MCP endpoint di loopback.
Cara paling cepat menilai apakah ini berguna untuk workflow Anda: install, index satu repo, lalu tanyakan sesuatu yang biasanya Anda cari pakai grep dan sesuatu yang tidak bisa dijawab grep sama sekali. Kalau query kedua mengembalikan file yang tepat di posisi tiga teratas, itu jawabannya.
Sumber: github.com/zvec-ai/zvec-grep · dokumentasi
docs/· zvec (vector database in-process) · pengujian langsung dengan@zvec/zvec-grep0.2.2 pada Node.js 22.22.3 (macOS)