Namespaces resource
Admin-plane CRUD for Recall namespaces from Python — create, list, get, delete, stats, reembed, reextract, with the async background-job model.
Namespaces is a JWT-only resource. API keys are rejected with HTTP
403 on every namespaces endpoint. Authenticate via your control-plane
JWT issuer (typically your IDP); rotate JWTs through the
recall.identity.refresh() cycle.
list()
def list(self) -> List[Dict[str, Any]]: ...List every namespace owned by the calling org, newest first.
for ns in recall.namespaces.list():
print(ns['id'], ns['name'], ns['mode'])for ns in await recall.namespaces.list():
print(ns['id'], ns['name'], ns['mode'])create()
def create(self, req: Dict[str, Any]) -> Dict[str, Any]: ...Create a new namespace and bootstrap its data plane (Postgres pool, embedding column, indexes). Returns the namespace row with provisioning status.
reqdictrequiredNamespace creation request. Required keys: mode ('self-hosted' or
'cloud'), name. Optional: description, database_id, llm_id,
embedder. See the namespace concept page for full schema.
ns = recall.namespaces.create({
'mode': 'self-hosted',
'name': 'prod',
'description': 'Production namespace for support agent',
})
print('Created:', ns['id'])ns = await recall.namespaces.create({
'mode': 'self-hosted',
'name': 'prod',
'description': 'Production namespace for support agent',
})get()
def get(self, namespace_id: str) -> Dict[str, Any]: ...Fetch a namespace by ID, including its provisioning status.
ns = recall.namespaces.get('ns_01HEX…')
print(ns['provisioning_status'])ns = await recall.namespaces.get('ns_01HEX…')stats()
def stats(self, namespace_id: str) -> Dict[str, Any]: ...Return live operational counters for the namespace. Server caches the result for 30 seconds per namespace, so frequent calls don't hammer the data plane.
The response follows the NamespaceStats TypedDict (see
Types):
{
"id": "ns_…",
"memory_count": 12450,
"entity_count": 873,
"relation_count": 2104,
"bytes_used": "84 MB",
"embedding_coverage": 0.99,
"oldest_memory_at": "2025-12-15T…",
"last_write_at": "2026-05-08T…",
"pending_hype_jobs": 0,
"health": "ready",
"pending_admin_jobs": {"reembed": 1}
}s = recall.namespaces.stats('ns_01HEX…')
print(f"{s['memory_count']} memories, {s['embedding_coverage']:.0%} embedded")s = await recall.namespaces.stats('ns_01HEX…')delete()
def delete(self, namespace_id: str, *, confirm: str) -> None: ...Soft-delete a namespace and cascade-revoke its API keys. The confirm
kwarg MUST equal the namespace's slug exactly — GitHub-style "type the
name to confirm" gating. Mismatches return HTTP 400 with the expected
slug echoed back.
ns = recall.namespaces.get('ns_01HEX…')
recall.namespaces.delete(ns['id'], confirm=ns['name'])ns = await recall.namespaces.get('ns_01HEX…')
await recall.namespaces.delete(ns['id'], confirm=ns['name'])Soft-delete does NOT free the underlying Postgres rows immediately. The
retention worker eventually hard-deletes the data on the configured
schedule. To force immediate purge, follow up with the hard-delete
admin job (recall.namespaces.reembed(...) is unrelated; see ops
documentation for the hard-delete tool).
reembed()
def reembed(
self,
namespace_id: str,
*,
types: Optional[List[str]] = None,
only_missing: Optional[bool] = None,
batch_size: Optional[int] = None,
embedder: Optional[str] = None,
force: Optional[bool] = None,
) -> Dict[str, Any]: ...Enqueue a reembed admin job. Returns a JobAcceptedResponse (HTTP 202)
with a jobId; poll progress with recall.jobs.get(job_id).
Parameters
typeslist[str]optionalRestrict to specific memory types. Empty/omitted = all.
only_missingbooloptionalSkip memories that already have an embedding. Default: True server-side.
batch_sizeintoptionalPer-batch size; clamped server-side to [1, 500].
embedderstroptionalPin a non-default embedder model. Null/omitted keeps the namespace default.
forcebooloptionalPermit destructive operations. When True, the worker drops and
rebuilds the pgvector index if the embedder dimension differs.
Default False rejects dim changes.
job = recall.namespaces.reembed(
'ns_01HEX…',
only_missing=True,
batch_size=100,
)
print('Job:', job['jobId'], '→', job['status'])job = await recall.namespaces.reembed(
'ns_01HEX…',
only_missing=True,
batch_size=100,
)Polling pattern
import time
job = recall.namespaces.reembed('ns_…', only_missing=True)
job_id = job['jobId']
while True:
status = recall.jobs.get(job_id)
print(f"{status['status']}: {status['processed']}/{status['totalEstimated']}")
if status['status'] in {'done', 'failed', 'cancelled'}:
break
time.sleep(5)See Jobs for richer polling patterns including exponential backoff.
reextract()
def reextract(
self,
namespace_id: str,
*,
types: Optional[List[str]] = None,
batch_size: Optional[int] = None,
) -> Dict[str, Any]: ...Re-resolve persisted entity-name surface forms (subject_name,
object_name) against the current entity dictionary. Updates each
memory's subject / object EntityId whenever resolution yields a
different result. NO-OP for memories whose surface forms are both NULL.
reextract does not invoke the LLM and does not scan content.
It only re-resolves names that the write pipeline already extracted at
write time. To discover new entity mentions in raw conversation text,
re-run the write pipeline.
job = recall.namespaces.reextract(
'ns_01HEX…',
types=['fact', 'relation'],
)job = await recall.namespaces.reextract(
'ns_01HEX…',
types=['fact', 'relation'],
)Async background-job pattern
Both reembed and reextract follow the same enqueue-and-poll pattern:
- Call the resource method. Server returns
202 Acceptedwith aJobAcceptedResponsecarryingjobId,namespaceId,totalEstimated,status='queued', andkind. - Poll
recall.jobs.get(jobId)untilstatusis one of'done','failed', or'cancelled'. - Inspect
processed/failed_items/errorfor results.
Job state transitions are documented in Jobs along with the recommended polling backoff.
Errors
RecallAuthError401/403fatalMissing JWT, expired JWT, or API-key auth attempted on the admin plane.
RecallNotFoundError404fatalNamespace ID not found, or out of org.
RecallValidationError422fatalconfirm mismatch on delete; invalid mode or name on create;
out-of-range batch_size.
RecallApiError409fatalConcurrent provisioning or job-conflict (e.g. another reembed already running on the namespace).
Was this page helpful?