Brainby arc-labs/docs
Python SDK

Memories resource

Write, search, get, list, create, update, delete, feedback, and forget memories with full sync and async parity.

Every method below is documented once with both sync and async variants in tabs. The kwargs, return shapes, and error classes are identical between the two paths — only the await keyword differs.

write()

POST/v1/rememberAPI keystable
def write(
    self,
    messages: list[dict[str, str]],
    **options: Any,
) -> Any: ...

Send conversation turns through the seven-stage write pipeline (extract, classify, ground, dedupe, embed, persist, index) and receive the IDs of the typed memories that landed.

Parameters

ParameterTypeRequired
messageslist[dict[str, str]]required

A list of {role, content} dicts. The SDK rewrites each into a typed Turn ({id, role, content}) by auto-generating id as 'turn-{index}'. Roles must be 'user' or 'assistant'.

idempotency_keystroptional

Optional UUID-style key. When supplied, the server's idempotency middleware deduplicates retries of the same logical operation. Auto- generated by the transport when omitted.

Returns

A dict with the IDs of memories created in this call. The exact shape depends on the server version; commonly {'memoryIds': [...], 'count': int}.

Examples

result = recall.memories.write(messages=[
    {'role': 'user', 'content': 'I prefer dark mode.'},
    {'role': 'assistant', 'content': 'Saved.'},
])
result = await recall.memories.write(messages=[
    {'role': 'user', 'content': 'I prefer dark mode.'},
    {'role': 'assistant', 'content': 'Saved.'},
])

When to use. Whenever you have raw conversation turns and want Recall to extract typed memories from them. The pipeline does the heavy lifting: LLM-based extraction, dedupe against existing memories, and indexing.

POST/v1/searchAPI keystable
def search(
    self,
    query: str,
    limit: int = 10,
    *,
    memory_type: Optional[str] = None,
    min_confidence: Optional[float] = None,
) -> Any: ...

Hybrid retrieval — semantic + BM25 + entity graph + temporal — fused via RRF. Returns a relevance-ranked list, not a paginated cursor.

Parameters

ParameterTypeRequired
querystrrequired

Natural-language search string.

limitintoptional

Maximum number of results. Server clamps to [1, 100]. Renamed from top_k in 0.3.0 — the wire field is also limit.

memory_typestroptional

Filter by type — 'fact', 'preference', 'event', 'entity', or 'relation'. Sent as filters.memory_type on the wire.

min_confidencefloatoptional

Drop results whose confidence is below this threshold. Range [0.0, 1.0]. Sent as filters.min_confidence.

Examples

hits = recall.memories.search(
    query='UI preferences',
    limit=5,
    memory_type='preference',
    min_confidence=0.6,
)
for h in hits['results']:
    print(h['content'], h['confidence'])
hits = await recall.memories.search(
    query='UI preferences',
    limit=5,
    memory_type='preference',
    min_confidence=0.6,
)

See the dedicated Search page for the full filter shape and response payload.

get()

GET/v1/memories/:idAPI keystable
def get(self, memory_id: str) -> Any: ...

Fetch a single memory by its MemoryId.

memory = recall.memories.get('m_01HEX…')
memory = await recall.memories.get('m_01HEX…')

Raises RecallNotFoundError if the memory does not exist or is not in the caller's scope.

list()

GET/v1/memoriesAPI keystable
def list(
    self,
    memory_type: Optional[str] = None,
    limit: int = 20,
    offset: int = 0,
    cursor: Optional[str] = None,
) -> Any: ...

Browse memories with cursor or offset pagination.

ParameterTypeRequired
memory_typestroptional
Filter by memory type.
limitintoptional
Per-page row count.
offsetintoptional

Skip the first N rows. Use cursor instead for stable pagination on high-write namespaces.

cursorstroptional

Opaque cursor returned by the previous page's response.

page = recall.memories.list(memory_type='fact', limit=50)
while page.get('cursor'):
    page = recall.memories.list(memory_type='fact', limit=50, cursor=page['cursor'])
page = await recall.memories.list(memory_type='fact', limit=50)
while page.get('cursor'):
    page = await recall.memories.list(memory_type='fact', limit=50, cursor=page['cursor'])

create()

