A

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.

10 menit bacaAhmad Apandi

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/, berisi manifest.json, files.zvec, dan index.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/.svelte ikut 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-remote untuk 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 main lebih baru dari rilis npm. Docs di branch main memakai gaya flag (zg --index, zg --install), sementara @zvec/zvec-grep 0.2.2 masih memakai subcommand. Di 0.2.2, zg --index dijawab Error: Unknown command: --index. Selalu cek zg --help dan zg <command> --help dari versi yang terpasang, bukan dari README.
  • Target zg install ikut versi. 0.2.2 mengenal codex, claude, qwen, qoder, opencode, cursor, auto, all. Target vscode dan copilot muncul di dokumentasi main.
  • Install script npm bisa diblokir. Saat saya npm install, npm 12 memblokir install script @zvec/zvec, node-llama-cpp, onnxruntime-node, sharp, dan protobufjs (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 --rg bukan rg. zg yang memiliki format output, jadi opsi pengubah output seperti --json, --count, -l, -o, dan --vimgrep ditolak. Pakai -A/-B/-C untuk 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.
  • --debug untuk diagnosa. Ada di mode direct maupun server. Di 0.2.2, zg status --debug menambahkan 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-grep 0.2.2 pada Node.js 22.22.3 (macOS)

Artikel terkait