How Apache Maka Manages sessionId, turnId, runId, and invocationId: A Deep Dive into the Execution Model

Apache Maka generates and validates a four-tier hierarchy of identifiers—sessionId, turnId, runId, and invocationId—to maintain deterministic execution, strict ordering, and complete provenance across every agent conversation and tool invocation.

Apache Maka is an open-source AI agent framework that relies on a strict hierarchy of identifiers to maintain deterministic execution and provenance. Understanding how sessionId, turnId, runId, and invocationId are generated, scoped, and validated is essential for debugging complex agent workflows. This article examines the actual source implementation across the runtime host and storage packages to explain the complete lifecycle of these critical identifiers.

The Four-Tier Identifier Hierarchy

Session ID (sessionId): The Conversation Boundary

The sessionId represents the logical "conversation" belonging to a user or client connection. All subsequent turns, runs, and invocations that belong to the same conversation share this identifier. In packages/runtime-host/src/server/connection-session.ts, the session is created when a client first connects, while packages/runtime-host/src/server/client-capability-coordinator.ts binds the session to specific connection capabilities. The identifier is persisted in packages/storage/src/sqlite-session-metadata-store.ts, where it functions as the primary key for session-scoped metadata and capability snapshots. This ID tracks the lifetime of the entire conversation and serves as the root scope for all downstream identifiers.

Turn ID (turnId): The Prompt-Response Cycle

The turnId identifies a single round-trip of a prompt/response cycle inside a session. Each time the model asks the user for input or generates a new output, a distinct turnId is allocated. In packages/runtime-host/src/server/interactive-run-composer.ts, the system computes a composite storage key using ${sessionId}\u0000${turnId} to ensure uniqueness. This composite key guarantees ordering of prompts within the session and allows the UI to correlate frontend turns with underlying backend events. The turn data is stored in packages/storage/src/task-ledger-store.ts, which maintains the turn’s content and metadata keyed by this composite identifier.

Run ID (runId): The Execution Chain

The runId identifies the execution of a single "agent run"—a chain of turns that belong to one logical operation such as a skill execution, tool call, or user-initiated flow. The AgentRunStore class assigns this identifier via methods like appendRuntimeEvent and readImmutableRuntimeEvents, as demonstrated in packages/runtime-host/src/__tests__/execution-model-composition.test.ts. Every RuntimeEvent record stored in packages/storage/src/sqlite-runtime-store.ts carries this runId, enabling the system to group turns that belong to the same logical operation and support features like deterministic replay, copy-on-write, and debugging of specific runs.

Invocation ID (invocationId): The Tool Call Boundary

The invocationId provides the finest level of granularity, uniquely identifying a specific tool invocation or internal sub-run within a run. When a tool call frame is created, the system generates frame.invocationId using crypto.randomUUID(). This ID propagates through packages/storage/src/sqlite-runtime-store.ts, where the authority layer validates it to enforce sandbox-boundary checks and secure provenance tracking. The invocationId ensures that each tool call can be uniquely referenced for conflict detection and deterministic replay.

How the IDs Interact and Validate

The identifiers form a strict containment hierarchy that enforces data integrity across the storage layer. The sessionId serves as the top-level key for all data belonging to a user interaction. Within that session, turnId is scoped by the sessionId, with every turn record storing both identifiers. The runId is also scoped by sessionId, with each turn belonging to a specific run, allowing a single session to host many concurrent runs. The invocationId is scoped by both runId and turnId, ensuring each tool call inside a run receives its own unique trace identifier.

The system enforces strict invariants in packages/storage/src/sqlite-runtime-store.ts. Runtime events must satisfy RuntimeEvent.sessionId === stored.sessionId and RuntimeEvent.runId === stored.runId (lines 378‑383). Additionally, conflict detection prevents two runtime events from sharing the same invocationId unless they also share the same turnId (lines 3240‑3250), ensuring no duplicate tool invocations corrupt the execution state.

Implementation Examples

The following TypeScript examples demonstrate the creation and propagation of these identifiers through the Apache Maka runtime:

// 1️⃣ Creating a new session (packages/runtime-host/src/server/connection-session.ts)
const sessionId = await connectionSession.createSession();

// 2️⃣ Starting a new turn inside that session 
// (packages/runtime-host/src/server/interactive-run-composer.ts)
const turnId = await turnManager.nextTurnId(sessionId);
const turnKey = `${sessionId}\u0000${turnId}`; // Composite key for task-ledger indexing

// 3️⃣ Starting a new agent run (e.g., a skill execution)
// (packages/runtime-host/src/__tests__/execution-model-composition.test.ts)
const runId = await agentRunStore.startRun(sessionId);

// 4️⃣ Invoking a tool within that run with unique invocationId
// (packages/storage/src/sqlite-runtime-store.ts)
const invocationId = crypto.randomUUID(); // Generated per tool call frame
await runtimeStore.appendRuntimeEvent(sessionId, runId, {
  invocationId,
  turnId,
  // …other event fields
});

Summary

  • sessionId is created at connection time in connection-session.ts and persisted in sqlite-session-metadata-store.ts, serving as the root identifier for all conversation data.
  • turnId uses a composite key ${sessionId}\u0000${turnId} in interactive-run-composer.ts to guarantee ordering and is stored in task-ledger-store.ts.
  • runId is assigned by AgentRunStore and attached to every RuntimeEvent in sqlite-runtime-store.ts, grouping related turns into logical execution chains.
  • invocationId is generated via crypto.randomUUID() for each tool call frame and validated by conflict detection logic in sqlite-runtime-store.ts to ensure provenance integrity.
  • The hierarchy enforces strict invariants: session > run > turn > invocation, with storage-layer validation preventing cross-contamination of identifiers.

Frequently Asked Questions

How does Apache Maka ensure that turn IDs maintain proper ordering within a session?

Apache Maka guarantees turn ordering by generating turnId values sequentially within the session scope and using the composite key ${sessionId}\u0000${turnId} in interactive-run-composer.ts. This composite key is stored in task-ledger-store.ts, ensuring that turn records are retrieved in the exact sequence they were created. The system treats the turnId as an immutable identifier for that specific prompt-response cycle.

What prevents duplicate invocation IDs from corrupting the runtime state?

The sqlite-runtime-store.ts file implements conflict detection logic (lines 3240‑3250) that rejects any runtime event attempting to reuse an invocationId within the same turn context. Because invocationId is generated using crypto.randomUUID() for every tool call frame, and the storage layer validates uniqueness against existing records, the system prevents duplicate tool invocations from overwriting or colliding with existing execution data.

Can multiple runs exist within a single session simultaneously?

Yes, a single sessionId can host multiple concurrent runId values. The AgentRunStore assigns distinct runId identifiers for each logical operation, and sqlite-runtime-store.ts maintains separate event streams for each runId under the same sessionId. This architecture allows the system to execute parallel skill flows or handle multiple user requests within one persistent conversation session.

Where is the session metadata physically stored in the Apache Maka architecture?

Session metadata is persisted in packages/storage/src/sqlite-session-metadata-store.ts, which maintains session lifecycle data, capability snapshots from client-capability-coordinator.ts, and provenance validation records. The sessionId serves as the primary key in this SQLite-backed store, enabling fast lookups of session-scoped configuration and state across the distributed runtime.

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 →