Skip to main content

Groundwire

A retrieval + verification layer that sits in front of an LLM. Groundwire keeps your corpus off the GPU and puts only the top-k retrieved chunks in front of the model — so a small, weak reader can answer correctly over a body of source far larger than its context window. Part of the tina4stack.

pip install tina4-groundwire      # zero runtime dependencies — stdlib only
  • Off-GPU corpus. The index lives in RAM/disk (SQLite FTS5 by default). The model only ever sees the prompt plus a handful of retrieved chunks, so its GPU footprint is constant regardless of corpus size.
  • Lossless lexical retrieval. The default backend is an exact-token inverted index (BM25/FTS5), so a rare identifier — a symbol, a clause number, GRM-2026-XT-5590 — comes back byte-for-byte. No embedding compression to smear it away.
  • Zero dependencies. Core is pure stdlib (same ethos as tina4-python). The optional dense backend needs no numpy — vector math is stdlib (veclite.py) and the encoder is a thin HTTP client to an embeddings server you already run.
  • Verification, not just retrieval. Optional verified ranking sinks code that doesn't run; the answer-reduce read loop maps a weak reader over batches when the retrieved set overflows its window, rather than silently truncating.

Quickstart

from groundwire import Groundwire

gw = Groundwire(memory="sqlite_fts", k=5)
gw.ingest(open("big_manual.txt").read())            # or a list of docs
gw.ingest_code(open("router.py").read(), title="router.py")

# retrieval only — build your own prompt / call your own model:
for cid, text, score in gw.retrieve("where is the route registered?"):
    print(text)

# or let a reader answer over the retrieved chunks:
from groundwire.answer import make_generator
gw = Groundwire(reader=make_generator("api"), k=6)  # any OpenAI-compatible endpoint
print(gw.ask("what was the Q3 revenue figure?"))

retrieve() is the whole product; ask() is a convenience that runs a reader over the hits. The corpus can be gigabytes — only k chunks ever reach the model.

How it works

ingest → chunk → index (off-GPU, RAM/disk) → retrieve top-k → prompt → read
                        └─ the whole corpus lives here ─┘   └─ model sees ~k chunks ─┘

"Unlimited context" here is retrieval substituting for attention: the index holds everything; the model reads only what matched. The ceiling isn't the model's context length — it's disk.

Backends (all off-GPU)

backend store notes
sqlite_fts disk (FTS5) default. BM25 over an inverted index; flat RAM, scales past 3M tokens.
bm25 RAM pure-Python BM25; fastest queries; memory grows with corpus.
dense RAM (stdlib) semantic retrieval via an embeddings server you run; no numpy/torch.
hybrid fused Reciprocal-Rank-Fusion of lexical + dense.
iterative lexical pointer-walk retrieval for multi-hop chains.

The trick that makes lexical work for code: the fold() tokenizer (lowercase + strip accents + de-comma numbers + split camelCase), applied symmetrically to both document and query — so a query for field reaches IntegerField, and 24,601 is findable. Optionally, Groundwire(rerank="dense") reorders a lexical pool by dense cosine (query embedded once, candidates cached by id) — dense discrimination without embedding the whole corpus.

What the numbers actually say

Measured with python -m groundwire.harness (network-free retrieval recall = "needle chunk in top-k"). The headline is counterintuitive:

Recall is essentially independent of corpus size — for lexical retrieval. A distinctive-identifier query holds 100% from 8K to 3M tokens; only latency moves.

corpus chunks lexical recall query latency
8K 20 100% 0.2 ms
512K 1,202 100% 1.0 ms
1M 2,348 100% 1.9 ms
3M 7,043 100% 5.3 ms

Even 128 lexical distractors per needle don't dent it — filler that doesn't share the query's discriminative terms is invisible to an inverted index.

Where recall is capped, it's the query type, not size (each row is flat across 8K–3M):

