Toute la base de connaissances dans un seul fichier

Urna stocke textes, images et références, déjà convertis en vecteurs, dans un seul .urna. Votre app copie ce fichier et répond aux questions en citant la source, sans serveur, sans internet et sans clé API.
v0.5.1 · open source sous MIT · Rust + Python
.csv
.jsonl
.sqlite
.jpg
Island
Basic Land · Island
corpus/
01001001 01110011 01101100 01100001 01101110 01100100IslandBasic Land · Island256 nombres par chunk, avec potion
corpus.toml
[source] kind = "sqlite"
[[models]] preset = "potion"
[[models]] preset = "clip-vit-b32"
Island
JPEGAV1
Basic Land · Island
JPEGAV1
103 kB → 13 kBmoyenne par carteJPEG, source · AV1, dans le fichier
drift p50 0,961
scans des cartes4 GB
.urna533 MB
plus petit
100 % de l'exact61 % de l'exact34 % de l'exact26 % de l'exact21 % de l'exact
model_hashclip-vit-b32
HNSW + BM25 → cosine
Island
Forest
Mountain
p50, texte vers image
Island
Basic Land · Island
urna validateheadersectionsfichiercontenu
Le runtime n'ouvre jamais de socket

Un dossier et quelques lignes de TOML deviennent un seul .urna : chunks, vecteurs, index, médias et manifest, chaque section signée.

Les scans des cartes entrent dans le fichier en AV1 et les vecteurs passent à un preset plus petit. Le fichier rétrécit, la citation reste la même.

Le gate model_hash vérifie le modèle, HNSW parcourt le graphe, BM25 trouve le mot et le cosinus exact fixe l'ordre.

La réponse porte une citation qui ramène à la source, et urna validate vérifie chaque couche avant la première requête, hors ligne.

comment ça marche

D'un dossier de documents
à un fichier qui répond

1
Rassemblez les sources
Textes, PDF, tableurs, images. Vous décrivez d'où vient chaque élément et quel modèle va le lire, dans un TOML de quelques lignes.
2
Générez le .urna
Un appel fait le reste : urna.build en Python, ou urna build --spec depuis un checkout du dépôt. Il découpe en extraits, calcule les vecteurs, construit les index et signe chaque section en SHA-256. Le résultat est un seul fichier, identique octet pour octet sur n'importe quelle machine.
3
Interrogez depuis l'app
Le runtime Rust ouvre le fichier en mmap et renvoie les extraits les plus proches, chacun avec une citation urna:// qui ramène au texte d'origine.
Ouvert à l'audit, comme toute base de données devrait l'être
Autonome, vérifiable, reproductible, hors ligne.
Le fichier est toute la base
Extraits, vecteurs, index, médias et manifeste dans le même .urna. Copiez-le comme un fichier SQLite, versionnez-le dans git, embarquez-le dans l'installeur. Pas de service à lancer, pas d'index à synchroniser.
Chaque réponse pointe vers un extrait vérifiable
Chaque section a son SHA-256, le fichier entier aussi, et le contenu décodé aussi. La citation urna://content_hash/chunk_id reste la même après compression du texte, et urna cite la résout vers l'extrait stocké.
Hors ligne, sans exception
Le runtime n'ouvre jamais de socket. Le modèle de texte par défaut est livré dans le paquet Python, ou urna setup le télécharge une fois à l'installation. Si le modèle de la requête ne correspond pas à celui du fichier, la recherche s'arrête net au lieu de renvoyer n'importe quoi déguisé en réponse.
en pratique

Benchmark public, même étalon

urna face à usearch, hnswlib, sqlite-vec et lancedb, sur la même machine, avec les données et la commande pour reproduire
0,72 ms
p50
1,02 ms
p99
recall 1,0
0,72 ms par requête, recall 1,0
100 000 vecteurs de 384 dimensions, 200 requêtes, un thread. Le preset hybrid a répondu avec un p50 de 0,72 ms et un p99 de 1,02 ms. C'est le seul du tableau qui vérifie ses propres octets avant la première requête ; cela coûte environ 360 ms à l'ouverture.
Voir dans la documentation: 0,72 ms par requête, recall 1,0
38 000 cartes Magic dans 533 MB
4 GB de scans JPEG sont devenus un fichier 7,46 fois plus petit, avec le texte, les vecteurs, l'index et les images AV1 à l'intérieur, et la recherche trouve la carte aussi souvent que sur le fichier lossless.
Voir dans la documentation: 38 000 cartes Magic dans 533 MB
30 725
extraits
7
datasets
FakeRecogna11,9 k
Fake.br7,2 k
FakeTrue.Br3,6 k
factck-br1,3 k
30 000 extraits de fact-checking
truw évalue des affirmations en portugais face à sept datasets publics de fake news. Le corpus est un .urna de 30 725 extraits : 120 MB avec le preset exact, 31 MB avec tiny.
Voir dans la documentation: 30 000 extraits de fact-checking

