@membank/core
v0.19.0
Published
Core library for membank — handles storage, embeddings, deduplication, and semantic search.
Readme
@membank/core
Core library for membank — handles storage, embeddings, deduplication, and semantic search.
Overview
Provides the database layer, embedding inference, and query engine that all other membank packages build on. Uses SQLite with vector search for local, offline-capable memory storage.
Requirements
- Node.js >=24
- Native modules:
better-sqlite3,sqlite-vec(pre-built binaries, not compiled on install)
Installation
npm install @membank/coreStorage
Memories are stored in ~/.membank/memory.db (SQLite). Embeddings live in a sqlite-vec virtual table alongside the main memories table.
Default location can be overridden via DatabaseManager.open(customPath).
Usage
Initialize
import { DatabaseManager, EmbeddingService, MemoryRepository, ProjectRepository, QueryEngine } from '@membank/core'
const db = DatabaseManager.open()
const embedding = new EmbeddingService()
const projects = new ProjectRepository(db)
const repo = new MemoryRepository(db, embedding, projects)
const engine = new QueryEngine(db, embedding, repo)Save a memory
const memory = await repo.save({
content: 'Always use `--filter` when running pnpm commands in this monorepo',
type: 'preference',
tags: ['pnpm', 'monorepo'],
})Query memories
const results = await engine.query({
query: 'how to run commands in one package',
limit: 5,
})
for (const { content, score } of results) {
console.log(score.toFixed(3), content)
}Session injection
import { SessionContextBuilder } from '@membank/core'
const builder = new SessionContextBuilder(db)
const { stats, pinnedGlobal, pinnedProject } = builder.getSessionContext(projectHash)Memory types
Types are ranked by priority, which affects query scoring:
| Type | Weight | When to use |
|------|--------|-------------|
| correction | 1.0 | A mistake was made and corrected |
| preference | 0.8 | Tool, style, or pattern preference |
| decision | 0.6 | Architectural or design choice |
| learning | 0.4 | Concept understood or insight gained |
| fact | 0.2 | Static reference information |
Deduplication
On every save, the new content is embedded and compared against existing memories of the same type and scope:
- Similarity >0.92 — auto-overwrites the existing memory (merge semantics)
- Similarity 0.75–0.92 — flags the existing memory with
needs_review=trueand creates a new entry - Similarity <0.75 — creates a new memory with no conflict
Query scoring
Results are ranked by a weighted combination of signals:
score = 0.40 × type_weight
+ 0.30 × access_frequency # count / (count + 10)
+ 0.20 × recency # 1 / (1 + days_since_update)
+ 0.10 × is_pinnedScope
Each memory is tagged with a scope derived from the project's git remote URL (SHA256, first 16 chars). Falls back to a hash of the current working directory if git is unavailable. Global memories use "global" as scope.
import { resolveProject, resolveScope } from '@membank/core'
const { hash, name } = await resolveProject() // preferred: returns hash + repo name
const scopeHash = await resolveScope() // returns hash string onlyEmbeddings
Uses Xenova/bge-small-en-v1.5 (384 dimensions, ~33 MB) via @huggingface/transformers. The model is downloaded on first use and cached at ~/.membank/models/. All inference runs locally on CPU — no network calls after initial download.
API
DatabaseManager
DatabaseManager.open(dbPath?: string): DatabaseManager
DatabaseManager.openInMemory(): DatabaseManagerEmbeddingService
new EmbeddingService(options?: { progressCallback? })
embed(text: string): Promise<Float32Array>MemoryRepository
save(options: SaveOptions): Promise<Memory>
update(id: string, patch: Partial<SaveOptions>): Promise<Memory>
delete(id: string): void
list(opts?: { type?: MemoryType; pinned?: boolean }): Memory[]
stats(): MemoryStats
incrementAccessCount(id: string): voidQueryEngine
query(options: QueryOptions): Promise<Array<Memory & { score: number }>>SessionContextBuilder
new SessionContextBuilder(db: DatabaseManager)
getSessionContext(projectHash: string, synthesis?: string): SessionContextlistMemoryTypes
Standalone function (not a class method):
import { listMemoryTypes } from '@membank/core'
listMemoryTypes(): MemoryType[]