Your first Semurg calls from Python or Elixir: remember a fact, recall it
12 October 2026 · Semurg · 3 min read · Markdown
Verified: every command below ran on a fresh node of r11.78.20261012.bc0d94f (how)
sdkpythonelixirgetting-startedhow-to
Three calls and you are talking to a node from your own code: is it up, remember a fact, recall it. This guide does it from Python or Elixir, in about five minutes if a node is already running. A client takes the node's address and its API token, and that is all: there is no hosted service in the middle and no account.
No node yet? Start with the five-minute guide, which installs one.
Get the client
All the client libraries ship in one signed archive beside the installer. Download it with the published checksums and check it before you unpack anything:
curl -fsSLO https://one.semurg.io/dl/clients.tar.gz
curl -fsSLO https://one.semurg.io/dl/SHA256SUMS
sha256sum -c --ignore-missing SHA256SUMSExpected: the checksum line for the archive, ending in OK
Then unpack it with tar xzf clients.tar.gz. Inside is one folder per language and CONNECTING.md, the guide to pointing a client at your node.
Python
The Python client has no dependencies beyond the standard library. Install it from the unpacked archive with pip install -e clients/python, then:
import os
from semurg import Client
with Client("http://localhost:4000", token=os.environ["SEMURG_API_TOKEN"]) as client:
print(client.health())
client.remember("hello", facts={
"entities": [{"name": "Ada", "type": "Person"}, {"name": "Acme", "type": "Company"}],
"relations": [{"source": "Ada", "target": "Acme", "type": "WORKS_AT"}],
})
answer = client.recall("hello", subject="Ada")
print(answer["state"])
for item in answer.get("items", []):
print(item.get("text"))The first call says whether the node is up. The second stores two entities and the relationship between them in a scope called hello. The third finds Ada and returns what is connected to her, starting with state: answered when something matched, nothing_stored when nothing did.
Elixir
The Elixir client needs Elixir 1.18 or newer. From the folder that holds the unpacked archive, save this as hello.exs and run it with elixir hello.exs:
Mix.install([{:semurg, path: "clients/elixir"}])
client = Semurg.new("http://localhost:4000", token: System.fetch_env!("SEMURG_API_TOKEN"))
{:ok, health} = Semurg.health(client)
IO.inspect(health, label: "health")
{:ok, _} =
Semurg.Client.remember(client, %{
scope: "hello",
facts: %{
entities: [%{name: "Ada", type: "Person"}, %{name: "Acme", type: "Company"}],
relations: [%{source: "Ada", target: "Acme", type: "WORKS_AT"}]
}
})
{:ok, answer} = Semurg.Client.recall(client, %{scope: "hello", subject: "Ada"})
IO.inspect(answer, label: "recall")Every call returns {:ok, term} or {:error, %Semurg.Error{}}, and the error carries a kind you can match on, such as :unprocessable for a refused call or :timeout.
The other languages
The archive also holds clients for Go, Java, C#, F#, Erlang, Rust, OCaml, Julia and C++, each with its own README showing the first calls and how to build it. What each one covers today:
- Health, status, ingest and query are in all eleven.
- The memory calls (status, remember, recall, relate, forget and context) are in Python, Go, Java, C#, F#, Elixir, Erlang, Rust and OCaml; Julia has remember, recall and context; the C++ client reaches them over plain HTTP.
- Rust needs a
2024-edition toolchain, C++ needs the libcurl development package, Erlang needs rebar3 and OCaml needs dune.
Some methods described in the archive's READMEs (fetch_batch among them) call routes the node no longer serves and are being removed. The calls above, and the memory calls, are the ones to build on.
When a call fails
Every client passes on the node's own refusal, and the node names what to change. A missing or wrong token is 401; a memory call without a scope is refused with 422 "missing scope".
Next
- Connecting over REST: the same calls without a client library.
- Look after your node: the calls that tell you how it is doing.
How these commands were checked
Our test farm ran each of the 1 command block marked runnable, exactly as written, with the answer checked against the expectation printed under it, against a fresh node of the published release r11.78.20261012.bc0d94f. A post is published only when every one of them passed there.