CortexDB Docs
SDKs & Clients

TypeScript SDK

Reference for cortexdbai — V1Client and typed errors.

The official TypeScript / JavaScript client for CortexDB v1. Single V1Client class, isomorphic (Node + browser).

npm install cortexdbai

Requires Node 18+ or any runtime with fetch + AbortController. npm package: cortexdbai (current release: 0.9.3). Module: cortexdbai/v1. The SDK version is independent of the server version — see Versioning and SDK compatibility.

Install cortexdbai, not the bare cortexdb name

An unrelated, unaffiliated package squats the bare cortexdb name on npm (it self-describes as an "official" client but is not published by the CortexDB project). Always install cortexdbai.

The one-liner: V1Client.signup()

The shortest path from npm install to stored-and-retrieved memory:

import { V1Client } from "cortexdbai/v1";

const client = await V1Client.signup();
await client.experience(client.actor, {
  text: "hello memory",
  observedAt: new Date().toISOString(),
  idempotencyKey: "first-001",
});
const pack = await client.recall(client.actor, {
  query: "hello",
  diagnostics: "none",
});

signup() posts to /v1/auth/signup, gets a token/actor/scope, and returns a fully-wired client. Free tier — 7-day TTL, no email, no card.

Explicit construction

import { V1Client } from "cortexdbai/v1";

const client = new V1Client({
  apiUrl: "https://api-v1.cortexdb.ai",
  actor:  "user:alice",
  bearer: process.env.CORTEX_TOKEN!,
  timeoutMs: 30_000,
});
OptionDefaultNotes
apiUrl— (required)v1 surface URL.
actor— (required)Sent as X-Cortex-Actor; must match the token's sub.
bearerundefinedPASETO v4 public token — or, self-hosted, the server's CORTEX_API_KEY value. Optional only when the server runs with CORTEX_INSECURE_NO_AUTH=1.
timeoutMs60000Per-request timeout.
fetchglobalThis.fetchOverride for tracing / retries / custom transport.

Auth

const me = await client.whoami();
// → { caller, tenant_id, deployment_preset, effective_capabilities, token }

const minted = await client.mintToken({
  subject:    "user:alice",
  ttlSeconds: 3600,
  scopes:     ["org:acme/user:alice"],
});
// → { token: "v4.public...", expires_at: "2026-05-15T11:42:00Z" }

The capability list is returned under effective_capabilities (snake_case).

Write path

const r = await client.experience(
  "org:acme/user:alice",
  {
    modality: "conversation",
    content:  { kind: "message", role: "user", text: "Acme upgraded to 200 seats." },
    context:  { observed_at: "2026-05-15T10:42:00Z" },
    idempotency_key: "alice-chat-001",
  },
  { wait: "indexed" },   // optional: "captured" | "indexed" | "consolidated"
);

const bulk = await client.experienceBulk(
  "org:acme/user:alice",
  [
    { modality: "conversation", content: { ... }, context: { ... }, idempotency_key: "k1" },
    { modality: "conversation", content: { ... }, context: { ... }, idempotency_key: "k2" },
  ],
);

experienceBulk options are { wait? } only

The options object is { wait? } — there is no ordering field (passing one is a TS type error). Items are ingested in list order; encode temporal order in each item's context.observed_at. ordering is a REST body field, not an SDK option.

With wait omitted, a write returns captured (202) once the WAL append succeeds — not fully indexed; pass { wait: "indexed" } to block on indexing. For full envelope shape see Experience Envelope.

Read path

const pack = await client.recall("org:acme/user:alice", {
  view:    "holistic",
  query:   "What did we decide about Acme?",
  include: ["beliefs", "facts", "episodes"],
  budgets: { max_tokens: 4000 },
  temporal:{ natural: "last 30 days" },
});
// pack is a fully-typed StratifiedPack

const ans = await client.answer("org:acme/user:alice", {
  question: "Did Acme renew?",
  view:     "holistic",
  answer_model: "claude-opus-4-6",
  temporal: { natural: "last 30 days" },
});
// ans is a fully-typed AnswerResponse

answer_model is a cloud default

