Skip to main content

cortadel

Official Python SDK for Cortadel — self-hosted long-term temporal graph memory for AI agents. A thin, typed client over the Cortadel REST API.

pip install cortadel
# or: uv add cortadel / poetry add cortadel

Python ≥ 3.10. Ships two facades: an async client and a real blocking client — pick whichever fits your program.

Quickstart (async)

import asyncio
from cortadel import ChatMessage, CortadelClient, SearchOptions

async def main() -> None:
    async with CortadelClient("http://localhost:3001", "alice") as cortadel:
        # apiKey: pass api_key="<token>" — omit when the server runs with auth disabled

        # Store
        await cortadel.add("Alice prefers dark mode and ships on Fridays.")

        # Recall (hybrid BM25 + vector + RRF)
        hits = await cortadel.search("what are alice's preferences?", SearchOptions(top_k=5))
        for h in hits.results:
            print(h.rrf_score, h.content)

        # Ingest a conversation
        await cortadel.add_conversation([
            ChatMessage(role="user", content="I'm allergic to peanuts."),
            ChatMessage(role="assistant", content="Noted — I'll avoid peanut recipes."),
        ])

        # List / get / delete
        page = await cortadel.list()
        one = await cortadel.get(page.items[0].id)
        await cortadel.delete([page.items[0].id])

asyncio.run(main())

Quickstart (blocking)

from cortadel import SyncCortadelClient

with SyncCortadelClient("http://localhost:3001", "alice") as cortadel:
    cortadel.add("Alice prefers dark mode and ships on Fridays.")
    hits = cortadel.search("what are alice's preferences?")
    for h in hits.results:
        print(h.rrf_score, h.content)

SyncCortadelClient is a real blocking client, not asyncio.run(...) called once per method — see cortadel/sync_client.py's module docstring for why that distinction matters (connection-pool reuse, and correctness when called from a thread that already has a running event loop) and how it is implemented (one persistent background event loop, for the client's lifetime).

Auth

Pass api_key in either constructor and every request carries Authorization: Bearer <key>. Omit it (or leave it None) when the server runs with auth disabled — no header is sent, and the client never mutates an httpx.AsyncClient you bring in either way.

import os
from cortadel import CortadelClient

cortadel = CortadelClient("https://my-box:3001", "alice", api_key=os.environ.get("CORTADEL_API_KEY"))

Reuse a single client per base URL + user. Every call it makes is scoped to the user_id you construct it with.

Methods

Both clients expose the same seven methods (async def on CortadelClient, blocking on SyncCortadelClient):

Method Returns Notes
add(text, options=None) MemoryCreated Store a memory. options.infer (default True) runs background entity/category extraction; False stores verbatim (dedup still applies).
add_conversation(messages, options=None) ConversationResult Distill atomic facts from a transcript and store each one.
search(query, options=None) SearchResults Hybrid search (BM25 + vector fused with RRF); set options.rerank = "cross_encoder" to rerank.
list(options=None) MemoryList Paginated, newest-first. options.size defaults to 20 (a deliberate SDK-wide choice — see below).
get(memory_id) MemoryDetail | None None when the memory doesn't exist; never raises for a 404. Content field is .text.
delete(memory_ids) str Deletes one or more memories; returns the server's confirmation message.
health() HealthResult Database + embedding provider reachability. Does not raise when the server reports itself degraded — a degraded server is a normal return value (status == "degraded"), not an exception.

ListOptions.size defaults to 20, not the REST contract's own default of 10 — kept in sync with the .NET and TypeScript SDKs so every Cortadel SDK behaves identically regardless of which one you're reading examples for.

Errors

Any non-success response — other than a degraded health check, which health() returns instead of raising — raises a CortadelError:

from cortadel import CortadelClient, CortadelError

async with CortadelClient("http://localhost:3001", "alice") as cortadel:
    try:
        await cortadel.add("")
    except CortadelError as err:
        print(err.status, err.code, err.message)
    # asyncio.CancelledError from a cancelled task/timeout propagates untouched instead —
    # it is never wrapped as a CortadelError.
Attribute Meaning
status HTTP status code. 0 when the transport failed before a status was known.
code Machine-readable error code (e.g. not_found, validation_error).
message Human-readable message — for a 400 from model validation, this folds in the
server's per-field errors instead of a generic "the request failed".

Bring your own HTTP client

Both constructors accept http_client: httpx.AsyncClient to reuse an existing client (connection pooling, proxies, custom TLS, etc. all carry over). It is never mutated or closed by the SDK — you own its lifecycle either way.

import httpx
from cortadel import CortadelClient

async with httpx.AsyncClient(proxy="http://proxy.internal:8080") as http_client:
    cortadel = CortadelClient("http://localhost:3001", "alice", http_client=http_client)
    ...

License

Apache-2.0

Metadata

Release files for cortadel 1.1.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for cortadel 1.1.0
File Size Uploaded
cortadel-1.1.0.tar.gz 31.0 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for cortadel 1.1.0
File Interpreter ABI Platform
cortadel-1.1.0-py3-none-any.whl Python 3 none any Details

Total release size: 92.4 kB

Release files / cortadel-1.1.0.tar.gz

Download URL cortadel-1.1.0.tar.gz
Size 31.0 kB
Tags Source
SHA-256 checksum
How to use checksums
1e7ba0cbb8e73169ab7d15ec2348613255ce9a540dc5b89c62cb53268fff843b
BLAKE2b-256 checksum
How to use checksums
e696bd165c3e42a7831dee24df49a2943728f85140c9805a66d9e69b56bd9fab
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.13.14

Release files / cortadel-1.1.0-py3-none-any.whl

Download URL cortadel-1.1.0-py3-none-any.whl
Size 61.3 kB
Tags Python 3
SHA-256 checksum
How to use checksums
3a2b7f5310de2b47a9a38b27e83543c4ab94a8bff67bf34040f1eefcccdb4f57
BLAKE2b-256 checksum
How to use checksums
e454be562cb7354f4c5fc2856ae28c6f7845d19053f023e2f97ff2e7b94ef479
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.13.14

Release history Release notifications | RSS feed

1.2.0

2 release files

1.1.1

2 release files

This release

1.1.0 This release

2 release files

1.0.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page