FishMem

Quickstart

Install the fishmem engine and run your first add and search in your own code.

This page gets the fishmem engine running inside your own application — no hosted API, no API key. You construct a Memory instance, add a memory, and search it back.

The method surface (add, search, get, update, delete, history) matches the hosted FishMem Cloud API, so code you write against the engine moves to the cloud as a client change, not a rewrite.

Install

npm i fishmem

Set provider keys

The engine needs an LLM provider (for fact extraction and reconciliation) and an embedding provider (to turn facts into vectors). Both default to OpenAI-style APIs. Set your key in the environment:

export OPENAI_API_KEY="sk-..."

If your LLM and embeddings live behind different keys or endpoints, set them explicitly in the config object — see Configuration.

Instantiate Memory

Construct a Memory instance with your providers, a graph store, and a vector index. The example below uses the bundled local stores, which are the simplest way to get running; swap them for D1 + Vectorize or other backends in Configuration.

memory.ts
import { Memory } from 'fishmem'

export const memory = new Memory({
  llm: {
    provider: 'openai',
    model: 'gpt-4o-mini',
    apiKey: process.env.OPENAI_API_KEY,
  },
  embedder: {
    provider: 'openai',
    model: 'text-embedding-3-small',
    apiKey: process.env.OPENAI_API_KEY,
  },
  graphStore: { provider: 'local', path: './fishmem.db' },
  vectorStore: { provider: 'local', path: './fishmem.vec' },
})
memory.py
from fishmem import Memory

memory = Memory(config={
    "llm": {"provider": "openai", "model": "gpt-4o-mini"},
    "embedder": {"provider": "openai", "model": "text-embedding-3-small"},
    "graph_store": {"provider": "local", "path": "./fishmem.db"},
    "vector_store": {"provider": "local", "path": "./fishmem.vec"},
})

Add a memory

Pass conversation messages and a scope. The engine extracts the durable facts — it does not store the raw text. The result lists what changed.

add.ts
import { memory } from './memory'

const result = await memory.add(
  [{ role: 'user', content: 'I prefer dark mode and write TypeScript.' }],
  { userId: 'alex' },
)

console.log(result)
// [{ id: 'mem_...', memory: 'Prefers dark mode', event: 'ADD' },
//  { id: 'mem_...', memory: 'Writes TypeScript', event: 'ADD' }]

Scope every memory with at least one of userId, agentId, or runId. Scopes keep one user's memories from leaking into another's search. See Scoping.

Search it back

Search runs hybrid recall — vector similarity, keyword match, temporal ordering, and graph diffusion — and returns the relevant facts for the same scope.

search.ts
import { memory } from './memory'

const hits = await memory.search('what does alex like?', {
  userId: 'alex',
  topK: 5,
})

console.log(hits)
// [{ id: 'mem_...', memory: 'Prefers dark mode', score: 0.82 }, ...]

That is the whole loop: add during a conversation, search before you answer. Pass infer: false on add when you want to store content verbatim instead of extracting facts — see How memory works.

Next steps

On this page