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

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, 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 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, 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, 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 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, 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, 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:

// 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:

// 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:

// 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:

// 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 bounds memory usage to 12 sessions and 1024 turns per session.
  • State isolation occurs through explicit sessionId checks in transcript-projection.ts and 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, 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.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →