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

@alphaone/ai-memory

v0.6.4

Published

TypeScript SDK for the ai-memory HTTP API — persistent, tier-aware memory for AI agents.

Readme

@alphaone/ai-memory

TypeScript SDK for the ai-memory HTTP API — persistent, tier-aware memory for AI agents, built on top of the same daemon that powers the MCP server.

Status: 0.6.0-alpha.0. Target server is ai-memory v0.6.0 HTTP API at /api/v1/. Some endpoints (subscriptions, notify/inbox, cluster, metrics, grant/revoke) target v0.6.0.0 shape and may not be merged server-side yet.

Install

npm install @alphaone/ai-memory
# or
pnpm add @alphaone/ai-memory
# or
yarn add @alphaone/ai-memory

This SDK is not yet published to npm. During the alpha, consume it via the workspace directly or a tarball (npm pack). See the root ROADMAP.

Quickstart

import { AiMemoryClient } from "@alphaone/ai-memory";

const memory = new AiMemoryClient({
  baseUrl: "http://localhost:9077",
  apiKey: process.env.AI_MEMORY_API_KEY,     // optional
  agentId: "ai:claude-opus-4.7@laptop:pid-1234", // optional default header
});

// Store
const m = await memory.store({
  title: "DNS zone refresh procedure",
  content: "Run `rndc reload` then check SERIAL bump in named.log …",
  tier: "long",
  namespace: "ops/dns",
  tags: ["bind9", "runbook"],
  priority: 8,
});

// Recall — fuzzy, scored, mutates access_count + TTL
const hits = await memory.recall({
  context: "how do I refresh a dns zone",
  namespace: "ops/dns",
  limit: 5,
});
for (const hit of hits.memories) {
  console.log(hit.score.toFixed(3), hit.title);
}

Methods

All methods return typed Promise<T> and throw typed errors (see Error handling). RequestOptions (last argument) lets you override agentId, pass an AbortSignal, or add custom headers.

| Method | Endpoint | Description | | --- | --- | --- | | store(body, opts?) | POST /api/v1/memories | Create a new memory. | | storeBulk(memories, opts?) | POST /api/v1/memories/bulk | Batch insert up to 1000. | | get(id, opts?) | GET /api/v1/memories/:id | Fetch by id. | | update(id, body, opts?) | PUT /api/v1/memories/:id | Patch fields. | | delete(id, opts?) | DELETE /api/v1/memories/:id | Delete by id. | | promote(id, opts?) | POST /api/v1/memories/:id/promote | Promote to long tier. | | list(query?, opts?) | GET /api/v1/memories | Paginated list with filters. | | recall(body, opts?) | POST /api/v1/recall | Fuzzy hybrid recall. | | search(query, opts?) | GET /api/v1/search | AND keyword search. | | forget(body, opts?) | POST /api/v1/forget | Bulk delete by pattern/ns/tier. | | link(body, opts?) | POST /api/v1/links | Link two memories. | | getLinks(id, opts?) | GET /api/v1/links/:id | Fetch all links for a memory. | | stats(opts?) | GET /api/v1/stats | Aggregate stats. | | health(opts?) | GET /api/v1/health | Liveness probe. | | namespaces(opts?) | GET /api/v1/namespaces | List namespaces w/ counts. | | agents(opts?) | GET /api/v1/agents | List registered agents. | | registerAgent(body, opts?) | POST /api/v1/agents | Register an NHI. | | metrics(opts?) | GET /api/v1/metrics | Prometheus text-format. | | subscribe(body, opts?) | POST /api/v1/subscriptions | Register a webhook. | | unsubscribe(id, opts?) | DELETE /api/v1/subscriptions/:id | Remove a webhook. | | listSubscriptions(opts?) | GET /api/v1/subscriptions | List current webhooks. | | grant(memoryId, body, opts?) | POST /api/v1/memories/:id/grant | Grant access. | | revoke(memoryId, body, opts?) | POST /api/v1/memories/:id/revoke | Revoke access. | | notify(body, opts?) | POST /api/v1/notify | Send inbox message. | | inbox(query?, opts?) | GET /api/v1/inbox | Read inbox. | | cluster(body, opts?) | POST /api/v1/cluster | Peer management. |

Examples

.store()

await memory.store({
  title: "Rust trait bounds refresher",
  content: "Trait bounds `where T: Send + Sync` …",
  tier: "mid",
  namespace: "rust",
  tags: ["rust", "traits"],
  priority: 6,
  confidence: 0.9,
  metadata: { source_commit: "abc123" },
});

.recall()

const { memories, tokens_used } = await memory.recall({
  context: "what's our nginx reload command?",
  namespace: "ops",
  budget_tokens: 2000,
});

.search()

const { results } = await memory.search({
  q: "bind9 AND reload",
  namespace: "ops/dns",
  limit: 20,
});

.list()

const { memories } = await memory.list({
  namespace: "rust",
  tier: "long",
  limit: 50,
  offset: 0,
});

.get() / .delete()

const m = await memory.get("b4e3…");
await memory.delete("b4e3…");

.subscribe() + webhook verification

import express from "express";
import { verifyWebhookSignature } from "@alphaone/ai-memory/webhooks";

const sub = await memory.subscribe({
  callback_url: "https://myapp.example.com/webhooks/ai-memory",
  events: ["memory.stored", "memory.updated"],
  secret: process.env.WEBHOOK_SECRET,
});

