Understanding the Event Sourcing Pattern in Maka's Runtime Event Log

Maka implements a classic event sourcing architecture where immutable, append-only JSON events serve as the single source of truth for runtime state, enabling durable execution and deterministic replay across sessions and turns.

The Apache Maka project utilizes a sophisticated event sourcing pattern within its runtime to manage AI-driven workflow execution. Unlike traditional mutable state management, Maka treats the event log as the primary record of truth, deriving all current state through deterministic replay of historical events. This approach powers critical capabilities like cross-turn durability, audit trails, and crash recovery.

Core Architecture of the Event Log

Maka's runtime centers on an append-only event log owned by each Session and Turn. Every state-changing action—whether tool invocations, step transitions, UI updates, or permission changes—generates an immutable JSON-encoded event that records the minimal data necessary to reconstruct that fact.

Immutable Append-Only Storage

The RuntimeEventLog class in packages/runtime/src/runtime-event-log.ts enforces strict append-only semantics. When the runtime performs an action, it creates a new event object containing a unique identifier, timestamp, and payload, then appends it to the log file without mutation.

import { RuntimeEventLog } from '@maka/runtime';

async function invokeTool(toolId: string, args: any) {
  const event = {
    type: 'ToolInvoked' as const,
    id: crypto.randomUUID(),
    timestamp: Date.now(),
    payload: { toolId, args },
  };
  await RuntimeEventLog.append(event);   // immutable append
}

This append-only design guarantees tamper-proof history essential for debugging and compliance. No in-place updates occur; the file grows monotonically with each new event.

Event Types and Structure

Events are implemented as discriminated unions capturing specific runtime actions. According to the source code in packages/runtime/src/model-adapter.ts, key event types include:

  • ToolInvoked – Records tool identifier and arguments
  • ToolResult – Captures return values and execution metadata
  • StepStarted and StepCompleted – Track workflow progression
  • PermissionPaused and PermissionGranted – Document security decisions
  • Continuation and Resume – Enable cross-turn execution

Each event carries a timestamp and unique ID, forming a complete audit trail of the session lifecycle.

Reconstructing Runtime State

Rather than maintaining mutable state objects, Maka rebuilds its current view from the event log through pure read model reconstruction.

The RuntimeEventReadModel

The RuntimeEventReadModel class defined in packages/runtime/src/runtime-event-read-model.ts consumes the event log to incrementally build an in-memory representation of the current session, active context, UI state, and permission status. Because this read model is pure (no side effects), it can be reconstructed at any point.

import { RuntimeEventReadModel } from '@maka/runtime';
import { RuntimeEventLog } from '@maka/runtime';

async function rebuildState(): Promise<RuntimeState> {
  const readModel = new RuntimeEventReadModel();

  // Optionally start from a snapshot if one exists
  const snapshot = await RuntimeEventLog.loadLatestSnapshot();
  if (snapshot) {
    readModel.applySnapshot(snapshot);
  }

  // Replay remaining events
  const events = await RuntimeEventLog.readFrom(
    snapshot ? snapshot.lastEventIndex + 1 : 0,
  );
  for (const ev of events) {
    readModel.apply(ev);
  }
  return readModel.state;
}

Snapshot Optimization for Performance

For long-running sessions, Maka implements periodic snapshots of the read model to mitigate replay latency. During reconstruction, the runtime loads the latest snapshot via RuntimeEventLog.loadLatestSnapshot(), then replays only events occurring after that point.

This optimization reduces startup time from O(n) to O(delta), where delta represents events since the last snapshot rather than the entire session history.

Durable Execution Across Turns

The event sourcing pattern enables Maka's signature "durable work" capability, allowing execution to survive individual turns and process restarts.

Handling Permission Pauses and Resumes

Permission-related events like PermissionPaused and PermissionGranted are persisted in the log, ensuring the runtime can replay identical security decisions when resuming a session. This maintains deterministic security posture across process boundaries.

The log spans multiple turns, enabling tools to emit events that resume execution in subsequent turns even after the original host process terminates:

async function canResume(turnId: string): Promise<boolean> {
  const state = await rebuildState();
  const turn = state.turns.find(t => t.id === turnId);
  return turn?.status === 'paused' && turn?.hasPendingEvents === false;
}

As detailed in docs/session-task-ledger-lifecycle.md, this architecture separates the ledger (event log) from the execution engine, allowing work to survive crashes and enabling distributed execution models.

Summary

  • Immutable event logs in packages/runtime/src/runtime-event-log.ts serve as the single source of truth for all runtime state
  • RuntimeEventReadModel in packages/runtime/src/runtime-event-read-model.ts reconstructs current state through deterministic replay
  • Snapshot optimization allows fast recovery by starting from recent checkpoints rather than replaying entire histories
  • Cross-turn durability enables workflows to survive process crashes and resume execution hours or days later
  • Audit compliance is inherent to the append-only design, capturing every tool invocation, permission decision, and state transition

Frequently Asked Questions

What makes Maka's event log immutable?

The log enforces append-only semantics where new events are written to the end of the file without modifying existing entries. This immutability is fundamental to the event sourcing pattern, ensuring that historical records remain tamper-proof and can serve as an accurate audit trail for debugging and compliance purposes.

How does snapshotting improve performance in Maka?

Snapshotting allows the runtime to bypass replaying potentially thousands of historical events when reconstructing state. By periodically persisting the RuntimeEventReadModel state and recording the last event index, Maka can restore from the snapshot and process only events occurring after that point, reducing initialization time from linear to constant relative to session length.

Can Maka resume execution after a process crash?

Yes, the event sourcing pattern enables durable execution where work survives process termination. Because the event log persists to storage and the read model is pure (no side effects), a new process instance can rebuild the exact state from the log and resume execution from the precise point of interruption, including replaying permission decisions stored as PermissionPaused events.

Where are events defined in the Maka source code?

Event type definitions and the bridge between domain events and the read model reside in packages/runtime/src/model-adapter.ts. The high-level architectural documentation explaining the event sourcing approach is located in docs/ARCHITECTURE.md, while docs/session-task-ledger-lifecycle.md details the specific lifecycle mechanics of the session ledger.

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 →