Quickstart
Add your first memory and ask a question in 60 seconds. Python, TypeScript, and curl code samples.
Quickstart
You'll have memory working in under a minute. This guide adds one fact, searches it back, gets a synthesized answer — and explains exactly what's happening at each step.
Get an API key
Sign in to the MemHQ dashboard and create a project. Open the project and go to its API Keys tab to generate a key and copy it.
export MEMHQ_API_KEY="mem_..."Project keys are scoped to a single project and authorize the
/v1/memhq/* endpoints. Keep them server-side — they grant write
access to memory.
Install the SDK
pip install memhqAdd a memory
Memories belong to a user_id (per-user graph) or a group_id (shared
graph). We'll use a per-user graph here.
from memhq import MemoryClient
client = MemoryClient() # reads MEMHQ_API_KEY from the environment
result = client.add(
user_id="user_42",
messages=[
{"role": "user", "content": "I prefer dark roast coffee, no sugar."},
],
)
print(result)Response:
{
"user_id": "user_42",
"internal_user_id": "usr_9f3c1b7e",
"thread_id": "thr_4d8a2e60",
"messages_stored": 1,
"memories_queued": 1
}What just happened?
The call returns immediately (under 100 ms). messages_stored confirms
the messages were persisted; memories_queued is how many of them were
handed to extraction (user-role messages only). In the background,
MemHQ's extraction pipeline:
- Chunks the conversation into atomic units
- Extracts typed entities and facts using an LLM — in this case,
{type: "preference", content: "Prefers dark roast coffee, no sugar"} - Writes the fact to
user_42's knowledge graph and creates a vector embedding for it
By the time the next step below runs, the fact is indexed and ready to retrieve.
Search it back
results = client.search(
user_id="user_42",
query="what coffee does the user like?",
limit=5,
)
for hit in results.memories:
print(f"{hit.score:.2f} {hit.content}")Response:
{
"memories": [
{
"id": "m_xyz123",
"content": "Prefers dark roast coffee, no sugar",
"score": 0.94,
"type": "preference",
"valid_from": "2026-06-19T00:00:00Z",
"valid_until": null
}
],
"total": 1
}What just happened?
search runs three retrieval lanes in parallel — BM25 keyword, vector
similarity, and graph traversal — then merges the results with Reciprocal
Rank Fusion. The score (0–1) reflects combined relevance across all
three lanes. valid_until: null means the fact is currently true (no
contradiction has overridden it yet).
Ask a synthesized question
For agent-style Q&A, skip search and go straight to ask. MemHQ
retrieves, synthesizes, and returns an answer with citations in a single
call — no LLM invocation needed on your side.
answer = client.ask(
user_id="user_42",
question="If I'm making them coffee, how should I prepare it?",
)
print(answer.answer)
# → "Brew a dark roast with no sugar."
for citation in answer.citations:
print(f" [{citation.score:.2f}] {citation.content}")
# → [0.94] Prefers dark roast coffee, no sugarFull response:
{
"answer": "Brew a dark roast with no sugar.",
"citations": [
{
"memory_id": "m_xyz123",
"content": "Prefers dark roast coffee, no sugar",
"score": 0.94,
"valid_from": "2026-06-19T00:00:00Z"
}
],
"question_mode": "lookup"
}What just happened?
ask is a convenience wrapper around the full retrieve → ground →
synthesize pipeline:
- Retrieve — same hybrid search as
search, returning the top-k memories - Ground — memories are packed into a grounding prompt: "Answer ONLY using these facts. Cite each one."
- Synthesize — an LLM generates the answer, tagging each claim with the memory ID it came from
question_mode: "lookup" means MemHQ classified this as a factual
retrieval question. Other modes are aggregate (counting questions) and
temporal (questions about what was true at a specific time).
Complete working example
Here's the full script from this guide in one place:
import time
from memhq import MemoryClient
client = MemoryClient() # MEMHQ_API_KEY from environment
# 1. Add a fact
client.add(
user_id="user_42",
messages=[
{"role": "user", "content": "I prefer dark roast coffee, no sugar."},
],
)
# Give the async extraction pipeline a moment to finish
time.sleep(3)
# 2. Search it back
results = client.search(
user_id="user_42",
query="coffee preference",
limit=5,
)
for hit in results.memories:
print(f"search {hit.score:.2f} {hit.content}")
# 3. Ask a synthesized question
answer = client.ask(
user_id="user_42",
question="If I'm making them coffee, how should I prepare it?",
)
print(f"ask {answer.answer}")
for c in answer.citations:
print(f" [{c.score:.2f}] {c.content}")The time.sleep(3) / setTimeout(3000) is only needed in scripts where
you add and immediately search in the same run. In production, facts
are added during one conversation turn and searched in the next — the
async extraction window is invisible.
Where to go next
- Memory API reference — the full shape of
add,search, andask - Concepts — the ingest pipeline, knowledge graph, and hybrid retrieval explained
- Cookbook: Chatbot with memory — wire MemHQ into a complete chat loop
- SDKs — language-specific guides and configuration