kaibo has no runtime dependencies, works anywhere fetch does (Node 20+, Bun, Deno, Workers, browsers), and ships ESM and CJS.1bun add kaibo # or npm install, pnpm add, yarn add
12345import { 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) })
code, the requestId, and a hint for the common ones.1234await 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.pack is the JSON the API sends, plus a few helpers so you do not dig through it:pack.found | true when something citable matched. In TypeScript this narrows pack.top and pack.answer to non-null |
pack.answer | the best match's text |
pack.top | the best match as an item (pass it to explain, memories.edit, verifyMemory) |
pack.text | every item's text, one per line, for a prompt |
pack.sources | the source events, each listed once |
pack.reason | why there is no answer, when there is none |
pack.items, pack.abstain | the raw fields, as in the API reference |
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.1const 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.123for await (const event of kaibo.recall.stream("who owns the smoke tests")) { if (event.type === "final") console.log(event.pack); }
123for 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 });
12import { verifyStream } from "kaibo/verify"; const { events, result } = await verifyStream(kaibo, "default");
12345const 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);
12import { verifyWebhook } from "kaibo/webhooks"; const event = await verifyWebhook(await req.text(), req.headers.get("x-kaibo-signature"), secret);
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.