@leumas/memory-web
memory.leumas.tech — knowledge banks a person owns, and the scoped agent tokens that let Cursor, Claude, Ollama and Leviathan read exactly the parts they were given.
@leumas/memory-web — memory.leumas.tech
Knowledge banks a person owns, and the scoped agent tokens that let Cursor, Claude, Ollama and Leviathan read exactly the parts they were given.
A thin React shell. Everything it does is /api/knowledge, served by @leumas/knowledge-service — read that package first if you are changing behaviour rather than layout.
pnpm dev memory # http://127.0.0.1:5088 (needs `pnpm dev api` for the API)
pnpm -F @leumas/memory-web build
pnpm smoke:memory # the routes, over real HTTP
pnpm check:memory-access # the permission rules, against real SQLite
Pages
| Route | What it is |
|---|---|
/ | The front door. The only page that works signed out. |
/banks | Your banks, with inline creation. Built-in reference banks sit behind a second tab. |
/banks/:id | One bank — Content (with the drop surface), Variables, Push, Access. |
/search | Cross-bank search. Scoping is entirely server-side. |
/agents | Mint, list and revoke agent tokens. The secret is shown once. |
/connect | Paste-ready setup per client, plus the webhook and live-stream recipes. Public. |
/activity | What agents did, including what they were refused. |
/pricing | Reads GET /membership/plans. Never hard-codes a price. |
Four things that will bite you
Never introduce a base URL. Every path in src/api.js is relative, because the httpOnly leumas_session cookie only travels same-origin. In production the Imperium worker proxies /api and /auth to leumas-api; in dev the Vite proxy forwards the same list. Setting VITE_API_BASE makes every call cross-origin, the cookie is dropped, and the whole app renders as permanently signed out with nothing in the console to explain it.
The site row is provisioned by the API, not by this deploy target. ensureMemorySite runs at leumas-api boot. pnpm deploy:memory alone ships the frontend and leaves the subdomain 404ing until leumas-api is released too.
Media never travels as JSON. A document is posted to /banks/:bank/ingest as { filename, text } and parsed into items. An image or video goes to /api/storage/upload as multipart (512MB) and is then LINKED to an item by reference. Putting a video in a JSON body is how upload broke in the media manager.
Button takes no as prop. It renders a real <button> and spreads the rest onto it, so as={Link} is silently ignored — the control renders, looks right, and does nothing. Navigate with useNavigate.
Ports
memory is 5088 in ops/infra/scripts/ports.mjs, which both dev.mjs and vite.config.js read. It was authored as 5080 on the branch it was built on; workflows has that number now.