const app = express();
app.post(
  "/webhooks/ai-memory",
  express.raw({ type: "application/json" }),
  (req, res) => {
    const sig = String(req.header("X-AI-Memory-Signature") ?? "");
    if (!verifyWebhookSignature(req.body, sig, process.env.WEBHOOK_SECRET!)) {
      return res.status(401).send("bad signature");
    }
    const event = JSON.parse(req.body.toString("utf8"));
    console.log("event", event);
    res.status(204).end();
  },
);

.unsubscribe()

await memory.unsubscribe(sub.id);

.notify() / .inbox()

await memory.notify({
  to: "ai:codex-5.4@ci:pid-42",
  subject: "review needed",
  body: "please approve pending action pa_123",
  memory_id: "b4e3…",
});

const { messages, unread } = await memory.inbox({ unread: true, limit: 20 });

.grant() / .revoke()

await memory.grant("b4e3…", { agent_id: "alice", permission: "read" });
await memory.revoke("b4e3…", { agent_id: "alice" });

.cluster()

const { peers } = await memory.cluster({ action: "list" });

.agents() / .registerAgent()

await memory.registerAgent({
  agent_id: "ai:claude-opus-4.7@ci:pid-99",
  agent_type: "ai:claude-opus-4.7",
  capabilities: ["memory_write", "memory_recall"],
});
const { agents } = await memory.agents();

.health()

const h = await memory.health();
if (h.status !== "ok") throw new Error("memory daemon unhealthy");

Agent identity (NHI)

agent_id precedence (from docs/CLAUDE.md §Agent Identity):

  1. Explicit body-level agent_id on .store() / .registerAgent() etc.
  2. X-Agent-Id HTTP header — set via new AiMemoryClient({ agentId }) or per-call opts.agentId.
  3. Server-side anonymous:req-<uuid8> fallback (logged at WARN).

The id must match the regex ^[A-Za-z0-9_\-:@./]{1,128}$ — permits prefixed forms like ai:claude-opus-4.7@host:pid-123 and future SPIFFE-style ids. Rejects whitespace, null bytes, control chars, shell metacharacters.

Authentication

API key (X-API-Key)

The daemon's api_key_auth middleware checks X-API-Key (or ?api_key= query param) when an API key is configured. Pass it to the client once:

const memory = new AiMemoryClient({
  baseUrl: "https://memory.internal",
  apiKey: process.env.AI_MEMORY_API_KEY,
});

mTLS

ai-memory itself is HTTP-only by design. Terminate TLS and client-certificate auth at a reverse proxy (nginx, Caddy, Envoy) in front of the daemon, then forward the verified identity via a header to the backend.

Example nginx snippet:

server {
  listen 443 ssl;
  ssl_certificate     /etc/ssl/memory.crt;
  ssl_certificate_key /etc/ssl/memory.key;
  ssl_client_certificate /etc/ssl/ca.crt;
  ssl_verify_client on;

  location / {
    proxy_set_header X-Agent-Id $ssl_client_s_dn_cn;
    proxy_pass http://127.0.0.1:9077;
  }
}

Error handling

All methods reject with a typed error:

import {
  ApiError,
  ValidationError,
  UnauthorizedError,
  NotFoundError,
  ConflictError,
  ServerError,
  NetworkError,
} from "@alphaone/ai-memory";

try {
  await memory.get("bogus");
} catch (err) {
  if (err instanceof NotFoundError) {
    // 404
  } else if (err instanceof ValidationError) {
    // 400 — err.message carries the server's reason
  } else if (err instanceof UnauthorizedError) {
    // 401/403 — missing or bad API key
  } else if (err instanceof ApiError) {
    console.error(err.status, err.code, err.message);
  } else if (err instanceof NetworkError) {
    // connection refused, DNS, TLS, timeout, etc.
  } else {
    throw err;
  }
}

Claude Code / Cursor integration

Claude Code (MCP server already includes memory tools)

Run ai-memory as the MCP server and this SDK in your own tooling scripts:

// ~/.config/claude-code/settings.json
{
  "mcpServers": {
    "memory": { "command": "ai-memory", "args": ["serve"] }
  }
}

Inside a Claude Code slash command script (or hook) you can call the HTTP SDK against the same daemon, e.g. to fan-out a memory bulk-create from a CI hook:

import { AiMemoryClient } from "@alphaone/ai-memory";
const mem = new AiMemoryClient({ baseUrl: "http://localhost:9077" });
await mem.storeBulk(newFacts.map(f => ({ title: f.title, content: f.body, tier: "long" })));

Cursor

In Cursor's .cursorrules or a project-level script, use the same client. Cursor's agent surface will find stored memories via the MCP server; the SDK is for bespoke tool integrations (post-commit hooks, review automation).

Claude desktop extensions

Register the SDK-driven tool under .claude/commands/*.ts and import the client as shown in Quickstart.

Browser usage

undici.fetch is a Node module. For browsers, pass the native fetch:

import { AiMemoryClient } from "@alphaone/ai-memory";
// @ts-ignore - browser globalThis.fetch
const memory = new AiMemoryClient({ baseUrl: "/api" }, globalThis.fetch);

Webhook verification (verifyWebhookSignature) uses node:crypto; for the browser use the Web Crypto API (crypto.subtle.importKey + sign("HMAC")) — not yet shipped in this package.

Development

npm install        # (not run by the scaffold generator — review first)
npm run typecheck  # tsc --noEmit
npm run build      # emit ./dist
AI_MEMORY_TEST_DAEMON=1 npm test   # integration tests against a live daemon

Links