WOLBΛRG

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

EventWhen
rememberNew memory inserted
updateExisting memory upserted / update()
forgetMemory deleted
compressCompression archived sources + wrote summary
ingestDocument ingest completed
*Subscribe to all of the above

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 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.

TopologySQLite subscribe
One process, many async writers✅ Events delivered
Many processes, shared file❌ No cross-process delivery
Need multi-host / multi-process eventsUse 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).

DetailBehavior
DeliveryCross-process and cross-host (same database)
FilteringOrg / agent / event filtered client-side after notify
PayloadIDs + metadata only (NOTIFY capped at ~8000 bytes)
ReconnectListener reconnects if the connection drops
PoolingListen 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".