vunareap the open web
v0 preview — it does not yet crawl-to-query end to end

Keep the tally, not the field.

A decentralized crawl → extract → index engine that stores the index, not the pages. Vuna is Swahili for to harvest, to reap.

Volunteer nodes crawl a distributed, subscribable list of URLs, run pluggable extractors over each page, and contribute the result — keyword postings, vector embeddings, link-graph edges, a snippet, and a pointer back to the live URL — into a shared index replicated across the network. The page body is never archived, which is what collapses storage from datacenter scale to roughly 2 GB per volunteer node at billion-page scale. One engine, two verticals so far — web search/RAG and retail price-radar — designed against the KOTVA substrate's identity, PUB, DHT and SEARCH primitives. That binding lives in vuna-node, which is a Wave-2 stub, so nothing here runs on KOTVA today. No token, no page archive, no new crypto.

Reading keycolour is load-bearing on this page
Running

Built and tested against its own fixtures. You can run it today.

Not built

Specified in the design docs, absent from the tree. A Wave-2 stub.

Mock data

The screen renders; the numbers behind it are fixtures, not a live node.

Design claim

An argued property of the design. Nothing has demonstrated it at scale.

Every claim below carries one of these four marks. Nothing here is coloured for decoration.
The Vuna desktop app in its light theme: a search box over a list of results, each tagged local, peer or indexer, with a snippet and a score, beside a node panel showing documents indexed, storage used, peers, embedding spaces served and subscribed URL lists The same Vuna desktop app search view in its dark theme
The desktop node. Local and peer results with source chips, beside your node's own dashboard. mock datavuna-query and vuna-node are Wave-2 stubs, so every number in this shot is a fixture. See status.

01  /  The idea

Four objects. That's the whole system.

Crawl, extract and index are three separable stages joined by seam traits in vuna-core. A new embedding model, a new vertical or a new ranking strategy is a new implementation of an existing trait — not a fork of the engine.

01

URL list

A signed, versioned, subscribable list of URLs — the ad-filter-list model applied to a crawl frontier. Anyone can publish one; you choose which to trust. Deduped and DHT-assigned across nodes.

02

Embedding space

A recognized model index, model_id@dim/quant. Each is an independent parallel space; the keyword index and graph stay model-agnostic and shared. New model → new space, adopted opt-in, never a fleet-wide flag day.

03

Index shard

Derived per-node state: postings, vectors per space served, graph edges, a snippet, a pointer to the live URL — and the chunk text, which is what makes re-embedding a local recompute instead of a re-crawl.

04

Node descriptor

Which lists this node subscribes to and which spaces it serves. A node running one list, the default space and the web extractor is already a complete participant.

No page archive

Only postings, vectors, graph edges, a snippet and a pointer back to the live URL. The author's copy stays the only copy, and the index is derived, rebuildable, never authoritative — on any disagreement the author's signed content wins.

Quorum where nobody signs

In the retail vertical the store is a non-participant that signs nothing, so agreement across k distinct, anchored observers is the only ground truth. vuna-core::quorum is built and tested; one observer cannot stuff the ballot.

KOTVA, not new crypto

Identity, PUB, DHT and SEARCH are all meant to come from the substrate rather than be reinvented here. vuna-node is the only crate that will bind it — and today it is a stub, with the kotva-core dependency still commented out in Cargo.toml and no crate in the tree declaring it. That is why the rest of the workspace compiles and tests fully offline.

Storage at ~6 KB per page design claim
CorpusOne copy×3 redundant / 10k nodes
1 billion pages~6 TB~1.8 GB / node
10 billion pages (Google-ish)~60 TB~18 GB / node

Keyword ~2 KB · embeddings (int8) ~2.5 KB · graph ~0.3 KB · metadata ~0.7 KB. These are budgets derived from the design, not measurements of a running network — there isn't one. Compute, not storage, is the recurring cost, and the honest trade-offs (compute-vs-disk volunteer supply, Sybil resistance at small scale, freshness) are in viability. Read it before believing the pitch.

02  /  Ranking

No global score — so there is no position to sell.

