contextkitDocs

Reference

Cloud SDK API reference

Every public class and method in outhad-contextkit-sdk 1.10.0, generated from the release on PyPI.

Generated from outhad-contextkit-sdk 1.10.0, the latest release on PyPI. This page is rebuilt from the published wheel after every release, so it always matches what pip install gives you.

Constants

NameValue
DEFAULT_HOST'https://api.contextkit.outhad.com'
DEV_HOST'http://localhost:8000'

MemoryClient

from outhad_contextkit_sdk.client.main import MemoryClient

Synchronous client for the Outhad ContextKit cloud.

Args

api_key
ock_live_… or ock_test_… token minted at the dashboard. Falls back to the OUTHAD_CONTEXTKIT_API_KEY env var when omitted; raises :class:AuthenticationError when neither is provided.
host
Override the cloud host. Defaults to :data:DEFAULT_HOST (production). Pass DEV_HOST for a local backend.
timeout
Per-request timeout in seconds.
client
Pre-built httpx.Client. When supplied, base_url and Authorization headers are overwritten so the rest of the SDK works as-expected.
allow_dev_fallback
When True, a connection failure against the production default URL retries once against DEV_HOST and pins the client to it for the session. Defaults to False (since 1.10.0). Ignored when the host was set explicitly.

__init__

def __init__(
    api_key: Optional[str] = None,
    *,
    host: Optional[str] = None,
    timeout: float = DEFAULT_TIMEOUT,
    client: Optional[httpx.Client] = None,
    allow_dev_fallback: bool = False,
) -> None

No description.

add

def add(
    messages: Any,
    *,
    user_id: Optional[str] = None,
    agent_id: Optional[str] = None,
    run_id: Optional[str] = None,
    metadata: Optional[Dict[str, Any]] = None,
    infer: bool = True,
    llm: Optional[Dict[str, Any]] = None,
    embedder: Optional[Dict[str, Any]] = None,
    expiration_date: Optional[str] = None,
) -> Any

Persist memories.

messages accepts the original contextkit-compat shape [{"role": "user", "content": "..."}] or the OpenAI vision shape with content blocks::

messages=[{
    "role": "user",
    "content": [
        {"type": "text", "text": "Vacation in Tokyo"},
        {"type": "image_url",
         "image_url": {"url": "https://example.com/sushi.jpg"}},
    ],
}]

When a content-block list arrives the cloud routes it through the project's vision-capable LLM, gets a description, and stores that as a normal text fact — image bytes never leave the LLM call.

llm / embedder are per-request model overrides:

client.add(
    messages=[...],
    user_id="alice",
    llm={"provider": "anthropic", "model": "claude-haiku-4-5-20251001"},
)

Pass api_key inside the dict to BYOK for that single call::

llm={"provider": "anthropic", "model": "claude-haiku-4-5-20251001",
     "api_key": "sk-ant-…"}

expiration_date (ISO-8601) makes the row invisible to retrieval after the cutoff. Stored as metadata.expiration_date; TTL enforcement is at retrieval time, no background sweep.

get_all

def get_all(
    *,
    user_id: Optional[str] = None,
    agent_id: Optional[str] = None,
    run_id: Optional[str] = None,
    limit: int = 100,
    page: Optional[int] = None,
    page_size: Optional[int] = None,
    version: Optional[str] = None,
    output_format: Optional[str] = None,
    includes: Optional[List[str]] = None,
    excludes: Optional[List[str]] = None,
) -> Any

List memories matching the supplied scope.

page / page_size slice the materialised result set at the route layer. Walking deeper than limit requires raising limit accordingly — the underlying vector store only fetches limit rows. Default behaviour (omit page kwargs) is unchanged.

version / output_format / includes / excludes behave as in :meth:search — contextkit-compat passthrough that re-shapes the client-side response.

get

def get(memory_id: str) -> Any

No description.

search

