Apache Maka Crash Recovery: How the Runtime Resume Protocol Survives Process Failures

Apache Maka guarantees that a turn (an atomic interaction with a model) can survive a process crash and be safely resumed through a durable SQLite event log and a deterministic four-phase recovery protocol.

This article explains how Apache Maka implements crash recovery based on the runtime architecture documented in apache/maka. The design centers on an append-only RuntimeEventStore, a RecoveryResolver decision engine, and layered resume phases that range from basic safety checks to full side-effect reconciliation.


Core Components of Apache Maka Crash Recovery

Apache Maka's crash recovery system relies on three interconnected components that ensure deterministic, fail-closed behavior after unexpected termination.

RuntimeEventStore: The Durable Source of Truth

The RuntimeEventStore is a SQLite-backed append-only log (runtime.sqlite) that records every RuntimeEvent produced by the Runtime Host. It serves as the single source of truth for all recovery decisions.

Key characteristics of the store:

  • Atomic commits — events are written transactionally before any acknowledgment to the model
  • Prefix projection — recovery reads only the committed prefix of events, ignoring uncommitted writes
  • Immutable history — once committed, events are never modified or deleted

The store implementation lives in packages/runtime/src/runtime-event-store.ts. During normal operation, it receives events from the Runtime Host through the SessionManager → AgentRun pipeline. After a crash, a new store instance opens the same SQLite file to begin recovery.

Crash Contract (Phase 0): The Safety Gate

The Phase 0 Crash Contract defines what can be safely replayed after a crash. This contract, documented in docs/architecture/runtime-resume-phase0-crash-contract.md, inspects the committed event prefix and produces a deterministic ResumePlan.

The contract applies a simple but critical rule:

  • Safe replay — permitted if the committed prefix ends before any tool operation (before_function_call, after_function_call, etc.)
  • Blocked — required if any tool operation appears in the prefix, since side effects may have occurred

This fail-closed design ensures Maka never guesses about unknown states. If the contract cannot verify safety, it blocks automatic resumption.

RecoveryResolver: The Authoritative Decision Engine

The RecoveryResolver implements the complete decision logic across all recovery phases. Located in packages/runtime/src/recovery-resolver.ts, it:

  • Reads the committed prefix from RuntimeEventStore
  • Applies the Phase 0-3 contract rules
  • Emits deterministic decisions: completed, indeterminate, corruption, safe_replay, or blocked

The RecoveryResolver never guesses. Unknown states are treated as failures, forcing manual intervention rather than risking incorrect replay. The architectural decision record in docs/architecture/runtime-recovery-resolver-adr.zh-CN.md documents this fail-closed philosophy.


The Four-Phase Runtime Resume Architecture

Maka structures crash recovery across four phases, with each phase adding capabilities while maintaining safety guarantees.

Phase Purpose Safety Guarantee
Phase 0 — Crash Contract Determine if prefix is replay-safe No tool side-effects replayed; deterministic safe/blocked decision
Phase 1 — Safe Boundary Enable automatic resumption for Desktop/CLI Safe replay without manual intervention when contract permits
Phase 2 — Tool Boundary (T1/T2) Capture tool execution state atomically Tool dispatch events mark boundaries; journal is projection of event store
Phase 3 — Full Recovery Side-effect reconciliation and continuation runs Complete fail-closed recovery with idempotent re-execution

Only Phases 0 and 1 are required for basic crash-only safety. Phases 2 and 3 add sophistication for complex scenarios involving tool side effects and multi-turn continuations.

The system architecture flows from Runtime Host → SessionManager → AgentRun → RuntimeEventStore, with recovery traversing this path in reverse through the RecoveryResolver.


Enabling Automatic Safe-Boundary Resume

Apache Maka supports optional automatic crash recovery through an environment flag. When enabled, the Runtime Host queries the RecoveryResolver and automatically continues safe turns.


# Enable safe-boundary resume for Desktop or CLI

export MAKA_RUNTIME_SAFE_BOUNDARY_RESUME=1

With this flag active:

  1. The Runtime Host opens the workspace's RuntimeEventStore
  2. Invokes RecoveryResolver.computeResumePlan()
  3. If the plan is safe_replay, automatically re-executes the model turn
  4. If blocked, presents a manual "Resume" option in the UI or CLI diagnostic

Without the flag, all blocked turns require explicit user action.


Crash Recovery in Practice: A Step-by-Step Walkthrough

