---
title: "Semurg is on PyPI: pip install semurg, and your Python code gets a memory that cites its sources"
slug: pip-install-semurg
date: 2026-10-21
author: Semurg
section: how-to
tags: [python, sdk, pypi, getting-started, how-to]
summary: The Python client is published on PyPI. Install it with pip, point it at your own node, store facts and text, recall everything connected to an entity, and ask a question in plain words that comes back with cited evidence.
status: published
covers: [sdk:health, sdk:remember, sdk:recall, sdk:context]
constants: ["0.1.1", "3.9", "2.0", 1843, 4000, "127.0.0.1", 64]
---

The Python client for Semurg is on PyPI. One `pip install semurg` and your code can store what it learns, find it again by name or by
question, and get back the passages that support an answer, each cited to where it came from. The memory runs on your own machine;
the client talks to it and to nothing else.

> Diagram pypi-flow: pip install semurg gives your program a client; the client talks to your own Semurg node; your program stores facts and text, recalls an entity, and asks a question that comes back with cited passages.

## Install

The client needs Python 3.9 or newer and nothing outside the standard library. It is Apache-2.0 licensed, and it runs wherever Python
runs. The node it talks to runs on x86-64 Linux, natively or in Docker; from a Mac or an ARM machine, point the client at a node on an
x86-64 Linux machine (for example over an SSH tunnel: `ssh -L 4000:127.0.0.1:4000 you@that-machine`).

```bash
python3 -m venv .venv && . .venv/bin/activate
pip install semurg
```

On Ubuntu, `sudo apt install python3-venv` first if `venv` is missing.

## Start a node

No node yet? One Docker command starts one on your machine, listening only there. The token it prints is the key to its memory:

```bash
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 one.semurg.io/semurg
until docker logs semurg 2>&1 | grep -q 'Your API token'; do sleep 1; done
export SEMURG_API_TOKEN=$(docker exec semurg cat /var/lib/semurg/.api_token)
```

Prefer a native install on Ubuntu? The [install page](/install) has the one-line installer.

## Store, recall, ask

The program below ran as written against a fresh node of release r11.121.20261021.3619d35, with semurg 0.1.1 from PyPI. Save it as
`quickstart.py` and run it with `python quickstart.py`:

```python
import os
from semurg import Client

with Client("http://127.0.0.1:4000", token=os.environ["SEMURG_API_TOKEN"]) as mem:
    print(mem.health()["build"]["release"])

    # facts you extracted, stored as typed entities and a relationship
    mem.remember("research", facts={
        "entities": [{"name": "Ada Lovelace", "type": "person"},
                     {"name": "Analytical Engine", "type": "machine"}],
        "relations": [{"source": "Ada Lovelace", "target": "Analytical Engine", "type": "wrote_notes_on"}],
    })

    # text, stored as cited passages, linked to the names it mentions
    mem.remember("research", source="notes-1843", date="1843-09-01",
                 content="Ada Lovelace published notes on the Analytical Engine. "
                         "Her Note G describes an algorithm for Bernoulli numbers.")

    # everything connected to one entity
    answer = mem.recall("research", subject="Ada Lovelace", compact=True)
    print(answer["state"])
    for item in answer["items"]:
        if item["kind"] == "fact":
            print(item["subject"], item["relation"], item["object"])

    # a question in plain words: the evidence, cited to its source
    ctx = mem.context("research", query="What did Ada Lovelace describe in Note G?")
    print(ctx["grounding"]["state"])
    for item in ctx["items"]:
        if item["kind"] == "passage":
            print(item["citation"]["source"]["name"], "|", item["text"][:70])
```

It prints:

```text
r11.121.20261021.3619d35
answered
Ada Lovelace wrote_notes_on Analytical Engine
grounded
notes-1843 | Ada Lovelace published notes on the Analytical Engine. Her Note G desc
```

Four things happened. `remember` with `facts` stored two typed entities and the relationship between them, exactly as sent: no model
guessed at them. `remember` with `content` stored the text as passages under the source label `notes-1843`, dated 1843-09-01,
and linked each passage to the names it mentions. `recall` found everything connected to Ada Lovelace and said so in `state`. And
`context` answered a question in plain words with the passage that holds the answer, cited to its source, with a `grounding` verdict:
`grounded` here, because the passage covers the question.

## Read the state before the items

Every answer starts with `state`: `answered` when something matched, `nothing_stored` when nothing did, and `could_not_judge` when a
step could not run, named in the answer. An empty list is never presented as an answer. `context` adds `grounding`, which tells your
agent whether the evidence really answers the question (`grounded`), only shares some of its words (`related`), or is missing, so it can
say "I do not know" instead of guessing.

## Where to go next

- One memory, many programs: a `scope` is a named memory, and every program or agent that uses the same scope shares it.
- Each of your users apart: pass `user_id` and every call stays inside that user's own memory. See
  [one memory per end user](/blog/one-memory-per-end-user).
- Time: what was true on a date, and what was known then. See [memory with a timeline](/blog/knowledge-layer-3-time-and-history).
- Reasoning: facts that follow from a relationship's meaning. See [facts that follow](/blog/knowledge-layer-5-reasoning).
- Agents: the same memory over MCP for Claude Code and other agents, in [five minutes](/blog/agent-memory-mcp-five-minutes).
- Every memory call the client makes is in the [API description](/llms.txt).