POST/v1/memoriesAPI keystable
def create(
    self,
    content: str,
    memory_type: str = 'fact',
    tags: Optional[list[str]] = None,
    confidence: Optional[float] = None,
    *,
    idempotency_key: Optional[str] = None,
) -> Any: ...

Create a memory directly, bypassing the LLM extraction pipeline. Use sparingly — pre-extracted memories skip the dedupe and grounding guards.

ParameterTypeRequired
contentstrrequired
The memory's body text.
memory_typestroptional

One of fact, preference, event, entity, relation.

tagslist[str]optional
Optional free-form labels.
confidencefloatoptional
Range [0.0, 1.0].
idempotency_keystroptional
Override the auto-generated UUID.
recall.memories.create(
    content='User onboarded on 2026-05-01.',
    memory_type='event',
    tags=['onboarding'],
    confidence=1.0,
)
await recall.memories.create(
    content='User onboarded on 2026-05-01.',
    memory_type='event',
    tags=['onboarding'],
    confidence=1.0,
)

When to use. For deterministic facts you already have in structured form — onboarding events, billing transitions, system-generated audit notes. For anything you'd want the LLM to extract, use write().

update()

PATCH/v1/memories/:idAPI keystable
def update(
    self,
    memory_id: str,
    content: Optional[str] = None,
    confidence: Optional[float] = None,
    add_tags: Optional[list[str]] = None,
) -> Any: ...

Partially update a memory. Only provided fields are sent on the wire.

recall.memories.update(
    'm_01HEX…',
    confidence=0.95,
    add_tags=['verified'],
)
await recall.memories.update(
    'm_01HEX…',
    confidence=0.95,
    add_tags=['verified'],
)

add_tags is additive — the server merges the list into the existing tags array.

delete()

DELETE/v1/memories/:idAPI keystable
def delete(self, memory_id: str) -> Any: ...

Soft-delete a single memory. The row remains in the database with deleted_at set and is hidden from search.

recall.memories.delete('m_01HEX…')
await recall.memories.delete('m_01HEX…')

For batch deletes or hard deletes, use forget(). Note: DELETE does not carry an Idempotency-Key — REST DELETE is already idempotent at the semantic level.

feedback()

POST/v1/feedbackAPI keystable
def feedback(
    self,
    memory_id: str,
    signal: str,
    replacement: Optional[str] = None,
    duplicate_of: Optional[str] = None,
    reason: Optional[str] = None,
    *,
    idempotency_key: Optional[str] = None,
) -> Any: ...

Send a correction signal about a memory. See Feedback and forget for full details.

ParameterTypeRequired
memory_idstrrequired
Target memory.
signalstrrequired

One of 'correct', 'duplicate', 'irrelevant'.

replacementstroptional
Replacement content for signal='correct'.
duplicate_ofstroptional
Canonical ID for signal='duplicate'.
reasonstroptional
Free-text human-readable rationale.
recall.memories.feedback(
    memory_id='m_01HEX…',
    signal='correct',
    replacement='User prefers light mode.',
)
await recall.memories.feedback(
    memory_id='m_01HEX…',
    signal='correct',
    replacement='User prefers light mode.',
)

forget()

POST/v1/forgetAPI keystable
def forget(
    self,
    ids: Optional[list[str]] = None,
    hard: bool = False,
    *,
    idempotency_key: Optional[str] = None,
) -> Any: ...

Soft-delete (or hard-delete) a batch of memories.

recall.memories.forget(ids=['m_01HEX…', 'm_01HEY…'])
recall.memories.forget(ids=['m_old1', 'm_old2'], hard=True)
await recall.memories.forget(ids=['m_01HEX…', 'm_01HEY…'])
await recall.memories.forget(ids=['m_old1', 'm_old2'], hard=True)

hard=True triggers retention pruning — the row is removed from the database. Reserve hard delete for GDPR-style erasure or namespace cleanup.

Errors

Every memory method can raise the following:

CodeStatusRetry
RecallAuthError401/403fatal

API key missing, expired, or revoked.

RecallNotFoundError404fatal

Memory ID does not exist or is out of scope.

RecallValidationError422fatal

Invalid memory type, malformed body, etc.

RecallRateLimitError429fatal

Rate limit exceeded. Inspect .retry_after_ms.

RecallServerError5xxfatal

Server-side failure. Retried automatically up to max_retries.

Was this page helpful?

On this page