query type lexical note
distinctive identifier 100% the regime most code queries live in
paraphrase / synonym (NoLiMa) ~71% zero shared words — see below
multi-hop chain (k=5 → k=50) 14% → 100% a top-k coverage limit, fixed by wider k or iterative

Dense retrieval is the opposite of lexical — it decays with size. Measured with a real nomic-embed-text server on the paraphrase (NoLiMa) task:

corpus lexical dense (nomic-embed)
8K 71% 100%
64K 71% 57%
256K 71% 43%
1M 71% 43%

Dense recovers the paraphrase at small scale then falls below lexical as filler crowds the manifold. This is why Groundwire is lexical-first and treats dense as a reranker over a small lexical pool, not a whole-corpus retriever: lexical bounds a size-invariant candidate set; dense only reorders it, never fighting the whole haystack. The residual gap — a zero-overlap paraphrase that never enters the lexical pool — is best closed lexically at ingest/query time (fold, camelCase split, synonym expansion), the only size-invariant lever.

The answer-reduce read loop

The fixes above all widen the retrieved set (multi-hop wants a big k, hybrid widens the pool, code chunks run long) — until it overflows a weak reader's window and gets silently truncated, dropping the very chunks a wider k was meant to catch. So when the chunks don't fit, ask() maps the question over budget-sized batches and reduces by verified-answer selection instead of truncating:

gw = Groundwire(reader=make_generator("api", num_ctx=8192), k=40, verify=my_verifier)
gw.ask("…")   # auto-batches when retrieved chunks exceed the reader's window

The reducer prefers a candidate the retrieved text actually grounds (present in the batch it came from); pass a custom verify(question, answer, chunks) -> score to plug in your own signal (e.g. "the code boots"). Validated end-to-end against a live 7B reader. See groundwire/mapreduce.py.

The GPU edge

Full attention holds a KV cache in VRAM that grows linearly with context. Retrieval keeps the corpus on RAM/disk and runs the model over the prompt plus a few chunks — a constant footprint. Same Qwen2.5-7B, both ways (python -m groundwire.memory_model):

context full-attention VRAM GPU needed retrieval VRAM ratio
256K 29 GB 1× 48GB ~15 GB 1.9×
1M 69 GB 1× 80GB ~15 GB 4.5×
3M 175 GB 4× 80GB (~256GB) ~15 GB 11×

At 3M tokens a full-attention 7B needs a ~256GB four-GPU rig; retrieval fits on a single 20GB card, and usually runs faster (no prefill over the whole context). The honest trade is a capability give-back on tasks needing global reasoning across the whole context — which is what the multi-hop / NoLiMa rows above quantify.

Isn't this just RAG?

It shares one mechanic — retrieve text, put it in the prompt — and differs in what matters. Classic RAG embeds documents into vectors and does approximate-nearest- neighbour search for semantically similar chunks. Groundwire's default is lossless exact-token retrieval, and it's positioned as a context-window substitute (what the model would otherwise hold in KV), not a knowledge-base feature you write into an app.

classic (dense) RAG Groundwire (default)
representation lossy: chunks → vectors lossless: exact tokens in FTS5/BM25
match fuzzy semantic (cosine) exact lexical — the token is there, verbatim
GPU at ingest/query an embedding model none for lexical; constant footprint
scaling dense recall decays with corpus size lexical recall flat to 3M
failure mode embedding misses a paraphrase → silent miss if the token exists it is found

Groundwire isn't anti-embeddings — the dense/hybrid backends are embedding retrieval, for the semantic tail. The point is the default and the headline rest on exact-token retrieval, because that's what solves the long-context problem off-GPU.

The NIAH harness

Groundwire ships the long-context recall harness it was validated with:

groundwire-bench --backend sqlite_fts --context-tokens 64000 256000 1000000
groundwire-bench --task nolima  --backend dense --encoder openai:nomic-embed-text
groundwire-bench --task multihop --backend iterative
python -m groundwire.harness --help

