npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@claiv/memory

v0.6.4

Published

Official JavaScript/TypeScript SDK for the Claiv Memory API (V6 - Catalog Memory + Deterministic Routing)

Readme

@claiv/memory

Official JavaScript/TypeScript SDK for the Claiv Memory API, aligned with the current V6.3 API.

Installation

npm install @claiv/memory

Quick Start

import { ClaivClient } from '@claiv/memory';

const client = new ClaivClient({ apiKey: 'your-api-key' });

// Store a memory event
await client.ingest({
  user_id: 'user-123',
  conversation_id: 'session-abc',   // required: stable conversation scope
  type: 'message',
  role: 'user',
  content: 'I use React and TypeScript at work.',
});

// Recall relevant memory
const result = await client.recall({
  user_id: 'user-123',
  conversation_id: 'session-abc',
  query: 'What stack does this user work with?',
});

// Inject the pre-synthesized narrative into your LLM
const messages = [
  { role: 'system', content: result.llm_context.text || 'No memory found.' },
  { role: 'user',   content: userMessage },
];

Memory Scoping

Facts and document chunks can be scoped to control visibility across recalls:

| scope | Visible when | |---------|-------------| | 'global' (default) | All recalls for this user | | 'project' | Same project_id only | | 'conversation' | Same conversation_id only |

// Global memory — visible everywhere (default)
await client.ingest({
  user_id: 'user-123',
  conversation_id: 'session-abc',
  type: 'message',
  role: 'user',
  content: 'My name is Alex.',
  // scope: 'global' is the default
});

// Project-scoped — only visible within this project
await client.ingest({
  user_id: 'user-123',
  conversation_id: 'session-abc',
  project_id: 'project-xyz',
  scope: 'project',
  type: 'message',
  role: 'user',
  content: 'This project uses Next.js and Prisma.',
});

// Conversation-scoped — only visible in this session
await client.ingest({
  user_id: 'user-123',
  conversation_id: 'session-abc',
  scope: 'conversation',
  type: 'message',
  role: 'user',
  content: 'Actually, ignore the last instruction.',
});

API Reference

new ClaivClient(options)

| Option | Type | Default | Description | |--------------|------------|-------------------------|-----------------------------------| | apiKey | string | required | API key (sent as Bearer token) | | baseUrl | string | https://api.claiv.io | API base URL | | timeout | number | 30000 | Request timeout in milliseconds | | maxRetries | number | 2 | Retries on 429/5xx (0 to disable) | | fetch | function | globalThis.fetch | Custom fetch implementation |

Core Methods

client.ingest(request) / client.ingestV6(request)

Store a memory event.

const { event_id, deduped } = await client.ingest({
  user_id: 'user-123',              // required
  conversation_id: 'session-abc',   // required
  project_id: 'project-xyz',        // provide when using project-scoped facts
  scope: 'global',                  // optional: 'global' | 'project' | 'conversation'
  type: 'message',                  // required: 'message' | 'tool_call' | 'app_event'
  role: 'user',                     // optional: 'user' | 'assistant' | 'system' | 'tool'
  content: 'The actual text',       // required
  metadata: { source: 'chat' },     // optional: arbitrary key-value pairs
  event_time: '2025-01-01T00:00:00Z', // optional: ISO 8601 or Unix timestamp
  idempotency_key: 'msg-001',       // optional: prevents duplicate ingestion
});

client.recall(request) / client.recallV6(request)

Retrieve relevant memory for a query. Automatically includes matching document chunks in llm_context.text when documents exist for the user.

Document retrieval mode is auto-detected from the query:

  • Semantic (default): top-K chunks by cosine similarity, controlled by limits.document_chunks.
  • Working-set: triggered by structural references ("chapter 3", "the introduction") — returns the full section plus a document summary and summaries of other sections.
const result = await client.recall({
  user_id: 'user-123',              // required
  conversation_id: 'session-abc',   // required
  project_id: 'project-xyz',        // optional: include project-scoped facts
  document_id: 'doc_uuid',          // optional: restrict to a specific document
  query: 'What stack does this user prefer?', // required
  reference_time: null,             // optional: ISO datetime for temporal anchoring
  limits: {
    answer_facts: 12,               // default: 12
    supporting_facts: 12,           // default: 12
    background_facts: 30,           // default: 30
    document_chunks: 5,             // default: 5 — max chunks in semantic mode (1–50)
  },
  include: {
    pending_plan: true,             // default: true
    debug: false,                   // default: false
  },
});

