dotnet-srndx.any
0.1.0
dotnet add package dotnet-srndx.any --version 0.1.0
NuGet\Install-Package dotnet-srndx.any -Version 0.1.0
<PackageReference Include="dotnet-srndx.any" Version="0.1.0" />
<PackageVersion Include="dotnet-srndx.any" Version="0.1.0" />
<PackageReference Include="dotnet-srndx.any" />
paket add dotnet-srndx.any --version 0.1.0
#r "nuget: dotnet-srndx.any, 0.1.0"
#:package dotnet-srndx.any@0.1.0
#addin nuget:?package=dotnet-srndx.any&version=0.1.0
#tool nuget:?package=dotnet-srndx.any&version=0.1.0
srndx
Offline semantic + keyword search over your local text — docs, notes, source, and git history. Ask in plain language and get back the passages that mean the same thing, even when they share no keywords.
srndx is a small .NET CLI that composes three pure-managed, no-native-dependency libraries
through the standard .NET AI ecosystem abstractions:
| Library | Role | Ecosystem abstraction |
|---|---|---|
| FastText.Net | Detects each item's language (lid.176) |
— |
| Model2Vec.Net | Turns text into embeddings | Microsoft.Extensions.AI.IEmbeddingGenerator |
| Hnsw.Net | Approximate-nearest-neighbor vector index | Microsoft.Extensions.VectorData |
No GPU, no cloud, no API key, no native binary — everything runs in-process, anywhere .NET runs. Search is hybrid: a built-in BM25 lexical index (exact-token relevance) is fused with the semantic vector index via reciprocal-rank fusion, so both keyword and intent matches surface from the same query box.
Install
srndx is published to this repository's private GitHub Packages
NuGet feed as a RID-specific .NET tool:
native-AOT packages for common platforms plus a portable fallback. The CLI picks the best match for your
machine, and the ML models are bundled in, so the tool is self-contained. CI publishes a rolling
prerelease on every push to main, and a stable version on each v* tag.
You need the .NET SDK and the GitHub CLI,
signed in (gh auth login). Then install (or upgrade) with one line, which fetches and runs the helper
eng/install.sh (eng/install.ps1 on Windows):
bash <(gh api repos/ericstj/srndx/contents/eng/install.sh -H "Accept: application/vnd.github.raw")
gh api repos/ericstj/srndx/contents/eng/install.ps1 -H "Accept: application/vnd.github.raw" | Out-String | iex
The script grants gh the read:packages scope if needed and installs the tool, passing the feed token
through an environment variable so it is never written to any NuGet config. Equivalent manual steps:
gh auth refresh -h github.com -s read:packages # let gh read packages
dotnet nuget add source https://nuget.pkg.github.com/ericstj/index.json --name srndx # URL only — no secret on disk
# The token lives only in this environment variable, scoped to the one command
NuGetPackageSourceCredentials_srndx="Username=$(gh api user --jq .login);Password=$(gh auth token)" \
dotnet tool update -g dotnet-srndx --prerelease
dotnet tool installhas no flag for feed credentials, so NuGet reads them from theNuGetPackageSourceCredentials_<source-name>environment variable, matched to the source by name — keeping the token out ofnuget.configentirely. This reusesgh's managed session token (revoke any time withgh auth logout);ghcan't mint a throwaway PAT because GitHub no longer exposes a token-creation API. To use your own token instead, create a personal access token withread:packagesand put it in thePassword=field.
Usage
# Index a docs folder and a repo's recent history into one index file
srndx index --files ./docs --git ./my-repo --max-commits 500 --out project.index
# Semantic search (add --lang / --source / --top to filter)
srndx search "how do we authenticate requests" --index project.index
# Run as a live service: watch a directory, keep the index current, query interactively
srndx serve --files ./src --index project.index
# Run as an MCP server over stdio (a 'search' tool over a live, self-updating index)
srndx mcp --files ./src --index project.index
# Stop a backgrounded serve/mcp process (flushes the index first)
srndx stop --index project.index
# Wire srndx into a repository for agents
srndx install-mcp --repo . # merge an 'srndx' server into .github/mcp.json
srndx install-skill --repo . # emit .github/skills/srndx/SKILL.md
Run srndx --help (or srndx <command> --help) for all options. While a serve/mcp process is
running, a one-shot srndx search against the same index is answered by that resident process over a
loopback socket — skipping the cold-start load — and falls back to loading locally when none is running.
Performance
On dotnet/runtime (57,923 files → 624,656 passages) with the Native-AOT build:
Query, warm (resident serve/mcp) |
~40–80 ms |
Query, cold (one-shot search) |
~1.1 s (model load + mmap + query) |
| Index build (one-time) | 624,656 passages in ~2.5 min; amortized over every later query |
Indexing and querying scale with cores: language detection and embedding run in parallel, and the vector
index is split into independent HNSW shards (--shards, default 8) that build, memory-map, and search in
parallel while preserving recall. Cold start is kept roughly independent of index size by memory-mapping
the shards and the lexical index. Details in docs/BENCHMARKS.md.
Scope. srndx finds relevant passages by meaning and keyword. It is not a symbol-aware code
navigator — it won't reliably resolve which Dictionary you mean among same-named files, find a type's
references, or beat a language server at "go to definition." It shines for offline, private, no-dependency
search over prose and mixed text (docs, notes, tickets, commit messages) and for intent queries with no
shared keywords. See Limitations and scope for the honest edges.
How it works
indexsplits files into passages and reads commit messages, language-detects and embeds each, adds its tokens to a BM25 index, and writes the sharded vector index plus BM25 to one file.searchfuses semantic similarity and BM25 relevance with reciprocal-rank fusion.serve/mcpkeep an index in sync with a watched directory and answer queries — interactively or as a Model Context Protocol tool for agents.install-mcp/install-skillwiresrndxinto a repository for agents.
Architecture, the Native-AOT design, persistence, packaging, and the performance engineering behind the numbers above are documented in docs/DESIGN.md.
Models
The tool needs two model files. When installed as a packaged tool they are bundled alongside the binary;
otherwise they are resolved from the models/ folder next to the binary:
lid.176.ftz— FastText language-identification model.potion-base-2M/— Model2Vec embedding model (config.json,model.safetensors,tokenizer.json).
Bring your own model
Each model can be swapped independently via environment variables (no rebuild required):
| Variable | Points to | Effect |
|---|---|---|
SRNDX_LANGUAGE_MODEL |
a FastText model file | Replaces the language-ID model. |
SRNDX_EMBEDDING_MODEL |
a Model2Vec model directory | Replaces the embedding model. |
SRNDX_MODELS |
a directory holding both defaults | Replaces both at once. |
Swapping the embedding model changes the vector dimension, so re-run srndx index to rebuild any index
with the new model. A larger Model2Vec model trades startup/footprint for better semantic ranking with no
code change.
Why this exists
A working showcase of a fully managed semantic-search stack with zero native dependencies — for private, offline retrieval that ships as plain NuGet packages and runs everywhere the .NET runtime does.
Learn more about Target Frameworks and .NET Standard.
This package has no dependencies.
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated |
|---|---|---|
| 0.1.0 | 144 | 7/23/2026 |