# How Maka's Transcript Projection Derives UI Views from the Event Log

> Learn how Maka derives UI views from its event log using transcript projection. Discover its incremental pipeline for materializing views and reconciling identities for React stability.

- Repository: [The Apache Software Foundation/maka](https://github.com/apache/maka)
- Tags: internals
- Published: 2026-09-01

---

**Maka derives UI views from its immutable event log by incrementally projecting stored messages through a pipeline that materializes canonical view models, overlays live and incremental updates, and reconciles object identities to preserve React rendering stability.**

Apache Maka records every user interaction, tool execution, and system change as an append-only **runtime event stream** rather than mutable UI state. The transcript projection layer transforms this raw event log into presentation-ready structures without rebuilding the entire view on each render. This architecture ensures that React components receive stable references to unchanged data, enabling efficient differential updates based on object identity rather than deep equality checks.

## The Event Log Foundation

At the core of the system lies an ordered list of `StoredMessage` objects representing each conversation turn. These messages contain raw markdown content, tool call metadata, and other execution details. Rather than passing these raw events directly to components, the UI consumes them through the `TranscriptProjection` interface defined in [`packages/ui/src/transcript-projection.ts`](https://github.com/apache/maka/blob/main/packages/ui/src/transcript-projection.ts).

The projection operates on `TranscriptProjectionInput`, which bundles the `messages` array with locale settings, optional live turn data, and incremental shell-run updates. This input remains immutable; the projection engine derives new view models while preserving references to unchanged objects.

## The Five-Stage Projection Pipeline

The transformation from event log to UI-ready structures follows a strict sequence of pure functions that progressively enhance and stabilize the view model.

### Stage 1: Materializing Stored Messages

The pipeline begins in [`packages/ui/src/materialize.ts`](https://github.com/apache/maka/blob/main/packages/ui/src/materialize.ts), where the `materializeTurns(messages, locale)` function transforms raw `StoredMessage` objects into an array of `TurnViewModel` instances. Each view model encapsulates rendered markdown, a list of `ToolActivityItem` objects, and display flags such as `compact` and `headingLevel`.

This step produces the **canonical transcript representation**—the base state onto which all incremental updates are applied.

### Stage 2: Overlaying Live Turns

When the system generates a response stream, the `overlayLiveTurn(settledTurns, liveTurn)` function injects a provisional turn into the settled array. This allows the UI to render in-flight content—such as streaming LLM output—without mutating the underlying event log. The overlay creates a temporary view model that merges with the canonical turns only for display purposes.

### Stage 3: Applying Shell-Run Updates

As background tools execute, they emit `ShellRunUpdate` objects that report incremental progress. The projection handles these through two operations:

1. `foldShellRunUpdates(updates)` collapses the update array into a map of `ShellRunOverlayEntry` objects indexed by turn ID.
2. `applyShellRunOverlay(turns)` traverses the turn array, using `applyShellRunOverlayEntry` to patch the `tools` array of affected turns with the latest execution results.

This mechanism updates tool status indicators and output panels without regenerating the entire transcript.

### Stage 4: Reconciling Identities for Stable Rendering

To prevent React from unnecessarily re-rendering unchanged turns, the `reconcileTurnIdentities(previous, next)` function compares structural values using `valuesEqual`. When two turns are semantically identical, the function retains the **previous object reference**, ensuring that `TurnViewModel` instances maintain referential equality across projection cycles. This step is critical for performance in long conversations where only the latest turns change.

## React Hook Integration

The `useTranscriptProjection` hook in [`packages/ui/src/use-transcript-projection.ts`](https://github.com/apache/maka/blob/main/packages/ui/src/use-transcript-projection.ts) exposes the projection engine to React components. It initializes a singleton projector via `createTranscriptProjection()` and memoizes the projection result:

```typescript
// packages/ui/src/use-transcript-projection.ts
import { createTranscriptProjection } from './transcript-projection.js';
import { useMemo } from 'react';

export function useTranscriptProjection(input) {
  const projector = useMemo(() => createTranscriptProjection(), []);
  return useMemo(() => projector.project(input), [
    input.sessionId,
    input.locale,
    input.messages,
    input.liveTurn,
    input.shellRunUpdates,
  ]);
}

```

The dependency array ensures that projection only recalculates when the underlying event data changes, while identity reconciliation guarantees that unchanged turns return identical references.

## Rendering the Derived Views

UI components such as `ChatView` in [`packages/ui/src/chat-view.tsx`](https://github.com/apache/maka/blob/main/packages/ui/src/chat-view.tsx) consume the stable `TurnViewModel` array directly:

```tsx
// packages/ui/src/chat-view.tsx
import { useTranscriptProjection } from './use-transcript-projection.js';

function ChatView(props) {
  const turns = useTranscriptProjection({
    sessionId: props.sessionId,
    locale: props.locale,
    messages: props.messages,
    liveTurn: props.liveTurn,
    shellRunUpdates: props.shellRunUpdates,
  });

  return (
    <div className="maka-transcript">
      {turns.map(turn => (
        <Turn key={turn.turnId} viewModel={turn} />
      ))}
    </div>
  );
}

```

Because `reconcileTurnIdentities` preserves object identity for stable turns, React's diffing algorithm can efficiently update only the specific DOM nodes corresponding to new or modified content.

## Summary

- **Immutable Event Log**: Apache Maka stores all interactions as `StoredMessage` objects in an append-only stream.
- **Materialization**: `materializeTurns()` in [`packages/ui/src/materialize.ts`](https://github.com/apache/maka/blob/main/packages/ui/src/materialize.ts) converts raw events into `TurnViewModel` instances.
- **Live Overlays**: The system supports streaming content through `overlayLiveTurn()` without mutating canonical state.
- **Incremental Tool Updates**: `foldShellRunUpdates()` and `applyShellRunOverlay()` merge background execution progress into the view.
- **Identity Preservation**: `reconcileTurnIdentities()` ensures stable React rendering by reusing object references for unchanged turns.
- **Hook Abstraction**: `useTranscriptProjection()` provides a memoized interface to the projection pipeline for UI components.

## Frequently Asked Questions

### How does Maka prevent unnecessary React re-renders when the event log grows?

Maka prevents unnecessary re-renders through **identity reconciliation**. The `reconcileTurnIdentities()` function compares the structural values of previous and newly projected turns using `valuesEqual`. When turns are semantically identical, the function returns the previous object reference, ensuring React's diffing algorithm recognizes them as unchanged. This allows long transcripts to update efficiently even as new messages arrive.

### What is the purpose of the `liveTurn` overlay in the projection pipeline?

The `liveTurn` overlay enables real-time streaming of partial LLM responses without corrupting the canonical event log. The `overlayLiveTurn()` function injects a provisional turn into the settled turn array, allowing the UI to display in-flight content. Once the stream completes, the live turn is removed and replaced by the permanent `StoredMessage` in the event log, ensuring the projection remains deterministic.

### How do shell-run updates integrate with the transcript view models?

Shell-run updates propagate through a two-phase folding process. First, `foldShellRunUpdates()` collapses incoming `ShellRunUpdate` arrays into a map of `ShellRunOverlayEntry` objects. Then, `applyShellRunOverlay()` patches the `tools` array within each affected `TurnViewModel`. This updates tool execution status and output panels incrementally without regenerating the entire transcript projection.

### Where does the transcript projection hook initialize its state?

The `useTranscriptProjection` hook initializes a singleton projection instance via `createTranscriptProjection()` using React's `useMemo()` with an empty dependency array. This ensures the projection engine persists across component re-renders while the hook's second `useMemo()` call recalculates the view model only when `messages`, `locale`, `liveTurn`, or `shellRunUpdates` change.