When a process terminates unexpectedly, Apache Maka follows this deterministic sequence:

  1. Crash occurs — process receives SIGKILL or equivalent; SQLite file contains committed event prefix

  2. Workspace reopened — new RuntimeEventStore instance opens runtime.sqlite from the workspace

  3. Prefix projection — store identifies the last fully committed sequence of events

  4. ResumePlan generation — RecoveryResolver applies Phase 0 contract rules:

    • Ends before before_function_call? → safe_replay
    • Contains any tool boundary event? → blocked
  5. Safe replay execution — for safe_replay, Runtime Host re-executes from last model turn using recorded messages; no tool code runs

  6. Blocked handling — for blocked, UI shows Resume button or CLI emits diagnostic; user chooses retry, edit, or abort

Throughout this process, the durable ledger remains read-only during decision-making. No mutations occur until a definitive safe replay is confirmed.


Code Example: Querying Recovery State

The following TypeScript demonstrates how applications can integrate crash recovery detection:

// Enable safe-boundary resume (optional)
process.env.MAKA_RUNTIME_SAFE_BOUNDARY_RESUME = '1';

import { RuntimeEventStore, RecoveryResolver } from '@maka/runtime';

async function evaluateCrashRecovery(workspacePath: string): Promise<string> {
  const store = await RuntimeEventStore.open(workspacePath);
  const resolver = new RecoveryResolver(store);
  
  // Returns 'safe_replay' | 'blocked' | 'completed' | 'indeterminate' | 'corruption'
  const plan = await resolver.computeResumePlan();
  return plan;
}

// CLI integration example
(async () => {
  const workspace = process.argv[2] || '/path/to/workspace';
  const plan = await evaluateCrashRecovery(workspace);
  
  switch (plan) {
    case 'safe_replay':
      console.log('✅ Crash recovery: safe to resume automatically');
      // RuntimeHost.resumeTurn(workspace) replays model turn
      break;
    case 'blocked':
      console.warn('⚠️ Crash recovery: manual intervention required');
      process.exitCode = 1;
      break;
    case 'completed':
      console.log('Turn already completed, no recovery needed');
      break;
    default:
      console.error(`❌ Recovery failed: ${plan}`);
      process.exitCode = 2;
  }
})();

The RecoveryResolver class encapsulates all phase transitions, ensuring consistent behavior across Desktop, CLI, and embedded deployments.


Source Files for Apache Maka Crash Recovery

Path Description
docs/architecture/runtime-resume-phase0-crash-contract.md Formal contract defining safe-replay vs. blocked outcomes
docs/architecture/runtime-recovery-resolver-adr.zh-CN.md Architectural decision record for the RecoveryResolver
packages/runtime/src/runtime-event-store.ts SQLite-backed durable event log implementation
packages/runtime/src/recovery-resolver.ts Recovery decision engine with Phase 0-3 logic
README.md (Local Data and Recovery section) Feature overview and environment flag documentation
ARCHITECTURE.md System-wide architecture with Runtime Resume component placement

Summary

  • Apache Maka crash recovery depends on an append-only SQLite RuntimeEventStore as the single source of truth
  • The Phase 0 Crash Contract deterministically classifies crashes as safe_replay or blocked based on whether tool operations appear in the committed prefix
  • The RecoveryResolver implements fail-closed decision logic across four phases, never guessing about unknown states
  • Safe-boundary resume can be enabled via MAKA_RUNTIME_SAFE_BOUNDARY_RESUME=1 for automatic recovery in Desktop and CLI environments
  • All recovery operations are read-only until safety is confirmed, preserving ledger integrity

Frequently Asked Questions

What happens if Apache Maka crashes during a tool execution?

If the committed event prefix contains any tool boundary event (before_function_call, after_function_call, or after_function_response), the Phase 0 Crash Contract returns blocked. The turn cannot be automatically resumed because side effects may have occurred. The user must manually decide whether to retry, edit, or abort the turn.

How does Apache Maka ensure the event log isn't corrupted during a crash?

The RuntimeEventStore uses SQLite's atomic transaction guarantees. Events are committed to disk before any acknowledgment returns to the Runtime Host. During recovery, only the committed prefix is read—partial writes in the WAL or journal files are excluded by the prefix projection logic in runtime-event-store.ts.

Can I disable automatic crash recovery in Apache Maka?

Yes. Automatic safe-boundary resume is opt-in via the MAKA_RUNTIME_SAFE_BOUNDARY_RESUME environment variable. Without this flag, all turns that would qualify for safe_replay still require explicit user confirmation through the UI or CLI, matching the behavior of blocked turns.

What is the difference between Phase 1 and Phase 3 recovery?

Phase 1 (Safe Boundary) enables automatic resumption when the Phase 0 contract returns safe_replay—essentially crashes that occurred before any tool execution. Phase 3 (Full Recovery) handles complex scenarios with tool side effects through the complete RecoveryResolver decision table, including tool_recovery_decided events and continuation-run manifests for multi-turn recovery.

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 →