Benchmark du 2026-09-10 sur arm64, un seul thread. Ce qu'Urna ne fait pas : mise à jour et suppression en place, filtres sur les métadonnées, écritures concurrentes. Voir le tableau complet.

benchmarks

Les benchmarks d'urna

Mesure la compression, la recherche et la latence sur les 38 627 cartes Magic (3,98 GB de JPEG) stockées dans un fichier .urna, et urna face à usearch, hnswlib, sqlite-vec et lancedb sur les mêmes vecteurs et la même machine

Compression contre recherche par nom

7 fichiers · 1 000 requêtes chacun
facteur de compression sans perte côté recherche7,46x

fois plus petit que les 3,98 GB de JPEG d'origine. Le fichier en crf50 pèse 533 MB et trouve la carte par son nom aussi souvent que le fichier lossless de 3,61 GB : txt@1 à +0,001, dans l'erreur type.

lossless · 3,61 GB
neardup · 1,37 GB
crf50 · 533 MB

Ce que mesure cette métrique

txt@1 est la fraction des 1 000 requêtes où la bonne carte est arrivée en premier. La requête est le nom de la carte en texte ("artwork of the card {name}"), cherché dans l'espace image de clip : le modèle ne voit que l'illustration, d'où un niveau bas dans tous les fichiers ; ce qui compte, c'est l'endroit où il chute.

Le drift est le cosinus entre le vecteur de l'image compressée et celui de l'originale : 1,00 veut dire identique, et plus il descend, plus le codec a changé ce que voit le modèle. Le pire décile (p10) est la carte à la limite des 10 % qui ont le plus changé ; la médiane (p50) est la carte du milieu.

Comment lire ce graphique

Chaque colonne est un fichier avec les mêmes 38 627 cartes, du lossless (3,61 GB) à l'AV1 en crf60 (230 MB), par ordre de compression.

En haut, les deux lignes de drift descendent tout du long et passent sous le floor du gate dès le deuxième fichier. En bas, la recherche reste plate jusqu'à crf50 : les barres vertes sont à moins d'une erreur type du lossless ; la ligne pointillée marque l'endroit où la recherche chute, et les barres rouges sont les fichiers au-delà.

fichiertailledrift p10txt@1±1 erreur typez vs lossless
lossless3,61 GB0,99680,0920,00910,00
neardup1,37 GB0,96660,0960,00930,31
avif q481,2 GB0,96800,0960,00930,31
crf40981 MB0,95940,0890,0090-0,23
crf50533 MB0,93890,0930,00920,08
crf55370 MB0,92110,0740,0083-1,46
crf60230 MB0,88660,0690,0080-1,89

1 000 requêtes par fichier, les mêmes cartes dans tous ; erreur type binomiale ; z est l'écart entre le txt@1 de chaque fichier et celui du lossless, en erreurs types combinées : jusqu'à crf50, aucun ne dépasse 1.

mesuré le 2026-09-12 · benchmark/experiments/14-utility-ladder/results.json