It reports, per context size: retrieval recall (needle in top-k), optional answer recall (a reader extracts the value), and throughput (ingest tok/s, query latency). Encoder specs: ollama:MODEL, openai:MODEL (any OpenAI-compatible endpoint incl. vLLM/Azure), hash:DIM (offline). Config via EMBED_URL / EMBED_MODEL.

Verified ranking (for code retrieval)

Groundwire(verified_scorer=...) scores each source once at ingest — canonical framework source is trusted; docs/how-tos are boot-gated in an isolated subprocess against a real framework instance — and sinks examples that don't run below ones that do at query time (the query path only reads the cached score, staying pure stdlib). Set GROUNDWIRE_VERIFIED_RANK=0 for a clean A/B baseline.

Experimental

Desktop app

A native chat app that owns every turn — retrieving over your sanctioned folders before the model answers and post-filling verbatim spans after — while talking to a local Ollama model or a cloud model:

pip install -e ".[desktop]"
python -m groundwire.desktop            # native window (WKWebView / WebView2)

Architecture, routing, Mac setup, and status: docs/APP.md. Building signed installers: docs/PACKAGING.md.

Not part of the tested core; useful but rougher: groundwire.proxy (a transparent drop-in Ollama proxy that injects retrieved context into every request), groundwire.server (an OpenAI-compatible proxy with an import verify-and-correct loop), groundwire.mcp_server (a Tina4-stack MCP server), and a desktop tray (groundwire.tray, pip install "tina4-groundwire[app]") / native macOS menu-bar app (macos/).

Development

python -m unittest discover tests      # 73 tests, network-free, seconds

Every fix ships with a deterministic regression test. See CLAUDE.md for the working constraints and BENCHMARKS.md for the benchmark plan.

Layout

groundwire/
  pipeline.py        # Groundwire: ingest/chunk/retrieve/ask, _stitch, verified ranking
  memory_systems.py  # backends + fold() tokenizer: bm25, sqlite_fts, dense, hybrid, iterative
  rerank.py          # DenseReranker: reorder a lexical pool by dense cosine, cached, off-GPU
  encoders.py        # stdlib HTTP embedding clients (Ollama / OpenAI-compatible)
  answer.py          # readers: regex_extract (GPU-free), qwen, api
  mapreduce.py       # answer-reduce read loop + map-reduce summarizer
  verified.py        # boot-gate verified ranking (rank by whether code runs)
  harness.py         # long-context NIAH recall/throughput harness + CLI

License

MIT © Andre van Zuydam. Part of the tina4stack.

Release files for tina4-groundwire 0.1.1

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for tina4-groundwire 0.1.1
File Size Uploaded
tina4_groundwire-0.1.1.tar.gz 208.1 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for tina4-groundwire 0.1.1
File Interpreter ABI Platform
tina4_groundwire-0.1.1-py3-none-any.whl Python 3 none any Details

Total release size: 411.1 kB

Release files / tina4_groundwire-0.1.1.tar.gz

Download URL tina4_groundwire-0.1.1.tar.gz
Size 208.1 kB
Tags Source
SHA-256 checksum
How to use checksums
b3db4eee424c0e6afc5c7c71f15f8890ec0af5bed4555227f9e67025d6e68169
BLAKE2b-256 checksum
How to use checksums
c6ef449eea3bf9d776e0599843183ad13ed804ac951119f15bf59385c3347f75
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.14.5

Release files / tina4_groundwire-0.1.1-py3-none-any.whl

Download URL tina4_groundwire-0.1.1-py3-none-any.whl
Size 203.0 kB
Tags Python 3
SHA-256 checksum
How to use checksums
7c3f9228a21df9b0d2a23d186e5385b72d1052736ae81caed2850b9cf9172cbf
BLAKE2b-256 checksum
How to use checksums
655ba72ee5f9fb37a1eac5a529a15e75be8824ed343b6d15499a71771cb425a4
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.14.5

Release history Release notifications | RSS feed

This release

0.1.1 This release

2 release files

0.1.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page