The memory is yours. The model is a guest.

Your coding agent answered out of the wrong file. Ulpia is the memory it asks instead: your own markdown, indexed where it sits, with zero guessing.

See the benchmarks Read the source

Pre-launch. Used daily.

A library that lives with you.

Ulpia is a library, named for Trajan's. Your notes, your decisions, your protocols are its books: markdown files, in folders, on your disk. A folder with a note in it is already a base, with no git init and no manifest, and moving the folder moves everything, because no absolute path exists anywhere inside a fleet.

Vesta is its librarian. Ask her a question and she answers with the files that should open, and no model reads your library to do it. When she is wrong, she says why.

What you would use it instead of.

A notes app, and Obsidian is the one people name. Graph view, backlinks, canvas, sync, a plugin ecosystem years deep, and Ulpia has none of them. Every one is drawn for a person to look at. The agent in your repository opens a shell, not a vault: it greps your markdown, and grep has no opinion about which file is right. If you read your own notes with your own eyes, keep Obsidian.

A vector memory layer. It fixes the matching and leaves the certainty alone: a ranking has a top entry whether or not the corpus holds the answer, so the confident wrong citation survives the upgrade. It does ingest without asking you to write anything, which Ulpia does not.

Ulpia organises the same files for the query instead of for the eye, and nothing in its retrieval path guesses, which is also what lets a score come up short. On LongMemEval, a public benchmark of 500 instances, the fleet got that call right 29 of 30 on 24 August 2026, and answered 51 of 56 on single-session-assistant in the same run.

Watch her work.

$ kb route "why is there no embedding model in the retrieval path" decisions --hybridquestion: why is there no embedding model in the retrieval pathindexed:  40 entries across 1 agents, 0 aliases  0.033  decisions 0018-no-model-in-the-retrieval-path.md       keywords #1 + text #2  0.032  decisions 0027-a-model-decides-who-answers.md          keywords #4 + text #1  0.029  decisions 0017-no-dense-scorer-yet.md                  keywords #6 + text #13
Real output, re-run 4 September 2026 at commit 9ffe0df on Windows: the first three of the five files it listed, with each passage preview left out and nothing else touched.

Two scorers read every question: one over the Search for line each note carries under its title, the label on the book, and one over the full text. The verdict is hit, guess or nothing, from one number: the top file's keyword score against a floor that scales with the library.

Whether the second scorer agreed is reported beside it, in the last column, and never as the verdict. The score shown fuses both rankings; kb route --json prints the keyword score behind the verdict and its floor.

A miss is answered too: instead of an empty screen, the library offers the nearest keys it does hold. And when a subject belongs to nobody in your fleet, Vesta says exactly that, which no score can do. The guest below is who does.

How long one question takes.

A hosted memory layer embeds your question and crosses a network. This one reads an index sitting beside the files it indexes. That gap is the two mechanisms, not an optimisation.

128x mem0's own published search p50 against ours, measured. Against Zep's fastest published figure, 69x at the same percentile.

  1. Ulpiawe measured it

    1.16 ms

  2. mem0their paper

    148 ms

  3. Zeptheir blog

    150 ms

  4. Supermemorytheir site

    under 300 ms

  5. Lettatheir docs

    none published

Gold is ours, measured in this repository, in process, on the laptop that built it. The redder the bar, the slower the system. Each red bar is that vendor's own published claim about itself, linked at its source on the benchmarks page, and the hatching is what says so if this chart is ever seen without its caption. None of them was run here. A grey rule means the vendor publishes no figure at all. Linear scale, so our bar is drawn at the width the ratio actually gives it.
No bar here includes the network. Every vendor figure is server-side or harness-side and stops before the caller's round trip; ours is a local process with no round trip to add. We measured that floor too, the TCP connect from this machine to each vendor's real API host before a single request is sent, and it ran from 5 ms to 213 ms. It is deliberately not drawn, and not in our favour: four of the five resolve to CDN edges, so the floor understates the distance to the application behind them rather than overstating it. Either way it is a cost on their bars and never on ours. The figures are in benchmarks/latency/RESULTS.md.

The model is a guest.

An embedding model between you and your own notes buys semantic matching, and your notes have been somewhere you did not choose. A line of keys on each note is a smaller bill, paid earlier, and this is what it buys back.

One step may still call a model, and it is about your fleet, not your notes. Finding the file is a lookup, and code does that exactly. Choosing the agent is a judgement, so a model does that one.

It sees your question, the roster, the file names Vesta found with the words that matched, and the one line at the top of each where you said what it is for. Never the files: a briefing at the door, never the shelves. It takes seconds, and you name the command it calls, or remove it and let the keyword scores pick.

A model may stand between you and your fleet. Never between you and your notes. Hand the files to whatever model you like: yours, locally; Claude, through MCP; something else next year. The memory outlives the model.

Where it stands. The doors are open.

Early, used daily, and honest about which is which. The core is tested; no count is printed because the number moves between sessions. The tray app is Windows only and young. There is no hosted instance, and local model routing is not built. The command line tool ships built for Linux, Windows and macOS, each artifact executed on its own architecture before it is published and each one signed, so a stranger can check where it came from and not only that it arrived whole.

The source is public at github.com/richard-wollyce/ulpia, Apache 2.0, cloneable today. The benchmarks put every number of ours beside its command, machine and date.

Our address is hello@ulpia.io, a plain mailto under this button. Press it and the address goes to your clipboard, and you can leave yours: we write when there is something you can install, rarely otherwise.

Write to hello@ulpia.io

Would you like to be told when it opens?

Our address is on your clipboard, so you can write whenever you like. This is the other direction: leave yours and we will tell you when there is something you can install. Rarely otherwise, and never more than once a month.

hello@ulpia.io

We need an address to write to.

You are on the list.

We will write when there is something you can install. Our address is still on your clipboard, if you have something to say before then.