// result.llm_context.text       → pre-synthesized narrative (inject as system prompt)
// result.answer_facts           → Array<RecallFact> — direct answers to the query
// result.supporting_facts       → Array<RecallFact> — corroborating evidence
// result.background_context     → Array<RecallFact> — broader user context
// result.working_memory         → WorkingMemory | null — current conversation state
// result.routing                → { mode, kinds, predicates, temporal_intent }

Recommended system prompt pattern:

const systemPrompt = result.llm_context.text
  ? `You are a helpful assistant. Here is what you remember about this user:\n\n${result.llm_context.text}`
  : 'You are a helpful assistant.';

client.uploadDocument(request)

Upload and index a document for RAG retrieval. Chunking and embedding happen synchronously — the document is fully indexed when the response returns.

const result = await client.uploadDocument({
  user_id: 'user-123',              // required
  content: documentText,            // required: full document text (up to 5 MB)
  document_name: 'Product Manual',  // required: shown as citation in llm_context
  document_id: 'manual-v2',         // optional: stable ID; re-uploading replaces all chunks
  conversation_id: 'session-abc',   // optional: scope chunks to this conversation
  project_id: 'project-xyz',        // optional: scope chunks to this project
  scope: 'global',                  // optional: 'global' | 'project' | 'conversation'
  chunk_size: 800,                  // optional: target chars per chunk (200–4000)
  chunk_overlap: 100,               // optional: overlap between chunks (0–500)
});

// result.document_id       → use on recall to target this document
// result.chunks_ingested   → number of chunks stored
// result.chunk_ids         → UUIDs for each stored chunk

// The document is now ready — no polling needed.
// Subsequent recalls will automatically include matching chunks in llm_context.text.

// To target recall at this document only:
const recall = await client.recall({
  user_id: 'user-123',
  conversation_id: 'session-abc',
  query: 'What does the manual say about installation?',
  document_id: result.document_id,
});

// To delete the document later:
await client.forget({
  user_id: 'user-123',
  document_id: result.document_id,
});

client.forget(request)

Delete memory matching a scope.

const { receipt_id, deleted_counts } = await client.forget({
  user_id: 'user-123',                    // required
  conversation_id: 'session-abc',         // optional
  project_id: 'project-xyz',              // optional
  document_id: 'manual-v2',              // optional: removes all chunks for this document
  from_time: '2025-01-01T00:00:00Z',      // optional: lower bound
  to_time:   '2025-06-01T00:00:00Z',      // optional: upper bound
});
// deleted_counts: { events, chunks, episodes, facts, claims, open_loops }

Usage Methods

// Aggregated summary with daily breakdown ('7d' | '30d' | 'month' | 'today')
const summary = await client.getUsageSummary('30d');

// Breakdown by endpoint
const breakdown = await client.getUsageBreakdown('today');

// Current plan limits and quota
const limits = await client.getUsageLimits();

Health Check

const { ok } = await client.healthCheck(); // no auth required

Error Handling

All errors extend ClaivError.

import { ClaivApiError, ClaivTimeoutError, ClaivNetworkError } from '@claiv/memory';

try {
  await client.ingest({ ... });
} catch (err) {
  if (err instanceof ClaivApiError) {
    console.log(err.status);    // HTTP status code
    console.log(err.code);      // 'invalid_request' | 'unauthorized' | 'quota_exceeded' | ...
    console.log(err.requestId); // server request ID for support
    console.log(err.details);   // validation errors, quota info, etc.
  } else if (err instanceof ClaivTimeoutError) {
    // request timed out
  } else if (err instanceof ClaivNetworkError) {
    // DNS failure, connection refused, etc.
  }
}

Retries

The SDK automatically retries on 429 (rate limited) and 5xx (server error) responses with exponential backoff and jitter. Client errors (400, 401, 403, 404) are never retried.

const client = new ClaivClient({ apiKey: 'key', maxRetries: 0 }); // disable retries
const client = new ClaivClient({ apiKey: 'key', maxRetries: 5 }); // more retries

TypeScript

All request/response types are exported:

import type {
  // Core V6 types
  MemoryScope,
  IngestRequest,    IngestResponse,
  RecallRequest,    RecallResponse,
  RecallFact,       WorkingMemory,    PendingPlan,
  V6LLMContext,     V6TemporalMatch,
  ForgetRequest,    ForgetResponse,   DeletedCounts,
  // Document types
  DocumentUploadRequest, DocumentUploadResponse,
  // Usage types
  UsageSummaryResponse, UsageBreakdownResponse, UsageLimitsResponse,
} from '@claiv/memory';