# How Session and Turn Identities Are Managed in Maka: A Technical Deep Dive

> Discover how Maka manages session and turn identities using stable IDs LRU caches and stateful hooks for efficient conversation context tracking. Learn more.

- Repository: [The Apache Software Foundation/maka](https://github.com/apache/maka)
- Tags: deep-dive
- Published: 2026-08-22

---

**Maka uses stable session IDs to isolate conversation contexts and unique turn IDs to track individual messages, implementing LRU caches and stateful hooks that reset automatically when session boundaries change.**

In the Apache Maka conversation framework, identity management forms the backbone of state isolation. Every interaction flows through a hierarchy where **session and turn identities** provide immutable references that prevent cross-contamination between conversations. This architecture ensures that UI components, caches, and projection engines maintain precise boundaries while optimizing for performance.

## Core Concepts of Session and Turn Identity

### Session IDs as Conversation Containers

A **session** represents the top-level container for a complete conversation. According to the Maka source code, each session receives a **session-id**—a stable, opaque string generated as a UUID by the backend when a conversation begins. This identifier survives navigation events, page reloads, and UI re-mounting, serving as the root key for all per-session stores including drafts, scroll positions, and virtual height caches.

In [`packages/ui/src/use-turn-virtualizer.ts`](https://github.com/apache/maka/blob/main/packages/ui/src/use-turn-virtualizer.ts), the hook checks `input.sessionId` before querying cached heights, ensuring that virtualized lists never confuse data between sessions. Similarly, [`packages/ui/src/use-chat-scroll.ts`](https://github.com/apache/maka/blob/main/packages/ui/src/use-chat-scroll.ts) maintains a mutable reference to the current `sessionId` for scroll calculations, validating that scroll state remains bound to its specific conversation context.

### Turn IDs as Message Identifiers

Within a session boundary, every discrete piece of exchanged text—whether a user message, assistant reply, or tool output—constitutes a **turn**. Each turn receives a **turn-id** that is unique within its parent session. The core logic generates these identifiers (typically via `uuidv4()` or monotonic counters) and attaches them to `StoredMessage` objects as they flow through the system.

Downstream consumers including the virtualizer, `TurnHeightIndex`, and interaction queues use this `turnId` as a lookup key. In [`packages/ui/src/turn-height-index.ts`](https://github.com/apache/maka/blob/main/packages/ui/src/turn-height-index.ts), the cache records heights using a composite key of `(sessionId, layoutKey, turnId)`, guaranteeing that UI measurements remain isolated to specific messages.

## Implementation Details in the Maka UI

### TurnHeightIndex LRU Cache

The `TurnHeightIndex` implements a bounded LRU cache that maps `(sessionId, layoutKey)` pairs to collections of `turnId → height` mappings. As implemented in [`packages/ui/src/turn-height-index.ts`](https://github.com/apache/maka/blob/main/packages/ui/src/turn-height-index.ts), this system enforces two critical limits:

- **Session capacity**: Defaults to 12 sessions maximum. When exceeded, the cache evicts old sessions entirely.
- **Turn capacity**: Each session retains only the most recent 1024 turn heights.

The `record()` function in [`turn-height-index.ts`](https://github.com/apache/maka/blob/main/turn-height-index.ts) stores heights using the `turnId` as the unique key within the session-scoped map, while `lookup()` retrieves them only when the `sessionId` matches the current context.

### TranscriptProjection Lifecycle

The transcript projection engine maintains incremental state as messages append to a conversation. Located in [`packages/ui/src/transcript-projection.ts`](https://github.com/apache/maka/blob/main/packages/ui/src/transcript-projection.ts), this module tracks the active `sessionId` in a module-level variable. When `updateProjection()` detects that `input.sessionId !== sessionId`, it immediately resets the projection to prevent stale turn data from persisting across conversation switches.

### InteractionQueue Isolation

Pending tool interactions queue per session rather than globally. In [`packages/ui/src/interaction-queue.ts`](https://github.com/apache/maka/blob/main/packages/ui/src/interaction-queue.ts), the `enqueueInteraction()` function stores interactions in a map keyed by `sessionId`. This design ensures that tool calls initiated in one conversation never execute in another, even when users rapidly switch between chat contexts.

## Code Examples

### Accessing Session Context in Hooks

Components consume session identity through typed input properties. The virtualizer hook validates session presence before cache access:

```typescript
// packages/ui/src/use-turn-virtualizer.ts
function useTurnVirtualizer(input: {
  sessionId?: string;
  // …
}) {
  const heights = input.sessionId && layoutKey
    ? turnHeightIndex.lookup(input.sessionId, layoutKey)
    : undefined;
  // …
}

```

### Recording Per-Turn Measurements

The height index exposes a `record()` method that binds measurements to specific turns:

```typescript
// packages/ui/src/turn-height-index.ts
export function createTurnHeightIndex(...) {
  record(sessionId: string, layoutKey: string, turnId: string, height: number) {
    const entry = entryFor(sessionId, layoutKey);
    entry.heights.set(turnId, height);
    // LRU eviction logic ensures bounds
  }
}

```

### Session-Bound Interaction Storage

Interactions queue using the session ID as the root key:

```typescript
// packages/ui/src/interaction-queue.ts
export function enqueueInteraction(
  queues: InteractionQueues,
  sessionId: string,
  interaction: Interaction
) {
  const queue = queues[sessionId] ?? [];
  return { ...queues, [sessionId]: [...queue, interaction] };
}

```

### Automatic Reset on Session Change

The projection engine detects boundary crossings and sanitizes state:

```typescript
// packages/ui/src/transcript-projection.ts
let sessionId: string | undefined;
export function updateProjection(input: { sessionId?: string }) {
  if (hasProjected && input.sessionId !== sessionId) reset();
  sessionId = input.sessionId;
}

```

## Summary

- **Session IDs** act as stable conversation roots generated by the Maka backend, surviving navigation and UI lifecycle events.
- **Turn IDs** provide unique identifiers within sessions for individual messages, enabling precise state tracking.
- **LRU caching** in [`turn-height-index.ts`](https://github.com/apache/maka/blob/main/turn-height-index.ts) bounds memory usage to 12 sessions and 1024 turns per session.
- **State isolation** occurs through explicit `sessionId` checks in [`transcript-projection.ts`](https://github.com/apache/maka/blob/main/transcript-projection.ts) and [`interaction-queue.ts`](https://github.com/apache/maka/blob/main/interaction-queue.ts), preventing data leakage.
- **UI hooks** receive session identities as props rather than generating them, ensuring consistency with the backend conversation model.

## Frequently Asked Questions

### What is the difference between a session ID and a turn ID in Maka?

A **session ID** identifies an entire conversation context and persists across page reloads, while a **turn ID** identifies a single message exchange within that session. The backend generates the session ID as a UUID when the conversation begins, whereas turn IDs are generated per-message by the core logic to track individual contributions to the transcript.

### How does Maka prevent data leakage between sessions?

Maka implements boundary checks in stateful modules like [`transcript-projection.ts`](https://github.com/apache/maka/blob/main/transcript-projection.ts), which compares incoming `sessionId` values against cached references and resets projections when mismatches occur. Additionally, the `TurnHeightIndex` LRU cache evicts entire session entries when capacity limits are reached, ensuring turn data from old sessions cannot contaminate new conversations.

### Where are session and turn identities generated in Maka?

The **session ID** originates in the backend when a new conversation starts, then propagates to the UI through URL parameters or navigation state. The **turn ID** is generated by the core runtime logic when creating new `StoredMessage` objects, typically using `uuidv4()` or incrementing counters, before flowing to UI components through the message pipeline.

### How does the TurnHeightIndex manage memory across sessions?

The `TurnHeightIndex` maintains a two-tier LRU strategy: it stores at most 12 sessions globally, and within each session, retains only the 1024 most recent turn heights. When `record()` is called on a full cache, the system evicts the least-recently-used session entirely, bounding memory consumption while preserving recent conversation context for smooth scrolling performance.