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

brian-memory

v0.1.0

Published

TypeScript SDK for Brian Memory — persistent memory for AI agents

Readme

brian-memory

TypeScript/JavaScript SDK for Brian Memory — persistent memory for AI agents.

Zero runtime dependencies. Uses built-in fetch (Node 18+).

Installation

npm install brian-memory

Quick Start

import { BrianMemory } from "brian-memory";

const client = new BrianMemory({ apiKey: "brian_..." });
await client.store({ content: "User prefers dark mode", tags: ["preferences"] });
const results = await client.search({ query: "dark mode" });
console.log(results.results);

Authentication

Pass your API key when creating the client. Optionally provide an encryption key for BYOK encryption:

const client = new BrianMemory({
  apiKey: "brian_...",
  encryptionKey: "a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2", // optional, 256-bit hex key for server-side BYOK encryption
});

The API key is sent via the X-API-Key header on every request.

Core Operations

Store a Memory

const result = await client.store({
  content: "PostgreSQL uses MVCC for concurrency control",
  memory_type: "semantic",       // "semantic", "episodic", or "procedural"
  project_id: "my-project",
  memory_scope: "project",       // "global", "project", "agent", "user", "session"
  tags: ["databases", "postgres"],
  metadata: { source: "docs" },
  confidence: 0.95,
  force_store: false,            // bypass deduplication
  valid_from: "2025-01-01T00:00:00Z",
});
console.log(result.id, result.status); // "stored", "duplicate_found", etc.

Search Memories

const results = await client.search({
  query: "concurrency control",
  memory_type: "semantic",
  project_id: "my-project",
  tags: ["databases"],
  limit: 10,
  min_relevance: 0.3,
  detail_level: "summary",       // "ids", "summary", or "full"
  include_archived: false,
  as_of: "2025-06-01T00:00:00Z", // point-in-time search
});
for (const memory of results.results) {
  console.log(memory.content, memory.relevance_score);
}

Get a Memory

const memory = await client.get("memory-uuid");
console.log(memory.content, memory.tags);

Update a Memory

await client.update("memory-uuid", { content: "Updated content", tags: ["new-tag"] });

Delete and Restore

await client.delete("memory-uuid", { reason: "outdated" });
await client.restore("memory-uuid");

List Memories

const result = await client.list({
  project_id: "my-project",
  memory_type: "semantic",
  status: "active",              // "active", "archived", "deleted"
  tags: ["databases"],
  sort_by: "created_at",         // "created_at", "last_accessed_at", "access_count", "trust_score"
  sort_order: "desc",
  limit: 20,
  offset: 0,
});
for (const memory of result.results) {
  console.log(memory);
}

Analysis

Find Related Memories

const related = await client.related({
  id: "memory-uuid",
  limit: 5,
  min_similarity: 0.5,
  memory_type: "semantic",
  project_id: "my-project",
});

Compare Memories

const comparison = await client.compare(["uuid-1", "uuid-2", "uuid-3"]);

Timeline

const timeline = await client.timeline({
  project_id: "my-project",
  after: "2025-01-01T00:00:00Z",
  before: "2025-12-31T00:00:00Z",
  as_of: "2025-06-01T00:00:00Z",
  show_history: true,
});

Diff

const changes = await client.diff({
  after: "2025-01-01T00:00:00Z",
  before: "2025-06-01T00:00:00Z",
  project_id: "my-project",
});

Consolidate Duplicates

// Preview duplicate groups
const preview = await client.consolidate({ mode: "preview", threshold: 0.85, project_id: "my-project" });

// Merge them
const merged = await client.consolidate({ mode: "merge", threshold: 0.85, project_id: "my-project" });

Knowledge Graph

Search Entities

const entities = await client.graphSearch({ query: "PostgreSQL", entity_type: "technology", limit: 20 });

Explore Entity Relationships

const graph = await client.graphExplore("entity-uuid", { max_hops: 2, limit: 20 });

Get Entity Details

const entity = await client.graphEntity("entity-uuid");

Get Entities for a Memory

const entities = await client.memoryEntities("memory-uuid");

Mental Models

Mental models are auto-synthesized living documents built from scoped subsets of your memories.

Create a Model

const model = await client.createModel({
  name: "Project Architecture",
  scope_filter: { project_id: "my-project", tags: ["architecture"] },
  description: "Living doc of architectural decisions",
  auto_update: true,
  update_threshold: 5, // re-synthesize after 5 new matching memories
});
console.log(model.id, model.name);

Get a Model

const model = await client.getModel("model-uuid"); // also accepts name
console.log(model.content); // the synthesized document

List, Update, Delete

const models = await client.listModels({ status: "active" });
const updated = await client.updateModel("model-uuid", { name: "New Name", auto_update: false });
await client.deleteModel("model-uuid");

Trigger Re-synthesis

await client.synthesizeModel("model-uuid");

Export and Import

Streaming Export

for await (const memory of client.exportMemories({ format: "jsonl" })) {
  console.log(memory.content);
}

// Get export stats
const stats = await client.exportStats();

Bulk Import

const jsonlData = '{"content":"fact 1","memory_type":"semantic"}\n{"content":"fact 2","memory_type":"semantic"}';
const result = await client.importMemories(jsonlData, { format: "jsonl", skip_duplicates: true });
console.log(result);

API Key Management

// Create a new key
const newKey = await client.createKey("my-agent-key");
console.log(newKey.key); // full key, only shown once

// List keys
const keys = await client.listKeys();

// Revoke a key
await client.revokeKey("key-uuid");

Encryption (BYOK)

Brian supports bring-your-own-key encryption. Your data is encrypted server-side with your key — Brian never stores it.

// Enable encryption (256-bit key as 64 hex chars)
await client.enableEncryption("a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2");

// Check status
const status = await client.encryptionStatus();
console.log(status.enabled, status.key_version);

// Rotate key
await client.rotateEncryption(
  "a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2",
  "f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5a1b2c3d4e5f6a1b2c3d4e5f6a1b2",
);

// Disable encryption
await client.disableEncryption("a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2");

Once enabled, pass the encryption key on every request via the encryptionKey constructor option.

Configuration

const client = new BrianMemory({
  apiKey: "brian_...",                       // required
  baseUrl: "https://memory.example.com",        // or set BRIAN_URL env var
  timeout: 30_000,                          // milliseconds, default 30000
  maxRetries: 3,                            // default 3, exponential backoff
  encryptionKey: undefined,                 // optional BYOK encryption key
});

Error Handling

All errors extend BrianError, which includes status and body properties:

import {
  BrianError,
  AuthenticationError,     // 401 — invalid or missing API key
  ValidationError,         // 400 — invalid request parameters
  NotFoundError,           // 404 — memory or resource not found
  SensitiveContentError,   // 422 — blocked by sensitive content guard
  RateLimitError,          // 429 — rate/plan limit exceeded
  ServerError,             // 5xx — server error
} from "brian-memory";

try {
  await client.store({ content: "some content" });
} catch (e) {
  if (e instanceof RateLimitError) {
    console.log(`Rate limited. Retry after: ${e.retryAfter}s`);
  } else if (e instanceof SensitiveContentError) {
    console.log("Content blocked — contains sensitive data like API keys or passwords");
  } else if (e instanceof BrianError) {
    console.log(`Error ${e.status}: ${e.message}`);
  }
}

The client automatically retries on 429 (respecting Retry-After) and 5xx errors with exponential backoff, up to maxRetries attempts.

Requirements

  • Node.js 18+ (uses built-in fetch)
  • Zero runtime dependencies

Documentation

Full API reference and guides: https://memory.example.com/docs