Build vector + graph RAG on one engine. No new query language.
- Vectors and graph on one copy of the data: retrieval and traversal over the same stored records.
- Write relationships as you write the data; afterwards every read is a get, a walk or a scan.
- No query planner to coax and no indexes to declare.
- Five doors answer today: the cluster console, the REST API, the WebSocket, the binary wire and clients for the languages you already use. Each one reads AND writes.
- The binary wire is the engine's own 64-byte frame path, and it reads and writes: a node takes an ingest over the wire as well as over HTTP, and a passage written on either is found by a search on the other. The clients encode and decode those frames today; the published wire specification follows.
Five doors, one engine
The first five minutes
Install, prove the token, write, read, open the console. Every command below is one the installer prints or the release's own install test runs against a node you just installed. There is no account.
1. Install. The installer ends with a SUCCESS banner that prints your API token and your
console address. Keep both.
curl -fsSL https://one.semurg.io/install | sudo bash
One prerequisite, and the installer checks it. The data directory must sit on a real disk filesystem, ext4 or xfs. A network share, a container overlay or a shared folder from a desktop virtual machine cannot take the writes this engine makes, and the installer stops and says so rather than running on top of one. On a normal Linux machine this is already true and there is nothing to do.
Already running a node? Take the new release with semurg update --apply (the node checks the
signed manifest, downloads, verifies, swaps and restarts, and rolls back if the new release does not come up).
Re-running the install command on a node that already has a completed install is REFUSED on purpose, because a
plain re-run would rewrite its environment from a fresh hardware scan and could leave your stored bytes
unserved; say what you mean with SEMURG_INSTALL_MODE=upgrade if you want the installer to do it.
2. Put the token in your shell. It is stored on the node, so you can read it back at any time.
TOKEN=$(sudo grep '^SEMURG_API_TOKEN=' /etc/semurg/semurg.env | cut -d= -f2-)
1b. Or run it in Docker. The same node, from the published image (checksummed, then loaded). Every
/v1 call needs the token exactly as on bare metal; Docker prints it in the container log at first
start and keeps it on the node.
curl -fsSLO https://one.semurg.io/dl/SHA256SUMS && curl -fsSLO https://one.semurg.io/dl/semurg-substrate-r11-amd64.tar.gz grep ' semurg-substrate-r11-amd64.tar.gz$' SHA256SUMS | sha256sum -c - docker load -i semurg-substrate-r11-amd64.tar.gz docker run -d --name semurg -p 127.0.0.1:4000:4000 \ --ulimit memlock=-1 --ulimit nofile=1048576:1048576 --security-opt seccomp=unconfined \ -v semurg-data:/var/lib/semurg semurg/substrate:r11-test docker logs semurg | grep -A1 'Your API token' TOKEN=$(docker exec semurg cat /var/lib/semurg/.api_token)
--security-opt seccomp=unconfined is not optional: Docker's default profile
blocks the system calls the engine reads and writes with, and without it the container exits
at start with a message naming this flag. --ulimit memlock=-1 is what lets it register its
buffers. Binding to 127.0.0.1 keeps the node on the host until you decide otherwise.
No licence key, ever, on one node. A single node runs the full engine, writes included, with nothing to obtain. A stale or foreign key file on the node changes nothing. A key exists only to join a second node to a cluster.
3. Prove the gate is on. Without the token the API answers 401 on purpose. With it, 200.
curl -si http://127.0.0.1:4000/v1/whoami | head -1 curl -si -H "Authorization: Bearer $TOKEN" http://127.0.0.1:4000/v1/whoami | head -1
4. Write something. A passage is the simplest thing to write: text goes in, and the node keeps one copy.
curl -s -H "Authorization: Bearer $TOKEN" -H 'content-type: application/json' \
-d '{"passages":[{"text":"Semurg keeps one copy of your data and answers every kind of question about it."}]}' \
http://127.0.0.1:4000/v1/ingest
5. Read it back. A search answers with three numbers: how many stored items matched, how many it looked at, and how many bytes that took. A search matches inside one stored 64-byte container, so keep the needle to 20 bytes or fewer: a longer passage is split across containers.
curl -s -H "Authorization: Bearer $TOKEN" -H 'content-type: application/json' \
-d '{"op":"search","needle":"Semurg keeps"}' \
http://127.0.0.1:4000/v1/query
6. Open your cluster admin console. The installer printed one URL and the one-time admin secret at the end of
its run. Open the URL and sign in with the secret and, from r11.24, the six-digit code from an authenticator app enrolled
from the banner file the installer names (/opt/semurg/tmp/.admin_bootstrap_banner; it also holds eight
recovery codes and is removed on your first sign-in). There is one way in: for a node you installed,
the URL the installer printed; for Semurg's own cluster, cluster.semurg.io. (From r11.24; a node installed
before that prints its console address with semurg admin status.)
A new node comes up with a small sample graph already loaded (a Panama Papers subset from the ICIJ
Offshore Leaks data), so a traversal answers straight away and a search's "looked at" count includes the sample. To
start empty, set SEMURG_PRELOAD_PANAMA=0 in /etc/semurg/semurg.env, delete the store's
user_store directory and restart; the installer's banner prints the exact paths. On a fresh Docker node the count is about 262,000 containers (the sample plus what you write); to start empty there, add -e SEMURG_PRELOAD_PANAMA=0 to the docker run line. See
the workloads for data that carries relationships of your own. Similarity search over your own passages
(vector_search, which returns the matching text rather than a count) needs an embedding model on the node;
the free node ships without one today, and the API says so plainly if you call it. Every call above works on a fresh node.
How you work with it
Write the relationships
You say what connects to what as you write. That is the work, and it is done once, at write time.
Read three ways
Get one thing by id, walk from it to what it connects to, or scan a run of it. Those are the reads.
No query language
Ordinary code in the language you already use. There is nothing new to learn and nothing to tune.
The clients
A client points at the base URL of a node you operate, with a token if you set one. There is no Semurg-hosted control plane in the middle, and nothing about your data leaves your network.
- Eleven languages: C++, C#, Elixir, Erlang, F#, Go, Java, Julia, OCaml, Python and Rust, in one
archive: one.semurg.io/dl/clients.tar.gz, with
CONNECTING.md, the guide to pointing a client at your node. A run of every client against a live node on the current release is not yet recorded; the four verbs below are the ones each client carries. Elixir needs Elixir 1.18 or newer and Rust needs a 2024-edition toolchain (rustup), which the Ubuntu 24.04 packages do not meet; C++ needslibcurl4-openssl-dev, Erlang needsrebar3and OCaml needsdune. The archive'sfetch_batch,benchmarks,dashboardandbenchmethods call routes that no longer exist and are being removed; the four verbs below work in every client - What they cover today: health, status, ingest and query in all eleven; the cluster and licence reads in five (Python, Go, Elixir, C#, Julia). The retrieval, analytics and generate verbs are REST-only today and are being added to the clients now.
- For a coding agent: the memory calls (status, remember, recall, relate, forget, context) are in the Python, Go, Java, C#, F#, Elixir, Erlang, Rust and OCaml clients; Julia has remember, recall and context; C++ reaches them over HTTP. The tools, routes and calls are in one plain-text file, generated from the source: one.semurg.io/llms.txt.
- The same small surface in each, written in that language's idiom, so the mental model carries across your stack.
Interfaces you do not have to build
The console is server-rendered and interactive, so operating a node needs no front-end application and no front-end team. The same approach is available to what you build on top.