MemoryClient API Reference
MemoryClient is the recommended Python interface for PRME. It’s synchronous, manages its own event loop, and works in scripts, notebooks, FastAPI apps, and any other context.
Creating a Client
from prme import MemoryClient
# From a directory path (creates if needed)
client = MemoryClient("./my_memories")
# With explicit config
from prme.config import PRMEConfig
config = PRMEConfig(db_path="./custom.duckdb", vector_path="./vecs.usearch", lexical_path="./lex")
client = MemoryClient(config=config)Always use as a context manager or call close():
# Context manager (recommended)
with MemoryClient("./my_memories") as client:
client.store("hello", user_id="alice")
# Manual lifecycle
client = MemoryClient("./my_memories")
try:
client.store("hello", user_id="alice")
finally:
client.close()store()
Store a memory node across all backends (event store, graph, vector index, lexical index).
def store(
content: str,
*,
user_id: str,
session_id: str | None = None,
role: str = "user",
speaker: str | None = None,
node_type: NodeType = NodeType.NOTE,
scope: Scope = Scope.PERSONAL,
metadata: dict | None = None,
confidence: float | None = None,
epistemic_type: EpistemicType | None = None,
source_type: SourceType | None = None,
event_time: datetime | None = None,
ttl_days: int | None = ...,
) -> str # returns event UUIDParameters:
| Parameter | Type | Default | Description |
|---|---|---|---|
content | str | required | Text content to store |
user_id | str | required | Owner of this memory |
session_id | str | None | None | Group related memories |
role | str | "user" | Source role: user (the memory’s owner), participant (another human in the conversation), assistant, tool or system |
speaker | str | None | None | Name of who said it, shown by the reader context |
node_type | NodeType | NOTE | Type of memory node |
scope | Scope | PERSONAL | Visibility scope |
metadata | dict | None | None | Arbitrary key-value metadata |
confidence | float | None | None | Override initial confidence (0.0-1.0) |
event_time | datetime | None | None | When the event occurred (default: now) |
epistemic_type | EpistemicType | None | None | Override inferred assertion status |
source_type | SourceType | None | None | Override inferred source provenance |
ttl_days | int | None | ... | Omit for configured default; None disables expiry; an integer sets days |
Returns: Event UUID as a string.
Example:
from prme.types import NodeType, Scope
event_id = client.store(
"The deployment target is AWS us-east-1.",
user_id="alice",
node_type=NodeType.DECISION,
scope=Scope.PROJECT,
metadata={"source": "architecture-review"},
)retrieve()
Search memories using the 6-signal hybrid retrieval pipeline.
def retrieve(
query: str,
*,
user_id: str,
scope: Scope | list[Scope] | None = None,
time_from: datetime | None = None,
time_to: datetime | None = None,
reference_time: datetime | None = None,
knowledge_at: datetime | None = None,
token_budget: int | None = None,
) -> RetrievalResponseParameters:
| Parameter | Type | Default | Description |
|---|---|---|---|
query | str | required | Natural language search query |
user_id | str | required | User whose memories to search |
scope | Scope | list | None | None | Filter by scope(s) |
time_from | datetime | None | None | Validity window start; excludes assertions expired at or before this time (ENTITY/PREFERENCE exempt) |
time_to | datetime | None | None | Validity window end; excludes assertions that become valid after this time (ENTITY/PREFERENCE exempt) |
knowledge_at | datetime | None | None | Point-in-time snapshot (bi-temporal) |
reference_time | datetime | None | None | Timezone-aware clock for relative query dates and scoring; defaults to request time and is recorded in response metadata |
token_budget | int | None | None | Max tokens for context packing |
max_per_source | int | None | None | Max results sharing an exact source passage and evidence set |
Returns: RetrievalResponse with:
results— list ofRetrievalCandidateobjects, each with.node(MemoryNode) and.composite_score(float)bundle— packed context bundle for LLM consumptionmetadata— retrieval timing, candidate counts, backends used
Use response.bundle.render() for the exact context counted by
response.bundle.tokens_used. The bundle records its tokenizer. Reconstructing
text from the full node objects bypasses that budget. See
rendered context and budgets.
Example:
response = client.retrieve("What tech stack are we using?", user_id="alice")
for result in response.results[:5]:
node = result.node
print(f"[{result.composite_score:.3f}] {node.node_type.value}: {node.content}")Deferred raw ingestion
For raw ingestion without an LLM, the synchronous client also supports durable deferred processing:
event_id = client.ingest_fast("Alice prefers dark mode", user_id="alice")
result = client.process_pending(user_id="alice", budget_ms=1000)
status = client.processing_status(event_id, user_id="alice")These methods have the same status, retry, scope, and cooperative-budget
semantics as the async processing API.
They track new direct store() writes and raw-source indexing from both
ingest_fast() and ingest(). LLM derivations use extraction_status().
ingest()
Ingest content through the LLM extraction pipeline. Automatically extracts entities, facts, relationships, preferences, and decisions.
Requires an LLM API key (OPENAI_API_KEY, ANTHROPIC_API_KEY, or Ollama).
def ingest(
content: str,
*,
user_id: str,
role: str = "user",
speaker: str | None = None,
session_id: str | None = None,
scope: Scope = Scope.PERSONAL,
) -> str # returns event UUIDExample:
event_id = client.ingest(
"I just finished migrating our auth system from JWT to session tokens.",
user_id="alice",
scope=Scope.PROJECT,
)ingest_batch()
Ingest multiple messages at once. Each message dict must have role and content keys, and can set speaker.
def ingest_batch(
messages: list[dict],
*,
user_id: str,
session_id: str | None = None,
scope: Scope = Scope.PERSONAL,
) -> list[str] # returns list of event UUIDsExample:
event_ids = client.ingest_batch(
[
{"role": "user", "content": "Let's use Redis for caching."},
{"role": "assistant", "content": "Good call. I'll note that decision."},
],
user_id="alice",
session_id="planning-session",
)observe()
def observe(
self,
source: str | os.PathLike[str] | bytes,
*,
user_id: str,
captured_at: datetime | None = None,
source_name: str | None = None,
session_id: str | None = None,
metadata: dict | None = None,
scope: Scope = Scope.PERSONAL,
) -> list[str]Remember what a photo or a saved video showed (RFC-0018, phase 1). Off by
default: the client’s configuration needs vision.enabled
(PRME_VISION__ENABLED=true), a vision model the configured provider can reach
(a local Ollama server by default) and, for video, ffmpeg. Returns the ids
of the observation events, one per photo or per kept keyframe; each has role
tool, the capture clock as event_time and metadata naming the source, the
frame, the thumbnail and the vision model. client.get_blob(event.metadata["thumbnail"])
returns the keyframe thumbnail.
ids = client.observe("~/Pictures/receipt.jpg", user_id="alice",
captured_at=datetime(2026, 10, 12, 8, 41, tzinfo=timezone.utc))
event = client.get_event(ids[0], user_id="alice")
thumbnail = client.get_blob(event.metadata["thumbnail"]) # JPEG bytesget_node()
Get a single node by ID.
def get_node(node_id: str) -> MemoryNode | NoneExample:
node = client.get_node("550e8400-e29b-41d4-a716-446655440000")
if node:
print(f"{node.node_type.value}: {node.content}")
print(f"State: {node.lifecycle_state.value}, Confidence: {node.confidence:.2f}")query_nodes()
Query nodes with filters.
def query_nodes(**kwargs) -> list[MemoryNode]Supported keyword arguments: user_id, node_type, lifecycle_state, limit, offset.
Example:
from prme.types import NodeType
facts = client.query_nodes(user_id="alice", node_type=NodeType.FACT, limit=20)
for fact in facts:
print(f"[{fact.lifecycle_state.value}] {fact.content}")organize()
Run organizer maintenance jobs (promotion, decay, deduplication, summarization, etc.).
def organize(
*,
user_id: str | None = None,
jobs: list[str] | None = None,
budget_ms: int = 5000,
) -> OrganizeResultParameters:
| Parameter | Type | Default | Description |
|---|---|---|---|
user_id | str | None | None | Scope jobs to a specific user |
jobs | list[str] | None | None | Specific jobs to run (None = all) |
budget_ms | int | 5000 | Time budget in milliseconds |
Available jobs: promote, decay_sweep, archive, deduplicate, alias_resolve, summarize, feedback_apply, centrality_boost, tombstone_sweep, snapshot_generation, consolidate.
Example:
# Run all jobs
result = client.organize(user_id="alice")
print(f"Jobs run: {result.jobs_run}")
# Run specific jobs
result = client.organize(jobs=["promote", "deduplicate"], budget_ms=2000)close()
Shut down the engine and background event loop. Called automatically when using a context manager.
client.close()Integration Patterns
FastAPI
from fastapi import FastAPI
from prme import MemoryClient
app = FastAPI()
client = MemoryClient("./memories")
@app.on_event("shutdown")
def shutdown():
client.close()
@app.post("/remember")
def remember(content: str, user_id: str):
event_id = client.store(content, user_id=user_id)
return {"event_id": event_id}
@app.get("/recall")
def recall(query: str, user_id: str):
response = client.retrieve(query, user_id=user_id)
return [{"content": r.node.content, "score": r.composite_score} for r in response.results]LangChain / Agent Framework
from prme import MemoryClient
client = MemoryClient("./agent_memory")
def store_memory(content: str, user_id: str):
"""Tool for the agent to store memories."""
return client.store(content, user_id=user_id)
def recall_memory(query: str, user_id: str):
"""Tool for the agent to recall relevant memories."""
response = client.retrieve(query, user_id=user_id)
return "\n".join(r.node.content for r in response.results[:5])Jupyter Notebook
from prme import MemoryClient
client = MemoryClient("./notebook_memories")
# Store during analysis
client.store("Customer churn rate is 5.2% this quarter.", user_id="analyst")
# Query later
response = client.retrieve("What is the churn rate?", user_id="analyst")
response.results[0].node.content
# → "Customer churn rate is 5.2% this quarter."
# Don't forget to close
client.close()Source: documentation/memory-client.md in PRME at 7c97bce7.