@luminascale/pi-zvec-grep
v0.3.1
Published
π zvec-grep's local-first hybrid (semantic + exact) search as native pi tools
Maintainers
Readme
pi-zvec-grep
Extends pi with zvec-grep (a.k.a. zg) as a native tool + commands β local-first hybrid search across your workspace for humans and agents.
- π§ Semantic + exact in one call β hybrid (BM25) + vector retrieval behind
zvec_search - π Ranked, source-linked hits β file, line range, symbols, source
- π Local-first β index + embeddings on your machine; remote only with your explicit consent
- π οΈ Agent-native β three tools + two commands, no MCP server required
Install
Requires Node 22+ and the CLI globally:
npm i -g @zvec/zvec-grepThen install this package into pi:
pi install npm:@luminascale/pi-zvec-grepOr from git:
pi install git:github.com/MikkelKappelPersson/pi-zvec-grepRestart pi or run /reload.
Tools
| Tool | What it does |
| --- | --- |
| zvec_search | Hybrid semantic + keyword search over an indexed workspace. Query groups (query, queries, fts, vector), fuse, globs, file types, symbol focus, modified-after filters, and a root (defaults to cwd). |
| zvec_index | Create, update, rebuild, or drop a workspace index. Prefers a local embedding model. |
| zvec_status | Show index presence, coverage, freshness, and the suggested next action. Missing index is a normal state. |
Commands
One slash command, /zg, dispatches on a subcommand. All take an optional [path] (workspace root; defaults to the current directory). Bare /zg or /zg help prints usage.
| Command | What it does |
| --- | --- |
| /zg index [path] | Create or incrementally update the workspace index. |
| /zg rebuild [path] | Recreate the index from scratch. |
| /zg drop [path] | Permanently delete the workspace index (runs with --yes; no prompt). |
| /zg status [path] | Show index presence, coverage, freshness, and the suggested next action. |
| /zg settings | Open the settings menu (interactive TUI): settings scope, default search limit, auto index on start. |
| /zg help | Print usage. |
Settings
/zg settings opens a scoped settings menu. Two config layers:
| Layer | File | Contents |
| --- | --- | --- |
| User (default) | ~/.pi/agent/pi-zvec-grep/config.json | Values only β the base defaults for every workspace that has NOT activated project scope. Scope flags never apply from this file: a projectScope key here is ignored, and a legacy settingsScope key is ignored and stripped on the next save. |
| Project | <workspace>/.zvec-grep/config.json (anchored at cwd, no walk-up) | Self-contained β the whole project config as the full values object, plus the boolean activation flag projectScope. true: this file alone is authoritative for this workspace only (values = built-in defaults + its contents, no user values mixed in), so the committed file means the same on every machine β and activating it can never flip any other project. false (or absent in a hand-written file): the values are stored but dormant and the user layer applies. Files the menu manages always carry the flag, so a committed file declares its state explicitly. Fields missing from the file fall back to the built-in defaults. (A legacy settingsScope: "project" string in an old file is still read as true; never written.) |
- Settings scope (
user|project): where the menu reads its values from and writes its edits to β per workspace, never machine-wide. Activation is the booleanprojectScopeflag inside the project file: a repo can only ever change the settings of its own workspace. Pickingprojectsaves the project file (creating it if missing,Config created at β¦on first creation) withprojectScope: trueplus the values β a dormant file's parked values win over your user values, so activating a team file never overwrites it. PickingusersetsprojectScope: falseβ stored values stay dormant, the file is never deleted, and this workspace's user values apply again. - Default search limit (1β50): the
--limitused byzvec_searchwhen the tool call passes no explicitlimit. An explicit tool-call limit always wins. - Auto index on start (off by default): on every
session_start, the hook runszg status --check-readyin the working directory and, when the index is missing or stale, builds/updates it in the background (fire-and-forget; never blocks startup or the lifecycle hook). Healthy indices cost one fast guard call per start; only a missing/stale index triggers a build. Enabled in the user file for all workspaces, or in the project file for one workspace. The first build can take a while and may download the local embedding model β hence off by default.
Config files are read fresh on every use (mtime-cached), so hand edits take effect immediately.
Committing project settings to a repo. The file is self-contained, so sharing it via the repo is the intended way to make settings team-wide. Note that .gitignore commonly ignores the whole .zvec-grep/ directory (it holds runtime index artifacts) β and git cannot track files inside an ignored directory, so a bare .zvec-grep/ entry keeps the config out of the repo too. Re-include just the config with:
.zvec-grep/*
!.zvec-grep/config.json// user: ~/.pi/agent/pi-zvec-grep/config.json (values only β no scope flag)
{
"defaultLimit": 7,
"autoIndex": false
}
// project: .zvec-grep/config.json (self-contained β values + boolean flag)
{
"defaultLimit": 25,
"autoIndex": true,
"projectScope": true
}Quickstart
# index a workspace once (local model auto-downloads, stays on disk)
/zg index
# then just ask the agent β it picks zvec_search on its ownOr, from the CLI directly:
zg index /path/to/workspace --embedding local/potion-code-16m-v2
zg query "how is the token validated"Design: what it is (and is not)
zvec-grep unifies ripgrep, BM25, and vector search behind one interface. But its own guidance is explicit: keep native rg for exact text. So this package is not a drop-in grep replacement β it's a first-class search layer for the cases rg can't reach:
- meaning / fuzzy / concept-based discovery
- cross-file, call-chain, data-flow, and architectural synthesis
- design-rationale questions where you don't already know the exact identifier
rg stays the workhorse for exact strings, regex, counts (-c), file lists (-l), and anything you pipe. (Managed zg query --rg deliberately rejects output-format flags like -l/-c/--json and normalises its output/exit-codes β that's the boundary.)
The routing rule is baked into the tool descriptions and the promptGuidelines so the model chooses the right tool without extra prompting.
Layout
index.ts # entry β registers tools + commands
src/core/
queries.ts # buildQueryArgs β zvec_search argv contract
indexing.ts # buildIndexArgs β zvec_index argv contract
workspace.ts # normalizeRoot + clip
zg.ts # pi.exec wrapper around the global `zg`
src/extension/
tools.ts # the pi tool + command surface + auto-index session hook
config.ts # two-layer settings: values-only user file + self-contained project file with the boolean activation flag
settings-ui.ts # /zg settings menu (SettingsList)
test/
verify-*.mjs # plain node --experimental-strip-types harness
helpers/
test-utils.mjs # temp dirs, PASS/FAIL reporter
fake-zg.mjs # deterministic fake `zg` on PATH
pi-harness.mjs # fake ExtensionAPI with a real child_process execTesting
No test framework β Node's type stripping + a fake zg binary (no real zg/index/network needed). Tests run hermetically via a fake pi whose pi.exec is a real child_process.execFile bound to a PATH with the fake zg prepended.
npm test
# or individually:
npm run cli:test # real `zg` contract (needs zg installed)
npm run surface:test # tool surface + execute wiring (fake)
npm run queries:test # buildQueryArgs (pure)
npm run indexing:test # buildIndexArgs (pure)
npm run errors:test # normalizeRoot/clip/error shaping (pure)
npm run settings:test # config layers: per-workspace flag, dormant/legacy files, full writes (pure + tool wiring)
npm run autoindex:test # session-start auto-index hook: guard, fire-and-forget, in-flight (fake)
verify-cli.mjsshells out to the realzgand will FAIL if@zvec/zvec-grepis not installed β install it first, or rely on the hermetic suites for CI without it.
Publishing
Releases publish to npm via GitHub trusted publishing (OIDC, no static npm token). Tag a release matching the package.json version (e.g. v0.1.0); the workflow verifies the tag, runs the test suite, and publishes with provenance. See .github/workflows/publish.yml.
License
Apache-2.0. pi-zvec-grep is a thin integration layer over the separately-licensed @zvec/zvec-grep CLI and the zvec engine it ships.
