Agent-readable docs index: /docs/llms.txt. Full docs in one file: /docs/llms-full.txt. Download /docs/docs.zip to grep all markdown files locally.

TypeScript SDK

kaibo has no runtime dependencies, works anywhere fetch does (Node 20+, Bun, Deno, Workers, browsers), and ships ESM and CJS.
bun add kaibo # or npm install, pnpm add, yarn add
import { Kaibo } from "kaibo"; const kaibo = new Kaibo(); // Reads KAIBO_KEY, and KAIBO_URL and KAIBO_PROJECT when set. Or pass options: // new Kaibo({ apiKey, baseUrl, project (org-wide keys only), fetch, retries (2), timeoutMs (30000) })
A missing key throws an error that says how to fix it. API errors carry a stable code, the requestId, and a hint for the common ones.

Operations

await kaibo.remember("We ship on July 17.", { wait: true }); const pack = await kaibo.recall({ query: "ship date", asOf: "2026-07-01T00:00:00Z", budgetTokens: 1000 }); const why = pack.found ? await kaibo.explain(pack.top) : null; const { receipt } = await kaibo.forget({ memoryId: "..." }, { reason: "asked by user" });
forget has overloads: with dryRun: true it returns the matches and changes nothing.

What recall returns

pack is the JSON the API sends, plus a few helpers so you do not dig through it:
pack.foundtrue when something citable matched. In TypeScript this narrows pack.top and pack.answer to non-null
pack.answerthe best match's text
pack.topthe best match as an item (pass it to explain, memories.edit, verifyMemory)
pack.textevery item's text, one per line, for a prompt
pack.sourcesthe source events, each listed once
pack.reasonwhy there is no answer, when there is none
pack.items, pack.abstainthe raw fields, as in the API reference
The helpers are not part of the JSON, so JSON.stringify(pack) and verifyPack(pack) see exactly what the server sent.
explain returns { memory, chain, events }. Each chain entry has the content it said, its status and validity dates, so a history reads without extra requests.

Memory in your prompt

const memory = await kaibo.context("what did we decide about the release?");
context is recall rendered as text: delimited as stored data (with a fresh nonce, so stored text cannot forge the end marker), with citations, and with outdated, unverified and untrusted items marked. When recall abstains it returns a line telling the model not to guess. renderContext(pack) does the same for a pack you already have.

Streaming

for await (const event of kaibo.recall.stream("who owns the smoke tests")) { if (event.type === "final") console.log(event.pack); }

Lists and jobs

for await (const e of kaibo.events.list({ stream: "default" })) {} // follows cursors for await (const m of kaibo.memories.list({ status: "superseded" })) {} await kaibo.jobs.wait(jobId, { timeoutMs: 5000 });

Verify the chain

import { verifyStream } from "kaibo/verify"; const { events, result } = await verifyStream(kaibo, "default");

Import, export, keys

const dry = await kaibo.imports.create({ source: "mem0", content: fileText }, { dryRun: true }); // report only const done = await kaibo.imports.create({ source: "letta", content: afText }); for await (const r of kaibo.exports.stream({ include: ["events"] })) {} // throws if cut off before the end record const key = await kaibo.keys.create({ label: "ci", scopes: ["read"] }); // admin key; key.key is shown once await kaibo.keys.list(); await kaibo.keys.revoke(key.id);
Imports are retried safely (idempotency keys come from the records). Exports and key creation are never retried.

Webhooks

import { verifyWebhook } from "kaibo/webhooks"; const event = await verifyWebhook(await req.text(), req.headers.get("x-kaibo-signature"), secret);

Errors and retries

Every failure is a KaiboError: ApiError (has code, status, requestId), RateLimitError (has retryAfter), NetworkError, TimeoutError. Reads and remember retry on 408, 429 and 5xx with exponential backoff and full jitter, and honor Retry-After. remember adds an idempotency key so a retry cannot double-write. forget and webhook creation are never retried.