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
| Name | Value |
|---|---|
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_keyock_live_…orock_test_…token minted at the dashboard. Falls back to theOUTHAD_CONTEXTKIT_API_KEYenv var when omitted; raises :class:AuthenticationErrorwhen neither is provided.host- Override the cloud host. Defaults to :data:
DEFAULT_HOST(production). PassDEV_HOSTfor a local backend. timeout- Per-request timeout in seconds.
client- Pre-built
httpx.Client. When supplied,base_urlandAuthorizationheaders 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_HOSTand 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.