presets
Choisissez la taille. Le contenu reste le même
Cinq presets combinent compression du texte, précision des vecteurs et index, plus micro, qui coupe des dimensions. Trois ici, tous dans la documentation
Pour les questions avec sigles, noms propres, termes rares :
Texte compressé avec zstd
Vecteurs en float32
HNSW + BM25 comme candidats
Rerank par cosinus exact
Voir le preset
Mesuré sur 30 725 extraits. Ici, le recall mesure la stabilité du classement sous quantification, pas la justesse sur de vraies questions. Voir les cinq presets et micro.
intégration
S'installe en une commande. S'intègre en cinq lignes
Un binaire Rust avec trois groupes de verbes (engine, agent, setup) et une API Python. Une fois installé, tout ce qui suit tourne sans réseau
$
Installer
installeur
$
Construire
urna build
$
Demander
urna ask
L'installeur vérifie le SHA-256 avant d'écrire. urna setup télécharge une fois l'embedder hors ligne et finit sur urna doctor, qui indique quelle couche a échoué, s'il y en a une.
curl -sSf https://raw.githubusercontent.com/hoffresearch/urna/main/scripts/install.sh | sh urna setup
Sources, médias et modèle dans un TOML, lancé depuis un checkout du dépôt. La même spec produit la même base sur n'importe quelle machine.
urna build --spec corpus.toml
Des extraits cités, directement dans le terminal.
urna ask corpus.urna "ça marche hors ligne ?" -k 3
Du JSONL avec extrait, source, score et citation, prêt pour votre app ou votre agent.
urna retrieve corpus.urna "ça marche hors ligne ?" -k 5 --format jsonl
Ouvre en mmap, renvoie des résultats cités. Le model_hash attendu bloque un mauvais modèle avant la recherche.
import urna from urna.embed_potion import potion_embedder emb, db = potion_embedder(), urna.open("corpus.urna") qvec = emb.embed_texts(["ça marche hors ligne ?"])[0] hits = db.retrieve(qvec, 5, expected_model_hash=emb.model_hash())
Tous les checksums avant de distribuer : en-tête, sections, fichier, contenu.
urna validate corpus.urna
De la citation au texte stocké, avec les hashes qui le prouvent.
urna cite corpus.urna "urna://content_hash/chunk_id"
Latence et recall sur votre machine, sur votre corpus.
urna benchmark corpus.urna -q 100 -k 10 --ann 100
canaux

Une release, tous les gestionnaires de paquets

Le même urna 0.5.1 sur crates.io, PyPI, npm et Homebrew, avec un checksum et une attestation à côté de chaque fichier
Le même binaire partout
cargo, pip, npm, bun, pnpm, yarn, brew, le one-liner curl et PowerShell installent le même build : macOS et Linux en arm64 et x86_64, Windows en x86_64. npx et uvx le lancent sans rien installer.
Voir dans la documentation: Le même binaire partout
tar.xz
zip
sha256
sigstore
SBOM
ssh tag
Une release qu'on peut vérifier
Chaque archive a son propre .sha256 et une attestation sigstore que gh attestation verify contrôle, plus un SBOM CycloneDX et des binaires compilés avec cargo-auditable. Les tags de release sont signés en ssh.
Voir dans la documentation: Une release qu'on peut vérifier
Dans votre application, sans la CLI
urna-format et urna-runtime sont sur crates.io pour Rust, et le paquet Python ouvre le même fichier. Le dépôt contient des exemples fastapi, flask et jupyter et un Dockerfile, et cargo install urna --no-default-features laisse une CLI moteur seul de 2,1 MB.
Voir dans la documentation: Dans votre application, sans la CLI
Sans installernpx @urna/cli validate corpus.urnauvx --from urna urna validate corpus.urnacargo binstall urna
dans le terminal

Trois groupes de verbes et un écran pour s'en servir

urna tui ouvre un .urna, lui pose des questions et vérifie l'installation sans quitter le terminal. urna setup montre le plan avant d'écrire quoi que ce soit et se termine sur les checks de doctor
urna tui sur l'onglet ask : dix résultats cités pour une question, le texte stocké du résultat sélectionné et sa citation
urna tui
urna setup à l'étape verify, tous les checks au vert
urna setup
engine

Un fichier et un vecteur en entrée, des résultats en sortie. Sans Python.

  • inspect
  • validate
  • stats
  • media
  • search
  • search-ann
  • search-graph
  • search-space
  • search-text
  • benchmark
  • cite
  • doctor
agent

Du texte ou une spec en entrée, des réponses citées en sortie, via l'embedder Python hors ligne.

  • ask
  • retrieve
  • build
setup

L'installeur par lequel finit chaque canal, et l'explorateur du terminal.

  • setup
  • tui
Avant de commencer
Ce qui bloque souvent à la première lecture. Le reste est dans la documentation, avec la commande et sa sortie
Lire la documentation

Votre base de connaissances, prête à voyager

Installez, construisez le corpus, copiez le fichier dans l'app. Le reste, c'est du mmap
Installer
v0.5.1 · MIT · macOS, Linux et Windows