github dualeai/seek v0.21.0

3 hours ago

v0.21.0 uses the local model for every query that gives it text, and removes the fixed limits on files, matches, time, and lock waits. The default path, the output, and the exit codes change, and every index rebuilds: read Breaking changes before you upgrade.

Breaking changes

  • Default path. With no path, Seek searches the current folder, not the whole Git repository. From a subfolder, give the repository root to search all of it.
  • Headers. A file header is the path as typed plus the path below it, as in rg and git grep, not a path relative to the repository. file: matches this path. With two or more nodes, a [git] or [folder] tag follows.
  • New output lines. When the model runs, copies with the same content and match print once, with an also: <path>, ... line. A last line counts the name-only files that could also match.
  • Exit codes. A failed node gives a warning, and the other nodes still answer. So Git missing from PATH, or type:repo, type:filematch, and a negated case: (sourcegraph/zoekt#1189), give exit code 0 or 1, not 2.
  • Index rebuild. Every index rebuilds, and the first search also builds the vector index. On a large repository, this takes tens of seconds or more and several GiB of memory. Vector indexes are larger: about 1.3 million rows on a Kubernetes checkout, against 204,694. Old indexes stay until the cache budget needs their space; seek gc --all removes every index that no search uses.
  • Slower one-word queries. A one-word query now runs the model, so it takes more time and memory (see Speed). Use --lexical-only for a fast exact lookup.
  • Every match. Seek keeps every match, so a very common word on a large repository costs more time and memory.
  • SEEK_GC_MAX_AGE is gone. Use SEEK_CACHE_BUDGET.

Search

  • The model runs for every query that gives it text: one word, an identifier, a phrase, an or of descriptions, or filter patterns (sym:Foo gives Foo). Before, only a description of two or more words used it.
  • Every node can add files by meaning, also dirty and untracked Git files. Before, only one clean Git tree, file, or folder could.
  • A file that only the model adds must pass a new threshold over the score of the same query against an empty document. So query words with no topic do not admit files. Write a description of three to six words.
  • The model scores every candidate, not at most 128 files. A long query keeps every token, in up to 127 windows of 128 tokens. Every byte of a file reaches a vector, also in generated files.
  • Text ranking no longer changes with the split of files into shards, nodes, or path scopes.
  • A regular expression that Go rejects, such as a{1,501}, is a query error, not a crash.
  • -A and -C take any value of 0 or more, not at most 512.

Limits and cache

  • Gone: the 10,000-match cap, the 60 s search limit, the folder caps (1,000,000 files or 10 GiB), the Git caps (10,000,000 files or 10 GiB), and the 10 s and 60 s lock-wait deadlines.
  • SEEK_CACHE_BUDGET (for example 20G) sets one budget for the index cache: by default, 10 % of the cache volume, or less to keep 5 % free. A search that does not fit stops with exit code 2. After a build, Seek removes the least recently used indexes until the cache fits.
  • seek gc also removes the runtimes of other Seek versions whose folders are older than 14 days.
  • During lock waits, the first Ctrl-C skips only the waiting nodes, and a second one ends the command.

Git and indexing

  • In a partial clone, Seek finds a missing file by name and indexes it when it arrives. This needs Git 2.45 or later, or a 2024 maintenance release (2.39.4, 2.40.2, 2.41.1, 2.42.2, 2.43.4, 2.44.1). With an older Git, Seek skips that node.
  • Seek finds by name only a file that it cannot read, and a macOS cloud-only file, which it never downloads. Before, it dropped an unreadable file with no notice.
  • Seek no longer reads .sourcegraph/ignore or the zoekt.* Git config. repo: matches only Seek's own git-<hash> name.
  • The "folder changed during index build" error is gone: Seek reads a changed node again. Seek now also sees a rewrite of the same size with the old mtime.

Security

  • Each Git command turns off the repository settings that run a program: the fsmonitor hook, hooks, core.sshCommand, signature checks, the external diff, ext:: transports, and local or worktree filter drivers. Global and system filter drivers, such as Git LFS, stay on. If Seek cannot read the driver list of a repository, it skips that node.

  • A search uses no network: GIT_NO_LAZY_FETCH=1 stops partial-clone fetches.

  • Seek no longer writes repository config. v0.5.0 to v0.20.1 set core.untrackedCache=true and, with Git 2.36 or later, core.fsmonitor=true, when the config did not name them. To remove them, run in each repository:

    git config --unset core.fsmonitor
    git config --unset core.untrackedCache
    git fsmonitor--daemon stop  # macOS
  • govulncheck reports GO-2026-6809 (crypto/x509, fixed in Go 1.27.3), and GO-2026-6860 and GO-2026-6866 (x/net/html, fixed in v0.62.0). govulncheck finds no call to a vulnerable function. This release uses Go 1.27.2 and x/net v0.61.0.

Speed

Each row compares the code before and after one change, on a shared 18-CPU Mac.

Case Before After Why
Remove 1 file from a 3,000-file folder 7.9 s 0.10 s Zoekt writes tombstones in place of a full build
Change 3,000 of 6,000 folder files 3.8 s 1.2 s Delta builds use all CPUs
Change 1 file in a folder of more than 64 full-build shards (test fixture) 5.0 s 0.16 s The delta cap counts only the shards above the last full build, so the change stays a delta
Index size after removing 36,000 of 40,000 files 396 MB 38 MB A full build runs when the dead content reaches the live content
Vector build after a 1-file commit (Kubernetes) 19.0–21.3 s 3.6–3.9 s Seek embeds only new windows and reuses unchanged graph shards
Vector scoring of 5 descriptions (Kubernetes) 301–438 ms 29–74 ms NumKong kernels score the vectors; warm descriptions are 12–20 % faster
Cold text search of 48 repositories of 40 files 1.80 s 1.59 s All nodes build at the same time, with build slots from the read budget in place of 4 workers
Time to see a free build lock (median) 1.32 s 6.5 ms Lock waits poll every 1–10 ms, not every 100 ms–2 s
One-word query, clean 50-file repository, warm (Core ML) 82 ms, 44 MiB 0.5 s, 640 MiB The query now runs the model (0.95 s on the CPU provider); use --lexical-only to skip it

Fixes

  • A damaged Zoekt shard no longer stops the process: Seek rebuilds the index once. Seek repairs damaged vector data once, not at each search.
  • A commit in a new month no longer rebuilds the Git index in full.
  • A commit in a nested repository no longer changes the state of its parent.
  • A failed publish step moves the live files back, so the index keeps its content.
  • A failed update of uncommitted files no longer rebuilds the committed index at each later search.
  • An edit during a build shows in the next search.
  • A FIFO, socket, device, or symlink that replaces a file after the walk no longer blocks a build.
  • Two builds no longer remove each other's temporary files.
  • A failed step, such as ctags, reports its own error, not "context canceled".
  • A .git entry that points to the Git directory of another work tree fails its node, so a search never shows or changes that repository.

Dependencies

  • USearch 2.26.2 to 2.26.5, with its int8 cosine metric. On Kubernetes, unreachable keys fell from 3.68 % to 0.0041 %.
  • NumKong 7.8.4 is new, embedded for each target.
  • gobwas/glob is no longer a dependency. Zoekt, ONNX Runtime 1.30.0, the model, and Go 1.27.2 do not change.

Known limits

  • A one- or two-word description adds few files by meaning, and a long one finds few. Files that contain every word still print.
  • If a command stops responding while it holds a lock, other searches of that node wait until you stop them.
  • On macOS, a non-ASCII path operand in a Git repository can find nothing, because Git stores NFC names and Seek can pass NFD names.
  • On a case-sensitive volume, the Git path operand a.go also returns A.go.
  • During another command's build, a dirty file that changed again can show its old uncommitted text.
  • Upstream defects:

Router plugin

  • A pathless rg, git grep, or fd command searches the current folder, as the original command does.
  • -A and -C pass to Seek up to the int64 maximum, with no seek --help check.
  • fd routes only a literal name with no / and no regular-expression operator.

Maintenance

  • CI also builds and tests on macOS 27 arm64 (the xcode-27 preview image).
  • make rerank-assets-upgrade is gone; use make search-assets-upgrade.

Packages

Four archives for macOS 15 or newer and glibc Linux (built on Ubuntu 24.04; no musl), on amd64 and arm64, with SHA-256 checksums, a CycloneDX SBOM, and build-provenance and SBOM attestations. Each archive holds the binary (with its model and native libraries), the license, and the third-party notices. Seek needs Universal Ctags, and Git 2.36 or later for Git repositories.

Install

curl -sSfL \
  https://raw.githubusercontent.com/dualeai/seek/v0.21.0/install.sh |
  sh -s -- v0.21.0

Full changelog: v0.20.1...v0.21.0

Don't miss a new seek release

NewReleases is sending notifications on new releases.