# SSEBroadcaster for Real-Time UI Updates: Architecture and Implementation in Claude-Mem

> Discover the SSEBroadcaster architecture in Claude-Mem for real-time UI updates. Learn how it efficiently broadcasts JSON payloads to synchronize UIs instantly without polling.

- Repository: [Alex Newman/claude-mem](https://github.com/thedotmack/claude-mem)
- Tags: architecture
- Published: 2026-02-16

---

**The SSEBroadcaster in Claude-Mem manages Server-Sent Events (SSE) connections by maintaining a Set of active Express Response objects and broadcasting JSON payloads directly to all connected clients in a single pass, enabling instantaneous UI synchronization without polling overhead.**

The Claude-Mem repository implements a lightweight real-time communication layer using the SSEBroadcaster class to push live updates to the viewer UI. This architecture eliminates traditional polling overhead by leveraging Server-Sent Events (SSE) to stream domain-specific events directly from the worker service to connected browsers. Understanding the SSEBroadcaster for real-time UI updates reveals how Claude-Mem maintains synchronized state across multiple viewer clients with minimal latency.

## Core Architecture Layers

The SSEBroadcaster operates through three distinct layers that manage client lifecycle, message distribution, and service integration.

### Client Management Layer

At the foundation, the SSEBroadcaster maintains a `Set<SSEClient>` containing active Express `Response` objects. When a browser connects to the `/stream` endpoint defined in [`src/services/worker/http/routes/ViewerRoutes.ts`](https://github.com/thedotmack/claude-mem/blob/main/src/services/worker/http/routes/ViewerRoutes.ts), the broadcaster invokes `addClient(res)` to register the connection. The implementation attaches a `close` event listener to automatically trigger `removeClient` when the browser disconnects, preventing memory leaks. Upon successful registration, the broadcaster immediately transmits a `connected` event to confirm the SSE stream is active.

### Event Broadcasting Layer

The `broadcast(event)` method in [`src/services/worker/SSEBroadcaster.ts`](https://github.com/thedotmack/claude-mem/blob/main/src/services/worker/SSEBroadcaster.ts) handles message distribution through a single-pass iteration over the client set. For each event, the method constructs a JSON payload enriched with a server-side timestamp, formats it according to the SSE protocol, and writes directly to each client's response stream using `client.write(data)`. This direct-write approach ensures all connected viewers receive identical snapshots simultaneously without intermediate queuing or batching delays.

### Integration Points

The SSEBroadcaster serves as a shared dependency across multiple high-level services:

- **ViewerRoutes**: Creates the `/stream` endpoint and pushes initial `initial_load` and `processing_status` events upon client connection.
- **SessionEventBroadcaster**: Translates domain actions into SSE events including `new_prompt`, `session_started`, `observation_queued`, and `session_completed`.
- **WorkerService**: Invokes `broadcastProcessingStatus()` to emit real-time queue depth updates via `processing_status` events whenever the internal state changes.

## Real-Time Data Flow

The SSEBroadcaster facilitates a continuous data pipeline from server to browser:

1. **Client Connection**: Browser opens `EventSource` to `GET /stream` → ViewerRoutes calls `SSEBroadcaster.addClient(res)`.
2. **Warm-up Payload**: Server immediately sends `initial_load` (project list) and current `processing_status`.
3. **Event Trigger**: Business logic fires (e.g., new prompt arrives) → SessionEventBroadcaster calls `SSEBroadcaster.broadcast()`.
4. **Client Update**: All connected browsers receive the event via open EventSource, update React state, and re-render UI instantly.
5. **Disconnection**: Browser closes tab → `close` event triggers `SSEBroadcaster.removeClient`, cleaning up the response object.

Because the broadcaster writes directly to the raw `Response` stream, there is no JSON-API wrapper or polling overhead; the UI stays in sync with the worker's internal state with minimal latency.

## Implementation Examples

### Registering an SSE Client

When a viewer connects to the stream endpoint, the Express response is configured for SSE and registered with the broadcaster:

```typescript
// In src/services/worker/http/routes/ViewerRoutes.ts
res.setHeader('Content-Type', 'text/event-stream');
res.setHeader('Cache-Control', 'no-cache');
res.setHeader('Connection', 'keep-alive');

this.sseBroadcaster.addClient(res);

```

### Broadcasting Custom Events

Any service can emit real-time updates by invoking the broadcast method with a typed event payload:

```typescript
// Example: Notifying the UI when an observation is stored
this.sseBroadcaster.broadcast({
  type: 'observation_saved',
  observationId: 'obs-12345',
  project: 'claude-mem',
  timestamp: Date.now()
});

```

### Client-Side Event Consumption

The browser connects to the SSE endpoint and listens for specific event types to update the UI state:

```javascript
const evtSource = new EventSource('http://localhost:37777/stream');

evtSource.addEventListener('new_prompt', (ev) => {
  const data = JSON.parse(ev.data);
  // Update React state with the new prompt information
  updateUI(data);
});

```

### Broadcasting Processing Status

The worker service automatically emits queue status updates whenever the processing state changes:

```typescript
// Inside WorkerService.broadcastProcessingStatus()
this.sseBroadcaster.broadcast({
  type: 'processing_status',
  isProcessing: this.isProcessing,
  queueDepth: this.queue.length
});

```

## Summary

- The SSEBroadcaster maintains a `Set` of active Express `Response` objects to manage persistent SSE connections.
- The `broadcast()` method writes JSON payloads directly to all connected clients in a single pass, ensuring synchronized real-time updates.
- Integration points include ViewerRoutes for the `/stream` endpoint, SessionEventBroadcaster for domain events, and WorkerService for processing status.
- Automatic cleanup via `removeClient` prevents memory leaks when browsers disconnect from the SSE stream.

## Frequently Asked Questions

### How does SSEBroadcaster handle client disconnections?

The SSEBroadcaster attaches a `close` event listener to each Express `Response` object upon registration. When a browser closes the connection or navigates away, the `close` event fires and automatically invokes `removeClient` to delete the response from the internal `Set`, preventing memory leaks and stale connections.

### What types of events can be broadcast through SSEBroadcaster?

The SSEBroadcaster supports any JSON-serializable event payload. Common event types used in Claude-Mem include `connected`, `initial_load`, `processing_status`, `new_prompt`, `session_started`, `observation_queued`, `session_completed`, and `observation_saved`. The `type` field in the payload allows the client-side EventSource to route events to appropriate handlers.

### How does the SSEBroadcaster differ from WebSocket implementations?

Unlike WebSockets, which require bidirectional message framing and protocol negotiation, the SSEBroadcaster leverages HTTP's native Server-Sent Events protocol. This approach uses standard Express `Response` objects with `text/event-stream` headers, eliminating the need for separate WebSocket libraries or connection upgrade logic. The architecture is unidirectional (server-to-client), making it ideal for broadcasting state updates without client-to-server messaging overhead.

### Where is the SSEBroadcaster instantiated in the Claude-Mem codebase?

The SSEBroadcaster is instantiated as a singleton within the worker service architecture and injected into dependent services. It is created in the service composition layer and passed to `ViewerRoutes` for the HTTP endpoint handling, `SessionEventBroadcaster` for domain event translation, and `WorkerService` for processing status updates. This dependency injection pattern ensures a single source of truth for all SSE communications across the worker service.