The searcher runs their own node, and ranking is local-first: your shard answers first, always, offline-safe. Peer and indexer reach is layered on top and merged with Min-PPR over your link graph and your subscriptions. No network-wide authority computes one number per document, so there is no ranking slot anyone could auction — and an opt-in indexer adds reach without ever becoming authoritative (KOTVA SEARCH's SRCH-2: the index is derived, rebuildable, never authoritative).

Result provenance is always shown, never inferred
  • local
    Answered from your own shard
    Always available, offline-safe, and first. Gold means "yours" — nothing else on this page is gold.
  • peer
    Reached over the mesh from another volunteer node
    Adds coverage you have not crawled. Merged into your ranking, never over it.
  • indexer
    An opt-in global indexer coordinator
    Deliberately uncoloured. An indexer adds reach and never authority, and the palette says so by omission.
not built  The read path that does this — vuna-query — is a Wave-2 stub. The contract it will implement (query::QueryEngine, Source, RankedHit) is frozen and tested in vuna-core; the fan-out and the Min-PPR merge are not written yet.
03  /  Status

v0 preview — honest about what's real.

132 tests green describes what compiles and behaves against its own fixtures. It is not 132 features shipped. Four of the six stage crates are implemented; there are zero live nodes and zero real users today.

ComponentWhat it doesStateTests
vuna-coreFrozen contract — types, seam traits, the retail quorum reconciler.done19
vuna-crawlPolite fetch — robots.txt, per-host rate limiting, body caps.done24
vuna-extractweb (chunks + links) and retail (JSON-LD/OG) extractors, plus the interpreter for declarative adapters/*.toml.done67
vuna-indextantivy BM25 + per-space HNSW vectors + link graph.done9
vuna-frontierDistributed URL lists, dedup, DHT assignment.done12
vuna-querySEARCH read path — local-first + fan-out + Min-PPR merge.stub · wave 2
vuna-nodeDaemon + kotva-core binding — the crawl→extract→index→publish loop.stub · wave 2
app/Tauri v2 desktop node (React). Builds and runs.mock data

It does not yet crawl-to-query end to end. The substrate contract and four of the six stage crates are implemented and tested; the desktop app builds and runs on mock data. Until vuna-node lands, nothing here is fed by a live crawl — including the adapters. See architecture for the crate-by-crate detail and viability for the two open risks — compute-volunteer supply and small-network Sybil resistance — neither of which this design claims to have solved.


04  /  Screens

The reference client, running on fixtures.

The desktop app is one screen today: a search box over local and peer results, and a node panel that surfaces exactly what your box is doing — no hidden telemetry. These are real screenshots of the real UI. The corpus behind them is a mock, and the app says so on screen, in the app.

Search view, light theme: results tagged local, peer and indexer, each with a title, URL, snippet and score Search view, dark theme
Search. mock data Local-shard and peer results with source chips and per-result scores. Index only — the pages stay where they live.
Node dashboard, light theme: documents indexed, storage used, peers, spaces served, extractors enabled, subscribed URL lists and a query-visibility disclosure Node dashboard, dark theme
Your node. mock data Docs indexed, storage, spaces served, extractors enabled, lists subscribed — and an explicit query-visibility disclosure. The panel carries its own mock chip so the crop cannot be quoted out of context.
05  /  Quick start

One Cargo workspace. One Tauri app.

No Docker, no database server, no keys and no network access are required to run the tests. vuna-core keeps minimal dependencies; tantivy, HNSW, reqwest and the embedding runtimes live only in the crate that needs them.

shell
git clone https://github.com/vul-os/vuna
cd vuna

# the engine — offline, no network, no keys
cargo test --workspace     # 132 tests green
cargo build --workspace

# the desktop app — mock data today, real UI
cd app && npm install
npm run tauri dev          # or: npm run dev (plain Vite)
  1. 1
    BuildRust 1.75+ and Node for the desktop shell. Everything except vuna-node compiles without the substrate.
  2. 2
    Test the enginecargo test --workspace runs all 132 tests across core, crawl, extract, index and frontier. vuna-query and vuna-node are stubs and are not exercised end to end.
  3. 3
    Preview the appThe Tauri shell runs against a mock corpus — app/src/lib/api.ts falls back to it whenever there is no live daemon, and the UI shows a mock-data banner the whole time it does.
06  /  The gaps

What this page does not claim.

The design docs are longer than the code. That is the accurate state of the project, and hiding it would make everything above worth less. Code is MIT OR Apache-2.0.

  • not built
    The end-to-end path

    There is no crawl → extract → index → query round trip. vuna-query and vuna-node are Wave-2 stubs; the four implemented crates are exercised against their own fixtures, not against each other over a network.

  • not built
    A live network

    Zero nodes, zero users, zero bytes of real index. Every number in the screenshots above comes from the fixtures in app/src/lib/api.ts and app/src-tauri/src/commands.rs.

  • bounded
    Adapter coverage

    The adapters/*.toml interpreter ships with three worked manifests. The format still cannot express secondary lookups, derived fetches or multi-offer aggregation, and a manifest that exceeds those bounds is rejected at load with a reason rather than silently degraded — the exact boundary is in adapters/README.md.

  • unsolved
    Two open risks

    Compute-volunteer supply — embedding, not disk, is the recurring cost — and Sybil resistance at small network sizes. Neither is solved here; both are argued honestly in viability.

  • scoped
    The open web is not a v1 promise

    v1 targets a bounded corpus — a federation's content or a curated vertical — where crawl is cheap and Sybil is dodged via KOTVA's vetted operators. The open web is a later research track.