What Does a Turn Represent in Maka's Session Architecture

A Turn in Apache Maka is the fundamental, immutable unit of work that captures a complete interaction cycle between the agent and runtime, from initial user input through all model-generated messages, tool calls, permission decisions, and side-effects until the runtime marks it as ended.

In Apache Maka's session architecture, understanding what a Turn represents is essential for building reliable agentic applications. A Turn encapsulates an entire logical interaction as an append-only segment of the Runtime Event Log, ensuring that every step—from initial prompt to final output—remains replayable and auditable. This design pattern allows the UI to render coherent conversation blocks while maintaining an immutable single source of truth in the underlying data layer.

The Turn as a Fundamental Unit of Work

Maka treats the Turn as the atomic boundary for agentic interactions. Unlike simple message passing, a Turn groups all related events into a single, coherent transaction that spans the full lifecycle of a request.

When a user submits input, the runtime creates a Turn that persists until the model finishes reasoning, executes any requested tools, resolves permissions, and generates final outputs. This architecture enables the UI to display complex multi-step interactions—such as "model speaks → runs a command → asks permission → you approve → result → edit → turn ends"—as a single visual block, as illustrated in the project README.

Turn Lifecycle and Event Flow

The Turn lifecycle follows a strict protocol defined in packages/runtime-host/src/protocol/turn.ts. Each phase corresponds to specific input types that transition the Turn through distinct states.

Turn Start with TurnStartInput

A Turn begins when the runtime receives a TurnStartInput payload. According to the source code in packages/runtime-host/src/protocol/turn.ts (lines 53-59), this input initializes the Turn context and assigns a unique turnId that tags all subsequent events.

import { RuntimeHostClient } from '@maka/runtime-host';
const client = new RuntimeHostClient();
await client.sendTurnStart({ 
  sessionId: 's1', 
  turnId: 't1', 
  text: 'Summarize repo' 
});

Runtime Events and Event Tagging

During the active phase, the runtime generates RuntimeEvent objects for every model message, tool call, permission decision, and file change. Each event carries the same turnId, creating an immutable audit trail in the Runtime Event Log. The TurnLedger—implemented in scripts/computer-use/direct-runtime-ledger.mjs—provides in-memory filtering to group these events by turnId for efficient session management.

Turn End with TurnStopInput

The runtime finalizes the Turn by emitting a TurnStopInput, defined at lines 86-90 of turn.ts. This marker completes the interaction cycle and makes the transcript viewable for UI rendering.

await client.sendTurnStop({ sessionId: 's1', turnId: 't1' });

Internal Data Structures

Maka implements the Turn concept through several specialized data structures that handle persistence, UI projection, and session state:

  • TurnStartInput / TurnStopInput – API protocol messages in packages/runtime-host/src/protocol/turn.ts that define the Turn boundaries.
  • TurnRecord – The persistent representation stored in the SQLite runtime database (runtime.sqlite), defined in packages/core/src/session.ts.
  • TurnViewModel – A UI-friendly model used by React renderers, constructed in packages/ui/src/materialize.ts (lines 404-412).
  • TurnLedger – An in-memory ledger that efficiently filters and groups events by turnId, located in scripts/computer-use/direct-runtime-ledger.mjs.

Practical Code Examples

Submitting Messages Within a Turn

Once a Turn is active, you submit messages using the turnId to maintain context. The message payload structure is defined in packages/runtime-host/src/protocol/message.ts (lines 93-100).

await client.sendMessage({
  sessionId: 's1',
  turnId: 't1',
  content: { 
    role: 'user', 
    text: 'What does a Turn represent?' 
  },
});

Rendering Turns in the UI

The UI materializes Turns using TurnViewModel objects created by functions like materializeTurns and projectTranscriptRows in packages/ui/src/transcript-projection.ts. React components consume these models to render complete interaction blocks.

import { TurnViewModel } from '@maka/ui';

function TurnPanel({ turn }: { turn: TurnViewModel }) {
  return (
    <div className="turn">
      <div className="turn-header">{turn.label}</div>
      <div className="turn-body">{turn.content}</div>
    </div>
  );
}

Key Source Files and Their Roles

File Role
packages/runtime-host/src/protocol/turn.ts Defines protocol messages (TurnStartInput, TurnStopInput) for Turn lifecycle management.
packages/core/src/session.ts Persists Turn data via TurnRecord and TurnStateMessage in the SQLite runtime database.
packages/ui/src/materialize.ts Builds UI-ready TurnViewModel objects from raw RuntimeEvents for React rendering.
scripts/computer-use/direct-runtime-ledger.mjs Implements in-memory event grouping by turnId for session-specific queries.
README.md (lines 39-42) Provides visual documentation of the Turn lifecycle in the product interface.

Summary

  • A Turn represents the complete interaction cycle in Maka's session architecture, from user input through all model-generated events to final completion.
  • The Runtime Event Log treats Turns as immutable, append-only segments identified by unique turnId values.
  • TurnStartInput and TurnStopInput in packages/runtime-host/src/protocol/turn.ts define the protocol boundaries for initiating and finalizing Turns.
  • TurnRecord in packages/core/src/session.ts provides persistent SQLite storage, while TurnViewModel in packages/ui/src/materialize.ts enables UI rendering.
  • All UI components project the immutable log into transcripts using functions like materializeTurns and projectTranscriptRows.

Frequently Asked Questions

How does a Turn differ from a Session in Maka?

A Session represents the long-running container for user interactions, persisting across multiple Turns and maintaining state such as conversation history and file system context. A Turn is a bounded unit of work within that Session, isolating a single logical interaction from start to finish. While a Session may contain many Turns over time, each Turn encapsulates one complete request-response cycle with its own immutable event log segment.

Can a Turn span multiple user messages?

No, a Turn represents a single logical interaction initiated by one user input (or automated trigger). While the model within a Turn may generate multiple messages, tool calls, and permission requests, the Turn itself begins with one TurnStartInput and concludes with one TurnStopInput. Subsequent user inputs initiate new Turns with distinct turnId values, ensuring clear separation between interaction cycles in the TurnLedger.

How does the UI render Turns from the event log?

The UI materializes Turns by querying the immutable Runtime Event Log and projecting events through materializeTurns and projectTranscriptRows in packages/ui/src/transcript-projection.ts. These functions filter RuntimeEvent objects by turnId and construct TurnViewModel instances. React components then render these view models as coherent blocks, displaying the full sequence of model messages, tool executions, and results as a single visual unit despite comprising multiple underlying events.

Are Turn events mutable after the Turn ends?

No, Turn events are strictly immutable. Once the runtime emits a TurnStopInput, the events tagged with that turnId become permanent entries in the SQLite-backed Runtime Event Log. This immutability serves as the "single source of truth," enabling deterministic replay, accurate auditing, and consistent rendering across different UI surfaces (desktop, TUI, or CLI) without risk of data corruption or state drift.

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 →