def search(
    query: str,
    *,
    user_id: Optional[str] = None,
    agent_id: Optional[str] = None,
    run_id: Optional[str] = None,
    filters: Optional[Dict[str, Any]] = None,
    limit: int = 10,
    llm: Optional[Dict[str, Any]] = None,
    embedder: Optional[Dict[str, Any]] = None,
    threshold: Optional[float] = None,
    use_context_graph: Optional[bool] = None,
    categories: Optional[List[str]] = None,
    top_k: Optional[int] = None,
    version: Optional[str] = None,
    output_format: Optional[str] = None,
    includes: Optional[List[str]] = None,
    excludes: Optional[List[str]] = None,
    use_tcmgm: Optional[bool] = None,
    time_window: Optional[Dict[str, Any]] = None,
    include_causal: Optional[bool] = None,
    keyword_search: Optional[bool] = None,
    filter_memories: Optional[bool] = None,
) -> Any

Vector-search the project. llm / embedder overrides accepted as in :meth:add.

threshold — minimum score [0..1]; rows below are dropped. use_context_graph — route through CGL pipeline (graph-first

seeding + BFS expansion + re-rank). Falls back to plain
vector search when CGL is disabled in MemoryConfig.

categories — list of metadata.categories values to match

(any-of). Equivalent to passing ``filters={"categories": [...]}``.

top_k — alias for limit; honoured when both are passed. version / output_format — contextkit-compat shape selectors.

Server currently emits the v1.1 shape regardless; the kwargs
are accepted so callers porting from contextkit don't have to
strip them, and ``output_format='v1.0'`` triggers a
client-side compatibility unwrap that returns a bare list.

includes / excludes — return-shape trimmers applied

client-side after the response arrives. Useful for slimming
payloads on memory-heavy clients (mobile / edge).

use_tcmgm — opt-in TCMGM (Temporal-Causal Multimodal Graph

Memory) fused retrieval. Combines vector hits with timeline
+ causal-graph expansion in a single ranked envelope.
Requires the project's ``enable_graph=True`` so the engine
has the graph + timeline stack initialised; otherwise it's
a no-op that falls back to plain vector search. Response
shape stays ``{"results": [...]}`` and gains
``timeline_results`` + ``causal_chains`` + ``fused_ranking``
siblings when TCMGM actually runs.

time_window — {"start": ISO, "end": ISO} filter on the

TCMGM timeline stage. No-op when ``use_tcmgm=False``.

include_causal — explicit override for causal-chain

expansion within TCMGM (defaults to ``True`` engine-side).

update

def update(memory_id: str, *, text: Optional[str] = None) -> Any

No description.

history

def history(
    memory_id: str,
    *,
    since: Optional[str] = None,
    until: Optional[str] = None,
) -> Any

Per-memory change log.

since / until are ISO-8601 timestamps that filter the events at the route layer. Without them the full log is returned — matches the original v1.0 behaviour.

delete

def delete(memory_id: str) -> Any

No description.

delete_all

def delete_all(
    *,
    user_id: Optional[str] = None,
    agent_id: Optional[str] = None,
    run_id: Optional[str] = None,
) -> Any

No description.

feedback

def feedback(
    memory_id: str,
    *,
    feedback: Optional[str] = None,
    helpful: Optional[bool] = None,
    feedback_reason: Optional[str] = None,
    user_id: Optional[str] = None,
    agent_id: Optional[str] = None,
    run_id: Optional[str] = None,
    query: Optional[str] = None,
) -> Any

Record a verdict on a retrieved memory (MSPR/F3).

Either pass contextkit-compat feedback="POSITIVE"|"NEGATIVE"|"VERY_NEGATIVE" OR engine-native helpful=True/False. helpful wins when both are set. The cloud maps both onto the engine's record_feedback boolean.

Returns {"recorded": True, "memory_id": ..., "delta_applied": ..., "new_relevance": ..., "event_id": ..., "helpful": ...} on success. Returns {"recorded": False, "reason": "..."} when MSPR or feedback is disabled in the cloud build — non-fatal so callers can wrap retrieval flows without try/except.

reset

def reset() -> Any

Tenant-scoped wipe — every row tagged with this API key's tenant.

users

def users(*, limit: int = 1000) -> Any

List every distinct user_id / agent_id / run_id under this tenant.

Returns {"results": [{"id": "...", "type": "user|agent|run"}]}.

delete_users

def delete_users(
    *,
    user_id: Optional[str] = None,
    agent_id: Optional[str] = None,
    run_id: Optional[str] = None,
) -> Any

Wipe every memory tagged with the given entity id.

Pass exactly one of user_id / agent_id / run_id.

batch_update

def batch_update(memories: List[Dict[str, Any]]) -> Any

Update up to 1000 memories per call.

Each entry: {"memory_id": "...", "text": "..."}.

batch_delete

def batch_delete(memory_ids: List[str]) -> Any

Delete up to 1000 memories per call by id.

summary

def summary(
    *,
    user_id: Optional[str] = None,
    agent_id: Optional[str] = None,
    run_id: Optional[str] = None,
    filters: Optional[Dict[str, Any]] = None,
    limit: int = 200,
    llm: Optional[Dict[str, Any]] = None,
) -> Any

LLM-distilled brief over rows matching the supplied scope.

Returns {"summary": "...", "memory_count": N}.

export

def export(
    *,
    user_id: Optional[str] = None,
    agent_id: Optional[str] = None,
    run_id: Optional[str] = None,
    filters: Optional[Dict[str, Any]] = None,
    include_history: bool = False,
    limit: int = 10000,
) -> Any

GDPR-style synchronous export.

Returns {"exported_at": ISO, "tenant_id": ..., "memory_count": N, "memories": [...]}. When include_history=True each row carries its full change log under a history key.

versions

def versions(memory_id: str) -> Any

Return every version row for memory_id (immutable mode).

latest_version

def latest_version(memory_id: str) -> Any

No description.

rollback

def rollback(memory_id: str, *, to_version: int) -> Any

Roll a memory back to to_version. Writes a new immutable row carrying the old payload + a rolled_back_from metadata tag. Original versions stay queryable via :meth:versions.

diff_versions

def diff_versions(old: str, new: str) -> Any

Diff two memory rows. Engine default uses unified-diff format.

tick_decay

def tick_decay() -> Any

No description.

archive_low

def archive_low(*, threshold: Optional[float] = None, dry_run: bool = False) -> Any

No description.

decay_score

def decay_score(memory_id: str) -> Any

No description.

demote_to_cold

def demote_to_cold(memory_id: str) -> Any

No description.

promote_from_cold

def promote_from_cold(memory_id: str) -> Any

No description.

record_reference

def record_reference(memory_id: str, *, strength: float = 1.0) -> Any

Distinct from feedback — call this when an agent actually consumed the row in its response (vs only retrieving it). Bumps access_count + last_accessed_at on the CGL node.

backfill

def backfill(
    kind: str,
    *,
    batch_size: Optional[int] = None,
    embed: Optional[bool] = None,
) -> Any

Idempotent reconstruction of context_graph / mspr / decay_v2 from existing vector + history rows. Useful after flipping a feature on a project that already has data.

reset_cgl

def reset_cgl() -> Any

No description.

reset_feedback

def reset_feedback(*, user_id: Optional[str] = None) -> Any

No description.

pin

def pin(memory_id: str) -> Any

Mark a memory immutable. update / delete return 409 on locked rows.

unpin

def unpin(memory_id: str) -> Any

No description.

add_idempotent

def add_idempotent(idempotency_key: str, messages: Any, **kwargs: Any) -> Any

Same as :meth:add but sends Idempotency-Key so a retry with the same key returns the cached response without re-running fact extraction.

Cache lives in-process on the cloud — replay protection is per worker, sufficient for the common "pre-flight POST timed out, retry once" pattern.

get_all_filtered

def get_all_filtered(
    filters: Dict[str, Any],
    *,
    user_id: Optional[str] = None,
    agent_id: Optional[str] = None,
    run_id: Optional[str] = None,
    limit: int = 100,
    page: Optional[int] = None,
    page_size: Optional[int] = None,
) -> Any

get_all with the full Phase 1.6 operator filter dict.

Body cannot be sent on a GET, so the dict is JSON-encoded into the filters_json query param. Operators supported: $eq, $ne, $gt, $gte, $lt, $lte, $in, $nin, $contains plus AND / OR / NOT composition. Example::

client.get_all_filtered(
    {"AND": [
        {"created_at": {"$gt": "2026-01-01T00:00:00Z"}},
        {"OR": [
            {"metadata.priority": {"$gte": 5}},
            {"metadata.tag": {"$in": ["urgent", "p0"]}},
        ]},
    ]},
    user_id="alice",
)

list_projects

def list_projects() -> Any

Every project the caller's organization owns.

create_project

def create_project(
    name: str,
    *,
    slug: Optional[str] = None,
    llm_provider: Optional[str] = None,
    llm_model: Optional[str] = None,
    embedder_provider: Optional[str] = None,
    embedder_model: Optional[str] = None,
    custom_instructions: Optional[str] = None,
    custom_categories: Optional[List[str]] = None,
    retrieval_criteria: Optional[Dict[str, Any]] = None,
    enable_graph: Optional[bool] = None,
    api_version: Optional[str] = None,
) -> Any

Create a project under the calling user's current org. Clerk-only.

get_project

def get_project(project_id: str) -> Any

No description.

update_project

def update_project(
    project_id: str,
    *,
    llm_provider: Optional[str] = None,
    llm_model: Optional[str] = None,
    llm_api_key: Optional[str] = None,
    embedder_provider: Optional[str] = None,
    embedder_model: Optional[str] = None,
    embedder_api_key: Optional[str] = None,
    custom_instructions: Optional[str] = None,
    custom_categories: Optional[List[str]] = None,
    retrieval_criteria: Optional[Dict[str, Any]] = None,
    enable_graph: Optional[bool] = None,
    api_version: Optional[str] = None,
    multilingual: Optional[bool] = None,
    memory_depth: Optional[int] = None,
    usecase_setting: Optional[str] = None,
) -> Any

PATCH a subset of project fields. Clerk-only.

Mirrors the dashboard Settings → Save flow — pass only the fields you want to change. None skips, empty string / list / dict clears.

Phase 1.7 fields:

  • multilingual — bool. When True, the cloud appends a 'preserve original-language phrasing' directive to the fact-extraction prompt.
  • memory_depth — int 1..200. Persisted on the project for dashboard surfacing; engine reads its own update-context limits.
  • usecase_setting — preset name (support / personal-assistant / research / sales). Cloud appends a use-case-specific instruction snippet to the extraction prompt.

delete_project

def delete_project(project_id: str) -> Any

Soft-delete (sets is_active=False; audit trail preserved). Clerk-only.

list_members

def list_members(project_id: str) -> Any

No description.

add_member

def add_member(project_id: str, *, email: str, role: str = 'READER') -> Any

Bind an existing user (matched by email) into the project's org.

update_member

def update_member(project_id: str, member_id: str, *, role: str) -> Any

No description.

remove_member

def remove_member(project_id: str, member_id: str) -> Any

No description.

list_webhooks

def list_webhooks(project_id: str) -> Any

No description.

create_webhook

def create_webhook(
    project_id: str,
    *,
    url: str,
    event_types: Optional[List[str]] = None,
    secret: Optional[str] = None,
    is_active: bool = True,
) -> Any

Register an outbound webhook. Returns the webhook + its secret.

The cloud signs every delivery's body with HMAC-SHA256 of the secret. Receivers should compute the same HMAC and compare in constant time.

update_webhook

def update_webhook(
    project_id: str,
    webhook_id: str,
    *,
    url: Optional[str] = None,
    event_types: Optional[List[str]] = None,
    secret: Optional[str] = None,
    is_active: Optional[bool] = None,
) -> Any

No description.

delete_webhook

def delete_webhook(project_id: str, webhook_id: str) -> Any

No description.

list_api_keys

def list_api_keys() -> Any

No description.

create_api_key

def create_api_key(
    name: str,
    *,
    scopes: Optional[List[str]] = None,
    environment: str = 'live',
    project_id: Optional[str] = None,
) -> Any

Mint a new API key. Clerk-only.

Phase 1.7 — pass project_id to bind the new key to a non-default project (e.g. minting a 'production' key for a team's prod project + a 'sandbox' key for their dev project). Caller must be a member of the same organization that owns the project, otherwise the route returns 403.

environment="test" mints a sandbox-prefixed key (ock_test_…); the cloud routes test-mode traffic to a physically separate pgvector collection per (project, env) so test rows can never leak into production memory.

revoke_api_key

def revoke_api_key(api_key_id: str) -> Any

No description.

rotate_api_key

def rotate_api_key(api_key_id: str, *, grace_seconds: int = 86400) -> Any

Mint a replacement key + pin the old key's expires_at.

Returns the new key (with full_key shown once). The old key keeps working for grace_seconds so workers can pick up the new value without an outage. Default 24h matches Stripe's rotation pattern. Set to 0 for immediate cutover.

update_api_key

def update_api_key(
    api_key_id: str,
    *,
    name: Optional[str] = None,
    scopes: Optional[List[str]] = None,
    ip_allowlist: Optional[List[str]] = None,
) -> Any

Edit an existing key without minting a new one.

scopes controls per-key permissions (memory.read / memory.write / audit.read / ...). ip_allowlist is a list of CIDR strings or plain IPs; empty list = no restriction, ["*"] = wildcard. Clerk-only.

audit_log

def audit_log(
    *,
    limit: int = 100,
    action: Optional[str] = None,
    resource_type: Optional[str] = None,
    since: Optional[str] = None,
    until: Optional[str] = None,
) -> Any

Read the calling org's audit log.

Filters all optional. API-key callers need audit.read scope (mint with client.create_api_key(name, scopes=["audit.read"])); Clerk JWT bypasses the check.

usage

def usage(*, since: Optional[str] = None, until: Optional[str] = None) -> Any

Aggregate usage summary for the caller's organization.

Returns counts / latency / status mix / token + cost roll-ups across the chosen window (default last 7 days).

requests

def requests(
    *,
    limit: int = 50,
    offset: int = 0,
    since: Optional[str] = None,
    until: Optional[str] = None,
    method: Optional[str] = None,
    path: Optional[str] = None,
    status_code: Optional[int] = None,
    min_status: Optional[int] = None,
    max_status: Optional[int] = None,
    user_id: Optional[str] = None,
) -> Any

Paginated request-log trace viewer.

Latest entries first. min_status=400 surfaces only failed requests; user_id filters by user_id_scope so dashboard drill-down works without a client-side filter.

top_users

def top_users(
    *,
    limit: int = 20,
    since: Optional[str] = None,
    until: Optional[str] = None,
) -> Any

Top user_id scopes by request count for the window.

graph_snapshot

def graph_snapshot(*, user_id: Optional[str] = None, limit: int = 200) -> Any

Return a CGL subgraph (nodes + edges) for the dashboard visualiser. enabled=False when enable_graph is off.

close

def close() -> None

No description.

AsyncMemoryClient

from outhad_contextkit_sdk.client.main import AsyncMemoryClient

Async equivalent of :class:MemoryClient (httpx.AsyncClient under the hood).

__init__

def __init__(
    api_key: Optional[str] = None,
    *,
    host: Optional[str] = None,
    timeout: float = DEFAULT_TIMEOUT,
    client: Optional[httpx.AsyncClient] = None,
    allow_dev_fallback: bool = False,
) -> None

No description.

validate async

async def validate() -> Dict[str, Any]

No description.

add async

async def add(
    messages,
    *,
    llm: Optional[Dict[str, Any]] = None,
    embedder: Optional[Dict[str, Any]] = None,
    **kw,
) -> Any

No description.

get_all async

async def get_all(**kw) -> Any

No description.

get async

async def get(memory_id: str) -> Any

No description.

search async

async def search(
    query: str,
    *,
    llm: Optional[Dict[str, Any]] = None,
    embedder: Optional[Dict[str, Any]] = None,
    **kw,
) -> Any

No description.

update async

async def update(memory_id: str, *, text: str) -> Any

No description.

history async

async def history(
    memory_id: str,
    *,
    since: Optional[str] = None,
    until: Optional[str] = None,
) -> Any

No description.

delete async

async def delete(memory_id: str) -> Any

No description.

delete_all async

async def delete_all(**kw) -> Any

No description.

feedback async

async def feedback(memory_id: str, **kw) -> Any

No description.

reset async

async def reset() -> Any

No description.

users async

async def users(*, limit: int = 1000) -> Any

No description.

delete_users async

async def delete_users(
    *,
    user_id: Optional[str] = None,
    agent_id: Optional[str] = None,
    run_id: Optional[str] = None,
) -> Any

No description.

batch_update async

async def batch_update(memories: List[Dict[str, Any]]) -> Any

No description.

batch_delete async

async def batch_delete(memory_ids: List[str]) -> Any

No description.

summary async

async def summary(**kw) -> Any

No description.

export async

async def export(**kw) -> Any

No description.

versions async

async def versions(memory_id: str) -> Any

No description.

latest_version async

async def latest_version(memory_id: str) -> Any

No description.

rollback async

async def rollback(memory_id: str, *, to_version: int) -> Any

No description.

diff_versions async

async def diff_versions(old: str, new: str) -> Any

No description.

tick_decay async

async def tick_decay() -> Any

No description.

archive_low async

async def archive_low(
    *,
    threshold: Optional[float] = None,
    dry_run: bool = False,
) -> Any

No description.

decay_score async

async def decay_score(memory_id: str) -> Any

No description.

demote_to_cold async

async def demote_to_cold(memory_id: str) -> Any

No description.

promote_from_cold async

async def promote_from_cold(memory_id: str) -> Any

No description.

record_reference async

async def record_reference(memory_id: str, *, strength: float = 1.0) -> Any

No description.

backfill async

async def backfill(
    kind: str,
    *,
    batch_size: Optional[int] = None,
    embed: Optional[bool] = None,
) -> Any

No description.

reset_cgl async

async def reset_cgl() -> Any

No description.

reset_feedback async

async def reset_feedback(*, user_id: Optional[str] = None) -> Any

No description.

pin async

async def pin(memory_id: str) -> Any

No description.

unpin async

async def unpin(memory_id: str) -> Any

No description.

add_idempotent async

async def add_idempotent(idempotency_key: str, messages: Any, **kw) -> Any

No description.

get_all_filtered async

async def get_all_filtered(filters: Dict[str, Any], **kw: Any) -> Any

No description.

list_projects async

async def list_projects() -> Any

No description.

create_project async

async def create_project(name: str, **kw) -> Any

No description.

get_project async

async def get_project(project_id: str) -> Any

No description.

update_project async

async def update_project(project_id: str, **kw) -> Any

No description.

delete_project async

async def delete_project(project_id: str) -> Any

No description.

list_members async

async def list_members(project_id: str) -> Any

No description.

add_member async

async def add_member(project_id: str, *, email: str, role: str = 'READER') -> Any

No description.

update_member async

async def update_member(project_id: str, member_id: str, *, role: str) -> Any

No description.

remove_member async

async def remove_member(project_id: str, member_id: str) -> Any

No description.

list_webhooks async

async def list_webhooks(project_id: str) -> Any

No description.

create_webhook async

async def create_webhook(project_id: str, *, url: str, **kw) -> Any

No description.

update_webhook async

async def update_webhook(project_id: str, webhook_id: str, **kw) -> Any

No description.

delete_webhook async

async def delete_webhook(project_id: str, webhook_id: str) -> Any

No description.

rotate_api_key async

async def rotate_api_key(api_key_id: str, *, grace_seconds: int = 86400) -> Any

No description.

update_api_key async

async def update_api_key(api_key_id: str, **kw) -> Any

No description.

audit_log async

async def audit_log(**kw) -> Any

No description.

usage async

async def usage(**kw) -> Any

No description.

requests async

async def requests(**kw) -> Any

No description.

top_users async

async def top_users(**kw) -> Any

No description.

graph_snapshot async

async def graph_snapshot(**kw) -> Any

No description.

aclose async

async def aclose() -> None

No description.