claude-opus-4-6 is the cloud default. Self-hosted, /v1/answer routes through the configured answer lane (CORTEX_ANSWER_*) and is disabled until that lane is set. See Self-hosting defaults.

Layer reads

await client.events("org:acme/user:alice", { view: "local", limit: 50 });
await client.episodes("org:acme/user:alice", "local");
await client.facts("org:acme/user:alice");
await client.beliefs("org:acme/user:alice");
await client.beliefWhy("belief_01HX...");
await client.understanding("org:acme/user:alice");

await client.buildEpisodes("org:acme/user:alice");
await client.buildBeliefs("org:acme/user:alice");
await client.synthesize("org:acme/dept:eng", ["sales_process"]);

Facts / Beliefs need enrichment on self-host

On a content-only self-hosted instance the Facts and Beliefs layers stay empty — they are LLM-derived. See Self-hosting defaults.

Forget

await client.forget("org:acme/user:alice", {
  layers:   ["beliefs"],
  selector: { predicate: "is_likely_to_renew" },
  cascade:  "derived_only",
  reason:   "User retracted speculation",
});

The audit-note field is reason

ForgetParams = { layers, selector, cascade, confirmAll, reason, fromPreviewId }. The audit note field is reason, not audit_note.

A selector of { memory_ids: [...] } purges every listed id. If a storage backend fails mid-delete the server returns 502 FORGET_BACKEND_FAILED rather than reporting success — deletes are idempotent, so retry the same call.

The two SDKs' forget APIs differ

The TypeScript forget takes a selector object; the Python forget does not — it targets by flat keyword (predicate=, memory_ids=, about_subject=). See the Python SDK.

Audit + Admin

await client.audit({ actor: "user:alice", capability: "forget.gdpr", limit: 100 });
await client.layerStats();    // experimental

Typed errors

import {
  V1Error,
  V1APIError,
  V1AuthError,
  V1PolicyDeniedError,
  V1RateLimitError,
  V1NotConfiguredError,
  V1InvalidRequestError,
  V1ConnectionError,
  V1TimeoutError,
} from "cortexdbai/v1";

try {
  await client.experience("org:acme/user:alice", { ... });
} catch (e) {
  if (e instanceof V1PolicyDeniedError) {
    console.error(`policy denied: ${e.message}`);
  } else if (e instanceof V1RateLimitError) {
    await new Promise(r => setTimeout(r, 1000));
  } else {
    throw e;
  }
}

Types

The SDK exports the full type set used by the v1 surface:

import type {
  StratifiedPack,
  AnswerResponse,
  ExperienceItem,
  RecallParams,
  AnswerParams,
  ForgetParams,
  Citation,
  Provenance,
  Diagnostics,
} from "cortexdbai/v1";

tsc --noEmit reports zero errors in the v1 surface — the SDK is suitable for strict TypeScript projects.

Method index

Beyond the paths shown above, the client (verified against 0.9.2) also exposes:

AreaMethods
ComposecomposePOST /v1/compose
Bi-temporal recordsqueryClaims · claimHistory · listConflicts · getConflict · resolveConflictClaims & Conflicts
Layer historybeliefHistory · conceptHistory
ErasureerasurePreview · forgetPreview/v1/erasures
ImportimportData/v1/import
BlobsuploadBlob · deleteBlob/v1/blobs
Beliefs (write)createBelief
VocabulariespatchVocabulary/v1/vocabularies
Auditaudit · auditChain · verifyAuditChain
Write statuswriteStatus — "did my write land?" by idempotency key or event id

The TypeScript surface is not identical to Python

Both clients were introspected (Python cortexdbai 0.11.1, TypeScript 0.9.2). Beyond the obvious snake_case to camelCase shift, three methods are named differently: Python's audit_list, audit_chain_verify and update_vocabulary are audit, verifyAuditChain and patchVocabulary here.

Five Python methods have no TypeScript equivalent: erase (the execute step — TypeScript ships erasurePreview only), import_status, audit_verify, index_audit and close. Use the REST endpoints for those. signup() is a static on V1Client, not an instance method.

On this page