Real-time events
Subscribe to memory changes with wolbarg.subscribe() — in-process EventEmitter for SQLite, LISTEN/NOTIFY for Postgres, with filters and safe callbacks.
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
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
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<SubscribableEvent, "*">;
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 | 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
organizationis required and always matched.agentoptional — omit to receive all agents in the org.eventoptional — omit or pass"*"for all event kinds; pass an array for a whitelist.
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. For multi-process event delivery, use Postgres.
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
- 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
React to preference updates only
ctx.subscribe(
{ organization: "my-org", event: "update" },
async (e) => {
await refreshUserProfile(e.memoryId);
},
);Fan-out all org activity to a log
ctx.subscribe({ organization: "my-org", event: "*" }, (e) => {
audit.write(e);
});Combine with upsert
When memory dedupe updates in place, you receive "update" (and may see upsertAction: "updated"). Fresh inserts still emit "remember".
Related pages
Concurrency
Multi-process SQLite write safety in Wolbarg 0.4 — BEGIN IMMEDIATE, busy_timeout, exponential backoff, WOLBARG_STORAGE_LOCKED, and published multi-writer benchmarks.
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.