npm install ai-histThe SDK is the same engine the CLI and MCP server use: one Rust core loaded as a prebuilt Node-API addon. Every API is async.
Discover, list, read
import {
discoverSessions,
hydrateSession,
listSessionCatalogPage,
getSession,
getSessionEventsPage,
sessionEvents,
search,
} from 'ai-hist';
await discoverSessions({ scope: 'local', limit: 100 });
const page = await listSessionCatalogPage({ scope: 'local', limit: 20 });
const first = page.sessions[0];
if (first) {
const { source, sessionId } = first;
await hydrateSession({ source, sessionId, scope: 'local' });
// Session ids collide across providers, so every read names the source too.
const prompts = await getSession(sessionId, { source });
const events = await getSessionEventsPage(sessionId, { source, limit: 200 });
for await (const event of sessionEvents(sessionId, { source })) {
// walks every page without holding the whole transcript in memory
}
}
const matches = await search('authentication', { scope: 'all' });| Call | Work it does |
|---|---|
listSessionCatalog / listSessionCatalogPage | Cache only. |
discoverSessions | Shallow discovery: refreshes catalog metadata. |
hydrateSession | Full indexing of one cataloged session. Returns hydrated, updated, unchanged, or capability_limited. |
sync | Full ingestion of every selected source. |
Reads on a missing database return empty results; they never trigger provider I/O.
Tool calls and file edits
Each comes as a page, an iterator, and a collecting convenience, and takes a source and a session id:
import { getSessionToolCallsPage, sessionToolCalls, sessionFileEdits } from 'ai-hist';
const tools = await getSessionToolCallsPage('claude', sessionId, { limit: 200 });
for await (const call of sessionToolCalls('claude', sessionId)) consume(call);
for await (const edit of sessionFileEdits('claude', sessionId)) consume(edit);A source outside the known set throws InvalidArgumentError rather than reading as an empty session. Use CATALOG_SOURCES and isCatalogSource() to validate input without copying the provider list.
Subagent trees
import { getSessionRelationships, getSessionTree, sessionEventsIncludingDescendants } from 'ai-hist';
const { asParent, asChild } = await getSessionRelationships({ source: 'codex', sessionId: rootId });
const tree = await getSessionTree({ source: 'codex', sessionId: rootId, maxDepth: 8 });
for await (const event of sessionEventsIncludingDescendants({ source: 'codex', sessionId: rootId })) {
// event.sessionId is the session that produced it, never rewritten to the root
}See Sessions for observed versus unlinked relationships.
Scopes
Collection and acquisition calls, including hydrateSession, take scope: 'local' | 'remote' | 'all', defaulting to 'local'. Hydrating a remote-only session needs scope: 'remote' or 'all' and a registered plugin. Results echo the requested scope, discovery reports locationsRun (what actually executed), and each session row lists the locations it was observed in. See Remote sources to register plugins.
Handoffs
createHandoff() and resumeHandoff() are the SDK form of the MCP handoff tools. See Handoffs.
From Rust
Rust programs depend on the ai-hist crate and use SessionStore::open, sync, sessions, session, and changes_since — no raw database connection. See the embedder guide.