Installation
Install the urna binary from Cargo, Homebrew, npm, pip or the one-liners, see what works after each channel, then run urna setup once.
Every channel except pip installs the same urna binary. The binary cannot carry the offline query embedder (a 30 MB table plus Python code) or a Python with numpy and tokenizers, so urna setup lays both down once and proves the result with the doctor checks. The pip wheel is a different program: it bundles the embedder table and needs no setup.
cargo install urna
urna setupWhat each channel installs
| Channel | What lands | Where | Platforms |
|---|---|---|---|
curl one-liner (install.sh) | binary and embedder payload | ~/.local/bin/urna; payload in ${XDG_DATA_HOME:-~/.local/share}/urna/forge | Linux x86_64 and aarch64 (static musl), macOS x86_64 and arm64 |
PowerShell one-liner (install.ps1) | binary and embedder payload | ~\.local\bin\urna.exe; payload in %LOCALAPPDATA%\urna\forge | Windows x86_64 only |
| Homebrew | binary | the brew prefix | macOS arm64 and x86_64, Linux arm64 and x86_64 |
npm, Bun, Yarn, pnpm (@urna/cli) | a Node wrapper that downloads the release binary | node_modules/.bin_real/urna inside the package | macOS arm64 and x64, Linux x64 and arm64 (glibc or musl), Windows x64; Windows arm64 gets the x64 build |
cargo install urna | binary compiled from source | ~/.cargo/bin/urna | any target Rust 1.88 builds |
cargo binstall urna | prebuilt binary from the GitHub release | ~/.cargo/bin/urna | the five release targets |
pip wheel urna | Python package with the extension, the potion table and a small urna command | the environment's site-packages and bin/ | Linux x86_64 and aarch64 (glibc 2.34+), macOS universal2, Windows x86_64; Python 3.12+ |
| Docker (build it yourself) | static binary in a scratch image | /urna | Linux amd64 and aarch64 |
| release archive by hand | binary and README.md | wherever you put it | the five release targets |
The five release targets are aarch64-apple-darwin, x86_64-apple-darwin, x86_64-unknown-linux-musl, aarch64-unknown-linux-musl and x86_64-pc-windows-msvc. The Linux binaries are statically linked, so they run on any distribution.
What works after each channel
| Capability | One-liner, then urna setup | Brew, npm, Cargo or binstall, then urna setup | pip wheel | Docker image | Repo checkout |
|---|---|---|---|---|---|
Engine verbs that need no Python: inspect, validate, stats, media, search, search-ann, search-graph, search-space, benchmark, cite | yes | yes | only validate, inspect, stats, search | yes | yes |
urna doctor | yes | yes | no | fails, no Python | yes |
ask, retrieve and the explorer's ask tab on a potion corpus | yes | yes | Python API only | no | yes |
ask, retrieve on a registry-model corpus (wemm, clip, jina) | no | no | Python API only | no | yes, with the model's deps |
search-text (sentence-transformers) | no | no | no | no | yes |
build --spec | no | no | no | no | yes |
setup, tui | yes | yes (not with --no-default-features) | no | compiled in, not usable | yes |
The installed binary only answers potion corpora
The embedder payload that urna setup and the one-liners lay down carries the potion query embedder only. urna ask and urna retrieve on a corpus built with a registry model (wemm, clip, jina) look for embed_query_model.py, which no release artifact ships, so they fail with "embedder script not found" and urna setup cannot fix it. Query those corpora from a repo checkout. urna build has the same limit: the forge it launches is not in any release artifact. See known limits.
Run urna stats corpus.urna to see which model a corpus declares: a model line that starts with minishlab/potion answers on any installed binary.
Channel notes
npm, Bun, Yarn and pnpm
All four install the same npm package, @urna/cli. Its urna command is a Node script (#!/usr/bin/env node), so node must be on PATH even when you install with Bun, Yarn or pnpm. The package downloads the release archive for your platform on install. When the package manager blocks install scripts (Bun and pnpm 10 do by default), the download happens on the first run of urna instead.
The wrapper downloads over HTTPS and does not check a checksum. The npm package carries registry signatures but no npm provenance. If you need a verified binary, use the one-liner, Homebrew or a release archive; see verify what you installed.
pip
pip install "urna[embed]"
uvx --from urna urna validate corpus.urnaThe wheel ships the urna Python module, its Rust extension, urna.embed_potion and the potion table. The embed extra adds numpy and tokenizers, which urna.embed_potion needs; the rest of the module works without it. The wheel needs no urna setup. There is no source distribution, so platforms outside the table above cannot install it. Python usage is in use urna from Python.
Two commands named urna
The wheel installs a console script also called urna. It is a separate Python program with four read-only verbs (validate, inspect, stats, search) and no setup, doctor, ask, retrieve, build or tui. When both are installed, whichever urna comes first on PATH runs. On Linux, pip install --user writes console scripts to ~/.local/bin, the directory the curl one-liner installs the binary into, so the two can overwrite each other.
Check which one you have:
urna --versionThe Rust binary prints urna 0.5.1. The wheel's command has no --version flag and prints a usage error. The wheel's command is documented in the wheel's urna command.
Cargo and cargo binstall
cargo install urna compiles the binary. It needs Rust 1.88 or newer (the terminal UI dependency sets that floor) and a C compiler, because zstd-sys builds C code.
cargo install urna --no-default-features builds an engine-only binary: no setup, no tui, and a bare urna always prints the help. That build has no built-in way to lay down the embedder payload.
cargo binstall urna fetches the prebuilt binary from the GitHub release instead of compiling. It checks nothing beyond HTTPS.
To build the unreleased tree:
cargo install --git https://github.com/hoffresearch/urna urna
urna setup --version 0.5.1urna setup fetches the payload of the binary's own version. A binary built from main can be ahead of any published release, and then setup fails with "this build is ahead of its tag; pass --version with a published one". Pass a published version as above.
Homebrew
brew tap hoffresearch/urna && brew install urnaThe formula (in hoffresearch/homebrew-urna) pins the release archive's SHA-256 and installs the binary only. Run urna setup afterwards.
The one-liners
install.sh downloads the release archive and the embedder payload, checks both against the release's .sha256 files before writing anything, installs the binary and unpacks the payload. It needs curl, tar with xz support, and sha256sum or shasum. After it, urna setup only has the Python env left to build.
Pin a release, or override the install directories:
curl -sSf https://raw.githubusercontent.com/hoffresearch/urna/main/scripts/install.sh | sh -s -- --version v0.5.1
curl -sSf https://raw.githubusercontent.com/hoffresearch/urna/main/scripts/install.sh | URNA_BIN_DIR=/opt/urna/bin URNA_DATA_DIR=/opt/urna/share shWith that layout the binary finds the payload through <binary dir>/../share. For any other URNA_DATA_DIR, keep the variable set whenever you run urna, or the binary looks only in the default data directories (paths).
install.ps1 does the same on Windows x86_64; it refuses any other architecture. The irm ... | iex form cannot pass parameters, so pin a version with a script block:
& ([scriptblock]::Create((irm https://raw.githubusercontent.com/hoffresearch/urna/main/scripts/install.ps1))) -Version v0.5.1Neither script edits PATH; both print a note when the binary directory is not on it. URNA_RELEASE_BASE points both at a mirror or a local directory, which is how the air-gapped install works. Every variable is listed in environment variables.
Upgrading in place on macOS
install.sh copies the new binary over the existing one with cp, without removing it first. macOS can kill a binary that was overwritten in place, and the next run exits with code 137. Before re-running the one-liner to upgrade, delete the old binary: rm -f ~/.local/bin/urna. See known limits.
Release archive by hand
Download urna-<target>.tar.xz (or the .zip on Windows) from the release page, check it (see verify what you installed), and put the binary anywhere on PATH. Besides the usual data directories, the binary looks for the payload in <dir of the binary>/../share/urna/forge, so a share/urna/forge tree next to bin/ works without setup.
Docker
The repository has a Dockerfile that builds the static binary into a scratch image. No image is published. The image has no Python, so it runs the engine verbs only. See run in Docker.
Build from source
A checkout is the only place where urna build, search-text and registry-model queries work.
git clone https://github.com/hoffresearch/urna
cd urna
sh scripts/fetch_potion.sh # or: git lfs pull
cargo build --release -p urnaThe potion table is stored in git-lfs. Without the real bytes, urna doctor exits 5, and urna setup cannot help inside a checkout because the repo's copy of the embedder wins the lookup. scripts/fetch_potion.sh downloads the table from its upstream and accepts it only when its SHA-256 matches the lfs pointer.
A binary at target/release/urna finds the checkout's python/ directory on its own, even when run from elsewhere. For urna build you also need a Python env with the forge dependencies and the extension built into python/_urna.so; the steps are in contributing.
Set up and check
urna setup scans the machine, shows a plan, downloads the payload through curl (HTTPS or a file:// mirror, checked against the release SHA-256), builds a venv with numpy and tokenizers through uv or pip, and ends on the doctor checks. It never touches the binary. In CI or a pipe, run it with --yes:
urna setup --yesurna doctor re-runs the checks at any time, offline, and exits with a typed code (0 ok, 2 to 6 for the first failing check):
urna doctorFlags, screens, exit codes and where the files go are in urna setup and urna doctor.
Setup suggests urna build
When setup finishes, it suggests urna build --spec corpus.toml. An installed binary cannot run urna build: the build tool is not in any release artifact. Build from a repo checkout. See known limits.
Uninstall
| Channel | Command | Removes | Leaves behind |
|---|---|---|---|
| any channel with setup | urna setup --uninstall | <data dir>/urna/forge and <data dir>/urna/venv | the binary |
| curl one-liner | sh install.sh --uninstall | ~/.local/bin/urna and the whole <data dir>/urna | nothing of urna's |
| PowerShell one-liner | install.ps1 -Uninstall | urna.exe and the whole <data dir>\urna | nothing of urna's |
| Homebrew | brew uninstall urna | the binary | the payload and venv |
| npm, Bun, Yarn, pnpm | npm uninstall -g @urna/cli (or your manager's remove) | the package | the payload and venv |
| Cargo, binstall | cargo uninstall urna | the binary | the payload and venv |
| pip | pip uninstall urna | the package | nothing (the wheel runs no setup) |
For package-manager channels, run urna setup --uninstall first, while the binary still exists. It resolves the data directory from the current environment, so run it with the same URNA_DATA_DIR, XDG_DATA_HOME or LOCALAPPDATA you installed with. To pass --uninstall to the one-liner, pipe it as sh -s -- --uninstall; on Windows, use the script block form shown above with -Uninstall.
With urna installed, the quickstart builds a small corpus and asks it a question.
Introduction
urna is a vector database in one memory-mapped file that checks its own hashes, scores hits by exact cosine and cites each one with a stable urna:// id.
Quickstart
Build the twelve-paragraph example corpus from a checkout, ask it a question, read the route it took, then cite, validate and open it in the terminal.