Run Vouch locally, end to end
This tutorial walks you from a fresh clone to two users matching through the Private Set Intersection protocol, all on your laptop, and then shows you the operator’s view of what just happened. You don’t need to understand the crypto to finish it. If you get curious about why it works, read The matching protocol afterwards.
Before you start
Section titled “Before you start”Install these once:
uv— Python toolchain and runnerjust— the task runner (justlists every recipe)docker(with Compose) — for Postgres- Node 22 — for the web client
- system libsodium — the crypto library the client vectors link against
1. Start the stack
Section titled “1. Start the stack”From the repository root:
just devThis starts Postgres 18 in Docker, applies the migrations, and runs the API on
:8000 with development secrets (the admin bootstrap token is local-admin,
SMS codes go to the log and to the admin outbox instead of a phone). Leave it
running; in another terminal:
just webVite serves the web client on http://localhost:5173 and proxies the API.
2. Make yourself an admin
Section titled “2. Make yourself an admin”Register in the browser with any username, a password, the two declarations
(18 or older, privacy notice read) and local-admin in the admin bootstrap
token field. Or from the terminal:
cd serveruv run vouch register root --admin-token local-admin --adult --accept-noticeuv run vouch whoamiThe CLI keeps a real session (a rotating refresh cookie) under
~/.config/vouch/cli.json, exactly like the browser does.
3. Verify a phone without a phone
Section titled “3. Verify a phone without a phone”The app sends you to phone verification first. Enter any E.164 number
(+32470123456). The code went to the dev outbox; read it either in the
browser at #/admin/sms or with:
uv run vouch admin sms-outboxType the code in. Behind the scenes the client proved, with a DLEQ proof, that the token it will publish is bound to the number you just verified.
4. Watch two users match
Section titled “4. Watch two users match”Add a couple of contacts on the contacts tab and publish. Then let the simulator create a second, compatible user who shares one of them:
just demo # = vouch sim demo against http://localhost:8000It registers two users, verifies their phones through the outbox, publishes
their padded, encrypted contact sets, syncs until they match, prints PASS,
and deletes them again. For a richer graph you can log in with, run
just seed (six users, password hunter2hunter2).
5. Look at it as the operator
Section titled “5. Look at it as the operator”Open http://localhost:5173/#/admin/overview: user, pair, match and report counts, what the background matcher last did, the migration revision, and the settings (secrets redacted). Browse users, open one, ban and unban them, read the SMS outbox, resolve reports, run the matcher by hand. The same view from the terminal:
uv run vouch admin overviewuv run vouch admin users --q demouv run vouch admin pairsuv run vouch api GET /me/export # any authenticated call, JSON in/outThe interactive API docs are at http://localhost:8000/docs.
6. Run the checks
Section titled “6. Run the checks”just check # everything CI runs: ruff, pytest, oxlint, tsc, vitest, helm, tofujust server-unit # only the tests that need no databasejust e2e # browser tests (Playwright): register → verify → publish → match, admin flowsThe browser tests in client/e2e/ drive the real SPA against the real API
in headless Chromium: two people register in separate browser contexts,
verify their phones through the outbox, publish, and match; an admin bans and
unbans a user; a sent code survives a reload. Every test creates its own
users, so they run against any database, including a throwaway one in CI.
The server suite runs against a throwaway Postgres from testcontainers (or
VOUCH_TEST_DATABASE_URL if you point it at one); it includes a
migration-drift guard that applies the Alembic chain and diffs it against the
models.
What you did
Section titled “What you did”You ran the whole system: database, API, web client, a live match, and the admin surface. From here:
- Deploy it → Deploy to the cluster
- Operate it → Admin UI and CLI
- Understand it → Architecture
- Look things up → API Reference