# Wolbarg — Full Documentation
> Complete Markdown export of Wolbarg docs for AI systems. Prefer /llms.txt for a curated index.
Generated from 73 documentation pages.
---
# Architecture
> How Wolbarg subsystems connect — Application, Wolbarg, Storage, Retrieval, Providers, and Database.
URL: /docs/architecture
## What is it? [#what-is-it]
The structural model of Wolbarg: a thin orchestration layer over storage, retrieval, and swappable providers.
## Why does it exist? [#why-does-it-exist]
Understanding the pipeline makes configuration and failure modes predictable.
## How does it work? [#how-does-it-work]
### Application [#application]
Your agents, tools, or server. They hold one `Wolbarg` instance per process / organization and call the public API. Keep provider factories in a dedicated folder — see [Project layout](/docs/installation#project-layout).
### Wolbarg facade [#wolbarg-facade]
Owns lifecycle (`ready`, `close`), validates options, selects providers, and exposes `remember`, `recall`, `ingest`, `compress`, `forget`, `history`, `stats`, `clear`, `subscribe`, and related helpers.
### Memory operations [#memory-operations]
* **remember** — embed + insert + optional keyword index update
* **ingest** — parse → enrich → chunk → batch embed → batch insert
* **compress** — LLM summarize + optional archive
* **forget** — archive / delete by id or filter
### Retrieval pipeline [#retrieval-pipeline]
1. Embed query
2. Vector search (+ optional BM25 when `hybrid: true` and `keywordSearch` is configured)
3. Metadata / agent filters
4. Optional MMR
5. Optional rerank (requires `reranker`; fail-closed)
6. Return `RecallResult[]`
### Storage provider [#storage-provider]
Abstracts SQLite vs PostgreSQL: vectors, metadata, history, transactions, migrations.
### Providers [#providers]
Network or local adapters for embeddings, LLM, keyword search, rerank, OCR, vision, chunking, compression. Missing hybrid/rerank providers fail closed when those flags are set; other optional features fail cleanly per method.
### Database [#database]
Physical persistence — a SQLite file with WAL / FTS5 / sqlite-vec, or PostgreSQL with JSONB / optional pgvector.
## When should you read this? [#when-should-you-read-this]
Before choosing backends, tuning retrieval, or debugging hybrid/rerank errors (usually missing `keywordSearch` / `reranker`).
## Related pages [#related-pages]
* [Provider Architecture](/docs/providers)
* [Installation](/docs/installation)
* [Semantic Search](/docs/search)
* [SQLite Backend](/docs/storage/sqlite)
* [PostgreSQL Backend](/docs/storage/postgresql)
* [Production](/docs/guides/production)
* [What's New](/docs/guides/whats-new)
---
# Benchmarks
> Methodology and published results for Wolbarg v0.4.0 — dual-backend v4 stress, embedding cache, multi-process concurrency, and how to reproduce locally.
URL: /docs/benchmarks
## What is it? [#what-is-it]
How Wolbarg **v0.4.0** measures startup, batch/bulk insert, recall latency, embedding-cache behavior, upsert/dedupe correctness, `subscribe()` delivery, and concurrency on **SQLite and PostgreSQL**.
Two embedding modes — **do not mix them**:
| Suite | Embeddings | What it measures |
| --------------------------- | ----------------------------------- | ---------------------------------------------------------------------------------- |
| **Storage / stress** (mock) | Local mock OpenAI-compatible server | SDK + database ceiling (I/O, indexes, concurrency, cache hits with instant embeds) |
| **LIVE** | Real providers (OpenAI, etc.) | End-to-end latency including network + provider time |
Interactive charts: [/benchmarks](/benchmarks).
### Published 0.4 artifacts [#published-04-artifacts]
| Artifact | Contents |
| ------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------- |
| [`version-0.4.0-sqlite-benchmark.json`](/benchmarks/version-0.4.0-sqlite-benchmark.json) · [`.md`](/benchmarks/version-0.4.0-sqlite-benchmark.md) | Full v4 stress suite on SQLite |
| [`version-0.4.0-postgres-benchmark.json`](/benchmarks/version-0.4.0-postgres-benchmark.json) · [`.md`](/benchmarks/version-0.4.0-postgres-benchmark.md) | Full v4 stress suite on Postgres |
| [`embedding-cache.json`](/benchmarks/embedding-cache.json) | Provider-call reduction microbench |
| [`multiprocess-concurrency.json`](/benchmarks/multiprocess-concurrency.json) | Multi-process SQLite writers (2–20) |
| [`benchmark.json`](/benchmarks/benchmark.json) · [`benchmark.md`](/benchmarks/benchmark.md) | Prior dual-backend quick suite (historical) |
Public suite repo: [`wolbarg-benchmarks`](https://github.com/wolbarg/wolbarg-benchmarks).
## Why it exists [#why-it-exists]
Vendor graphs without methodology mislead. These docs explain *what was measured* so you can compare fairly and reproduce locally — especially the difference between **mock stress** and **live API spots**, and between **same-process** vs **multi-process** concurrency.
## Headlines — v0.4.0 (2026-07-18) [#headlines--v040-2026-07-18]
Environment: Node **v24.13.1** · win32/arm64 · **8 CPUs** · mock embeddings · suite `v4-stress`.
| Metric | SQLite | PostgreSQL |
| ---------------------- | ----------------------------- | ----------------------------- |
| Cold `ready()` | **16.18 ms** | **91.39 ms** |
| Warm reopen | 1.87 ms | 59.89 ms |
| `rememberBatch` 200 | **5,795 ops/s** | **2,795 ops/s** |
| Bulk insert 2k | **7,509 ops/s** | **4,085 ops/s** |
| Recall p50 @ 2k | 4.12 ms | 23.29 ms |
| Recall p95 @ 2k | **4.83 ms** | **141.5 ms** |
| Cache speedup (spot) | **1.47×** | **1.18×** |
| Concurrency 8 writers | 6,084 ops/s · p95 3.05 ms | 2,555 ops/s · p95 8.51 ms |
| Concurrency 16 writers | **8,660 ops/s** · p95 2.46 ms | **3,335 ops/s** · p95 9.48 ms |
| Concurrency 32 writers | 6,798 ops/s · p95 22.94 ms | 3,802 ops/s · p95 14.77 ms |
| Mixed read/write storm | 0 failures | 0 failures |
| Suite result | 25 pass / 0 fail | 21 pass / 0 fail / 4 skip\* |
\*Postgres skips SQLite-only checks (schema meta table probe, SQLite EventDatabase telemetry file, file checkpoints, export/import bundles).
### Embedding cache microbench [#embedding-cache-microbench]
| Metric | Value |
| ----------------------- | --------------------------------- |
| Workload | 100 chunks · 20 unique · 2 passes |
| Uncached provider calls | 100 |
| Cached provider calls | 20 |
| **Call reduction** | **90%** |
| Hits / misses | 180 / 20 |
Source: [`embedding-cache.json`](/benchmarks/embedding-cache.json) · runner `benchmark/embedding-cache-bench.ts`.
### Multi-process SQLite concurrency [#multi-process-sqlite-concurrency]
Shared file, separate OS processes, `BEGIN IMMEDIATE` + busy retry (v0.4):
| Writers | Throughput (ops/s) | p50 (ms) | p95 (ms) | p99 (ms) | Error rate | Integrity |
| ------- | ------------------ | -------- | -------- | -------- | ---------- | --------- |
| 2 | 123 | 0.77 | 3.17 | 9.66 | 0% | OK |
| 5 | 221 | 0.78 | 6.09 | 43.94 | 0% | OK |
| 10 | 246 | 0.81 | 15.48 | 52.66 | 0% | OK |
| 20 | 245 | 0.79 | 77.77 | 319.74 | 0% | OK |
Source: [`multiprocess-concurrency.json`](/benchmarks/multiprocess-concurrency.json) · runner `benchmark/multiprocess-levels.ts`.
## Feature coverage in the v4 suite [#feature-coverage-in-the-v4-suite]
Beyond raw speed, the 0.4 suite asserts product correctness:
| Area | Cases |
| --------------------------------- | --------------------------------------------------------------------------------- |
| Startup / schema | Cold + warm `ready()`, schema version |
| Batch throughput | `rememberBatch` ops/sec |
| Embedding cache | Cold vs hot embed latency / speedup |
| Dedupe | Exact upsert + metadata merge; dedupe-off still duplicates |
| Subscribe | `remember` / `update` / `forget` delivery; throwing subscriber isolaton |
| Telemetry / checkpoint / transfer | SQLite paths for observability snapshots |
| Edge | Org/agent isolation, unicode metadata, filters, hybrid+compress, forget integrity |
| Concurrency | 8 / 16 / 32 writers, mixed R/W storm, concurrent exact-dedupe uniqueness |
## Methodology [#methodology]
### Mock vs LIVE (read this) [#mock-vs-live-read-this]
**Primary stress and push-to-failure concurrency use a local mock OpenAI-compatible embedding/LLM server.** Live OpenAI is **not** used for failure ramps because API **rate limits and quota errors would dominate long before SQLite or PostgreSQL contention**, masking true Wolbarg/storage breaking points.
A separate **LIVE spot suite** (`npm run benchmark:live`) reports real-network latency for representative paths. It does **not** ramp concurrency to failure.
### Failure criteria (breaking ramps) [#failure-criteria-breaking-ramps]
When using breaking / brutal modes, a concurrency level fails when:
* `errorRate > 1%`, **or**
* `p95 latency > 5s`, **or**
* a hard integrity/exception failure (duplicate IDs, crash, etc.)
Reports record `lastHealthyLevel` and `breakingLevel` with reason (`error_rate` | `p95_sla` | `exception` | `integrity` | `cap`).
### Storage matrix [#storage-matrix]
| Backend | Notes |
| ---------- | --------------------------------------------------------------------------------------------------------------------------------------------------------- |
| SQLite | Local file + WAL + `BEGIN IMMEDIATE` (0.4) |
| PostgreSQL | **Local native Postgres only** (`pgvector`). Docker Compose paths/ports are rejected. Hosted Neon/Supabase/Railway URLs measure network RTT, not Wolbarg. |
```bash
cd benchmark
npm run postgres:up
npx tsx v4-stress.ts # or your package script wrapping it
npx tsx embedding-cache-bench.ts
npx tsx multiprocess-levels.ts
```
Vector backend caveat: benchmarks assume pgvector/HNSW is enabled for Postgres and sqlite-vec is available for SQLite. When extensions are missing/unloadable, Wolbarg falls back to exact cosine scanning, which can change recall latency substantially.
### Commands (legacy + 0.4 runners) [#commands-legacy--04-runners]
| Command | Mode | Notes |
| ---------------------------------- | ---- | ---------------------------------- |
| `npm run benchmark` | mock | Full dual-backend historical suite |
| `npm run benchmark:quick` | mock | Quick scale (100 / 1k) |
| `npm run benchmark:brutal` | mock | Failure ramps (up to 4096) |
| `npm run benchmark:live` | live | Spot only — **no** failure ramp |
| `npx tsx v4-stress.ts` | mock | **0.4** feature + stress suite |
| `npx tsx embedding-cache-bench.ts` | mock | Cache call-reduction |
| `npx tsx multiprocess-levels.ts` | mock | Multi-process SQLite levels |
### Metrics glossary [#metrics-glossary]
| Benchmark | What it means |
| --------------------------- | ---------------------------------------------------- |
| Startup cold/warm | Time to `ready()` + reopen |
| Batch / bulk insert ops/sec | Sustained `remember` / `rememberBatch` throughput |
| Recall p50/p95 | Semantic search latency at corpus size |
| Cache speedup | Hot vs cold embed path |
| Concurrency N writers | Fixed writer count throughput + p95 |
| Multiprocess levels | Separate OS processes vs shared SQLite file |
| Compression % | Active-set reduction after `compress` (legacy suite) |
| DB size / memory | On-disk and heap/RSS (legacy suite) |
### Hardware [#hardware]
Always read the environment block in the artifact you cite (Node, CPU, RAM, mode, backends, dims). The 0.4 publish used Node v24.13.1 · win32/arm64 · 8 CPUs.
### Dataset [#dataset]
Synthetic memories with fixed templates. Mock dims typically **384**; live typically **1536** (`text-embedding-3-small`). Labels (`100`, `1k`, `2k`) are memory counts.
### Reproducibility [#reproducibility]
```bash
cd benchmark
npm install
cp .env.example .env # DATABASE_URL for postgres; API keys for --live
npx tsx v4-stress.ts
npx tsx embedding-cache-bench.ts
npx tsx multiprocess-levels.ts
```
Prefer recording: date, SDK version (`wolbarg@0.4.0`), Node version, CPU/RAM, mode (`mock`/`live`), backends, and git SHA.
## Interpretation [#interpretation]
* **Startup ms** — agents open memory without multi-second cold starts
* **Bulk insert vs recall** — know when Postgres/pgvector or sharding strategies matter (Postgres recall p95 in this run is network/engine dominated vs SQLite in-process)
* **Same-process vs multi-process** — multi-process SQLite serializes; throughput plateaus while p95 climbs (expected)
* **Cache reduction** — measure provider **calls**, not only ms, when arguing cost
* **Mock ≠ hosted SaaS** — do not compare mock embed timings to managed GPU indexes
* **Storage (mock) ≠ LIVE** — never mix the two suites in one comparison cell
* **Competitor accuracy evals ≠ storage ops/sec** — see the policy on [/benchmarks](/benchmarks#competitors)
## Related pages [#related-pages]
* [Performance](/docs/performance)
* [Concurrency](/docs/concurrency)
* [Embedding cache](/docs/embedding-cache)
* [Architecture](/docs/architecture)
* [SQLite](/docs/storage/sqlite) · [PostgreSQL](/docs/storage/postgresql)
* Live page: [/benchmarks](/benchmarks)
* [What's New](/docs/guides/whats-new)
---
# Chunking
> Pluggable chunking strategies for document ingest — fixed, sentence, paragraph, markdown, heading.
URL: /docs/chunking
## What is it? [#what-is-it]
Replaceable strategies that split extracted document text into embeddable chunks before storage.
## Why does it exist? [#why-does-it-exist]
Embedding quality depends on chunk boundaries. Markdown headings need different splits than prose or logs.
## How does it work? [#how-does-it-work]
```ts
import { createChunkingStrategy } from "wolbarg";
createChunkingStrategy("fixed")
createChunkingStrategy("sentence") // default when no markdown headings
createChunkingStrategy("paragraph")
createChunkingStrategy("markdown") // auto-inferred when headings present
createChunkingStrategy("heading")
```
Per-call options:
```ts
await ctx.ingest({
agent: "docs",
source: { path: "./guide.md" },
chunking: {
strategy: "markdown",
chunkSize: 800,
overlap: 100,
},
});
```
Set a default on the constructor with `chunking: createChunkingStrategy("markdown")`.
## When should it be used? [#when-should-it-be-used]
* `markdown` / `heading` for docs sites and READMEs
* `paragraph` for long articles
* `sentence` for dense prose
* `fixed` for uniform token budgets
## Performance notes [#performance-notes]
* Smaller chunks improve precision, increase storage and recall noise
* Overlap reduces boundary drops for multi-sentence facts
* Batch embedding amortizes network cost during ingest
## Related pages [#related-pages]
* [Document Ingestion](/docs/document-ingestion)
* [Provider Architecture](/docs/providers)
* [Performance](/docs/performance)
---
# Compression Pipeline
> Summarize and archive memories with an optional LLM via compress().
URL: /docs/compression
## What is it? [#what-is-it]
`compress()` uses a configured LLM to summarize selected memories into a compact record and optionally archive the originals.
## Why does it exist? [#why-does-it-exist]
Long agent histories explode context and storage. Compression keeps signal while shrinking volume.
## How does it work? [#how-does-it-work]
Requires `llm` on the constructor (compile-time + runtime):
```ts
import { Wolbarg, sqlite, openaiEmbedding, openaiLlm } from "wolbarg";
const ctx = new Wolbarg({
organization: "my-org",
storage: sqlite("./memory.db"),
embedding: openaiEmbedding({ /* … */ }),
llm: openaiLlm({
apiKey: process.env.OPENAI_API_KEY!,
model: "gpt-4.1-mini",
}),
});
const result = await ctx.compress({
agent: "research",
// filter / ids / strategy options per CompressOptions
});
```
Without `llm`, TypeScript rejects `compress` and runtime throws `ProviderNotConfiguredError`.
## When should it be used? [#when-should-it-be-used]
Periodic maintenance jobs, end-of-session summarization, or when agent history exceeds a token budget.
## Performance notes [#performance-notes]
* Dominated by LLM latency and input size
* Published mock suite shows high reduction ratios — verify on your own texts
* Archive carefully if you need reversible history (`history()` still tracks events)
## Related pages [#related-pages]
* [Provider Architecture](/docs/providers)
* [Example — Compression](/docs/examples/compression)
* [API lifecycle](/docs/api/lifecycle)
---
# Concurrency
> Multi-process SQLite write safety in Wolbarg 0.4 — BEGIN IMMEDIATE, busy_timeout, exponential backoff, WOLBARG_STORAGE_LOCKED, and published multi-writer benchmarks.
URL: /docs/concurrency
## What is it? [#what-is-it]
Wolbarg **0.4** hardens **multi-process writers** against a single SQLite `memory.db` — the topology most multi-agent setups use (one Node process or worker per agent, one shared file).
Before 0.4, SQLite mutating paths used deferred `BEGIN`. Under concurrent writers that commonly produced `SQLITE_BUSY` at commit time after work had already started. 0.4 acquires the write lock **up front** and retries with backoff when the lock is contended.
## Guarantees [#guarantees]
| Guarantee | Detail |
| --------------------- | --------------------------------------------------------------------------------------- |
| **WAL mode** | Enabled by default so readers do not block writers |
| **`BEGIN IMMEDIATE`** | Mutating transactions take the write lock before doing work |
| **Busy timeout** | SQLite `busy_timeout` pragma honors `lockTimeoutMs` |
| **App-level retry** | On `SQLITE_BUSY`, exponential backoff + jitter up to `maxRetries` |
| **Stable error** | Exhausted retries throw **`WOLBARG_STORAGE_LOCKED`** with an actionable suggestion |
| **In-process mutex** | Same-process concurrent writers are additionally serialized |
**PostgreSQL** is unchanged for this feature — it already uses row-level locking and connection pooling. Concurrency config is ignored on the Postgres provider.
## Why it matters for agents [#why-it-matters-for-agents]
Multi-agent frameworks often open the **same SQLite file** from several processes:
* Parallel tool workers writing preferences / facts
* Dev servers + background jobs sharing local memory
* CLI agents launched side-by-side against one project DB
Without write-lock discipline, you get intermittent failures, orphaned retries, or corrupted mental models when agents silently drop writes. Wolbarg 0.4 makes contention **visible**, **retryable**, and **bounded**.
## Configuration [#configuration]
```ts
import { wolbarg, sqlite, openaiEmbedding } from "wolbarg";
const ctx = wolbarg({
organization: "my-org",
storage: sqlite("./memory.db"),
embedding: openaiEmbedding({
apiKey: process.env.OPENAI_API_KEY!,
model: "text-embedding-3-small",
}),
concurrency: {
maxRetries: 5, // default — app-level retry attempts after SQLITE_BUSY
baseBackoffMs: 50, // default — first backoff floor
maxBackoffMs: 2000, // default — backoff ceiling
lockTimeoutMs: 5000, // SQLite busy_timeout pragma (ms)
},
});
```
Defaults are conservative for a handful of concurrent agent processes. Raise `maxRetries` / `lockTimeoutMs` for bursty writers; switch to Postgres when you need high fan-out multi-tenant write throughput.
### Defaults [#defaults]
| Field | Default | Meaning |
| --------------- | ------- | ------------------------------------------------- |
| `maxRetries` | `5` | How many times Wolbarg retries a busy transaction |
| `baseBackoffMs` | `50` | Starting delay before retry (grows exponentially) |
| `maxBackoffMs` | `2000` | Cap on backoff delay |
| `lockTimeoutMs` | `5000` | Passed to SQLite busy handler / busy\_timeout |
## How it works (internals) [#how-it-works-internals]
1. A mutating path (`remember`, `update`, `forget`, ingest writes, compress archive, …) opens a transaction with **`BEGIN IMMEDIATE`**.
2. If another process holds the write lock, SQLite returns busy within `lockTimeoutMs`.
3. Wolbarg sleeps with exponential backoff + jitter and retries up to `maxRetries`.
4. If all attempts fail, it throws `WOLBARG_STORAGE_LOCKED` — not a generic SQLite string.
5. Same-process callers also queue through an in-process mutex so Node async concurrency does not pile on top of OS-level lock storms.
## Tradeoffs [#tradeoffs]
| Upside | Cost |
| ------------------------------------------ | -------------------------------------------------------- |
| Far fewer surprise `SQLITE_BUSY` failures | p95/p99 latency rises under contention |
| Bounded, actionable errors | Very high writer fan-out still serializes on one file |
| Works with existing local-first topologies | Postgres remains better for SaaS-scale concurrent writes |
Tune for your workload, or move shared multi-tenant agents to the [PostgreSQL](/docs/storage/postgresql) backend.
## Errors [#errors]
| Code | When | What to do |
| ------------------------ | ---------------------------- | ------------------------------------------------------------------------------------- |
| `WOLBARG_STORAGE_LOCKED` | Write-lock retries exhausted | Increase `maxRetries` / `lockTimeoutMs`, reduce writer fan-out, or switch to Postgres |
Suggestion text on the error points at the same remediation.
## Benchmarks [#benchmarks]
### Same-process stress (v4 suite) [#same-process-stress-v4-suite]
Published dual-backend v0.4 stress numbers ([SQLite](/benchmarks/version-0.4.0-sqlite-benchmark.json) · [Postgres](/benchmarks/version-0.4.0-postgres-benchmark.json)):
| Writers | SQLite throughput | SQLite p95 | Postgres throughput | Postgres p95 |
| ----------- | ----------------- | ---------- | ------------------- | ------------ |
| 8 × 20 ops | 6,084 ops/s | 3.05 ms | 2,555 ops/s | 8.51 ms |
| 16 × 20 ops | 8,660 ops/s | 2.46 ms | 3,335 ops/s | 9.48 ms |
| 32 × 20 ops | 6,798 ops/s | 22.94 ms | 3,802 ops/s | 14.77 ms |
Mock embeddings; Node v24 · win32/arm64 · 8 CPUs · generated 2026-07-18. Absolute ops/sec vary by machine.
### Multi-process levels [#multi-process-levels]
True multi-process writers (separate OS processes, shared SQLite file):
```bash
npx tsx benchmark/multiprocess-levels.ts
```
Artifact: [`/benchmarks/multiprocess-concurrency.json`](/benchmarks/multiprocess-concurrency.json) — levels **2 / 5 / 10 / 20** writers with throughput, p50/p95/p99, error rate, and integrity checks. At 20 writers this run held **0% error rate** with integrity OK (p95 rises as expected under serialization).
Interactive charts: [/benchmarks](/benchmarks). Methodology: [Benchmarks](/docs/benchmarks).
## When to use Postgres instead [#when-to-use-postgres-instead]
Choose PostgreSQL when:
* Many agents share one cluster across hosts
* You need cross-process [real-time events](/docs/realtime-events) (`LISTEN`/`NOTIFY`)
* Write fan-out regularly exceeds what a single SQLite file can serialize comfortably
## Related pages [#related-pages]
* [Real-time events](/docs/realtime-events)
* [SQLite](/docs/storage/sqlite) · [PostgreSQL](/docs/storage/postgresql)
* [Benchmarks](/docs/benchmarks)
* [What's New](/docs/guides/whats-new)
* [Errors](/docs/reference/errors)
---
# Configuration
> Required and optional constructor options for Wolbarg — organization, storage, embedding, providers, concurrency, embeddingCache, memory.dedupe, and AbortSignal.
URL: /docs/configuration
## What is it? [#what-is-it]
The constructor API for `new Wolbarg(options)` / `wolbarg(options)`. Three options are required; everything else is optional and enables a specific capability.
## Why does it exist? [#why-does-it-exist]
Wolbarg uses constructor dependency injection so you compose only the backends you need — no global config files, no hidden services. Keep factories in a dedicated folder so swaps stay local — see [Project layout](/docs/installation#project-layout).
## Required [#required]
| Option | Type | Description |
| ---------------------- | ---------------------------------------------------- | ---------------------------------------------------------- |
| `organization` | `string` | Namespace isolating memories in a shared database |
| `storage` / `database` | `StorageProvider \| StorageConfig \| DatabaseConfig` | `sqlite(...)` / `postgres(...)` or `{ provider, url }` |
| `embedding` | `EmbeddingProvider \| EmbeddingConfig` | Any OpenAI-compatible embedding factory or custom provider |
## Optional [#optional]
| Option | Enables |
| ------------------------------------ | --------------------------------------------------------------------------- |
| `llm` | `compress()` (typed at compile time) |
| `keywordSearch` | Hybrid recall — **required** when `hybrid: true` (fail-closed) |
| `reranker` | `recall({ rerank: true })` — **required** when `rerank: true` (fail-closed) |
| `ocr` / `vision` | Image ingest enrichment |
| `chunking` | Default ingest chunking strategy |
| `compression` | Custom compression provider (overrides llm default) |
| `retrieval` | Default hybrid / MMR / over-fetch settings |
| `telemetry` | Independent EventDatabase observability |
| `checkpoint` / `checkpointDirectory` | SQLite first-party snapshots |
| `concurrency` | SQLite multi-writer retries / busy\_timeout |
| `embeddingCache` | Transparent embedding reuse (default on) |
| `memory.dedupe` | Write-time upsert / near-dup detection (default off) |
## Storage options [#storage-options]
### SQLite [#sqlite]
```ts
sqlite("./data/memory.db")
// or
{ provider: "sqlite", url: "./data/memory.db" }
```
Prefer **one file per organization** when using export/checkpoint. See [Production](/docs/guides/production).
### PostgreSQL [#postgresql]
```ts
postgres({
connectionString: process.env.DATABASE_URL!,
schema: "wolbarg", // optional namespaced deployment
maxPoolSize: 20, // default; raise only if the host allows
// ssl: false, // opt out of default require for remote (not recommended)
})
```
* Non-loopback hosts without `sslmode` / `ssl` in the URL get **`sslmode=require`**
* Loopback (`localhost`, `127.0.0.1`, `::1`) is left unchanged
* `schema` creates a dedicated Postgres schema for tables, indexes, and a suffixed NOTIFY channel
* Schema names: `^[A-Za-z_][A-Za-z0-9_$]*$`, max 48 characters
## AbortSignal [#abortsignal]
Pass `signal?: AbortSignal` (or `AbortSignal.timeout(ms)`) on:
* `remember` / `rememberFromMessages`
* `recall`
* `update`
* `compress`
* `forget`
Cancellation throws `CancellationError`; in-flight embedding HTTP aborts.
```ts
await ctx.recall({
query: "billing",
signal: AbortSignal.timeout(5_000),
});
```
## Concurrency [#concurrency]
```ts
concurrency: {
maxRetries?: number; // default 5
baseBackoffMs?: number; // default 50
maxBackoffMs?: number; // default 2000
lockTimeoutMs?: number; // default 5000 — SQLite busy_timeout
multiProcess?: boolean; // longer timeouts when multiple OS processes share one file
}
```
Ignored for Postgres. Guide: [Concurrency](/docs/concurrency).
## Embedding cache [#embedding-cache]
```ts
embeddingCache: {
enabled?: boolean; // default true
ttlMs?: number; // optional lazy TTL
maxEntries?: number; // optional LRU
}
```
Guide: [Embedding cache](/docs/embedding-cache).
## Memory dedupe [#memory-dedupe]
```ts
memory: {
dedupe: {
enabled?: boolean; // default false
strategy?: "exact" | "near" | "exact-or-near";
nearThreshold?: number; // default 0.92
nearCandidateLimit?: number; // default 8
},
}
```
Guide: [Memory upsert](/docs/memory-upsert).
## Telemetry [#telemetry]
```ts
telemetry: {
enabled: true,
database: { provider: "sqlite", url: "./telemetry.db" },
captureQueries: false, // default since 0.6.0
}
```
## Full example [#full-example]
```ts
import {
wolbarg, sqlite, openaiEmbedding, openaiLlm,
bm25, jinaReranker, tesseract, geminiVision,
} from "wolbarg";
const ctx = wolbarg({
organization: "my-org",
storage: sqlite("./memory.db"),
embedding: openaiEmbedding({
apiKey: process.env.OPENAI_API_KEY!,
model: "text-embedding-3-small",
}),
llm: openaiLlm({
apiKey: process.env.OPENAI_API_KEY!,
model: "gpt-4.1-mini",
}),
keywordSearch: bm25(),
reranker: jinaReranker({ apiKey: process.env.JINA_API_KEY! }),
ocr: tesseract(),
vision: geminiVision({ apiKey: process.env.GEMINI_API_KEY! }),
retrieval: {
overFetchFactor: 4,
hybrid: { semanticWeight: 0.7, keywordWeight: 0.3 },
},
concurrency: { maxRetries: 5, lockTimeoutMs: 5000 },
embeddingCache: { enabled: true, maxEntries: 10_000 },
memory: {
dedupe: { enabled: true, strategy: "exact-or-near" },
},
});
```
## Lazy initialization [#lazy-initialization]
Storage opens and embedding dimensions are probed on the first API call, or when you call `await ctx.ready()`. Optional providers are not probed until used. Embedding cache wraps the provider after construction.
## Related pages [#related-pages]
* [Provider Architecture](/docs/providers)
* [Installation](/docs/installation)
* [Production](/docs/guides/production)
* [SQLite Backend](/docs/storage/sqlite)
* [PostgreSQL Backend](/docs/storage/postgresql)
* [Concurrency](/docs/concurrency)
* [Embedding cache](/docs/embedding-cache)
* [Memory upsert](/docs/memory-upsert)
* [API](/docs/api)
* [What's New](/docs/guides/whats-new)
---
# Document Ingestion
> Parse PDF, DOCX, Markdown, and other documents into chunked semantic memories with ingest().
URL: /docs/document-ingestion
## What is it? [#what-is-it]
`ingest()` parses a document, chunks it, embeds each chunk, and stores memories in batch.
## Why does it exist? [#why-does-it-exist]
Agents need grounded knowledge from handbooks, tickets, and product docs — not only free-form `remember()` calls.
## How does it work? [#how-does-it-work]
Pipeline: parse → OCR/vision (if configured) → chunk → embed (batch) → store (batch transaction).
### Sources [#sources]
```ts
source: { path: "./file.pdf" }
source: { buffer: buf, filename: "file.docx" }
source: { text: "# Markdown…" }
```
### Formats [#formats]
| Family | Extensions | Peer required |
| ------ | ----------------------------- | ----------------- |
| Text | `.txt` `.md` `.csv` `.json` | None |
| PDF | `.pdf` | `pdf-parse@1.1.4` |
| DOCX | `.docx` | `mammoth` |
| Images | `.png` `.jpg` `.jpeg` `.webp` | OCR and/or vision |
```bash
npm install pdf-parse@1.1.4 # required for .pdf
npm install mammoth # required for .docx
```
Peers are not bundled with `Wolbarg`. Missing peers throw when that format is used.
### Example [#example]
```ts
const result = await ctx.ingest({
agent: "docs",
source: { path: "./handbook.pdf" },
chunking: { strategy: "paragraph", chunkSize: 1000, overlap: 120 },
metadata: { collection: "handbook" },
});
console.log(result.chunkCount);
```
## When should it be used? [#when-should-it-be-used]
Knowledge bases, onboarding PDFs, and any offline corpus that should become recallable memory.
## Related pages [#related-pages]
* [Chunking](/docs/chunking)
* [Image Ingestion](/docs/image-ingestion)
* [OCR](/docs/ocr)
* [Example — PDF Memory](/docs/examples/pdf-memory)
* [ingest()](/docs/api/ingest)
---
# Embedding cache
> Transparent hash(content)+model embedding cache in Wolbarg 0.4 — cut provider cost and latency on repeated text with optional LRU and TTL.
URL: /docs/embedding-cache
## What is it? [#what-is-it]
Wolbarg **0.4** wraps your embedding provider with a **transparent cache** keyed by:
```
hash(content) + model
```
Identical text for the **same model** skips the provider call. A model change always forces a miss — critical so you never mix vectors from different embedding spaces during recall.
## Why it exists [#why-it-exists]
Agent memory workloads repeat text constantly:
* Re-ingesting the same docs / chunks
* Agents restating the same preference or fact
* Batch jobs that overlap corpora across runs
* Dedupe near-match paths that re-embed candidates
Without a cache, every `remember` / ingest / near-dedupe path pays full provider latency and token cost. The cache is **on by default** in 0.4 (disable if you need every call to hit the network).
## Configuration [#configuration]
```ts
import { wolbarg, sqlite, openaiEmbedding } from "wolbarg";
const ctx = wolbarg({
organization: "my-org",
storage: sqlite("./memory.db"),
embedding: openaiEmbedding({
apiKey: process.env.OPENAI_API_KEY!,
model: "text-embedding-3-small",
}),
embeddingCache: {
enabled: true, // default
ttlMs: undefined, // no expiry by default
maxEntries: 10_000, // optional LRU bound
},
});
```
Disable entirely:
```ts
embeddingCache: { enabled: false }
```
### Options [#options]
| Field | Default | Meaning |
| ------------ | ------- | ---------------------------------------- |
| `enabled` | `true` | Master switch |
| `ttlMs` | unset | Lazy expiry on read when set |
| `maxEntries` | unset | LRU eviction via `last_used_at` when set |
## How it works [#how-it-works]
1. Every single and batch `embed` path checks the cache first.
2. **Hits** return stored vectors immediately (no provider round-trip).
3. **Misses** call the provider — batch paths only request uncached items.
4. Results persist in the `embedding_cache` table (schema v3+) on SQLite, or an in-memory fallback when a durable store is unavailable.
5. LRU eviction (if `maxEntries` is set) drops least-recently-used rows by `last_used_at`.
6. TTL (if set) is checked **lazily on read** — expired entries miss and re-embed.
### Cache key discipline [#cache-key-discipline]
* Content is hashed after the same normalization the write path uses for identity where applicable.
* **Model id is part of the key** — changing `text-embedding-3-small` → `text-embedding-3-large` never reuses old vectors.
* Provider API keys / base URLs are **not** part of the key; if you point two incompatible endpoints at the same model string, use distinct model labels or disable the cache.
## Cost & latency impact [#cost--latency-impact]
Published embedding-cache microbench ([`embedding-cache.json`](/benchmarks/embedding-cache.json)):
| Metric | Value |
| ----------------------- | ----------------------------------------------- |
| Workload | 100 chunks, 20 unique, 2 passes (mock provider) |
| Uncached provider calls | 100 |
| Cached provider calls | 20 |
| Call reduction | **90%** |
| Cache hits / misses | 180 / 20 |
v4 stress suite headlines (repeated-text spot):
| Backend | Cold avg | Hot avg | Speedup |
| -------- | -------- | ------- | --------- |
| SQLite | 0.34 ms | 0.23 ms | **1.47×** |
| Postgres | 0.77 ms | 0.66 ms | **1.18×** |
Reproduce:
```bash
npx tsx benchmark/embedding-cache-bench.ts
```
## Interaction with other 0.4 features [#interaction-with-other-04-features]
| Feature | Interaction |
| ------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------ |
| [Memory upsert](/docs/memory-upsert) | Exact matches skip re-embed; near matches re-embed (cache helps paraphrases that hash differently but share substrings only when text matches exactly) |
| [Concurrency](/docs/concurrency) | Cache reads are cheap; provider misses still participate in normal write locking when results are persisted |
| Schema | Requires schema with `embedding_cache` table (auto-migrated) |
## Operational notes [#operational-notes]
* Cache is **correctness-preserving** for identical content+model; it does not change recall ranking for distinct strings.
* Clearing the memory DB does not always imply you want to drop the cache — but a full wipe / new file typically recreates schema cleanly.
* For compliance environments that forbid persisting embeddings of PII, disable the cache or scope database lifecycle carefully.
## Related pages [#related-pages]
* [Memory upsert](/docs/memory-upsert)
* [Configuration](/docs/configuration)
* [Benchmarks](/docs/benchmarks)
* [What's New](/docs/guides/whats-new)
---
# FAQ
> Frequently asked questions about Wolbarg installation, providers, storage, and retrieval.
URL: /docs/faq
## What is Wolbarg Workspace? [#what-is-wolbarg-workspace]
[`@wolbarg/workspace`](https://www.npmjs.com/package/@wolbarg/workspace) is the product layer for coding agents (Cursor, Claude Code, Codex). It keeps shared, reconciled project truth on top of the `wolbarg` SDK. See [Wolbarg Workspace](/docs/workspace).
## What is Wolbarg? [#what-is-wolbarg]
A TypeScript SDK for shared semantic memory across AI agents. It is not an agent framework and not a hosted vector database. Start with the [Quick Start](/docs/quick-start), then read [Concepts](/docs/getting-started).
## What Node version do I need? [#what-node-version-do-i-need]
Node.js **22.5+** because SQLite uses built-in `node:sqlite`.
## Why does hybrid search throw ValidationError? [#why-does-hybrid-search-throw-validationerror]
You likely set `hybrid: true` without `keywordSearch: bm25()`. Since **0.6.0**, hybrid is fail-closed — there is no silent semantic-only fallback. See [Hybrid Search](/docs/hybrid-search).
## Do I need an LLM to use Wolbarg? [#do-i-need-an-llm-to-use-wolbarg]
No. LLM is required only for `compress()` (and for experimental `rememberFromMessages({ mode: "extract" })`). Remember/recall need storage + embedding.
## Why does PDF ingest fail? [#why-does-pdf-ingest-fail]
Install `pdf-parse@1.1.4` in your app. Scan-only PDFs without a text layer need OCR/vision on images. See [Document Ingestion](/docs/document-ingestion) and [Limitations](/docs/guides/limitations).
## Can I use PostgreSQL? [#can-i-use-postgresql]
Yes — `npm install pg` then `storage: postgres({ connectionString })`. Remote hosts default to `sslmode=require`. Optional `schema` namespacing and default `maxPoolSize: 20`. See [PostgreSQL Backend](/docs/storage/postgresql) and [Production](/docs/guides/production).
## Where did graph memory go? [#where-did-graph-memory-go]
Removed in **0.6.0**. Use [metadata](/docs/metadata-filtering) or an external store. See [Graph memory (removed)](/docs/graph-memory) and [Migration](/docs/migration).
## How do multiple agents share memory? [#how-do-multiple-agents-share-memory]
One `Wolbarg` instance, different `agent` ids on remember/recall filters. See [Multi-Agent Memory](/docs/guides/shared-memory).
## Where is the full docs dump for AI tools? [#where-is-the-full-docs-dump-for-ai-tools]
* [/llms.txt](/llms.txt) — curated index
* [/llms-full.txt](/llms-full.txt) — full Markdown export
* Append `.md` to any docs URL for that page as Markdown
## Related pages [#related-pages]
* [Quick Start](/docs/quick-start)
* [Concepts](/docs/getting-started)
* [Installation](/docs/installation)
* [Limitations](/docs/guides/limitations)
* [What's New](/docs/guides/whats-new)
---
# Concepts
> What Wolbarg is, why it exists, and the provider philosophy behind its architecture.
URL: /docs/getting-started
Ready to code? Start with the [Quick Start](/docs/quick-start) — remember/recall in under a minute.
## What is Wolbarg? [#what-is-wolbarg]
Wolbarg is a TypeScript SDK that gives AI agents a shared, persistent semantic memory. Store facts with `remember()`, retrieve them with `recall()`, optionally ingest documents, compress memories with an LLM, and react to changes with `subscribe()`.
Everything is built around **replaceable providers**: storage, embeddings, keyword search, rerankers, OCR, vision, chunking, and telemetry. The public API stays small; you swap backends by changing factory calls, not agent logic.
## Why does it exist? [#why-does-it-exist]
Most agent stacks either bolt memory onto a chat transcript or depend on a hosted vector database. Wolbarg sits in between: a **shared semantic memory layer for multi-agent systems**, with explicit providers, durable writes, and hybrid retrieval — plus [connectors](/connector) for Cursor and AI SDKs.
## Core philosophy [#core-philosophy]
* **Everything is configurable** — swap any provider.
* **Nothing is required unless necessary** — only `organization`, `storage`, and `embedding`.
* **Optional features fail cleanly** — `hybrid: true` / `rerank: true` without their providers throw `ValidationError` (fail-closed since 0.6.0); `compress` without `llm` is a `ProviderNotConfiguredError`.
* **Isolate providers in your app** — keep factories in a dedicated folder so switching SQLite ↔ Postgres is a one-file change. See [Project layout](/docs/installation#project-layout).
## Capabilities [#capabilities]
* Constructor DI + factories — SQLite / PostgreSQL storage, hybrid recall, metadata filters, MMR, rerankers, document `ingest`, chunking, optional LLM compression
* **Telemetry** — independent event database + trace IDs · [Observability](/docs/observability)
* **Wolbarg Studio** — local read-only observability dashboard · [Observability & Studio](/docs/observability)
* **Checkpoints** — `checkpoint` / `rollback` / `listCheckpoints` (SQLite file-backed, single-org)
* **Import / export** — portable SQLite memory bundles (single-org)
* **Batch APIs** — `rememberBatch` / `recallBatch`
* **Recall explain** — ranking diagnostics + timings
* **`subscribe()`** — real-time memory change events · [Real-time events](/docs/realtime-events)
* **AbortSignal** — cancellation on remember / recall / update / compress / forget
* **Concurrency hardening** — multi-writer SQLite retries · [Concurrency](/docs/concurrency)
* **Embedding cache** — transparent reuse · [Embedding cache](/docs/embedding-cache)
* **Memory upsert / dedupe** — update-instead-of-insert · [Memory upsert](/docs/memory-upsert)
## What it is not [#what-it-is-not]
* Not an agent / orchestration framework
* Not a hosted vector database SaaS
* Not a chat UI (Studio is a separate local observability app)
* Not a graph database — graph memory APIs were [removed in 0.6.0](/docs/graph-memory)
For out-of-the-box shared project truth in Cursor / Claude Code / Codex, see [Wolbarg Workspace](/docs/workspace) (`@wolbarg/workspace`).
## When should you use it? [#when-should-you-use-it]
Use Wolbarg when multiple agents (or one long-running agent) need durable, searchable memory with clear backends and no infrastructure lock-in.
## Related pages [#related-pages]
* [Quick Start](/docs/quick-start)
* [What's New](/docs/guides/whats-new)
* [Installation](/docs/installation)
* [Connectors](/connector)
* [Observability & Studio](/docs/observability)
* [Architecture](/docs/architecture)
* [Limitations](/docs/guides/limitations)
* [Migration](/docs/migration)
---
# Graph memory
> Graph memory was removed in Wolbarg 0.6.0. Use metadata or an external store for relationships.
URL: /docs/graph-memory
## Removed in 0.6.0 [#removed-in-060]
Graph memory is **no longer part of the Wolbarg core SDK**.
The following APIs and factories were removed:
* `sqliteGraph` / `neo4jGraph`
* `linkMemories` / `getRelated`
* `recall({ includeGraph: true })`
* `neo4j-driver` peer dependency
This page is kept so existing links and bookmarks resolve. Full release notes: [What's New](/docs/guides/whats-new) · [Migration](/docs/migration).
## What to use instead [#what-to-use-instead]
| Need | Approach |
| --------------------- | ------------------------------------------------------------------------------------------ |
| Tag related facts | Store relation ids / keys in [metadata](/docs/metadata-filtering) and filter with `meta.*` |
| Explicit graph walks | Use an external graph database or your own edge tables outside Wolbarg |
| Similarity + keywords | [Semantic search](/docs/search) + [hybrid BM25](/docs/hybrid-search) |
```ts
await ctx.remember({
agent: "support",
content: { text: "Refund SLA is 5 business days." },
metadata: { topic: "billing", relatedTo: ["pref-email"] },
});
const hits = await ctx.recall({
query: "refund timeline",
filter: { metadata: meta.eq("topic", "billing") },
});
```
## Upgrade checklist [#upgrade-checklist]
1. Remove `graph`, `sqliteGraph`, `neo4jGraph`, `linkMemories`, `getRelated`, and `includeGraph` from your code
2. Uninstall `neo4j-driver` if you only used it for Wolbarg
3. Install `wolbarg@0.6.0`
4. Re-express relationships with metadata or an external store
## Related pages [#related-pages]
* [What's New](/docs/guides/whats-new)
* [Migration](/docs/migration)
* [Metadata Filtering](/docs/metadata-filtering)
* [Limitations](/docs/guides/limitations)
* [API Overview](/docs/api)
---
# Hybrid Search
> Combine semantic vectors with BM25 keyword scores for more robust recall. Fail-closed since 0.6.0.
URL: /docs/hybrid-search
## What is it? [#what-is-it]
Hybrid search fuses semantic similarity with BM25 keyword scores so recall works for both meaning and exact tokens (IDs, product names, error codes).
## Why does it exist? [#why-does-it-exist]
Pure vector search can miss rare tokens. Pure keyword search misses paraphrase. Fusion covers both modes.
## How does it work? [#how-does-it-work]
### Setup [#setup]
```ts
import { bm25 } from "wolbarg";
new Wolbarg({
/* organization, storage, embedding */
keywordSearch: bm25(),
});
```
### Usage [#usage]
```ts
await ctx.recall({
query: "quick brown fox",
hybrid: true,
// or
hybrid: { semanticWeight: 0.7, keywordWeight: 0.3 },
});
```
Scores are normalized then fused. Tune weights for keyword-heavy vs semantic-heavy corpora.
### Fail-closed (0.6.0+) [#fail-closed-060]
If `hybrid: true` is set without a configured `keywordSearch` provider, Wolbarg throws **`ValidationError`**. There is no quiet semantic-only fallback. Keyword-channel failures also throw — they do not degrade to semantic-only.
Configure `keywordSearch: bm25()` (or a custom provider) before enabling hybrid.
## When should it be used? [#when-should-it-be-used]
Enable hybrid when queries contain proprietary names, codes, or short literal strings mixed with natural language.
## Performance notes [#performance-notes]
* Requires FTS indexing on SQLite (schema v2) or equivalent keyword path
* Keyword index updates happen with remember/ingest/forget
* Slightly higher recall-time cost than semantic-only
## Related pages [#related-pages]
* [Semantic Search](/docs/search)
* [Rerankers](/docs/rerankers)
* [Example — Hybrid Search](/docs/examples/hybrid-search)
* [Provider Architecture](/docs/providers)
* [What's New](/docs/guides/whats-new)
---
# Image Ingestion
> Store image-derived text as semantic memory using OCR and vision providers.
URL: /docs/image-ingestion
## What is it? [#what-is-it]
Ingesting `.png`, `.jpg`, `.jpeg`, and `.webp` files so visual content becomes searchable text memories.
## Why does it exist? [#why-does-it-exist]
Screenshots, UI captures, and slide photos often carry the facts agents need. Pure image bytes are not useful for text recall without extraction.
## How does it work? [#how-does-it-work]
Configure `ocr` and/or `vision`, then call `ingest` with an image path or buffer.
```ts
import { tesseract, geminiVision } from "wolbarg";
const ctx = new Wolbarg({
/* organization, storage, embedding */
ocr: tesseract(),
vision: geminiVision({ apiKey: process.env.GEMINI_API_KEY! }),
});
await ctx.ingest({
agent: "vision",
source: { path: "./screenshot.png" },
metadata: { kind: "ui-capture" },
});
```
OCR text, captions, descriptions, and entities are concatenated before chunking. If neither provider is configured, image ingest errors with a clear message unless other text is available.
## When should it be used? [#when-should-it-be-used]
Product screenshots, whiteboard photos, receipts, and charts where text/visual captions matter.
## Related pages [#related-pages]
* [OCR](/docs/ocr)
* [Vision Models](/docs/vision)
* [Example — Image Memory](/docs/examples/image-memory)
* [Document Ingestion](/docs/document-ingestion)
---
# Installation
> Install Wolbarg, optional peers, and a clean project layout that keeps providers swappable without refactoring agent code.
URL: /docs/installation
## What is it? [#what-is-it]
The install guide for the `wolbarg` npm package, optional peer dependencies, and a **recommended project layout** so storage and embedding factories live in one place — swap backends without rewriting your agents.
## Requirements [#requirements]
* Node.js **22.5+** (uses built-in `node:sqlite`)
* An OpenAI-compatible embedding endpoint (required for remember/recall)
* An LLM endpoint only if you use `compress()`
## Install [#install]
```bash
npm install wolbarg
```
```bash
pnpm add wolbarg
yarn add wolbarg
bun add wolbarg
```
Current release: **0.6.0** — [What's New](/docs/guides/whats-new).
Looking for coding-agent project memory instead of the SDK API? Install [Wolbarg Workspace](/docs/workspace) (`@wolbarg/workspace`).
## Optional peers [#optional-peers]
Install only what you need:
```bash
npm install pg # PostgreSQL storage
npm install pdf-parse@1.1.4 # PDF ingest (text-layer PDFs)
npm install mammoth # DOCX ingest
npm install tesseract.js # OCR on images
```
If you call `ingest()` on PDF or DOCX files, or use PostgreSQL storage, you **must** install the matching peer in the same app:
* `pdf-parse` for `.pdf`
* `mammoth` for `.docx`
* `tesseract.js` and/or a `vision` provider for images / scan-only PDFs
* `pg` for PostgreSQL storage
Plain text formats (`.txt`, `.md`, `.csv`, `.json`) need no extra packages. Missing peers throw when that path is used — not at import time.
Prefer pinning `pdf-parse@1.1.4` for the function API Wolbarg tests against.
## Project layout [#project-layout]
Keep **provider wiring** out of agent / business code. When you switch SQLite → Postgres, you change files under `providers/` only — not every `remember` / `recall` call site.
```text
src/
providers/
storage.ts # sqlite() | postgres()
embedding.ts # openaiEmbedding() | ollamaEmbedding() | …
llm.ts # optional — openaiLlm() | …
telemetry.ts # optional — sqlite telemetry config
index.ts # re-exports + env-based selection
memory/
client.ts # wolbarg({ …providers }) — single construction site
agents/
support.ts # uses client — never imports sqlite/postgres directly
research.ts
index.ts
```
### Example: `providers/storage.ts` [#example-providersstoragets]
```ts
import { sqlite, postgres } from "wolbarg";
export function createStorage() {
if (process.env.MEMORY_BACKEND === "postgres") {
return postgres({
connectionString: process.env.DATABASE_URL!,
schema: process.env.WOLBARG_SCHEMA ?? "wolbarg",
});
}
return sqlite(process.env.MEMORY_PATH ?? "./data/memory.db");
}
```
### Example: `memory/client.ts` [#example-memoryclientts]
```ts
import { wolbarg, bm25 } from "wolbarg";
import { createStorage } from "../providers/storage.js";
import { createEmbedding } from "../providers/embedding.js";
export const memory = wolbarg({
organization: process.env.WOLBARG_ORG ?? "my-org",
storage: createStorage(),
embedding: createEmbedding(),
keywordSearch: bm25(), // required when using hybrid: true
});
```
Agents import `memory` and call `remember` / `recall` — they never branch on database type. Full option table: [Configuration](/docs/configuration).
## Verify [#verify]
```ts
import { wolbarg, sqlite, openaiEmbedding } from "wolbarg";
const ctx = wolbarg({
organization: "demo",
storage: sqlite(":memory:"),
embedding: openaiEmbedding({
apiKey: process.env.OPENAI_API_KEY!,
model: "text-embedding-3-small",
}),
});
await ctx.ready();
console.log(ctx.isInitialized); // true
await ctx.close();
```
## Related pages [#related-pages]
* [Quick Start](/docs/quick-start)
* [Configuration](/docs/configuration)
* [Observability & Studio](/docs/observability)
* [Document Ingestion](/docs/document-ingestion)
* [SQLite Backend](/docs/storage/sqlite)
* [PostgreSQL Backend](/docs/storage/postgresql)
* [Limitations](/docs/guides/limitations)
* [What's New](/docs/guides/whats-new)
---
# Memory upsert & deduplication
> Opt-in write-time exact and near-duplicate detection in Wolbarg 0.4 — update existing facts instead of inserting duplicates, with RememberResult.action and update().
URL: /docs/memory-upsert
## What is it? [#what-is-it]
Wolbarg **0.4** adds **opt-in write-time deduplication**. When enabled, `remember()` can **update** an existing active memory instead of always inserting a new UUID.
Without dedupe, every `remember()` inserts a new row. Agents that restate facts create duplicates, inflate `compress()` cost, and noise recall — even when MMR hides near-duplicates at search time.
**Use dedupe for facts, preferences, and durable state. Keep append-only (default) for episodic logs and time-series observations.**
## Compatibility [#compatibility]
| Behavior | Default |
| ------------------- | ------------------------------------------------------------------- |
| Dedupe | **Off** (0.3-compatible append-only) |
| `remember()` return | `RememberResult` = `MemoryRecord` + `action` (additive field) |
| History | New event type `"updated"` when an upsert replaces content/metadata |
| Schema | `content_hash` column + unique active hash index (auto-migrated) |
Upgrading from 0.3.x requires **no code changes** unless you opt into dedupe or read `action`.
## Enabling [#enabling]
### Constructor [#constructor]
```ts
import { wolbarg, sqlite, openaiEmbedding } from "wolbarg";
const ctx = wolbarg({
organization: "my-org",
storage: sqlite("./memory.db"),
embedding: openaiEmbedding({
apiKey: process.env.OPENAI_API_KEY!,
model: "text-embedding-3-small",
}),
memory: {
dedupe: {
enabled: true,
strategy: "exact-or-near", // default when enabled
nearThreshold: 0.92, // cosine similarity
nearCandidateLimit: 8,
},
},
});
const result = await ctx.remember({
agent: "assistant",
content: { text: "User prefers dark mode" },
metadata: { source: "chat" },
});
// result.action === "created" | "updated"
```
### Per-call override [#per-call-override]
```ts
// Force on for one write
await ctx.remember({
agent: "assistant",
content: { text: "User prefers dark mode" },
dedupe: true,
});
// Exact-only for one write
await ctx.remember({
agent: "assistant",
content: { text: "Timezone is IST" },
dedupe: { strategy: "exact" },
});
// Force off even if constructor enabled
await ctx.remember({
agent: "logger",
content: { text: "Heartbeat at T+60s" },
dedupe: false,
});
```
### Config reference [#config-reference]
| Field | Default | Meaning |
| -------------------- | ------------------------------ | ------------------------------------------ |
| `enabled` | `false` | Master switch |
| `strategy` | `"exact-or-near"` when enabled | `"exact"` \| `"near"` \| `"exact-or-near"` |
| `nearThreshold` | `0.92` | Minimum cosine similarity for near match |
| `nearCandidateLimit` | `8` | Max ANN candidates considered for near-dup |
## Detection pipeline [#detection-pipeline]
1. **Exact** — normalize content (`NFC`, trim, collapse whitespace; **case preserved**), hash, look up unique active hash for the same `organization` + `agent`.
2. **Near** (when strategy includes near) — embed the new text, compare cosine similarity against up to `nearCandidateLimit` active memories for that agent; accept if ≥ `nearThreshold`.
3. **No match** — insert a new row (`action: "created"`).
### Match scope [#match-scope]
| Included | Excluded |
| ---------------------------- | -------------------------------- |
| Same `organization` | Other orgs |
| Same `agent` | Other agents |
| **Non-archived** active rows | Archived rows after `compress()` |
Archived memories are **never** match targets — compress must stay free to summarize history without resurrecting dead hashes as “live” facts.
## Update behavior [#update-behavior]
| Case | Behavior |
| ----------- | ------------------------------------------------------------------------ |
| Exact match | Merge metadata (shallow), bump `updated_at`, **keep** existing embedding |
| Near match | Replace content, **re-embed**, merge metadata |
| No match | Insert new row |
Additional side effects:
* History records an `"updated"` event on upsert.
* [`subscribe()`](/docs/realtime-events) emits `"update"` (not `"remember"`).
* Concurrent exact-dedupe races stay unique (v4 suite: 1 id, 11 updates under contention).
## RememberResult [#rememberresult]
```ts
interface RememberResult extends MemoryRecord {
action: "created" | "updated";
}
```
`rememberBatch()` returns `RememberResult[]` — each item carries its own action.
## Explicit update() [#explicit-update]
When you already know the memory id:
```ts
const result = await ctx.update({
id: memoryId,
content: { text: "Revised fact" },
metadata: { edited: true },
});
// result.action === "updated"
```
Use `update()` for user edits and admin tools; use dedupe for automatic fact convergence on write.
## When to leave dedupe off [#when-to-leave-dedupe-off]
* Audit / event logs where each utterance is a distinct fact
* Time-series observations (“temp was 72°F at 10:01”)
* Workflows that must never merge paraphrases
* Debug sessions where you want append-only archaeology
## Worked example — preference convergence [#worked-example--preference-convergence]
```ts
const a = await ctx.remember({
agent: "assistant",
content: { text: "User prefers dark mode" },
metadata: { source: "onboarding" },
dedupe: true,
});
// a.action === "created"
const b = await ctx.remember({
agent: "assistant",
content: { text: "User prefers dark mode" },
metadata: { source: "settings", confirmed: true },
dedupe: true,
});
// b.action === "updated"
// b.id === a.id
// metadata merged: { source: "settings", confirmed: true }
```
## Related pages [#related-pages]
* [remember()](/docs/api/remember)
* [update()](/docs/api/update)
* [Real-time events](/docs/realtime-events)
* [Embedding cache](/docs/embedding-cache)
* [Compression](/docs/compression)
* [What's New](/docs/guides/whats-new)
---
# Metadata Filtering
> Filter recall with meta.eq, contains, comparisons, and AND/OR/NOT boolean trees.
URL: /docs/metadata-filtering
## What is it? [#what-is-it]
Structured filters on memory metadata (and agent scope) applied during `recall()`, `forget()`, and related APIs.
## Why does it exist? [#why-does-it-exist]
Organizations share one store. Filters keep retrieval scoped to a topic, tenant facet, priority, or agent without re-embedding.
## How does it work? [#how-does-it-work]
```ts
import { meta } from "wolbarg";
meta.eq("topic", "billing")
meta.contains("title", "invoice")
meta.gt("score", 10)
meta.gte("score", 10)
meta.lt("score", 100)
meta.lte("score", 100)
meta.between("year", 2020, 2026)
meta.and(filterA, filterB)
meta.or(filterA, filterB)
meta.not(filterA)
```
```ts
await ctx.recall({
query: "pricing",
filter: {
agent: "sales",
metadata: meta.and(
meta.eq("region", "eu"),
meta.gte("priority", 2),
),
},
});
```
Opaque metadata is never validated by the SDK — store any JSON-serializable object and filter on known fields.
## When should it be used? [#when-should-it-be-used]
Always attach meaningful metadata at `remember` / `ingest` time. Prefer filters before raising `topK`.
## Related pages [#related-pages]
* [Semantic Search](/docs/search)
* [Example — Metadata Filtering](/docs/examples/metadata-filtering)
* [Best Practices](/docs/guides/best-practices)
---
# Migration
> Upgrade Wolbarg — 0.5 → 0.6 production hardening, earlier additive upgrades, and AgentOrc → Wolbarg rebrand notes.
URL: /docs/migration
## What is it? [#what-is-it]
Guides for moving between Wolbarg releases. Start with **0.5 → 0.6** if you are current; older sections cover earlier upgrades.
## 0.5 → 0.6 (breaking) [#05--06-breaking]
```bash
npm install wolbarg@0.6.0
# remove if you only used it for Wolbarg graph
npm uninstall neo4j-driver
```
| Area | Action |
| ---------------- | ----------------------------------------------------------------------------------------- |
| Graph APIs | Remove `graph`, `sqliteGraph`, `neo4jGraph`, `linkMemories`, `getRelated`, `includeGraph` |
| Hybrid / rerank | Ensure `keywordSearch` / `reranker` are configured when flags are set — **fail-closed** |
| Rerank errors | Catch `RerankError` instead of assuming soft / identity fallback |
| Postgres remote | Expect TLS (`sslmode=require`) unless you override with `ssl` |
| Pool size | Raise `maxPoolSize` if you relied on the old default of **64** (now **20**) |
| Telemetry | Set `captureQueries: true` if you need query strings persisted |
| Multi-org SQLite | One file per organization for export / checkpoint / import / rollback |
| AbortSignal | Optional on remember / recall / update / compress / forget |
From 0.5.x **without** graph:
```bash
npm install wolbarg@0.6.0
```
Most `remember` / `recall` call sites need no changes. Review hybrid, rerank, and Postgres SSL settings.
Deep dive: [What's New](/docs/guides/whats-new) · [Production](/docs/guides/production) · [Graph memory (removed)](/docs/graph-memory).
## 0.4 → 0.5 (historical) [#04--05-historical]
```bash
npm install wolbarg@^0.5.0
```
**0.5** introduced optional graph memory. That layer was **removed again in 0.6.0** — do not add new graph call sites. If you are jumping from 0.4 directly to 0.6, skip graph entirely and follow the **0.5 → 0.6** table above for fail-closed hybrid/rerank and Postgres defaults.
| Feature (0.5) | Status in 0.6 |
| ---------------------------------------------- | ----------------------------- |
| Graph memory | **Removed** |
| `linkMemories` / `getRelated` / `includeGraph` | **Removed** |
| Framework adapters (`@wolbarg/*`) | Separate packages — unchanged |
## 0.3 → 0.4 (additive) [#03--04-additive]
```bash
npm install wolbarg@^0.4.0
```
**No required code changes.** Schema migrates automatically on open.
| Feature | Default | Action needed |
| -------------------------- | ----------------- | ------------------------------------------------------------- |
| Embedding cache | **On** | Disable with `embeddingCache: { enabled: false }` if unwanted |
| Memory dedupe / upsert | **Off** | Opt in via `memory.dedupe` |
| `concurrency` tuning | Sensible defaults | Optional |
| `subscribe()` / `update()` | — | Opt in when needed |
| `RememberResult.action` | Always present | Ignore safely if unused |
### Behavior notes [#behavior-notes]
* `remember()` / `rememberBatch()` still return a full `MemoryRecord`; they additionally include `action: "created" | "updated"`.
* SQLite writers now use `BEGIN IMMEDIATE` — safer under multi-process contention; may change latency shape under lock storms (see [Concurrency](/docs/concurrency)).
* New history event `"updated"` appears when upserts run.
Guides: [Concurrency](/docs/concurrency) · [Real-time events](/docs/realtime-events) · [Embedding cache](/docs/embedding-cache) · [Memory upsert](/docs/memory-upsert).
## 0.3 — AgentOrc → Wolbarg [#03--agentorc--wolbarg]
```bash
npm uninstall agentorc
npm install wolbarg
```
```ts
// before
import { AgentOrc } from "agentorc";
const ctx = new AgentOrc({ /* … */ });
// after
import { Wolbarg, wolbarg } from "wolbarg";
const ctx = wolbarg({ /* … */ });
```
* Class / options / error: `AgentOrc*` → `Wolbarg*`
* Site: [wolbarg.com](https://wolbarg.com)
* GitHub: [wolbarg/wolbarg](https://github.com/wolbarg/wolbarg)
* Internal meta table: `agentorc_meta` → `wolbarg_meta` (recreate DBs or migrate)
## 0.1 → 0.2 breaking changes [#01--02-breaking-changes]
* `llm` is no longer required to operate the SDK
* Constructor instances without `llm` do not type `compress`
* `stats().llmModel` may be `null`
* Package version is **0.2.x+**
## API mapping (0.1 → 0.2) [#api-mapping-01--02]
```ts
// 0.1
const ctx = new Wolbarg();
await ctx.init({ organization, database, embedding, llm });
// 0.2+ (recommended)
import { wolbarg, sqlite, openaiEmbedding, openaiLlm } from "wolbarg";
const ctx = wolbarg({
organization,
storage: sqlite("./memory.db"),
embedding: openaiEmbedding({ /* … */ }),
llm: openaiLlm({ /* … */ }), // optional
});
// init() still works for compatibility
```
## Schema [#schema]
| Version | Notes |
| ------- | ------------------------------------------------------------------------------------------------------- |
| v2 | FTS5 hybrid |
| v3+ | `content_hash`, `embedding_cache`, history `"updated"` |
| v4 | drop unused global `created_at` index; strip archived vectors from ANN; add agent-active covering index |
SQLite auto-migrates on open. Embedding dimension changes still require a fresh DB.
Method names (`remember` / `recall` / …) are unchanged. New optional fields are additive unless called out in the 0.5 → 0.6 section.
## Related pages [#related-pages]
* [What's New](/docs/guides/whats-new)
* [Production](/docs/guides/production)
* [Graph memory](/docs/graph-memory)
* [Observability](/docs/observability)
* [init() Compatibility](/docs/reference/init-compat)
* [Limitations](/docs/guides/limitations)
* [Concurrency](/docs/concurrency)
* [Memory upsert](/docs/memory-upsert)
---
# Observability & Studio
> Enable Wolbarg telemetry and explore it in Wolbarg Studio — live dashboard, Trace Explorer waterfalls, and ops surfaces.
URL: /docs/observability
## Overview [#overview]
Wolbarg records what your agents' memory is doing into an **independent telemetry database** — never the same tables as your memory store. Explore that data with **Wolbarg Studio**, a local read-only dashboard for operations, traces, recalls, and checkpoints.
## Enabling telemetry [#enabling-telemetry]
```ts
import { wolbarg, sqlite, openaiEmbedding } from "wolbarg";
const ctx = wolbarg({
organization: "my-org",
storage: sqlite("./memory.db"),
embedding: openaiEmbedding({
apiKey: process.env.OPENAI_API_KEY!,
model: "text-embedding-3-small",
}),
telemetry: {
enabled: true,
database: { provider: "sqlite", url: "./telemetry.db" },
level: "debug", // off | error | warn | info | debug | trace
captureQueries: false, // default since 0.6.0 — set true to persist query strings
captureLatency: true,
captureErrors: true,
captureSimilarity: true,
},
});
```
Every operation (`remember`, `recall`, `ingest`, `compress`, `checkpoint`, `rollback`, `rememberBatch`, `recallBatch`, …) emits an event with:
* `session_id`, `trace_id`, `parent_trace_id` — for waterfall traces
* `organization`, `agent`, `tags`, `checkpoint_id`
* measured **stage spans** (embedding, vector search, ranking, database read/write)
* persisted recall explanations when `explain: true`
Call `await ctx.flushTelemetry()` before exiting short-lived scripts to ensure the async emitter drains.
Telemetry is **SQLite-only** today (the interface is ready for Postgres). It is fully independent of your memory backend, so you can use Postgres for memory and SQLite for telemetry. Keep telemetry on a **separate file** from memory storage.
## Recall explain mode [#recall-explain-mode]
```ts
const explained = await ctx.recall({ query: "recurring invoices", explain: true });
for (const hit of explained.results) {
console.log(hit.memory.id, hit.score, hit.rankingReason);
}
console.log(explained.searchTime, explained.rankingTime, explained.traceId);
```
## Schema versioning [#schema-versioning]
Telemetry SQLite files use an additive, versioned schema. On writable open, **v1** files are migrated in place to **v2** and keep all existing events. V2 adds organization, agent, tags, checkpoint, persisted recall explanations, and stage spans. Read-only access to an unmigrated v1 file remains supported.
`SqliteEventDatabase.query()` can filter by `organization`, `agentId`, `tag`, and `checkpointId`.
## Wolbarg Studio [#wolbarg-studio]
Studio is a standalone dashboard (Next.js) — **not** bundled into the SDK. The SDK writes events; Studio reads them (and can also open memory files for hydration).
```bash
git clone https://github.com/Atharvmunde11/wolbarg-studio
cd wolbarg-studio
npm install
npm run dev # http://localhost:3100
```
On first launch, use **Connect / Settings** to point at:
* Telemetry database (e.g. `./telemetry.db`)
* Memory database (optional — for counts / hydration)
* Checkpoint directory (optional)
Connections persist in your user config directory (`~/.wolbarg/studio.json` or the AppData equivalent), never inside the project.
### Dashboard [#dashboard]
Live overview of memory operations from the telemetry database — operations today, error rate, throughput, P95 latency, active agents, and charts. (See the screenshot at the top of this page.)
### Trace Explorer [#trace-explorer]
True waterfall of embedding → search → filtering → ranking → response, with expandable stage metadata and the root event JSON.
### What Studio shows [#what-studio-shows]
| Surface | Purpose |
| ---------------------- | ----------------------------------------------------------------- |
| **Dashboard** | Live stats and charts |
| **Stream** | Live SSE event tail |
| **Events** | Filterable operation stream (dedupe `created` / `updated` badges) |
| **Trace Explorer** | Waterfall + stage metadata |
| **Recalls** | Scores, timings, explain panels |
| **Memory Ops** | Per-operation breakdowns |
| **Errors** | Failed operations for triage |
| **Agents** | Per-agent activity |
| **Checkpoints** | List and compare snapshots |
| **Connect / Settings** | Wire telemetry, memory, checkpoints |
Studio may still show historical or visual graph views from older workflows; those are **Studio UI surfaces**, not SDK graph APIs (graph memory was [removed in 0.6.0](/docs/graph-memory)).
### Notes [#notes]
* Studio opens SQLite **read-only** — it never writes to your telemetry or memory databases
* Live mode polls on a configurable interval (default 2s)
* Postgres telemetry connections are represented in config but not implemented yet
## Related pages [#related-pages]
* [What's New](/docs/guides/whats-new)
* [Getting Started](/docs/getting-started)
* [Production](/docs/guides/production)
* [Performance](/docs/performance)
* [Architecture](/docs/architecture)
---
# OCR
> Extract text from images with tesseract.js during Wolbarg ingest.
URL: /docs/ocr
## What is it? [#what-is-it]
Optical character recognition via the `ocr: tesseract()` provider, used during image ingest.
## Why does it exist? [#why-does-it-exist]
Many useful facts live inside pixels (UI text, labels, scanned pages). OCR turns them into embeddable strings.
## How does it work? [#how-does-it-work]
```bash
npm install tesseract.js
```
```ts
import { tesseract } from "wolbarg";
ocr: tesseract()
```
OCR requires installing `tesseract.js` in your app. Scan-only PDFs are not OCR'd as PDFs in v0.2 — convert to images or use a vision provider on image fixtures.
## When should it be used? [#when-should-it-be-used]
Screenshots and photos with readable text where you do not need scene captions. Combine with [Vision Models](/docs/vision) for richer descriptions.
## Related pages [#related-pages]
* [Vision Models](/docs/vision)
* [Image Ingestion](/docs/image-ingestion)
* [Example — OCR](/docs/examples/ocr)
---
# Performance
> Tuning guidance for recall latency, ingest throughput, and storage growth in Wolbarg.
URL: /docs/performance
## What is it? [#what-is-it]
Practical notes on what dominates runtime cost and how to configure Wolbarg for speed vs quality.
## Why does it exist? [#why-does-it-exist]
Most latency is not “SQLite being slow” — it is embedding HTTP calls, rerank APIs, and scanning oversized candidate sets.
## How it works — cost drivers [#how-it-works--cost-drivers]
| Path | Dominated by |
| ---------- | --------------------------------------------- |
| `remember` | Embedding API + single insert |
| `recall` | Query embed + vector scan (+ hybrid + rerank) |
| `ingest` | Parse + N embeddings + batch insert |
| `compress` | LLM tokens |
## Tuning checklist [#tuning-checklist]
1. Call `await ctx.ready()` at startup to fail fast
2. Prefer [metadata filters](/docs/metadata-filtering) before raising `topK`
3. Keep `threshold` slightly above 0 for noisy corpora
4. Use hybrid only when you need exact tokens
5. Reserve rerankers for high-precision paths
6. Pick chunk sizes intentionally ([Chunking](/docs/chunking))
7. Match embedding dimensions to your model and never silently change them mid-database
## When should you use SQLite vs Postgres? [#when-should-you-use-sqlite-vs-postgres]
* **SQLite** — single node, lowest ops overhead
* **PostgreSQL** — multi-instance sharing and central ops
See [Benchmarks](/docs/benchmarks) for methodology and published numbers, and the live charts at [/benchmarks](/benchmarks).
## Related pages [#related-pages]
* [Architecture](/docs/architecture)
* [Benchmarks](/docs/benchmarks)
* [Best Practices](/docs/guides/best-practices)
---
# Provider Architecture
> Embedding, LLM, keyword search, reranker, OCR, vision, and chunking providers in Wolbarg.
URL: /docs/providers
## What is it? [#what-is-it]
Wolbarg treats embeddings, LLMs, keyword search, rerankers, OCR, vision, chunking, and storage as swappable providers. Factories ship for common APIs; custom objects work if they match the interface.
## Why does it exist? [#why-does-it-exist]
Agents already have preferred models and endpoints. The SDK must not hardcode a single cloud vendor. Isolate factories in your app so backend switches stay in one folder — see [Project layout](/docs/installation#project-layout).
## Embedding providers [#embedding-providers]
All factories wrap an OpenAI-compatible `/embeddings` HTTP API:
```ts
import {
openaiEmbedding,
ollamaEmbedding,
openRouterEmbedding,
lmStudioEmbedding,
geminiEmbedding,
togetherEmbedding,
vllmEmbedding,
openaiCompatibleEmbedding,
} from "wolbarg";
embedding: openaiEmbedding({
apiKey: process.env.OPENAI_API_KEY!,
model: "text-embedding-3-small",
})
embedding: ollamaEmbedding({
apiKey: "ollama",
model: "nomic-embed-text",
})
```
### Custom embedding provider [#custom-embedding-provider]
```ts
const embedding = {
model: "my-model",
async embed(text: string) {
/* return Float32Array */
},
async validate() {
const v = await this.embed("ping");
return { dimensions: v.length };
},
};
```
Changing embedding dimensionality on an existing database throws at startup — create a new DB file or wipe data first.
## LLM providers [#llm-providers]
```ts
import { openaiLlm, ollamaLlm, openRouterLlm } from "wolbarg";
llm: openaiLlm({
apiKey: process.env.OPENAI_API_KEY!,
model: "gpt-4.1-mini",
})
```
Without `llm`, TypeScript will not allow `compress()`. At runtime you get `ProviderNotConfiguredError`.
## Keyword search [#keyword-search]
```ts
keywordSearch: bm25()
```
Enables [Hybrid Search](/docs/hybrid-search). Since **0.6.0**, `hybrid: true` without `keywordSearch` throws `ValidationError` — there is no silent semantic-only fallback.
## Rerankers [#rerankers]
```ts
import { jinaReranker, cohereReranker, bgeReranker, crossEncoder } from "wolbarg";
reranker: jinaReranker({ apiKey: process.env.JINA_API_KEY! })
```
Pass `rerank: true` on recall. Missing `reranker` throws `ValidationError`; built-in adapters throw `RerankError` on failure. See [Rerankers](/docs/rerankers).
## OCR and vision [#ocr-and-vision]
```ts
import { tesseract, geminiVision, openaiVision } from "wolbarg";
ocr: tesseract(),
vision: geminiVision({ apiKey: process.env.GEMINI_API_KEY! }),
```
See [OCR](/docs/ocr) and [Vision Models](/docs/vision).
## Chunking [#chunking]
```ts
import { createChunkingStrategy } from "wolbarg";
chunking: createChunkingStrategy("markdown")
```
Strategies: `fixed`, `sentence`, `paragraph`, `markdown`, `heading`. Overridable per `ingest` call.
## Graph providers [#graph-providers]
**Removed in 0.6.0.** `sqliteGraph` / `neo4jGraph` are gone. See [Graph memory (removed)](/docs/graph-memory).
## When should it be used? [#when-should-it-be-used]
Configure only the providers you exercise. A semantic-only SQLite setup needs organization + storage + embedding. Add LLM for compression, BM25 before enabling hybrid, OCR/vision for images, and a reranker before enabling `rerank: true`.
## Related pages [#related-pages]
* [Configuration](/docs/configuration)
* [Installation](/docs/installation)
* [Hybrid Search](/docs/hybrid-search)
* [Rerankers](/docs/rerankers)
* [Compression Pipeline](/docs/compression)
* [Examples — Providers](/docs/examples/providers)
* [What's New](/docs/guides/whats-new)
---
# Quick Start
> Construct Wolbarg, remember facts, recall them, and optionally use hybrid search and document ingest.
URL: /docs/quick-start
## What is it? [#what-is-it]
A minimal path from zero to working semantic memory: construct, remember, recall, then optionally hybrid search and document ingest.
For production apps, put factories under `providers/` so you can swap SQLite ↔ Postgres without touching agent code — see [Project layout](/docs/installation#project-layout).
Use [Wolbarg Workspace](/docs/workspace) instead: `npx @wolbarg/workspace init`. This Quick Start is the **SDK** path for custom agents.
**No API key?** Point embeddings at local [Ollama](https://ollama.com) (`nomic-embed-text`) — see the [SDK README](https://github.com/wolbarg/wolbarg/blob/main/README.md) or use `npx wolbarg init` and pick Ollama as the provider.
### Projects (recommended) [#projects-recommended]
```bash
npx wolbarg init
```
```ts
import { createWolbargFromProjectConfig } from "wolbarg";
const ctx = createWolbargFromProjectConfig();
await ctx.ready();
```
Then continue with remember / recall below using that `ctx`.
## 1. Construct [#1-construct]
```ts
import {
wolbarg,
sqlite,
openaiEmbedding,
openaiLlm,
bm25,
} from "wolbarg";
const ctx = wolbarg({
organization: "my-org",
storage: sqlite("./data/memory.db"),
embedding: openaiEmbedding({
apiKey: process.env.OPENAI_API_KEY!,
model: "text-embedding-3-small",
}),
// Optional — enables compress()
llm: openaiLlm({
apiKey: process.env.OPENAI_API_KEY!,
model: "gpt-4.1-mini",
}),
// Required when using hybrid: true (fail-closed since 0.6.0)
keywordSearch: bm25(),
});
```
## 2. Remember [#2-remember]
```ts
const result = await ctx.remember({
agent: "research",
content: { text: "Stripe supports recurring invoices." },
metadata: { topic: "billing", source: "docs" },
});
```
From a chat transcript (experimental — default needs no LLM):
```ts
await ctx.rememberFromMessages(
[
{ role: "user", content: "Stripe supports recurring invoices." },
{ role: "assistant", content: "Noted." },
],
{ agent: "research", mode: "raw" },
);
```
## 3. Recall [#3-recall]
```ts
const results = await ctx.recall({
query: "How do recurring invoices work?",
topK: 5,
threshold: 0.3,
filter: { agent: "research" },
});
console.log(results[0]?.content.text, results[0]?.similarity);
```
## 4. Hybrid + filters (optional) [#4-hybrid--filters-optional]
Since **0.6.0**, `hybrid: true` throws `ValidationError` if `keywordSearch` is not configured. There is no silent semantic-only fallback.
```ts
import { meta } from "wolbarg";
const hits = await ctx.recall({
query: "recurring invoices",
topK: 5,
hybrid: true,
filter: {
agent: "research",
metadata: meta.eq("topic", "billing"),
},
});
```
## 5. Ingest a document (optional) [#5-ingest-a-document-optional]
Markdown / TXT ingest works out of the box. For PDF or DOCX install peers first (`pdf-parse@1.1.4`, `mammoth`). See [Document Ingestion](/docs/document-ingestion).
```bash
npm install pdf-parse@1.1.4 # required for .pdf ingest
npm install mammoth # required for .docx ingest
```
```ts
const result = await ctx.ingest({
agent: "docs",
source: { path: "./guide.md" },
chunking: { strategy: "markdown", chunkSize: 800, overlap: 100 },
});
console.log(result.chunkCount);
```
## When should you use this pattern? [#when-should-you-use-this-pattern]
Start here for every new project. Add hybrid search, rerankers, and ingest only when you need them. Switch backends via [Project layout](/docs/installation#project-layout) instead of scattering factory calls.
To debug what agents remembered and how recall ranked results, enable telemetry and open [Wolbarg Studio](/docs/observability).
## Related pages [#related-pages]
* [Installation](/docs/installation)
* [Configuration](/docs/configuration)
* [Observability & Studio](/docs/observability)
* [recall()](/docs/api/recall)
* [rememberFromMessages()](/docs/api/remember-from-messages)
* [ingest()](/docs/api/ingest)
* [Example — Vercel AI memory](/docs/examples/vercel-ai-memory)
* [Vercel AI integration](/docs/integrations/vercel-ai)
* [What's New](/docs/guides/whats-new)
* [Examples](/docs/examples)
---
# Real-time events
> Subscribe to memory changes with wolbarg.subscribe() — in-process EventEmitter for SQLite, LISTEN/NOTIFY for Postgres, with filters and safe callbacks.
URL: /docs/realtime-events
## What is it? [#what-is-it]
`subscribe()` registers a callback that fires when a memory operation **commits** — no polling `recall()` or `history()`.
Use it to:
* Mirror writes into UI / dashboards
* Trigger downstream agent tools when facts change
* Keep secondary indexes or caches coherent
* Audit live multi-agent activity
## Quick start [#quick-start]
```ts
const unsubscribe = ctx.subscribe(
{
organization: "my-org",
agent: "research",
event: ["remember", "update"],
},
(event) => {
console.log(event.event, event.memoryId, event.upsertAction);
},
);
// later
unsubscribe();
```
`close()` tears down **all** subscriptions for that client.
## API [#api]
```ts
subscribe(
filter: SubscribeFilter,
callback: MemoryChangeCallback,
): Unsubscribe
interface SubscribeFilter {
organization: string;
agent?: string;
event?: SubscribableEvent | SubscribableEvent[];
}
type SubscribableEvent =
| "remember"
| "update"
| "forget"
| "compress"
| "ingest"
| "*";
interface MemoryChangeEvent {
event: Exclude;
organization: string;
agent: string;
memoryId: string | string[];
timestamp: string;
traceId?: string;
sessionId?: string;
/** Present when upsert path ran during remember/ingest. */
upsertAction?: "created" | "updated" | "skipped";
}
```
## Event types [#event-types]
| Event | When |
| ---------- | -------------------------------------------- |
| `remember` | New memory inserted |
| `update` | Existing memory upserted / `update()` |
| `forget` | Memory deleted |
| `compress` | Compression archived sources + wrote summary |
| `ingest` | Document ingest completed |
| `*` | Subscribe to all of the above |
### Filter matching [#filter-matching]
* `organization` is **required** and always matched.
* `agent` optional — omit to receive all agents in the org.
* `event` optional — omit or pass `"*"` for all event kinds; pass an array for a whitelist.
## SQLite: in-process only (important) [#sqlite-in-process-only-important]
**SQLite `subscribe()` only delivers events within the same Node.js process.**
A second process writing to the same `memory.db` file will **not** notify subscribers in this process. SQLite has no cross-process pub/sub. This is intentional.
| Topology | SQLite subscribe |
| -------------------------------------- | --------------------------- |
| One process, many async writers | ✅ Events delivered |
| Many processes, shared file | ❌ No cross-process delivery |
| Need multi-host / multi-process events | Use **PostgreSQL** |
For multi-process **write safety** on SQLite, see [Concurrency](/docs/concurrency). For multi-process **event delivery**, use Postgres.
## PostgreSQL: LISTEN / NOTIFY [#postgresql-listen--notify]
Postgres backend uses transactional `NOTIFY wolbarg_events` with a dedicated `LISTEN` connection (not borrowed from the query pool).
| Detail | Behavior |
| --------- | --------------------------------------------------------- |
| Delivery | Cross-process and cross-host (same database) |
| Filtering | Org / agent / event filtered **client-side** after notify |
| Payload | IDs + metadata only (NOTIFY capped at \~8000 bytes) |
| Reconnect | Listener reconnects if the connection drops |
| Pooling | Listen connection is dedicated — not part of the pool |
Payloads intentionally exclude full memory text so notifications stay small and safe under the NOTIFY size limit.
## Safety [#safety]
* Subscriber callback errors are **caught and logged**.
* A throwing subscriber **never** fails the write that triggered the event.
* Unsubscribing is idempotent; closing the client clears remaining listeners.
## Patterns [#patterns]
### React to preference updates only [#react-to-preference-updates-only]
```ts
ctx.subscribe(
{ organization: "my-org", event: "update" },
async (e) => {
await refreshUserProfile(e.memoryId);
},
);
```
### Fan-out all org activity to a log [#fan-out-all-org-activity-to-a-log]
```ts
ctx.subscribe({ organization: "my-org", event: "*" }, (e) => {
audit.write(e);
});
```
### Combine with upsert [#combine-with-upsert]
When [memory dedupe](/docs/memory-upsert) updates in place, you receive `"update"` (and may see `upsertAction: "updated"`). Fresh inserts still emit `"remember"`.
## Related pages [#related-pages]
* [Memory upsert](/docs/memory-upsert)
* [Concurrency](/docs/concurrency)
* [subscribe() API](/docs/api/subscribe)
* [PostgreSQL](/docs/storage/postgresql)
* [What's New](/docs/guides/whats-new)
---
# Rerankers
> Optional cross-encoder reranking and MMR diversification for recall results. Fail-closed since 0.6.0 — throws RerankError on provider failure.
URL: /docs/rerankers
## What is it? [#what-is-it]
A second-stage ranking step. After vector (and optional hybrid) retrieval, a reranker scores query–document pairs. MMR diversifies the final set to reduce near-duplicates.
## Why does it exist? [#why-does-it-exist]
Bi-encoder retrieval is fast but coarse. Cross-encoders improve precision. MMR improves diversity for agent context windows. Incorrect ranking that looks successful is worse than a loud error — so since **0.6.0**, rerank fails closed.
## How does it work? [#how-does-it-work]
### Rerank [#rerank]
```ts
import { jinaReranker, cohereReranker } from "wolbarg";
reranker: jinaReranker({ apiKey: process.env.JINA_API_KEY! })
await ctx.recall({ query: "…", topK: 5, rerank: true });
```
Built-in factories: `jinaReranker`, `cohereReranker`, `bgeReranker`, `crossEncoder`, `openaiReranker`.
### Fail-closed (0.6.0+) [#fail-closed-060]
* `rerank: true` without a configured `reranker` throws **`ValidationError`**
* Built-in HTTP / OpenAI rerankers throw **`RerankError`** on provider failure or empty rankings — they do **not** fall back to identity order
Catch `RerankError` explicitly when you enable rerank.
### MMR [#mmr]
```ts
await ctx.recall({
query: "…",
topK: 5,
mmr: true, // lambda = 0.5
// mmr: { lambda: 0.7 } // higher = more relevance, less diversity
});
```
## When should it be used? [#when-should-it-be-used]
Use rerankers for high-stakes grounding (support answers, code RAG). Use MMR when agents repeatedly get near-duplicate snippets.
## Performance notes [#performance-notes]
* Over-fetch (`retrieval.overFetchFactor`) feeds the reranker more candidates
* Network latency depends on the remote rerank API
* Skip rerank in latency-critical hot paths
## Related pages [#related-pages]
* [Hybrid Search](/docs/hybrid-search)
* [Semantic Search](/docs/search)
* [Example — Rerankers](/docs/examples/rerankers)
* [What's New](/docs/guides/whats-new)
* [Errors](/docs/reference/errors)
---
# Semantic Search
> How Wolbarg embeds queries and retrieves memories by cosine similarity.
URL: /docs/search
## What is it? [#what-is-it]
Semantic search is the default `recall()` path: embed the query, compare against stored memory embeddings, return the top-K closest records.
## Why does it exist? [#why-does-it-exist]
Agents ask questions in natural language. Exact string match fails when vocabulary drifts; vectors catch meaning.
## How does it work? [#how-does-it-work]
1. `embedding.embed(query)` produces a query vector
2. Storage runs nearest-neighbor search (sqlite-vec / pgvector or in-process cosine)
3. Optional filters (`agent`, metadata, archived) shrink the candidate set
4. Results are ranked by similarity and trimmed to `topK`
```ts
const results = await ctx.recall({
query: "How do recurring invoices work?",
topK: 5,
threshold: 0.3,
filter: { agent: "research" },
});
```
## When should it be used? [#when-should-it-be-used]
Always. Semantic search is the baseline. Add [Hybrid Search](/docs/hybrid-search) when exact tokens matter, [Rerankers](/docs/rerankers) when precision matters, and [Metadata Filtering](/docs/metadata-filtering) to scope corpora.
## Performance notes [#performance-notes]
* Latency is dominated by embedding network calls + vector scan size
* Keep `threshold` above 0 for noisy corpora
* Prefer metadata filters before raising `topK`
## Related pages [#related-pages]
* [Hybrid Search](/docs/hybrid-search)
* [recall()](/docs/api/recall)
* [Performance](/docs/performance)
---
# Vision Models
> Caption and describe images with Gemini or OpenAI vision providers during ingest.
URL: /docs/vision
## What is it? [#what-is-it]
Vision providers that produce captions, descriptions, and entities from images, merged into ingest text before chunking.
## Why does it exist? [#why-does-it-exist]
OCR reads glyphs; vision models explain what an image *means* — charts, UI layout, diagrams.
## How does it work? [#how-does-it-work]
```ts
import { geminiVision, openaiVision } from "wolbarg";
vision: geminiVision({ apiKey: process.env.GEMINI_API_KEY! })
// or
vision: openaiVision({ apiKey: process.env.OPENAI_API_KEY! })
```
OCR text, captions, descriptions, and entities are concatenated before chunking. Configure either or both providers.
## When should it be used? [#when-should-it-be-used]
Charts, product photos, and UI screenshots where labels alone are insufficient. Prefer OCR-only for dense text scans to save cost.
## Performance notes [#performance-notes]
* Vision calls dominate ingest latency for images
* Cache originals outside Wolbarg if you re-process often
## Related pages [#related-pages]
* [OCR](/docs/ocr)
* [Image Ingestion](/docs/image-ingestion)
* [Provider Architecture](/docs/providers)
---
# Wolbarg Workspace
> Shared, reconciled project truth for Cursor, Claude Code, and Codex — install from npm with @wolbarg/workspace.
URL: /docs/workspace
Wolbarg Workspace is the product built on top of the
[`wolbarg`](/docs/quick-start) SDK. The SDK stays tool-agnostic; Workspace
adds project truth, reconciliation, and agent connectors.
## Why use it? [#why-use-it]
Cursor, Claude Code, and Codex forget everything when a session ends. They re-investigate the same code, reopen settled decisions, and act on stale context.
Wolbarg Workspace keeps one shared, always-current view of your project — decisions, architecture, tasks, bugs, conventions — and every connected agent reads and updates it automatically.
* Stop re-explaining your codebase every session.
* A decision made in Cursor is known to Claude Code and Codex.
* Old facts get replaced, not piled up.
* Runs fully local by default.
## Install [#install]
Published on npm as **`@wolbarg/workspace@0.1.0`**.
Run inside your project folder (not global):
```bash
npm install @wolbarg/workspace
npx @wolbarg/workspace init
```
A short wizard asks for storage and an embedding provider. Press Enter to keep the defaults (SQLite + Ollama, fully local).
Skip the wizard:
```bash
npx @wolbarg/workspace init --yes
```
Packages:
| Package | Purpose |
| -------------------------------------------------------------------------------- | ----------------------------------- |
| [`@wolbarg/workspace`](https://www.npmjs.com/package/@wolbarg/workspace) | CLI + domain library |
| [`@wolbarg/workspace-mcp`](https://www.npmjs.com/package/@wolbarg/workspace-mcp) | MCP server (installed by `connect`) |
Source: [github.com/wolbarg/workspace](https://github.com/wolbarg/workspace)
## Connect your agent [#connect-your-agent]
```bash
npx @wolbarg/workspace connect cursor
npx @wolbarg/workspace connect claude
npx @wolbarg/workspace connect codex
```
Restart the agent afterwards. No manual MCP JSON editing is required.
## Embedding provider [#embedding-provider]
Workspace needs an embedding model to search memory. The default is [Ollama](https://ollama.com):
```bash
ollama pull nomic-embed-text
```
The `init` wizard also offers OpenAI, Voyage AI, Gemini, LM Studio, OpenRouter, or any OpenAI-compatible endpoint. API keys go in `.env.wolbarg` — never commit that file.
## Config [#config]
`init` writes:
| File | What it is |
| -------------------------------- | ------------------------------- |
| `.wolbarg/workspace/config.json` | Storage + embedding settings |
| `.wolbarg/workspace/memory.db` | Local SQLite database (default) |
| `.env.wolbarg` | API keys — do not commit |
Defaults: SQLite storage, Ollama embeddings, 90-day retention. Teams can switch to Postgres in the wizard. Re-run `init` any time to change providers.
## Check that it works [#check-that-it-works]
```bash
npx @wolbarg/workspace doctor
npx @wolbarg/workspace status
npx @wolbarg/workspace review
```
## How it relates to the SDK [#how-it-relates-to-the-sdk]
| Layer | Package | Job |
| ------- | ------------------------------------------------------------------------ | ---------------------------------------------- |
| SDK | [`wolbarg`](https://www.npmjs.com/package/wolbarg) | Embeddings, storage, search, providers |
| Product | [`@wolbarg/workspace`](https://www.npmjs.com/package/@wolbarg/workspace) | Project truth, reconciliation, CLI, connectors |
Use the SDK when you are building your own agent memory. Use Workspace when you want Cursor / Claude Code / Codex to share current project truth out of the box.
## Related pages [#related-pages]
* [Quick Start (SDK)](/docs/quick-start)
* [Connectors](/connector)
* [Installation (SDK)](/docs/installation)
* [FAQ](/docs/faq)
---
# forget()
> Archive or delete memories by id or metadata/agent filter. Supports AbortSignal.
URL: /docs/api/forget
## Signature [#signature]
```ts
forget(options: ForgetOptions): Promise
```
## Example [#example]
```ts
await ctx.forget({ id: record.id });
await ctx.forget({
filter: { agent: "research" },
signal: AbortSignal.timeout(5_000),
});
```
Optional `signal?: AbortSignal` cancels with `CancellationError`.
## Related pages [#related-pages]
* [history()](/docs/api/history)
* [Metadata Filtering](/docs/metadata-filtering)
* [API Overview](/docs/api)
---
# getRelated()
> Removed in Wolbarg 0.6.0. Graph memory APIs are no longer part of the core SDK.
URL: /docs/api/get-related
## Removed in 0.6.0 [#removed-in-060]
`getRelated()` was part of the optional graph memory layer and is **no longer exported** from `wolbarg`.
Also removed: `linkMemories`, `sqliteGraph`, `neo4jGraph`, `includeGraph`, and the `neo4j-driver` peer.
This page is kept for redirects. See [Graph memory (removed)](/docs/graph-memory), [What's New](/docs/guides/whats-new), and [Migration](/docs/migration).
## Alternatives [#alternatives]
Filter related facts with [metadata](/docs/metadata-filtering), or run traversal in an external graph store.
## Related pages [#related-pages]
* [Graph memory](/docs/graph-memory)
* [linkMemories()](/docs/api/link-memories)
* [recall()](/docs/api/recall)
* [What's New](/docs/guides/whats-new)
* [Migration](/docs/migration)
---
# history()
> Read audit events for remember, forget, compress, and related operations.
URL: /docs/api/history
## Signature [#signature]
```ts
history(options?: HistoryOptions): Promise
```
Use history to audit what changed when debugging multi-agent writes or compression jobs.
## Related pages [#related-pages]
* [forget()](/docs/api/forget)
* [Compression Pipeline](/docs/compression)
---
# API Overview
> Index of the Wolbarg public API — constructor, remember, rememberFromMessages, update, recall, ingest, forget, history, subscribe, AbortSignal, and lifecycle.
URL: /docs/api
## What is it? [#what-is-it]
The public surface developers call after constructing `Wolbarg` / `wolbarg()`. Current SDK version: **0.6.0** (`SDK_VERSION`).
## Core entry points [#core-entry-points]
| Page | Method |
| ---------------------------------------------------------- | --------------------------------- |
| [Wolbarg](/docs/api/wolbarg) | construct / ready / close |
| [remember()](/docs/api/remember) | Store a memory (`RememberResult`) |
| [rememberFromMessages()](/docs/api/remember-from-messages) | Chat → memory (**experimental**) |
| [update()](/docs/api/update) | Update a memory by id |
| [recall()](/docs/api/recall) | Semantic / hybrid search |
| [ingest()](/docs/api/ingest) | Document → memories |
| [forget()](/docs/api/forget) | Archive / delete memories |
| [history()](/docs/api/history) | Audit events |
| [subscribe()](/docs/api/subscribe) | Real-time change events |
| [stats() / clear()](/docs/api/lifecycle) | Introspection / wipe |
Compression lives under [Compression Pipeline](/docs/compression).
## AbortSignal [#abortsignal]
Optional `signal?: AbortSignal` on `remember`, `rememberFromMessages`, `recall`, `update`, `compress`, and `forget`. Cancellation throws `CancellationError`.
## Errors (common) [#errors-common]
| Situation | Error |
| ------------------------------------------------------------- | ---------------------------- |
| `hybrid: true` / `rerank: true` without provider | `ValidationError` |
| Built-in reranker HTTP / empty ranking | `RerankError` |
| Cancelled via AbortSignal | `CancellationError` |
| SQLite lock exhaustion | `StorageLockedError` |
| CAS mismatch on `expectedVersion` | `VersionConflictError` |
| Feature used without provider (e.g. `compress` without `llm`) | `ProviderNotConfiguredError` |
See [Errors](/docs/reference/errors).
## Feature guides linked from the API [#feature-guides-linked-from-the-api]
| Capability | Docs |
| ------------------ | ---------------------------------------------------------------------------------------------- |
| Real-time events | [subscribe()](/docs/api/subscribe) · [guide](/docs/realtime-events) |
| Upsert / dedupe | [remember()](/docs/api/remember) · [update()](/docs/api/update) · [guide](/docs/memory-upsert) |
| Hybrid / rerank | [Hybrid Search](/docs/hybrid-search) · [Rerankers](/docs/rerankers) |
| Embedding cache | [Embedding cache](/docs/embedding-cache) |
| SQLite concurrency | [Concurrency](/docs/concurrency) |
## Not in core (0.6.0) [#not-in-core-060]
Graph APIs (`linkMemories`, `getRelated`, `sqliteGraph`, `neo4jGraph`, `includeGraph`) were **removed**. Stub pages remain for redirects: [linkMemories](/docs/api/link-memories) · [getRelated](/docs/api/get-related) · [Graph memory](/docs/graph-memory).
## Generated reference [#generated-reference]
Every exported type and factory is listed under [API Reference](/docs/api/reference).
## Related pages [#related-pages]
* [Configuration](/docs/configuration)
* [Quick Start](/docs/quick-start)
* [What's New](/docs/guides/whats-new)
* [Architecture](/docs/architecture)
* [Production](/docs/guides/production)
---
# ingest()
> Parse documents into chunked semantic memories.
URL: /docs/api/ingest
## Signature [#signature]
```ts
ingest(options: IngestOptions): Promise
// source: { path } | { buffer, filename? } | { text }
// chunking?: { strategy, chunkSize, overlap }
// metadata?: Record
```
Pipeline: parse → OCR/vision (if configured) → chunk → embed (batch) → store (batch transaction).
## Dependencies [#dependencies]
PDF and DOCX require peers: `npm install pdf-parse@1.1.4` · `npm install mammoth` · `npm install tesseract.js` for OCR.
## Example [#example]
```ts
await ctx.ingest({
agent: "docs",
source: { path: "./guide.md" },
chunking: { strategy: "markdown", chunkSize: 800, overlap: 100 },
});
```
## Related pages [#related-pages]
* [Document Ingestion](/docs/document-ingestion)
* [Chunking](/docs/chunking)
* [Limitations](/docs/guides/limitations)
---
# stats() / clear()
> Introspection and organization-scoped wipe helpers.
URL: /docs/api/lifecycle
## stats() [#stats]
```ts
const s = await ctx.stats();
// memory counts, models, storage info
```
`llmModel` may be `null` when no LLM is configured.
## clear() [#clear]
```ts
await ctx.clear(); // organization-scoped, destructive
```
## Related pages [#related-pages]
* [Wolbarg](/docs/api/wolbarg)
* [Best Practices](/docs/guides/best-practices)
---
# linkMemories()
> Removed in Wolbarg 0.6.0. Graph memory APIs are no longer part of the core SDK.
URL: /docs/api/link-memories
## Removed in 0.6.0 [#removed-in-060]
`linkMemories()` was part of the optional graph memory layer and is **no longer exported** from `wolbarg`.
Also removed: `getRelated`, `sqliteGraph`, `neo4jGraph`, `includeGraph`, and the `neo4j-driver` peer.
This page is kept for redirects. See [Graph memory (removed)](/docs/graph-memory), [What's New](/docs/guides/whats-new), and [Migration](/docs/migration).
## Alternatives [#alternatives]
Model relationships with [metadata](/docs/metadata-filtering) or an external graph store.
## Related pages [#related-pages]
* [Graph memory](/docs/graph-memory)
* [getRelated()](/docs/api/get-related)
* [What's New](/docs/guides/whats-new)
* [Migration](/docs/migration)
---
# recall()
> Semantic and hybrid search with filters, thresholds, MMR, and rerank. Fail-closed hybrid/rerank since 0.6.0. Supports AbortSignal.
URL: /docs/api/recall
## Signature [#signature]
```ts
recall(options: RecallOptions): Promise
```
## Options [#options]
| Field | Default | Description |
| ----------- | ------- | ----------------------------------------------- |
| `query` | — | Natural-language query (required) |
| `topK` | `5` | Max results (1–1000) |
| `threshold` | `0` | Minimum cosine similarity |
| `filter` | — | `agent`, `includeArchived`, `metadata` |
| `hybrid` | — | `true` or weights; **requires** `keywordSearch` |
| `mmr` | — | Diversification; `true` or `{ lambda }` |
| `rerank` | `false` | **Requires** configured `reranker` |
| `explain` | `false` | Ranking diagnostics + timings |
| `signal` | — | `AbortSignal` — throws `CancellationError` |
## Fail-closed hybrid and rerank [#fail-closed-hybrid-and-rerank]
* `hybrid: true` without `keywordSearch` → **`ValidationError`** (no semantic-only fallback)
* `rerank: true` without `reranker` → **`ValidationError`**
* Built-in rerankers throw **`RerankError`** on failure (no identity-order fallback)
## Example [#example]
```ts
import { meta } from "wolbarg";
const hits = await ctx.recall({
query: "billing invoices",
topK: 8,
threshold: 0.25,
hybrid: { semanticWeight: 0.7, keywordWeight: 0.3 },
mmr: { lambda: 0.6 },
rerank: true,
filter: {
agent: "research",
metadata: meta.and(
meta.eq("topic", "billing"),
meta.gte("priority", 1),
),
},
signal: AbortSignal.timeout(10_000),
});
```
## Related pages [#related-pages]
* [Semantic Search](/docs/search)
* [Hybrid Search](/docs/hybrid-search)
* [Rerankers](/docs/rerankers)
* [What's New](/docs/guides/whats-new)
* [API Overview](/docs/api)
---
# rememberFromMessages()
> Experimental conversation → memory bridge — store chat turns as memories (raw or LLM extract).
URL: /docs/api/remember-from-messages
## Signature [#signature]
```ts
/** @experimental until 1.0 */
rememberFromMessages(
messages: ConversationMessage[],
options: RememberFromMessagesOptions,
): Promise
interface ConversationMessage {
role: string;
content: string;
}
interface RememberFromMessagesOptions {
agent: string;
/** Default: "raw" */
mode?: "raw" | "extract";
/** Default: "last_user" — only for mode "raw" */
rawStrategy?: "last_user" | "all_user";
metadata?: Record;
dedupe?: boolean | MemoryDedupeConfig;
}
```
**Stability:** experimental until 1.0. Prefer pinning your `wolbarg` version if you depend on this shape.
## Modes [#modes]
| Mode | LLM required? | Behavior |
| --------------- | -------------------------- | ---------------------------------------------------- |
| `raw` (default) | No | Store user message text (`last_user` or `all_user`) |
| `extract` | Yes (`llm` in constructor) | Short prompt → one fact per line → `remember()` each |
## Example — raw (no LLM) [#example--raw-no-llm]
```ts
const saved = await ctx.rememberFromMessages(
[
{ role: "user", content: "I prefer dark mode" },
{ role: "assistant", content: "Noted." },
{ role: "user", content: "Deploy only on Fridays" },
],
{ agent: "assistant" },
);
// Default rawStrategy is last_user → one memory:
console.log(saved[0]?.content.text); // "Deploy only on Fridays"
```
## Example — extract (optional LLM) [#example--extract-optional-llm]
```ts
import { wolbarg, sqlite, openaiEmbedding, openaiLlm } from "wolbarg";
const ctx = wolbarg({
organization: "demo",
storage: sqlite("./memory.db"),
embedding: openaiEmbedding({
apiKey: process.env.OPENAI_API_KEY!,
model: "text-embedding-3-small",
}),
llm: openaiLlm({
apiKey: process.env.OPENAI_API_KEY!,
model: "gpt-4.1-mini",
}),
});
const facts = await ctx.rememberFromMessages(
[
{ role: "user", content: "I live in Berlin and prefer tea over coffee." },
{ role: "assistant", content: "Got it." },
],
{ agent: "assistant", mode: "extract" },
);
```
Without `llm`, `mode: "extract"` throws `ProviderNotConfiguredError`.
## Chat → memory → recall [#chat--memory--recall]
```ts
await ctx.rememberFromMessages(messages, { agent: "assistant", mode: "raw" });
const hits = await ctx.recall({
query: "What UI theme does the user like?",
topK: 3,
filter: { agent: "assistant" },
});
```
## Related pages [#related-pages]
* [remember()](/docs/api/remember)
* [Example — Conversation memory](/docs/examples/conversation-memory)
* [Example — Vercel AI memory](/docs/examples/vercel-ai-memory)
* [Vercel AI integration](/docs/integrations/vercel-ai)
* [Limitations](/docs/guides/limitations)
---
# remember()
> Store a semantic memory with embedding, optional metadata, optional dedupe, and RememberResult.action.
URL: /docs/api/remember
## Signature [#signature]
```ts
remember(options: RememberOptions): Promise
rememberBatch(items: RememberOptions[]): Promise
interface RememberOptions {
agent: string;
content: { text: string };
metadata?: Record;
/** Per-call dedupe override; undefined uses constructor `memory.dedupe`. */
dedupe?: boolean | MemoryDedupeConfig;
}
interface RememberResult extends MemoryRecord {
action: "created" | "updated";
}
```
## Example [#example]
```ts
const result = await ctx.remember({
agent: "research",
content: { text: "Acme raised Series B at $50M." },
metadata: { company: "Acme", year: 2024 },
});
console.log(result.id, result.action);
```
## Dedupe (0.4) [#dedupe-04]
Dedupe is **off by default**. Enable via constructor `memory.dedupe` or per call:
```ts
await ctx.remember({
agent: "assistant",
content: { text: "User prefers dark mode" },
dedupe: { strategy: "exact-or-near", nearThreshold: 0.92 },
});
```
When an existing active memory matches, `action` is `"updated"` and the row id is reused. Full guide: [Memory upsert](/docs/memory-upsert).
## Related pages [#related-pages]
* [Memory upsert](/docs/memory-upsert)
* [rememberFromMessages()](/docs/api/remember-from-messages)
* [update()](/docs/api/update)
* [recall()](/docs/api/recall)
* [subscribe()](/docs/api/subscribe)
* [Metadata Filtering](/docs/metadata-filtering)
* [Example — Basic Memory](/docs/examples/basic-memory)
* [Example — Conversation memory](/docs/examples/conversation-memory)
---
# subscribe()
> Register real-time callbacks for memory change events — filter by organization, agent, and event type.
URL: /docs/api/subscribe
## Signature [#signature]
```ts
subscribe(
filter: SubscribeFilter,
callback: (event: MemoryChangeEvent) => void,
): Unsubscribe
interface SubscribeFilter {
organization: string;
agent?: string;
event?: SubscribableEvent | SubscribableEvent[];
}
type SubscribableEvent =
| "remember"
| "update"
| "forget"
| "compress"
| "ingest"
| "*";
interface MemoryChangeEvent {
event: Exclude;
organization: string;
agent: string;
memoryId: string | string[];
timestamp: string;
traceId?: string;
sessionId?: string;
upsertAction?: "created" | "updated" | "skipped";
}
type Unsubscribe = () => void;
```
## Example [#example]
```ts
const stop = ctx.subscribe(
{ organization: "my-org", event: ["remember", "update"] },
(e) => console.log(e.event, e.memoryId),
);
await ctx.remember({
agent: "assistant",
content: { text: "Ships prefer express checkout" },
});
stop();
await ctx.close(); // also clears remaining subscriptions
```
## Backend notes [#backend-notes]
| Backend | Delivery |
| ---------- | ----------------------------------- |
| SQLite | Same Node process only |
| PostgreSQL | Cross-process via `LISTEN`/`NOTIFY` |
Full guide: [Real-time events](/docs/realtime-events).
## Related pages [#related-pages]
* [Real-time events](/docs/realtime-events)
* [update()](/docs/api/update)
* [remember()](/docs/api/remember)
* [close()](/docs/api/lifecycle)
---
# update()
> Explicitly update an existing memory by id — content and/or metadata — returning RememberResult.
URL: /docs/api/update
## Signature [#signature]
```ts
update(options: {
id: string;
content?: { text: string };
metadata?: Record;
}): Promise
interface RememberResult extends MemoryRecord {
action: "created" | "updated";
}
```
## Example [#example]
```ts
const result = await ctx.update({
id: memoryId,
content: { text: "User prefers dark mode (confirmed)" },
metadata: { editedBy: "admin", editedAt: new Date().toISOString() },
});
console.log(result.action); // "updated"
```
## Behavior [#behavior]
* Replaces content when provided (re-embeds).
* Merges metadata when provided (shallow).
* Emits history `"updated"` and subscribe `"update"`.
* Prefer automatic [dedupe / upsert](/docs/memory-upsert) when the agent restates facts without knowing the id.
## Related pages [#related-pages]
* [Memory upsert](/docs/memory-upsert)
* [remember()](/docs/api/remember)
* [subscribe()](/docs/api/subscribe)
* [history()](/docs/api/history)
---
# Wolbarg
> Lifecycle methods for the Wolbarg class — constructor options including concurrency, embeddingCache, memory.dedupe, ready, close, and subscribe.
URL: /docs/api/wolbarg
## Constructor [#constructor]
```ts
new Wolbarg(options) // preferred
wolbarg(options) // factory (recommended in docs)
new Wolbarg() // then init() for v0.1 compat
```
When `llm` is present, the instance type allows `compress`. Without it, calling `compress` is a compile-time error.
### Common options [#common-options]
```ts
import { wolbarg, sqlite, openaiEmbedding, bm25 } from "wolbarg";
const ctx = wolbarg({
organization: "my-org",
storage: sqlite("./memory.db"),
embedding: openaiEmbedding({ /* … */ }),
keywordSearch: bm25(), // required when using hybrid: true
concurrency: {
maxRetries: 5,
baseBackoffMs: 50,
maxBackoffMs: 2000,
lockTimeoutMs: 5000,
},
embeddingCache: {
enabled: true,
ttlMs: undefined,
maxEntries: 10_000,
},
memory: {
dedupe: {
enabled: false, // default — opt in for upsert
strategy: "exact-or-near",
nearThreshold: 0.92,
nearCandidateLimit: 8,
},
},
});
```
See [Configuration](/docs/configuration) for the full option table (including Postgres `schema` / SSL / `maxPoolSize`). Isolate factories with [Project layout](/docs/installation#project-layout).
## ready() [#ready]
```ts
await ctx.ready();
```
Opens storage (and telemetry when configured) and probes embedding dimensions. Called automatically by other methods; use explicitly to fail fast at startup.
## close() [#close]
```ts
await ctx.close();
```
Idempotent. Releases database connections and tears down all [`subscribe()`](/docs/api/subscribe) listeners.
## subscribe() [#subscribe]
```ts
const stop = ctx.subscribe({ organization: "my-org" }, (e) => {
console.log(e.event, e.memoryId);
});
```
See [subscribe()](/docs/api/subscribe) and [Real-time events](/docs/realtime-events). Organization cannot be overridden to another tenant.
## init() shim [#init-shim]
```ts
const ctx = new Wolbarg();
await ctx.init({
organization: "my-org",
database: { provider: "sqlite", connectionString: "./memory.db" },
embedding: { baseUrl, apiKey, model },
llm: { baseUrl, apiKey, model }, // optional
});
```
Prefer constructor / `wolbarg()` options. See [init() Compatibility](/docs/reference/init-compat).
## Related pages [#related-pages]
* [Configuration](/docs/configuration)
* [remember()](/docs/api/remember)
* [rememberFromMessages()](/docs/api/remember-from-messages)
* [update()](/docs/api/update)
* [recall()](/docs/api/recall)
* [subscribe()](/docs/api/subscribe)
* [API Overview](/docs/api)
* [What's New](/docs/guides/whats-new)
---
# Connectors
> Docs index for Wolbarg connectors — the product listing lives at /connector.
URL: /docs/connectors
## Product page [#product-page]
Browse every connector on the marketing page:
**[→ All connectors](/connector)**
That page lists **Wolbarg Workspace** (Cursor / Claude Code / Codex) and AI SDK adapters for custom agents.
## Wolbarg Workspace [#wolbarg-workspace]
Shared project truth for coding agents:
* [Workspace docs](/docs/workspace)
* npm: [`@wolbarg/workspace`](https://www.npmjs.com/package/@wolbarg/workspace)
```bash
npx @wolbarg/workspace init
npx @wolbarg/workspace connect cursor
```
## AI SDK adapters [#ai-sdk-adapters]
| Connector | Package | Docs |
| ------------- | --------------------- | -------------------------------------- |
| Vercel AI SDK | `@wolbarg/vercel-ai` | [Setup](/docs/integrations/vercel-ai) |
| OpenAI Agents | `@wolbarg/openai` | [Setup](/docs/integrations/openai) |
| LangChain | `@wolbarg/langchain` | [Setup](/docs/integrations/langchain) |
| LlamaIndex | `@wolbarg/llamaindex` | [Setup](/docs/integrations/llamaindex) |
| Mastra | `@wolbarg/mastra` | [Setup](/docs/integrations/mastra) |
Also see [AI SDKs overview](/docs/integrations).
---
# Best Practices
> Practical guidance for production Wolbarg usage — scoping, filters, peers, lifecycle, and provider isolation.
URL: /docs/guides/best-practices
## Scope memories [#scope-memories]
Use stable `agent` ids and meaningful metadata keys (`topic`, `source`, `collection`).
## Prefer metadata filters [#prefer-metadata-filters]
Narrow recall with `meta.*` before increasing `topK`. Combine with hybrid search for exact token matches. Model relationships with metadata when you need structure — graph APIs were [removed in 0.6.0](/docs/graph-memory).
## Isolate providers [#isolate-providers]
Keep `sqlite` / `postgres` / embedding factories in a `providers/` folder. Agents import one `memory` client. That way switching databases is a one-file change — see [Project layout](/docs/installation#project-layout).
## Configure hybrid and rerank before enabling flags [#configure-hybrid-and-rerank-before-enabling-flags]
Since 0.6.0, `hybrid: true` and `rerank: true` **fail closed**. Pass `keywordSearch: bm25()` and a `reranker` before setting those flags, or catch `ValidationError` / `RerankError`.
## Peers on demand [#peers-on-demand]
Do not install `pg` / `pdf-parse` / `mammoth` / `tesseract.js` unless you need them. If you ingest those formats or use Postgres, peers are **required**.
## Lifecycle [#lifecycle]
* Call `ready()` at process start to fail fast
* Always `close()` on shutdown
* One `Wolbarg` instance per process / org is enough
* Pass `AbortSignal` on long-running remember/recall when callers may cancel
## Production checklist [#production-checklist]
See the full [Production guide](/docs/guides/production) for SSL, pool sizing, backups, and troubleshooting.
## Related pages [#related-pages]
* [Performance](/docs/performance)
* [Production](/docs/guides/production)
* [Installation](/docs/installation)
* [Metadata Filtering](/docs/metadata-filtering)
* [Multi-Agent Memory](/docs/guides/shared-memory)
* [Limitations](/docs/guides/limitations)
---
# Limitations
> Honest boundaries of Wolbarg 0.6 — peers, PDF quality, SQLite, Postgres SSL/pool, fail-closed hybrid/rerank, and removed graph memory.
URL: /docs/guides/limitations
## Maturity [#maturity]
Core `remember` / `recall` (semantic + hybrid + metadata filters) on SQLite and PostgreSQL is the most battle-tested path. Document ingest, OCR/vision, and LLM compression are supported but depend on optional packages and external services where noted.
**Experimental (may change before 1.0):** [`rememberFromMessages()`](/docs/api/remember-from-messages) (especially `mode: "extract"`) and [`subscribe()`](/docs/realtime-events). Pin your `wolbarg` version if you depend on these shapes. Extract-mode quality is owned by your LLM.
For Vercel AI apps, prefer the stable middleware path in [`@wolbarg/vercel-ai`](/docs/integrations/vercel-ai) (AI SDK **v7+**) rather than hand-rolling recall/remember around `generateText`. Mid-stream cancel before the model `finish` event does not remember incomplete turns.
## Ingest dependencies [#ingest-dependencies]
```bash
npm install pdf-parse@1.1.4 # PDF
npm install mammoth # DOCX
npm install tesseract.js # OCR
npm install pg # PostgreSQL storage
```
* **.txt / .md / .csv / .json** — built-in
* **.pdf** — `pdf-parse` required; text-layer only unless OCR/vision on images
* **.docx** — `mammoth` required
* **images** — configure `ocr` and/or `vision`
See [Installation](/docs/installation).
## PDF extraction [#pdf-extraction]
* Scan / camera PDFs with no text layer yield empty extract
* Prefer simple text PDFs or pin `pdf-parse@1.1.4`
## SQLite [#sqlite]
* Uses Node `node:sqlite` — Node **22.5+**
* Hybrid BM25 uses FTS5 when available
* [`subscribe()`](/docs/realtime-events) on SQLite is **in-process only** (same Node process)
* Export / checkpoint / import / rollback are **whole-file** and refuse multi-org files — prefer one file per organization
* Under extreme lock contention, callers must handle `StorageLockedError` — see [Concurrency](/docs/concurrency)
## PostgreSQL [#postgresql]
* Requires `pg`
* `pgvector` optional; otherwise BYTEA + in-process cosine
* Remote hosts default to **`sslmode=require`** when unset; loopback is unchanged
* Default pool `maxPoolSize` is **20**
* Optional `schema` namespacing for tables, indexes, and NOTIFY channels
* Checkpoint / export / import require **file-backed SQLite**, not Postgres
See [Production](/docs/guides/production).
## Hybrid search and rerank (fail-closed) [#hybrid-search-and-rerank-fail-closed]
Since **0.6.0**, there is no silent degradation:
| Flag | Missing provider | Provider failure |
| -------------- | ----------------- | ------------------------------------ |
| `hybrid: true` | `ValidationError` | throws (no semantic-only fallback) |
| `rerank: true` | `ValidationError` | `RerankError` from built-in adapters |
Configure `keywordSearch: bm25()` (or a custom provider) before enabling hybrid. Catch `RerankError` explicitly — there is no identity-order fallback.
## Graph memory [#graph-memory]
**Removed in 0.6.0.** `sqliteGraph`, `neo4jGraph`, `linkMemories`, `getRelated`, and `includeGraph` are gone from core. There is no `neo4j-driver` peer. Model relationships with [metadata filters](/docs/metadata-filtering) or an external store. See [Graph memory (removed)](/docs/graph-memory) and [Migration](/docs/migration).
## Telemetry [#telemetry]
* Telemetry database is **SQLite only** today (Postgres is typed but not implemented)
* `captureQueries` defaults to **`false`** (privacy)
See [Observability](/docs/observability).
## Embedding cache [#embedding-cache]
* On Postgres, durable cache defaults **off** (L1-only) unless configured otherwise — [Embedding cache](/docs/embedding-cache)
## Optional providers [#optional-providers]
* `compress()` needs `llm` — otherwise `ProviderNotConfiguredError`
* `hybrid: true` / `rerank: true` require their providers — see fail-closed table above
## Out of scope [#out-of-scope]
* No hosted cloud control plane
* No built-in agent framework / chat UI
* No application authentication / authorization (`organization` is a namespace, not IAM)
* No graph memory APIs (removed in 0.6.0)
* No multi-process SQLite `subscribe()`
* No Postgres telemetry store
* No general memory TTL or cost-accounting APIs yet
## Related pages [#related-pages]
* [Production](/docs/guides/production)
* [Installation](/docs/installation)
* [What's New](/docs/guides/whats-new)
* [Migration](/docs/migration)
* [Document Ingestion](/docs/document-ingestion)
* [FAQ](/docs/faq)
---
# Production
> Operator guidance for deploying Wolbarg 0.6 — SQLite vs Postgres, SSL, schema, pooling, fail-closed hybrid/rerank, backups, and troubleshooting.
URL: /docs/guides/production
## What is it? [#what-is-it]
Operator-focused guidance for deploying Wolbarg **0.6.0**. This page prefers accuracy over marketing. For concurrency internals, see [Architecture](/docs/architecture) and [Concurrency](/docs/concurrency).
## Choosing a backend [#choosing-a-backend]
| | SQLite | PostgreSQL |
| ------------------- | ------------------------------- | --------------------------------- |
| Best for | Local agents, CLIs, single node | Multi-process / multi-host fleets |
| Subscribe | Same process only | Cross-process via `LISTEN/NOTIFY` |
| Checkpoint / export | File-backed SQLite only | Not supported |
| Embedding cache | Durable L1+L2 | L1 only |
| Isolation | Prefer one file per org | Prefer `schema` + org namespace |
## SQLite [#sqlite]
### Configuration [#configuration]
```ts
sqlite("./data/memory.db")
// or
{ provider: "sqlite", url: "./data/memory.db" }
```
### Concurrency [#concurrency]
* WAL + `BEGIN IMMEDIATE` + busy retries
* `concurrency.multiProcess: true` raises timeouts for multiple OS processes sharing one file
* Exhausted retries throw `StorageLockedError` (`WOLBARG_STORAGE_LOCKED`)
* `DatabaseSync` runs on the Node event loop — isolate heavy writers from latency-sensitive API processes, or prefer Postgres
### Backups [#backups]
* Stop writers or use SQLite online backup / filesystem snapshots of the DB **and** `-wal` / `-shm` consistently
* Prefer `export()` for portable bundles when the file contains a single organization
* Multi-org files: export/checkpoint/import/rollback **refuse** — split by organization first
### Migrations [#migrations]
Schema migrations run automatically on `open()` / `ready()`. Do not edit `wolbarg_meta` by hand. Keep a backup before upgrading major/minor releases that mention schema changes.
### Limitations [#limitations]
* No cross-process `subscribe()`
* File-level transfer cannot org-filter rows
* Under extreme lock contention, callers must handle `StorageLockedError`
## PostgreSQL [#postgresql]
### Configuration [#configuration-1]
```ts
postgres({
connectionString: process.env.DATABASE_URL!,
schema: "wolbarg", // recommended for shared DBs
maxPoolSize: 20, // default; raise only if the host allows
// ssl: false, // opt out of default require for remote (not recommended)
})
```
Install: `npm install pg`. Enable pgvector when you want HNSW ANN:
```sql
CREATE EXTENSION IF NOT EXISTS vector;
```
Without a usable `vector` type, Wolbarg falls back to blob cosine search.
### SSL / TLS [#ssl--tls]
* Non-loopback hosts without `sslmode` / `ssl` in the URL get **`sslmode=require`**
* Loopback (`localhost`, `127.0.0.1`, `::1`) is left unchanged for local Docker
* Overrides: `ssl: false` / `"disable"` (warns on remote), `ssl: true` / `"require"`, `"prefer"`
### Schema namespacing [#schema-namespacing]
`schema` creates a dedicated Postgres schema for tables, indexes, and a suffixed NOTIFY channel (`wolbarg_events_`). Use this when:
* Keeping Wolbarg out of shared `public`
* Running multiple deployments in one database
* Hosting different embedding dimensions side by side
Names: `^[A-Za-z_][A-Za-z0-9_$]*$`, max 48 characters.
### Pooling and timeouts [#pooling-and-timeouts]
Session GUCs (via connection URL): `statement_timeout=30000`, `lock_timeout=10000`, `idle_in_transaction_session_timeout=60000`, plus HNSW search settings. Deadlock (`40P01`) and serialization (`40001`) retries use full-jitter backoff.
### Backups [#backups-1]
Use normal Postgres backup tooling (`pg_dump`, continuous WAL archiving, managed snapshots). Wolbarg does not ship a Postgres export/checkpoint API.
### Migrations [#migrations-1]
DDL is applied on open. Catalog probes are schema-scoped. Prefer throwaway schemas in tests.
## Hybrid search and rerank [#hybrid-search-and-rerank]
Fail-closed since 0.6.0:
| Flag | Missing provider | Provider failure |
| -------------- | ----------------- | ------------------------------------ |
| `hybrid: true` | `ValidationError` | throws (no silent semantic-only) |
| `rerank: true` | `ValidationError` | `RerankError` from built-in adapters |
Configure `keywordSearch: bm25()` (or a custom provider) before enabling hybrid.
## Telemetry [#telemetry]
* SQLite telemetry DB only — **Postgres telemetry is not implemented**
* `captureQueries` defaults to **`false`** (privacy)
* Keep telemetry on a **separate file** from memory storage
* Studio (separate product) reads the telemetry database — see [Observability](/docs/observability)
## Security trust boundary [#security-trust-boundary]
* `organization` is a **data namespace**, not proof of identity
* Authenticate/authorize in your app before constructing a tenant context
* Do not pass end-user-controlled embedding/LLM/rerank `baseUrl` values (SSRF)
* Keep API keys in process env / `.wolbarg/.env` (gitignored by `wolbarg init`)
## Troubleshooting [#troubleshooting]
| Symptom | Likely cause | What to do |
| --------------------------------------- | --------------------------------- | ---------------------------------------------------------------------------------- |
| `StorageLockedError` | SQLite write contention | Retry with backoff; raise `concurrency` timeouts; reduce writers; move to Postgres |
| `VersionConflictError` | CAS mismatch on `expectedVersion` | Re-read and retry update |
| `RerankError` | Reranker HTTP/empty ranking | Fix provider; catch explicitly; do not assume identity fallback |
| `ValidationError` on hybrid/rerank | Flag set without provider | Pass `keywordSearch` / `reranker` |
| `ConfigurationError` telemetry postgres | Unsupported | Use SQLite telemetry URL |
| Export refused | Multi-org SQLite file | Split orgs to separate files |
| ANN slow / missing | No pgvector / wrong search\_path | Install extension; verify `to_regtype('vector')` |
| TLS errors to managed Postgres | Cert / sslmode mismatch | Set explicit `ssl` / `sslmode` for your host |
## Performance notes [#performance-notes]
* Insert coalescing amortizes commits (SQLite) / `unnest` batches (Postgres)
* Embedding cache cuts repeated provider calls; Postgres cache is L1-only
* HNSW is built lazily before first KNN (Postgres)
* Published website benchmark numbers are from a **v0.4** mock suite — re-benchmark before citing 0.6.0 numbers
## What Wolbarg does not provide [#what-wolbarg-does-not-provide]
* Application authentication / authorization
* Hosted control plane
* Multi-process SQLite subscribe
* Postgres telemetry store
* Graph memory APIs (removed in 0.6.0)
* Guaranteed zero lock contention under arbitrary writer counts
## Related pages [#related-pages]
* [What's New](/docs/guides/whats-new)
* [Limitations](/docs/guides/limitations)
* [Configuration](/docs/configuration)
* [Concurrency](/docs/concurrency)
* [Migration](/docs/migration)
* [Observability](/docs/observability)
---
# Multi-Agent Memory
> Share one Wolbarg instance across concurrent agents with agent-scoped filters.
URL: /docs/guides/shared-memory
## Pattern [#pattern]
```ts
const ctx = new Wolbarg({ /* … */ });
await ctx.remember({ agent: "writer", content: { text: "…" } });
await ctx.remember({ agent: "researcher", content: { text: "…" } });
await ctx.recall({
query: "…",
filter: { agent: "writer" },
});
// Org-wide shared recall — omit agent filter
await ctx.recall({ query: "…" });
```
## Isolation [#isolation]
Organizations isolate tenants in one database file. Agents isolate authors within an organization. Writes serialize via an in-process mutex and ACID transactions.
## Related pages [#related-pages]
* [Architecture](/docs/architecture)
* [Metadata Filtering](/docs/metadata-filtering)
* [Best Practices](/docs/guides/best-practices)
---
# What's New
> Wolbarg 0.6.0 release notes — fail-closed hybrid/rerank, Postgres SSL and schema, AbortSignal, concurrency hardening, and graph memory removal.
URL: /docs/guides/whats-new
## Highlights [#highlights]
Wolbarg **0.6.0** is a production-hardening release. Same core loop — `remember()` / `recall()` — with safer concurrency, fail-closed retrieval, multi-tenant isolation, and Postgres defaults that match real deployments.
| Feature | Deep-dive |
| ---------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------- |
| **Fail-closed hybrid & rerank** — missing providers throw; built-ins throw `RerankError` | [Hybrid Search](/docs/hybrid-search) · [Rerankers](/docs/rerankers) |
| **Postgres SSL + schema** — remote TLS defaults to require; optional schema namespacing | [Production](/docs/guides/production) · [Configuration](/docs/configuration) |
| **AbortSignal** on remember / rememberFromMessages / recall / update / compress / forget | [API Overview](/docs/api) |
| **Concurrency fixes** — SQLite write mutex / busy retries; Postgres `FOR UPDATE`, deadlock retries | [Concurrency](/docs/concurrency) |
| **Multi-tenant file safety** — SQLite export/checkpoint refuse mixed-organization files | [Limitations](/docs/guides/limitations) |
| **Graph memory removed** — `sqliteGraph`, `neo4jGraph`, `linkMemories`, `getRelated`, `includeGraph` | [Graph memory (removed)](/docs/graph-memory) · [Migration](/docs/migration) |
| **Privacy** — `captureQueries` defaults to `false` | [Observability](/docs/observability) |
## Install [#install]
```bash
npm install wolbarg@0.6.0
```
## Breaking for 0.5.x users [#breaking-for-05x-users]
| Change | Migration |
| --------------------------- | -------------------------------------------------------------- |
| Graph APIs removed | Delete graph imports and call sites |
| Hybrid/rerank fail-closed | Always pass `keywordSearch` / `reranker` when flags are set |
| Rerank no identity fallback | Catch `RerankError` |
| Postgres remote TLS | Expect `sslmode=require` or set `ssl` explicitly |
| Pool default 20 | Raise `maxPoolSize` if needed (was 64) |
| Multi-org SQLite transfer | One file per organization |
| Telemetry query capture | Set `captureQueries: true` if you need query strings persisted |
From 0.5.x without graph:
```bash
npm install wolbarg@0.6.0
```
Most `remember` / `recall` call sites need no changes. Review hybrid, rerank, and Postgres SSL settings. Full guide: [Migration](/docs/migration).
## Still experimental [#still-experimental]
* [`rememberFromMessages({ mode: "extract" })`](/docs/api/remember-from-messages) — quality depends on your LLM; API may change.
* [`subscribe()`](/docs/realtime-events) — still available; SQLite is same-process only.
## What this release does not claim [#what-this-release-does-not-claim]
* Postgres telemetry store (not implemented)
* Multi-process SQLite `subscribe()`
* Graph memory / Neo4j (removed)
* Application-layer auth — `organization` is a data namespace, not IAM
## Related pages [#related-pages]
* [Production](/docs/guides/production)
* [Migration](/docs/migration)
* [Limitations](/docs/guides/limitations)
* [Configuration](/docs/configuration)
* [API Overview](/docs/api)
---
# Overview
> Connect Wolbarg to agent frameworks and AI SDKs without putting framework types in the core package.
URL: /docs/integrations
## What is it? [#what-is-it]
Wolbarg stays **framework-agnostic**. Official adapters live in separate packages and docs under **AI SDKs**.
| Integration | Package | Docs |
| --------------------- | --------------------- | --------------------------------------------- |
| Vercel AI SDK | `@wolbarg/vercel-ai` | [Vercel AI SDK](/docs/integrations/vercel-ai) |
| OpenAI Agents SDK | `@wolbarg/openai` | [OpenAI Agents](/docs/integrations/openai) |
| LangChain / LangGraph | `@wolbarg/langchain` | [LangChain](/docs/integrations/langchain) |
| LlamaIndexTS | `@wolbarg/llamaindex` | [LlamaIndex](/docs/integrations/llamaindex) |
| Mastra | `@wolbarg/mastra` | [Mastra](/docs/integrations/mastra) |
Each shipped package is a thin adapter: your agent stack runs; Wolbarg owns durable shared memory.
## Related pages [#related-pages]
* [Quick Start](/docs/quick-start)
* [Example — Vercel AI memory](/docs/examples/vercel-ai-memory)
---
# LangChain / LangGraph
> Official @wolbarg/langchain — WolbargMemory (BaseMemory), WolbargStore (LangGraph BaseStore), and createWolbargTools.
URL: /docs/integrations/langchain
## What is it? [#what-is-it]
[`@wolbarg/langchain`](https://www.npmjs.com/package/@wolbarg/langchain) is the official [LangChain JS](https://js.langchain.com/) / [LangGraph JS](https://langchain-ai.github.io/langgraphjs/) adapter for Wolbarg shared memory.
Two integration surfaces:
1. **`WolbargMemory`** — `@langchain/core` `BaseMemory` (legacy chain memory: recall on load, remember on save)
2. **`WolbargStore`** — LangGraph `BaseStore` (**preferred** long-term memory for multi-agent / durable graphs)
Also: **`createWolbargTools`** — agent tools for `wolbarg_recall` / `wolbarg_remember`.
Soft-fail by default: recall/remember/store errors never crash the chain or graph. Provenance metadata always includes `source: "wolbarg-langchain"`.
Requires **Node ≥ 22**.
## Install [#install]
```bash
npm install wolbarg @wolbarg/langchain @langchain/core @langchain/langgraph
```
Peers: `wolbarg >= 0.6.0`, `@langchain/core >= 0.3 || >= 1`, `@langchain/langgraph >= 0.2 || >= 1`.
## Quick start — BaseMemory [#quick-start--basememory]
```ts
import { wolbarg, sqlite, openaiEmbedding } from "wolbarg";
import { createWolbargMemory } from "@wolbarg/langchain";
const memory = wolbarg({
organization: "my-app",
storage: sqlite("./memory.db"),
embedding: openaiEmbedding({
apiKey: process.env.OPENAI_API_KEY!,
model: "text-embedding-3-small",
}),
});
await memory.ready();
const chatMemory = createWolbargMemory({
memory,
agent: "assistant",
memoryKey: "history",
sessionId: "chat-1",
});
const vars = await chatMemory.loadMemoryVariables({
input: "What UI theme do I prefer?",
});
// vars.history — formatted string (or BaseMessage[] when returnMessages: true)
await chatMemory.saveContext(
{ input: "I prefer dark mode" },
{ output: "Noted — dark mode it is." },
);
```
## Quick start — LangGraph BaseStore [#quick-start--langgraph-basestore]
```ts
import { createWolbargStore } from "@wolbarg/langchain";
const store = createWolbargStore({
memory,
agent: "assistant",
});
await store.put(["users", "u1"], "prefs", { text: "dark mode" });
const item = await store.get(["users", "u1"], "prefs");
const hits = await store.search(["users"], {
query: "theme preference",
limit: 5,
});
```
Pass `store` into LangGraph as the long-term memory store (e.g. graph compile / store config). Prefer **`WolbargStore`** for new LangGraph apps; use **`WolbargMemory`** when you still need classic `BaseMemory` chains.
## Optional tools [#optional-tools]
```ts
import { createWolbargTools } from "@wolbarg/langchain";
const tools = createWolbargTools({ memory, agent: "assistant" });
// [wolbarg_recall, wolbarg_remember]
```
## Options [#options]
### WolbargMemory / createWolbargMemory [#wolbargmemory--createwolbargmemory]
| Option | Default | Notes |
| ---------------------------------------------------------- | ----------------- | ------------------------------------------------------ |
| `memory` | required | Wolbarg instance |
| `agent` | required | Agent id for recall/remember filters |
| `memoryKey` | `"history"` | Key returned from `loadMemoryVariables` |
| `inputKey` / `outputKey` | auto | Passed to LangChain `getInputValue` / `getOutputValue` |
| `topK` | `5` | Recall limit |
| `returnMessages` | `false` | Return `HumanMessage[]` instead of a string |
| `formatContext` | default formatter | Custom string formatter for hits |
| `rememberMode` | `"raw"` | Passed to `rememberFromMessages` |
| `sessionId` / `userId` / `tags` / `namespace` / `metadata` | — | Copied onto stored metadata |
| `onError` | — | Soft-fail hook |
### WolbargStore / createWolbargStore [#wolbargstore--createwolbargstore]
| Method | Wolbarg mapping |
| -------------------- | --------------------------------------------------------------------- |
| `put` | `remember` (text from `value.text` / `value.data` / `JSON.stringify`) |
| `get` | metadata key lookup (+ process cache) |
| `delete` | `forget` by memory id |
| `search` (+ `query`) | `recall` |
| `batch` | abstract entry point (put/get/delete/search/listNamespaces) |
Namespaces are stored in Wolbarg metadata (`storeNamespace`, `storeKey`, `storeValue`).
## Limitations [#limitations]
* BaseMemory is legacy LCEL/chain memory — LangGraph apps should prefer `WolbargStore`.
* Exact `get` after restart is best-effort via metadata-filtered recall; process-local cache is authoritative within a run.
* Soft-fail means store/memory errors never crash the chain — wire `onError` for observability.
## Related pages [#related-pages]
* [Quick Start](/docs/quick-start)
* [remember()](/docs/api/remember)
* [recall()](/docs/api/recall)
* [Limitations](/docs/guides/limitations)
---
# LlamaIndexTS
> Official @wolbarg/llamaindex — wolbargBlock / WolbargMemoryBlock for createMemory({ memoryBlocks }).
URL: /docs/integrations/llamaindex
## What is it? [#what-is-it]
[`@wolbarg/llamaindex`](https://www.npmjs.com/package/@wolbarg/llamaindex) is the official [LlamaIndexTS](https://ts.llamaindex.ai/) long-term memory block for Wolbarg shared memory.
It wires Wolbarg into LlamaIndex’s `createMemory({ memoryBlocks })` API via `BaseMemoryBlock`:
1. **`get`** — recalls relevant memories from the last user message
2. **`put`** — persists conversation turns with `rememberFromMessages`
Soft-fails by default so memory errors never break an agent turn.
Requires **Node ≥ 22**.
## Install [#install]
```bash
npm install wolbarg @wolbarg/llamaindex llamaindex
```
Peers: `wolbarg >= 0.6.0`, `@llamaindex/core >= 0.6.0`, optional `llamaindex >= 0.9.0`.
## Quick start [#quick-start]
```ts
import { createMemory } from "llamaindex";
import { wolbarg, sqlite, openaiEmbedding } from "wolbarg";
import { wolbargBlock } from "@wolbarg/llamaindex";
const client = wolbarg({
organization: "my-app",
storage: sqlite("./memory.db"),
embedding: openaiEmbedding({
apiKey: process.env.OPENAI_API_KEY!,
model: "text-embedding-3-small",
}),
});
await client.ready();
const memory = createMemory({
memoryBlocks: [
wolbargBlock({
memory: client,
agent: "assistant",
sessionId: "demo-session",
}),
],
});
await memory.add({ role: "user", content: "I prefer dark mode." });
await memory.manageMemoryBlocks();
const messages = await memory.getLLM();
```
`wolbargBlock` mirrors LlamaIndex’s `staticBlock` / `vectorBlock` naming. `createWolbargMemoryBlock` is an alias for `WolbargMemoryBlock`.
## Options [#options]
| Option | Default | Description |
| --------------------------------------------- | ------------- | ------------------------------------------------ |
| `memory` | required | Wolbarg client |
| `agent` | required | Agent id for recall filter + remember |
| `id` | auto UUID | Block id |
| `priority` | `1` | LlamaIndex block priority (`0` = always include) |
| `isLongTerm` | `true` | Long-term block flag |
| `topK` | `5` | Recall limit |
| `threshold` | — | Minimum similarity |
| `sessionId` / `userId` / `tags` / `namespace` | — | Attached to remember metadata |
| `metadata` | `{}` | Extra remember metadata |
| `formatContext` | default list | Format recall hits → memory message text |
| `rememberMode` | `"raw"` | `"raw"` or `"extract"` |
| `rawStrategy` | `"last_user"` | `"last_user"` or `"all_user"` |
| `onError` | — | Soft-fail hook `(error, phase)` |
### Behavior [#behavior]
| Method | Behavior |
| ---------------- | ---------------------------------------------------------------------------------------------- |
| `get(messages?)` | Query = last user message text → `memory.recall` → one `{ role: "memory", content }` (or `[]`) |
| `put(messages)` | Convert to conversation turns (skips `memory` role) → `rememberFromMessages` |
| Errors | Soft-fail: `get` → `[]`, `put` → no throw; optional `onError` |
Remembered rows include `metadata.source = "wolbarg-llamaindex"`.
## Config tips [#config-tips]
```ts
wolbargBlock({
memory: client,
agent: "assistant",
topK: 8,
threshold: 0.35,
rememberMode: "raw",
rawStrategy: "last_user",
formatContext: (hits) =>
hits.map((h) => `- ${h.content.text}`).join("\n"),
onError: (err, phase) => console.warn("[wolbarg]", phase, err),
});
```
## Limitations [#limitations]
* Recall query uses the **last user** message only (not a multi-turn window).
* `put` skips messages with role `"memory"` and empty content.
* Does not replace LlamaIndex short-term chat buffer — use alongside `createMemory`.
* Requires Node ≥ 22 and Wolbarg ≥ 0.5.5 (`rememberFromMessages`).
## Related pages [#related-pages]
* [Quick Start](/docs/quick-start)
* [rememberFromMessages()](/docs/api/remember-from-messages)
* [recall()](/docs/api/recall)
* [Limitations](/docs/guides/limitations)
---
# Mastra
> Official @wolbarg/mastra Processor — createWolbargProcessor for shared semantic recall and remember (not a Storage rewrite).
URL: /docs/integrations/mastra
## What is it? [#what-is-it]
[`@wolbarg/mastra`](https://www.npmjs.com/package/@wolbarg/mastra) is the official [Mastra](https://mastra.ai/) **Processor** for Wolbarg shared semantic memory.
It automatically:
1. **Recalls** relevant memories in `processInput` (from the last user text in `content.parts`)
2. **Injects** them as a system message (preferred) or a prepended memory message
3. **Remembers** the conversation in `processOutputResult` via `rememberFromMessages`
This is **not** a Mastra Storage / Memory rewrite. Keep [Mastra Memory](https://mastra.ai/docs/memory/overview) for thread history if you want it; add this processor for **shared semantic memory across agents**.
Requires **`@mastra/core` ≥ 1.0** (Processor API) and **Node ≥ 22**.
## Install [#install]
```bash
npm install wolbarg @wolbarg/mastra @mastra/core
```
Peers: `wolbarg >= 0.6.0`, `@mastra/core >= 1.0.0`. Optional peer: `@mastra/memory` (thread history only — not required by this package).
## Quick start [#quick-start]
```ts
import { Agent } from "@mastra/core/agent";
import { wolbarg, sqlite, openaiEmbedding } from "wolbarg";
import { createWolbargProcessor } from "@wolbarg/mastra";
const memory = wolbarg({
organization: "my-app",
storage: sqlite("./memory.db"),
embedding: openaiEmbedding({
apiKey: process.env.OPENAI_API_KEY!,
model: "text-embedding-3-small",
}),
});
await memory.ready();
// One instance for both input + output hooks
const wolbargMem = createWolbargProcessor({
memory,
agent: "assistant",
sessionId: "optional-session",
});
const agent = new Agent({
id: "assistant",
name: "Assistant",
instructions: "You are a helpful assistant.",
model: "openai/gpt-4.1-mini",
inputProcessors: [wolbargMem],
outputProcessors: [wolbargMem],
});
const result = await agent.generate("What UI theme do I prefer?");
console.log(result.text);
```
Alias: `wolbargProcessor` === `createWolbargProcessor`.
Register the **same** processor instance in **both** `inputProcessors` and `outputProcessors` — Mastra runs input and output hooks from separate lists.
## Options [#options]
| Option | Default | Description |
| --------------------------------------------- | ------------------- | ------------------------------------------------------------------------------------------ |
| `memory` | — | Wolbarg instance (**required**) |
| `agent` | — | Agent id for recall filter / remember (**required**) |
| `id` | `"wolbarg-memory"` | Processor `id` |
| `recall` | `true` | Run recall in `processInput` |
| `remember` | `true` | Run remember in `processOutputResult` |
| `topK` | `5` | Recall hit count |
| `injection` | `"system"` | `"system"` appends to `systemMessages`; `"message"` prepends a system-role MastraDBMessage |
| `sessionId` / `userId` / `tags` / `namespace` | — | Stored on remember metadata |
| `metadata` | `{}` | Extra remember metadata (`source: "wolbarg-mastra"` always set) |
| `formatContext` | default bullet list | Format recall hits into prompt text |
| `onError` | — | `(error, phase) => void` |
| `onTelemetry` | — | Soft telemetry events for recall / inject / remember |
## With Mastra Memory (optional) [#with-mastra-memory-optional]
```ts
import { Memory } from "@mastra/memory";
const agent = new Agent({
// ...
memory: new Memory({ /* thread / working memory */ }),
inputProcessors: [wolbargMem],
outputProcessors: [wolbargMem],
});
```
Mastra Memory handles conversation threads. Wolbarg handles cross-agent semantic recall.
## Soft-fail [#soft-fail]
Recall and remember failures **never crash** agent generation. Use `onError` / `onTelemetry` for observability.
## Limitations [#limitations]
* Not a Mastra Storage rewrite — thread history stays with Mastra Memory if you use it.
* Text extraction iterates `content.parts` where `type === "text"` (`MastraDBMessage` format 2).
* You must put the same instance in both processor arrays; input-only or output-only registration skips half the lifecycle.
## Related pages [#related-pages]
* [Quick Start](/docs/quick-start)
* [rememberFromMessages()](/docs/api/remember-from-messages)
* [recall()](/docs/api/recall)
* [Limitations](/docs/guides/limitations)
---
# OpenAI Agents SDK
> Official @wolbarg/openai Session — persist AgentInputItem history, semantic remember, and recall injection via createWolbargSessionInputCallback.
URL: /docs/integrations/openai
## What is it? [#what-is-it]
[`@wolbarg/openai`](https://www.npmjs.com/package/@wolbarg/openai) is the official [OpenAI Agents SDK](https://openai.github.io/openai-agents-js/) `Session` for Wolbarg shared memory.
It automatically:
1. **Persists** conversation `AgentInputItem[]` as a single Wolbarg session snapshot
2. **Hydrates** that snapshot when you resume with the same `sessionId`
3. **Remembers** user/assistant text as semantic memories on `addItems` (optional)
4. **Recalls** relevant memories via `createWolbargSessionInputCallback` before the model call
Drop-in for `MemorySession` — same `Session` surface the runner expects.
Requires **`@openai/agents` ≥ 0.13.0** and **Node ≥ 22**.
## Install [#install]
```bash
npm install wolbarg @wolbarg/openai @openai/agents
```
Peers: `wolbarg >= 0.6.0`, `@openai/agents >= 0.13.0`.
## Quick start [#quick-start]
```ts
import { Agent, run } from "@openai/agents";
import { wolbarg, sqlite, openaiEmbedding } from "wolbarg";
import {
createWolbargSession,
createWolbargSessionInputCallback,
} from "@wolbarg/openai";
const memory = wolbarg({
organization: "my-app",
storage: sqlite("./memory.db"),
embedding: openaiEmbedding({
apiKey: process.env.OPENAI_API_KEY!,
model: "text-embedding-3-small",
}),
});
await memory.ready();
const session = await createWolbargSession({
memory,
agent: "assistant",
sessionId: "chat-1",
});
const agent = new Agent({
name: "Assistant",
instructions: "Be concise.",
});
await run(agent, "What UI theme do I prefer?", {
session,
sessionInputCallback: createWolbargSessionInputCallback({
memory,
agent: "assistant",
}),
});
```
## WolbargSession [#wolbargsession]
Implements the Agents SDK `Session` interface:
| Method | Behavior |
| ------------------ | -------------------------------------------------------------- |
| `getSessionId()` | Returns the stable session id |
| `getItems(limit?)` | Returns cloned history (most recent `limit` when set) |
| `addItems(items)` | Append locally → persist snapshot → optional semantic remember |
| `popItem()` | Pop newest locally → persist snapshot |
| `clearSession()` | Clear local items + soft-fail forget snapshot |
```ts
import { WolbargSession } from "@wolbarg/openai";
const session = new WolbargSession({
memory,
agent: "assistant",
sessionId: "chat-1", // omit to auto-generate (no hydrate)
semanticRemember: true, // default
userId: "u1",
tags: ["support"],
onError: (err, phase) => console.warn(phase, err),
});
await session.ready(); // await soft-fail hydration
```
`createWolbargSession(options)` constructs `WolbargSession` and awaits hydration.
## Semantic recall injection [#semantic-recall-injection]
`createWolbargSessionInputCallback` returns a `SessionInputCallback` for `run(..., { sessionInputCallback })`:
1. Takes the last user text from `newItems`
2. Soft-fail `memory.recall`
3. Injects `{ role: "system", content }` when hits exist
4. Returns `[system?, ...historyItems, ...newItems]`
Use when the turn input is an `AgentInputItem[]` (string inputs merge history automatically; the callback is optional then).
## Options [#options]
| Option | Default | Notes |
| -------------------------------------------- | ----------- | ----------------------------------------------------------------------------- |
| `memory` | required | Wolbarg instance |
| `agent` | required | Agent id for snapshot + semantic memories |
| `sessionId` | random UUID | When provided, constructor hydrates from Wolbarg |
| `semanticRemember` | `true` | Store user/assistant text on `addItems` |
| `topK` | `5` | Used by `createWolbargSessionInputCallback` |
| `userId` / `tags` / `namespace` / `metadata` | — | Copied onto stored metadata |
| `onError` | — | Soft-fail hook (`recall` \| `remember` \| `persist` \| `hydrate` \| `forget`) |
Provenance metadata always includes `source: "wolbarg-openai"`. Session snapshots also set `kind: "wolbarg-session"`.
## Soft-fail [#soft-fail]
Snapshot persistence and semantic remember **never throw** into the Agents SDK run path. Wire `onError` for observability.
## Limitations [#limitations]
* Hydration finds the snapshot via filtered `recall` (metadata `kind` + `sessionId`). Extremely noisy corpora may need a dedicated agent namespace for session rows.
* `forget({ filter: { agent } })` would wipe all agent memories — `clearSession` forgets **by snapshot id** only.
* Does not implement optional Session extensions (`applyHistoryMutations`, compaction hooks).
* Multimodal user parts become text + `[attachment:…]` placeholders for semantic remember / recall queries.
## Related pages [#related-pages]
* [Quick Start](/docs/quick-start)
* [remember()](/docs/api/remember)
* [recall()](/docs/api/recall)
* [Limitations](/docs/guides/limitations)
---
# Vercel AI SDK
> Official @wolbarg/vercel-ai middleware — automatic recall, system injection, and remember with generateText and streamText (AI SDK v7+).
URL: /docs/integrations/vercel-ai
## What is it? [#what-is-it]
[`@wolbarg/vercel-ai`](https://www.npmjs.com/package/@wolbarg/vercel-ai) is the official AI SDK Language Model Middleware for Wolbarg.
It follows the same pattern the AI SDK documents for RAG, logging, and guardrails:
* **`transformParams`** — recall + inject memory into a tagged system message
* **`wrapGenerate` / `wrapStream`** — remember after the model step finishes
The core `wolbarg` package stays framework-agnostic. This package is the only place that depends on `ai`.
Requires **AI SDK v7+** (`LanguageModelV4` middleware).
## Install [#install]
```bash
npm install wolbarg @wolbarg/vercel-ai ai @ai-sdk/openai
```
Requires **Node ≥ 22.5**, `wolbarg >= 0.6.0`, and `ai ^7.0.0`.
## Quick start [#quick-start]
```ts
import { generateText, wrapLanguageModel } from "ai";
import { openai } from "@ai-sdk/openai";
import { wolbarg, sqlite, openaiEmbedding } from "wolbarg";
import { wolbargMiddleware } from "@wolbarg/vercel-ai";
const memory = wolbarg({
organization: "my-app",
storage: sqlite("./memory.db"),
embedding: openaiEmbedding({
apiKey: process.env.OPENAI_API_KEY!,
model: "text-embedding-3-small",
}),
});
await memory.ready();
const model = wrapLanguageModel({
model: openai("gpt-4.1-mini"),
middleware: wolbargMiddleware({
memory,
agent: "assistant",
}),
});
const { text } = await generateText({
model,
system: "You are a concise assistant.", // preserved
messages: [{ role: "user", content: "What do I prefer?" }],
});
```
Convenience helper:
```ts
import { createWolbargModel } from "@wolbarg/vercel-ai";
const model = createWolbargModel({
model: openai("gpt-4.1-mini"),
memory,
agent: "assistant",
});
```
## Streaming [#streaming]
```ts
import { streamText } from "ai";
const result = streamText({
model, // already wrapped with wolbargMiddleware
messages,
});
for await (const chunk of result.textStream) {
process.stdout.write(chunk);
}
```
Remember starts when the model emits **`finish`** (with a flush backup). Canceling after finish still persists memory. Canceling mid-generation before `finish` does not remember incomplete turns.
## Tools / multi-step [#tools--multi-step]
Middleware runs **per model step**. By default `remember: "final-step"` skips intermediate steps where `finishReason.unified === "tool-calls"`, so tool loops do not spam duplicate memories. Recall still runs every step so tools see memory context.
```ts
wolbargMiddleware({
memory,
agent: "assistant",
remember: "final-step", // default — or "every-step" | "never" | false
});
```
## Per-request metadata [#per-request-metadata]
```ts
await generateText({
model,
messages,
providerOptions: {
wolbarg: {
sessionId: "s1",
userId: "u1",
tags: ["support"],
namespace: "prod",
},
},
});
```
These fold into `rememberFromMessages` metadata (`source: "wolbarg-vercel-ai"`).
## Multimodal messages [#multimodal-messages]
User messages with file/image parts contribute `[attachment:mediaType:filename]` placeholders to the recall query so memory search still has text signal alongside captions.
## Failure semantics [#failure-semantics]
Recall and remember failures **never crash** model generation. Use hooks:
```ts
wolbargMiddleware({
memory,
agent: "assistant",
onError: (error, phase) => {
console.warn("[wolbarg]", phase, error);
},
onTelemetry: (event) => {
// phase: recall | remember | inject
},
});
```
## Options reference [#options-reference]
| Option | Default | Meaning |
| --------------------------------------------------------------------- | ------------------ | --------------------------------------------- |
| `memory` | required | `Wolbarg` instance |
| `agent` | required | Agent id for recall filter + remember |
| `recall` | `true` | Run recall before generate/stream |
| `remember` | `"final-step"` | When to persist after a step |
| `topK` / `threshold` | `5` / unset | Recall knobs |
| `injection` | `"system-prepend"` | Or `"system-append"` |
| `rememberMode` | `"raw"` | Passed to experimental `rememberFromMessages` |
| `formatContext` | built-in | Customize memory system text |
| `filter` / `metadata` / `sessionId` / `userId` / `tags` / `namespace` | — | Scoping + stored metadata |
## Related pages [#related-pages]
* [Example — Vercel AI memory](/docs/examples/vercel-ai-memory)
* [rememberFromMessages()](/docs/api/remember-from-messages)
* [Quick Start](/docs/quick-start)
* [Limitations](/docs/guides/limitations)
---
# Example — Basic Memory
> Minimal remember and recall with SQLite and OpenAI embeddings.
URL: /docs/examples/basic-memory
## What is it? [#what-is-it]
The smallest working Wolbarg program.
## Example usage [#example-usage]
```ts
import { Wolbarg, sqlite, openaiEmbedding } from "wolbarg";
const ctx = new Wolbarg({
organization: "demo",
storage: sqlite("./memory.db"),
embedding: openaiEmbedding({
apiKey: process.env.OPENAI_API_KEY!,
model: "text-embedding-3-small",
}),
});
await ctx.remember({
agent: "assistant",
content: { text: "The deploy window is Fridays at 16:00 UTC." },
});
const hits = await ctx.recall({ query: "when can we deploy?", topK: 3 });
console.log(hits[0]?.content.text);
await ctx.close();
```
## Related pages [#related-pages]
* [Quick Start](/docs/quick-start)
* [remember()](/docs/api/remember)
---
# Example — Compression
> Summarize memories with an LLM via compress().
URL: /docs/examples/compression
```ts
import { Wolbarg, sqlite, openaiEmbedding, openaiLlm } from "wolbarg";
const ctx = new Wolbarg({
organization: "demo",
storage: sqlite("./memory.db"),
embedding: openaiEmbedding({
apiKey: process.env.OPENAI_API_KEY!,
model: "text-embedding-3-small",
}),
llm: openaiLlm({
apiKey: process.env.OPENAI_API_KEY!,
model: "gpt-4.1-mini",
}),
});
await ctx.compress({ agent: "research" });
```
## Related pages [#related-pages]
* [Compression Pipeline](/docs/compression)
---
# Example — Conversation memory
> Chat transcript → rememberFromMessages → recall without hand-rolled extraction.
URL: /docs/examples/conversation-memory
## What is it? [#what-is-it]
Side-by-side style demo vs “chat → facts → retrieve” libraries: pass messages into Wolbarg, then recall.
Uses experimental [`rememberFromMessages()`](/docs/api/remember-from-messages). Default `mode: "raw"` needs **no LLM**.
## Example usage [#example-usage]
```ts
import { wolbarg, sqlite, openaiEmbedding } from "wolbarg";
const ctx = wolbarg({
organization: "demo",
storage: sqlite("./memory.db"),
embedding: openaiEmbedding({
apiKey: process.env.OPENAI_API_KEY!,
model: "text-embedding-3-small",
}),
});
const messages = [
{ role: "user", content: "I prefer dark mode in the IDE." },
{ role: "assistant", content: "I'll remember that." },
{ role: "user", content: "Also, only deploy on Fridays." },
];
// Store the last user turn (default)
await ctx.rememberFromMessages(messages, {
agent: "assistant",
mode: "raw",
});
// Or store every user turn:
await ctx.rememberFromMessages(messages, {
agent: "assistant",
mode: "raw",
rawStrategy: "all_user",
});
const hits = await ctx.recall({
query: "When can we deploy?",
topK: 3,
filter: { agent: "assistant" },
});
console.log(hits.map((h) => h.content.text));
await ctx.close();
```
## Optional extract mode [#optional-extract-mode]
Pass `llm` at construction and `mode: "extract"` to pull atomic facts with your model. Extraction quality is **not** a Wolbarg product promise — you own the LLM.
## Related pages [#related-pages]
* [rememberFromMessages()](/docs/api/remember-from-messages)
* [Example — Vercel AI memory](/docs/examples/vercel-ai-memory)
* [Quick Start](/docs/quick-start)
---
# Example — Hybrid Search
> Enable BM25 keyword search and fuse it with semantic recall.
URL: /docs/examples/hybrid-search
```ts
import { Wolbarg, sqlite, openaiEmbedding, bm25 } from "wolbarg";
const ctx = new Wolbarg({
organization: "demo",
storage: sqlite("./memory.db"),
embedding: openaiEmbedding({
apiKey: process.env.OPENAI_API_KEY!,
model: "text-embedding-3-small",
}),
keywordSearch: bm25(),
});
await ctx.remember({
agent: "ops",
content: { text: "Incident INC-2048: Redis failover completed." },
});
const hits = await ctx.recall({
query: "INC-2048 failover",
hybrid: { semanticWeight: 0.6, keywordWeight: 0.4 },
});
```
## Related pages [#related-pages]
* [Hybrid Search](/docs/hybrid-search)
---
# Example — Image Memory
> Ingest a PNG with OCR and vision enrichment.
URL: /docs/examples/image-memory
```bash
npm install tesseract.js
```
```ts
import { Wolbarg, sqlite, openaiEmbedding, tesseract, geminiVision } from "wolbarg";
const ctx = new Wolbarg({
organization: "demo",
storage: sqlite("./memory.db"),
embedding: openaiEmbedding({
apiKey: process.env.OPENAI_API_KEY!,
model: "text-embedding-3-small",
}),
ocr: tesseract(),
vision: geminiVision({ apiKey: process.env.GEMINI_API_KEY! }),
});
await ctx.ingest({
agent: "vision",
source: { path: "./screenshot.png" },
});
```
## Related pages [#related-pages]
* [Image Ingestion](/docs/image-ingestion)
---
# Examples
> Independent Wolbarg examples — basic memory, conversation bridge, Vercel AI adapter, hybrid search, storage backends, ingest, and providers.
URL: /docs/examples
## What is it? [#what-is-it]
Small, self-contained examples. Each page stands alone with copy-paste TypeScript.
| Example | Link |
| ------------------- | --------------------------------------------------------- |
| Basic Memory | [basic-memory](/docs/examples/basic-memory) |
| Conversation memory | [conversation-memory](/docs/examples/conversation-memory) |
| Vercel AI memory | [vercel-ai-memory](/docs/examples/vercel-ai-memory) |
| Hybrid Search | [hybrid-search](/docs/examples/hybrid-search) |
| SQLite | [sqlite](/docs/examples/sqlite) |
| PostgreSQL | [postgresql](/docs/examples/postgresql) |
| Image Memory | [image-memory](/docs/examples/image-memory) |
| PDF Memory | [pdf-memory](/docs/examples/pdf-memory) |
| Metadata Filtering | [metadata-filtering](/docs/examples/metadata-filtering) |
| Compression | [compression](/docs/examples/compression) |
| Providers | [providers](/docs/examples/providers) |
| Rerankers | [rerankers](/docs/examples/rerankers) |
| OCR | [ocr](/docs/examples/ocr) |
## Related pages [#related-pages]
* [Quick Start](/docs/quick-start)
* [API Overview](/docs/api)
---
# Example — Metadata Filtering
> Scope recall with meta helpers and agent filters.
URL: /docs/examples/metadata-filtering
```ts
import { meta } from "wolbarg";
await ctx.remember({
agent: "sales",
content: { text: "EU pricing starts at €49/seat." },
metadata: { region: "eu", priority: 3 },
});
const hits = await ctx.recall({
query: "pricing",
filter: {
agent: "sales",
metadata: meta.and(meta.eq("region", "eu"), meta.gte("priority", 2)),
},
});
```
## Related pages [#related-pages]
* [Metadata Filtering](/docs/metadata-filtering)
---
# Example — OCR
> Extract text from images with tesseract during ingest.
URL: /docs/examples/ocr
```bash
npm install tesseract.js
```
```ts
import { Wolbarg, sqlite, openaiEmbedding, tesseract } from "wolbarg";
const ctx = new Wolbarg({
organization: "demo",
storage: sqlite("./memory.db"),
embedding: openaiEmbedding({
apiKey: process.env.OPENAI_API_KEY!,
model: "text-embedding-3-small",
}),
ocr: tesseract(),
});
await ctx.ingest({
agent: "ocr",
source: { path: "./receipt.png" },
});
```
## Related pages [#related-pages]
* [OCR](/docs/ocr)
---
# Example — PDF Memory
> Ingest a text-layer PDF into chunked memories.
URL: /docs/examples/pdf-memory
```bash
npm install pdf-parse@1.1.4
```
```ts
import { Wolbarg, sqlite, openaiEmbedding } from "wolbarg";
const ctx = new Wolbarg({
organization: "demo",
storage: sqlite("./memory.db"),
embedding: openaiEmbedding({
apiKey: process.env.OPENAI_API_KEY!,
model: "text-embedding-3-small",
}),
});
await ctx.ingest({
agent: "docs",
source: { path: "./handbook.pdf" },
chunking: { strategy: "paragraph", chunkSize: 900, overlap: 100 },
metadata: { collection: "handbook" },
});
```
## Related pages [#related-pages]
* [Document Ingestion](/docs/document-ingestion)
---
# Example — PostgreSQL
> Shared PostgreSQL storage with the pg peer dependency.
URL: /docs/examples/postgresql
```bash
npm install pg
```
```ts
import { Wolbarg, postgres, openaiEmbedding } from "wolbarg";
const ctx = new Wolbarg({
organization: "prod",
storage: postgres({
connectionString: process.env.DATABASE_URL!,
schema: "wolbarg",
// maxPoolSize defaults to 20; remote TLS defaults to require
}),
embedding: openaiEmbedding({
apiKey: process.env.OPENAI_API_KEY!,
model: "text-embedding-3-small",
}),
});
await ctx.ready();
```
## Related pages [#related-pages]
* [PostgreSQL Backend](/docs/storage/postgresql)
---
# Example — Providers
> Mix OpenAI embeddings, Ollama LLM, and BM25 keyword search.
URL: /docs/examples/providers
```ts
import {
Wolbarg, sqlite, openaiEmbedding, ollamaLlm, bm25,
} from "wolbarg";
const ctx = new Wolbarg({
organization: "demo",
storage: sqlite("./memory.db"),
embedding: openaiEmbedding({
apiKey: process.env.OPENAI_API_KEY!,
model: "text-embedding-3-small",
}),
llm: ollamaLlm({ apiKey: "ollama", model: "llama3.2" }),
keywordSearch: bm25(),
});
```
## Related pages [#related-pages]
* [Provider Architecture](/docs/providers)
---
# Example — Rerankers
> Attach a Jina reranker and enable rerank on recall.
URL: /docs/examples/rerankers
```ts
import { Wolbarg, sqlite, openaiEmbedding, jinaReranker } from "wolbarg";
const ctx = new Wolbarg({
organization: "demo",
storage: sqlite("./memory.db"),
embedding: openaiEmbedding({
apiKey: process.env.OPENAI_API_KEY!,
model: "text-embedding-3-small",
}),
reranker: jinaReranker({ apiKey: process.env.JINA_API_KEY! }),
retrieval: { overFetchFactor: 4 },
});
await ctx.recall({ query: "refund policy", topK: 5, rerank: true });
```
## Related pages [#related-pages]
* [Rerankers](/docs/rerankers)
---
# Example — SQLite
> File-backed and in-memory SQLite storage examples.
URL: /docs/examples/sqlite
```ts
import { Wolbarg, sqlite, openaiEmbedding } from "wolbarg";
const file = new Wolbarg({
organization: "demo",
storage: sqlite("./agent-memory.db"),
embedding: openaiEmbedding({
apiKey: process.env.OPENAI_API_KEY!,
model: "text-embedding-3-small",
}),
});
const mem = new Wolbarg({
organization: "tests",
storage: sqlite(":memory:"),
embedding: openaiEmbedding({
apiKey: process.env.OPENAI_API_KEY!,
model: "text-embedding-3-small",
}),
});
```
## Related pages [#related-pages]
* [SQLite Backend](/docs/storage/sqlite)
---
# Example — Vercel AI memory
> Use @wolbarg/vercel-ai middleware with wrapLanguageModel for automatic recall and remember (AI SDK v7+).
URL: /docs/examples/vercel-ai-memory
## What is it? [#what-is-it]
Production path for apps on the [Vercel AI SDK](https://ai-sdk.dev/): wrap any provider model with [`wolbargMiddleware`](/docs/integrations/vercel-ai) so recall and remember happen automatically.
Runnable copy: `examples/adapters/vercel-ai/` (`npm start`, `npm run start:stream`, `npm run start:tools`).
Requires **AI SDK v7+**.
## Install [#install]
```bash
npm install wolbarg @wolbarg/vercel-ai ai @ai-sdk/openai
```
## Example usage [#example-usage]
```ts
import { generateText, wrapLanguageModel } from "ai";
import { openai } from "@ai-sdk/openai";
import { wolbarg, sqlite, openaiEmbedding } from "wolbarg";
import { wolbargMiddleware } from "@wolbarg/vercel-ai";
const memory = wolbarg({
organization: "my-app",
storage: sqlite("./memory.db"),
embedding: openaiEmbedding({
apiKey: process.env.OPENAI_API_KEY!,
model: "text-embedding-3-small",
}),
});
await memory.ready();
const model = wrapLanguageModel({
model: openai("gpt-4.1-mini"),
middleware: wolbargMiddleware({
memory,
agent: "assistant",
}),
});
const { text } = await generateText({
model,
messages: [{ role: "user", content: "What do I prefer?" }],
});
```
No manual `recall` / `remember` around `generateText` — the middleware owns that loop.
## Streaming + tools [#streaming--tools]
```bash
cd examples/adapters/vercel-ai
npm run start:stream # streamText
npm run start:tools # multi-step tools, final-step remember
```
## Related pages [#related-pages]
* [Vercel AI integration](/docs/integrations/vercel-ai)
* [rememberFromMessages()](/docs/api/remember-from-messages)
* [Example — Conversation memory](/docs/examples/conversation-memory)
* [Quick Start](/docs/quick-start)
---
# Errors
> Typed error hierarchy for Wolbarg 0.6 — ValidationError, RerankError, StorageLockedError, CancellationError, and more.
URL: /docs/reference/errors
## Hierarchy [#hierarchy]
* `WolbargError` — base
* `ConfigurationError` — bad config
* `ProviderNotConfiguredError` — method needs a missing provider (e.g. `compress` without `llm`)
* `InitializationError` — open / probe failed
* `ValidationError` — bad method arguments (including hybrid/rerank misconfig)
* `DatabaseError` / `EmbeddingError` / `CompressionError`
* `RerankError` — built-in reranker HTTP / empty ranking failure
* `MemoryNotFoundError`
* `VersionConflictError` — CAS mismatch on `expectedVersion`
* `StorageLockedError` — code `WOLBARG_STORAGE_LOCKED`
* `CancellationError` — AbortSignal cancelled an in-flight operation
* `wrapOperationError` — helper to wrap unknown errors
## Fail-closed hybrid / rerank (0.6.0) [#fail-closed-hybrid--rerank-060]
| Situation | Error |
| -------------------------------------- | ----------------- |
| `hybrid: true` without `keywordSearch` | `ValidationError` |
| `rerank: true` without `reranker` | `ValidationError` |
| Built-in reranker provider failure | `RerankError` |
There is no silent semantic-only or identity-order fallback. See [Hybrid Search](/docs/hybrid-search) and [Rerankers](/docs/rerankers).
## WOLBARG\_STORAGE\_LOCKED [#wolbarg_storage_locked]
Thrown when SQLite write-lock retries are exhausted under multi-process contention.
| Field | Meaning |
| ---------- | -------------------------------------------------------------------------------- |
| Code | `WOLBARG_STORAGE_LOCKED` |
| When | `BEGIN IMMEDIATE` / busy retries exceed `concurrency.maxRetries` |
| Suggestion | Increase retries / `lockTimeoutMs`, reduce writer fan-out, or switch to Postgres |
See [Concurrency](/docs/concurrency).
## CancellationError [#cancellationerror]
Thrown when `signal` aborts during `remember` / `recall` / `update` / `compress` / `forget` (and related helpers). In-flight embedding HTTP aborts.
## Graph errors (removed) [#graph-errors-removed]
`GraphCheckpointNotSupportedError` and graph-related `ProviderNotConfiguredError` examples are obsolete — graph memory was [removed in 0.6.0](/docs/graph-memory).
## Related pages [#related-pages]
* [Types](/docs/reference/types)
* [Concurrency](/docs/concurrency)
* [API Overview](/docs/api)
* [Production](/docs/guides/production)
* [FAQ](/docs/faq)
---
# init() Compatibility
> v0.1 init() API remains supported as a shim.
URL: /docs/reference/init-compat
## Usage [#usage]
```ts
const ctx = new Wolbarg();
await ctx.init({
organization: "my-org",
database: {
provider: "sqlite", // or "postgres"
connectionString: "./memory.db",
},
embedding: {
baseUrl: "https://api.openai.com/v1",
apiKey: process.env.OPENAI_API_KEY!,
model: "text-embedding-3-small",
},
llm: { // optional in 0.2
baseUrl: "https://api.openai.com/v1",
apiKey: process.env.OPENAI_API_KEY!,
model: "gpt-4.1-mini",
},
});
```
## Notes [#notes]
Prefer constructor DI + factories for new code. `init` maps `database` → storage and wires embedding / optional llm the same way.
## Related pages [#related-pages]
* [Migration](/docs/migration)
* [Wolbarg](/docs/api/wolbarg)
---
# Types
> Key public TypeScript types in Wolbarg.
URL: /docs/reference/types
## Domain [#domain]
```ts
MemoryRecord, MemoryContent, MemoryMetadata
RecallResult, HistoryEvent, HistoryResult
IngestResult, CompressResult, StatsResult
```
## Options [#options]
```ts
WolbargOptions, RememberOptions, RecallOptions
IngestOptions, CompressOptions, ForgetOptions
MemoryFilter, MetadataFilter, HybridConfig, MmrConfig
```
## Providers [#providers]
```ts
StorageProvider, EmbeddingProvider, LlmProvider
KeywordSearchProvider, RerankerProvider
OCRProvider, VisionProvider, ChunkingStrategy
CompressionProvider
```
## Related pages [#related-pages]
* [API Reference](/docs/api/reference)
* [Errors](/docs/reference/errors)
---
# PostgreSQL Backend
> Shared PostgreSQL storage with connection pooling, JSONB metadata, and optional pgvector.
URL: /docs/storage/postgresql
## What is it? [#what-is-it]
A `StorageProvider` implementation backed by PostgreSQL via the optional `pg` peer. Same public API as SQLite.
## Why does it exist? [#why-does-it-exist]
Teams that already run Postgres, or need multi-process / multi-host readers and writers against one database.
## How does it work? [#how-does-it-work]
```bash
npm install pg
```
```ts
import { postgres } from "wolbarg";
storage: postgres(process.env.DATABASE_URL!)
// or
storage: postgres({
connectionString: process.env.DATABASE_URL!,
schema: "wolbarg", // optional namespaced deployment
maxPoolSize: 20, // default since 0.6.0; raise only if the host allows
})
```
Features:
* Connection pooling (default `maxPoolSize` **20**)
* Remote hosts without `sslmode` / `ssl` in the URL get **`sslmode=require`** (loopback unchanged)
* Optional `schema` for tables, indexes, and NOTIFY channels
* JSONB metadata + GIN index
* pgvector when the extension is available (BYTEA + cosine fallback otherwise)
Install the optional `pg` peer before using `postgres()`. Operator details: [Production](/docs/guides/production).
## API parity [#api-parity]
Both backends implement the same `StorageProvider` contract: insert, batch insert, update, delete, vector search, metadata listing, history, transactions, and migrations. Switch storage by changing one constructor option.
## When should it be used? [#when-should-it-be-used]
Use PostgreSQL when multiple application instances share memory, or when you need central backups and ops. Use SQLite when the agent is single-node and file-based storage is enough.
## Related pages [#related-pages]
* [SQLite Backend](/docs/storage/sqlite)
* [Example — PostgreSQL](/docs/examples/postgresql)
* [Limitations](/docs/guides/limitations)
---
# SQLite Backend
> Local-first SQLite storage with WAL, sqlite-vec vectors, and FTS5 keyword indexing.
URL: /docs/storage/sqlite
## What is it? [#what-is-it]
The default storage backend. Memories live in a single SQLite file (or `:memory:`) using Node's built-in `node:sqlite`.
## Why does it exist? [#why-does-it-exist]
Zero infrastructure for development and most production single-node agents. No Docker, no managed DB — just a file.
## How does it work? [#how-does-it-work]
```ts
import { sqlite } from "wolbarg";
storage: sqlite("./memory.db")
// or
storage: sqlite(":memory:")
```
Uses:
* WAL mode for concurrent readers
* Prepared statements
* sqlite-vec when available (BLOB cosine fallback otherwise)
* FTS5 for keyword indexing (schema v2)
## When should it be used? [#when-should-it-be-used]
Prefer SQLite for local agents, demos, CI, and single-machine services. Move to [PostgreSQL](/docs/storage/postgresql) when you need multi-host access or central ops tooling.
## Performance notes [#performance-notes]
* Cold start is typically single-digit milliseconds in published benchmarks
* Database size scales roughly linearly with memory count (\~2.6 MB / 1k records in mock embedding suites)
* Hybrid BM25 needs `keywordSearch: bm25()` so FTS stays in sync
## Related pages [#related-pages]
* [PostgreSQL Backend](/docs/storage/postgresql)
* [Configuration](/docs/configuration)
* [Example — SQLite](/docs/examples/sqlite)
* [Performance](/docs/performance)
---
# Generated Exports
> Compact auto-generated catalog of public exports from the Wolbarg package entrypoint.
URL: /docs/api/reference/generated
## What is it? [#what-is-it]
Machine-generated list of every public symbol re-exported from `wolbarg` (`sdk/src/index.ts`). Prefer [curated API pages](/docs/api) for how-to docs; use this page for exhaustive symbol coverage (LLMs, grepping, audits).
Generated **191** exports.
## Public exports [#public-exports]
| Export |
| --------------------------------- |
| `applyEnvFile` |
| `assertEmbeddingPreset` |
| `BenchmarkReport` |
| `BenchmarkSample` |
| `bgeReranker` |
| `bm25` |
| `CancellationError` |
| `ChatMessage` |
| `CheckpointInfo` |
| `CheckpointMeta` |
| `CheckpointOptions` |
| `CheckpointProvider` |
| `Chunk` |
| `ChunkingOptions` |
| `ChunkingStrategy` |
| `ClearOptions` |
| `cohereReranker` |
| `CompressionError` |
| `CompressionProvider` |
| `CompressOptions` |
| `CompressResult` |
| `ConcurrencyConfig` |
| `ConfigurationError` |
| `ConversationMessage` |
| `CreateCheckpointOptions` |
| `createChunkingStrategy` |
| `createCompressionProvider` |
| `createDatabaseProvider` |
| `createEmbeddingProvider` |
| `CreateFromProjectConfigOptions` |
| `createLlmProvider` |
| `createStorageProvider` |
| `createTelemetryProvider` |
| `createWolbarg` |
| `createWolbargFromProjectConfig` |
| `crossEncoder` |
| `DatabaseConfig` |
| `DatabaseError` |
| `DatabaseProvider` |
| `DatabaseProviderName` |
| `DEFAULT_CONFIG_PATH` |
| `DEFAULT_ENV_PATH` |
| `DEFAULT_ORGANIZATION` |
| `DEFAULT_SQLITE_DB_PATH` |
| `defaultProjectConfig` |
| `EMBEDDING_PROVIDER_PRESETS` |
| `EmbeddingCacheConfig` |
| `EmbeddingConfig` |
| `EmbeddingError` |
| `EmbeddingProvider` |
| `EmbeddingProviderId` |
| `EmbeddingProviderPreset` |
| `EventDatabase` |
| `ExportResult` |
| `FixedChunkingStrategy` |
| `ForgetByFilterOptions` |
| `ForgetByIdOptions` |
| `ForgetOptions` |
| `geminiEmbedding` |
| `geminiVision` |
| `getEmbeddingProviderPreset` |
| `HeadingChunkingStrategy` |
| `HistoryEvent` |
| `HistoryOptions` |
| `HistoryResult` |
| `HybridConfig` |
| `ImportResult` |
| `IngestOptions` |
| `IngestResult` |
| `InitializationError` |
| `InitOptions` |
| `jinaReranker` |
| `KeywordDocument` |
| `KeywordSearchHit` |
| `KeywordSearchProvider` |
| `LatencyBreakdown` |
| `LlmCompressionProvider` |
| `LlmConfig` |
| `LlmProvider` |
| `lmStudioEmbedding` |
| `loadProjectConfig` |
| `MarkdownChunkingStrategy` |
| `MAX_MEMORY_CONTENT_CHARS` |
| `MAX_METADATA_JSON_BYTES` |
| `MemoryChangeCallback` |
| `MemoryChangeEvent` |
| `MemoryContent` |
| `MemoryDedupeConfig` |
| `MemoryDedupeStrategy` |
| `MemoryFilter` |
| `MemoryMetadata` |
| `MemoryNotFoundError` |
| `MemoryProvider` |
| `MemoryRecord` |
| `meta` |
| `MetadataComparison` |
| `MetadataFilter` |
| `MetaFilter` |
| `MmrConfig` |
| `NoopTelemetryProvider` |
| `OCRProvider` |
| `OcrResult` |
| `ollamaEmbedding` |
| `ollamaLlm` |
| `openaiCompatibleEmbedding` |
| `openaiCompatibleLlm` |
| `openaiEmbedding` |
| `openaiLlm` |
| `openaiReranker` |
| `openaiVision` |
| `openRouterEmbedding` |
| `openRouterLlm` |
| `ParagraphChunkingStrategy` |
| `PersistedRecallExplainPayload` |
| `postgres` |
| `postgresConfig` |
| `PostgresDatabaseConfig` |
| `PostgresStorageProvider` |
| `projectConfigToWolbargOptions` |
| `ProviderNotConfiguredError` |
| `RecallExplainResponse` |
| `RecallExplanationHit` |
| `RecallOptions` |
| `RecallResult` |
| `RememberAction` |
| `RememberFromMessagesOptions` |
| `RememberFromMessagesRawStrategy` |
| `RememberOptions` |
| `RememberResult` |
| `RerankDocument` |
| `RerankerProvider` |
| `RerankError` |
| `RerankHit` |
| `resolveConfigPath` |
| `resolveEmbeddingApiKey` |
| `resolveEnvPath` |
| `RetrievalConfig` |
| `runBenchmark` |
| `saveProjectConfig` |
| `SaveProjectConfigOptions` |
| `SDK_VERSION` |
| `SentenceChunkingStrategy` |
| `sqlite` |
| `sqliteCheckpoint` |
| `SqliteCheckpointProvider` |
| `sqliteConfig` |
| `SqliteDatabaseConfig` |
| `SqliteDatabaseProvider` |
| `SqliteEventDatabase` |
| `SqliteStorageProvider` |
| `sqliteTelemetry` |
| `SqliteTelemetryProvider` |
| `StageSpan` |
| `StatsResult` |
| `StorageConfig` |
| `StorageLockedError` |
| `StorageProvider` |
| `StorageProviderName` |
| `SubscribableEvent` |
| `SubscribeFilter` |
| `summarizeBenchmark` |
| `TelemetryConfig` |
| `TelemetryEmitter` |
| `TelemetryEvent` |
| `TelemetryEventInput` |
| `TelemetryLogLevel` |
| `TelemetryOperation` |
| `TelemetryProvider` |
| `TelemetryQuery` |
| `TelemetryQueryResult` |
| `TelemetryStatus` |
| `tesseract` |
| `togetherEmbedding` |
| `Unsubscribe` |
| `upsertEnvVar` |
| `ValidationError` |
| `VersionConflictError` |
| `VisionProvider` |
| `VisionResult` |
| `vllmEmbedding` |
| `wolbarg` |
| `Wolbarg` |
| `WolbargError` |
| `WolbargLogger` |
| `WolbargOptions` |
| `WolbargOptionsWithLlm` |
| `WolbargOptionsWithoutLlm` |
| `WolbargProjectConfig` |
| `WolbargProjectDatabaseConfig` |
| `WolbargProjectEmbeddingConfig` |
| `wrapOperationError` |
## Related pages [#related-pages]
* [API Overview](/docs/api)
* [Wolbarg](/docs/api/wolbarg)
* [Configuration](/docs/configuration)
* [Types](/docs/reference/types)
* [Errors](/docs/reference/errors)
* [Provider Architecture](/docs/providers)
---
# API Reference
> Export catalog and curated method pages for the wolbarg package.
URL: /docs/api/reference
## What is it? [#what-is-it]
Two layers of API docs:
1. **Curated method pages** — how to use `remember`, `recall`, graph, lifecycle, etc.
2. **[Generated Exports](/docs/api/reference/generated)** — exhaustive list of every public symbol from `sdk/src/index.ts` (compact table; regenerate with `npm run docs:api`).
Prefer curated pages for learning. Use the generated catalog when you need symbol coverage for tools and LLMs.
### Start here [#start-here]
* [Wolbarg](/docs/api/wolbarg)
* [remember()](/docs/api/remember)
* [recall()](/docs/api/recall)
* [Types](/docs/reference/types)
* [Errors](/docs/reference/errors)
Regenerate the export catalog:
```bash
npm run docs:api
```
## Related pages [#related-pages]
* [API Overview](/docs/api)
* [Configuration](/docs/configuration)