Archived on 2026-07-13. This is a point-in-time extraction record, not current architecture authority. Start with
ARCHITECTURE.md.
This document explains the runtime-kernel work in this change set: what changed, why it was needed, what stayed stable, and how it was verified.
Maka already had the pieces of a local desktop coding agent: sessions, model streams, tool calls, permission prompts, abort handling, usage telemetry, bot and gateway entry points, and persisted session messages. The problem was that the core execution responsibilities were still concentrated in a few large runtime paths, especially AiSdkBackend and SessionManager.sendMessage().
This change set keeps the product surfaces stable but introduces clearer internal runtime boundaries:
SessionManager -> AgentRun -> AiSdkBackend -> ModelAdapter -> ToolRuntime -> RunTrace -> AgentRunStore
The intent is not to rewrite the runtime or replace the Vercel AI SDK. The goal is to make the existing runtime easier to reason about, easier to recover after interruption, and easier to extend with future backends or workflow integrations.
ToolRuntime is now the internal boundary for the lifecycle of model-requested tools. The extracted runtime owns the work that used to be interleaved inside the AI SDK backend:
AiSdkBackend still bridges model stream behavior, but it no longer needs to own every detail of tool execution.
ModelAdapter is the provider-facing stream and error normalization layer. It keeps AI SDK-specific stream chunks, provider setup, usage normalization, and provider error mapping out of the higher-level backend orchestration shell.
This makes the boundary explicit:
provider / AI SDK details -> ModelAdapter -> Maka runtime events and usage records
That separation matters because future providers should not need to duplicate permission, tool, run, or session-state behavior.
RunTrace is an internal best-effort trace path for runtime events. It records milestones such as:
Trace recorder failures are intentionally non-fatal. A failed trace write must not alter model or tool execution.
The core package now defines internal AgentRun contracts:
AgentRunHeaderAgentRunEventAgentRunStatusAgentRunStoreThe storage package adds a file-backed run store:
sessions/<sessionId>/runs/<runId>/run.json sessions/<sessionId>/runs/<runId>/events.jsonl
The store provides:
run.json writesevent_corruptThis ledger is separate from the existing session message JSONL so runtime diagnostics and recovery state do not pollute user-visible conversation history.
SessionManager.sendMessage() now delegates the heavy turn lifecycle to internal AgentRun.execute().
AgentRun owns:
RunTrace events into the durable run ledgerrenderer.stop_buttonSessionManager remains the public runtime API and continues to own session CRUD, backend registry orchestration, active run lookup, and legacy recovery entry points.
The old active stream counters and turn-id side maps were replaced with:
activeRuns: Map<string, AgentRun> turnToRunId: Map<string, string>
This makes overlapping run behavior explicit. It also avoids masking active stream accounting bugs with defensive counter clamping.
recoverInterruptedSessions() now prefers the AgentRun ledger when run rows are available. It scans persisted run headers and events, classifies stale non-terminal runs, repairs them, and then converges the existing session/turn projection.
Recovered cases include:
created or running runsrun_started or model_stream_startedtool_startedpermission_requestedmodel_stream_completed without a terminal run eventevent_corruptLegacy sessions without run ledger rows still use the prior message and turn-state recovery path.
This work intentionally does not change:
window.maka.* preload APISessionEvent behaviorThe runtime kernel is internal. Public behavior should remain compatible while the internals become more explicit and recoverable.
Before this work, a single turn execution was spread across session management, backend stream handling, tool wrapping, permission policy, telemetry, and abort logic. That made several questions difficult to answer after a failure:
The AgentRun ledger gives the runtime a durable fact record for those answers. ToolRuntime and ModelAdapter then reduce the amount of model/tool/provider logic that has to be understood at once.
The new recovery path is conservative. It does not replay model streams or tools. Instead, it repairs stale state into deterministic terminal states so the app does not reopen with sessions permanently stuck in running or waiting_for_user.
When a stale non-terminal run is recovered, the runtime:
run_failed or run_completed.turn_state projection.The failure class for app-restart recovery is recorded as app_restarted. Diagnostics are limited to small reason-code fields such as recovered, failureClass, recoveryReason, lastEventType, and eventCorrupt; raw user text and raw event payloads are not copied into recovery diagnostics.
packages/runtime/src/tool-runtime.tspackages/runtime/src/model-adapter.tspackages/runtime/src/run-trace.tspackages/core/src/agent-run.tspackages/storage/src/agent-run-store.tspackages/runtime/src/agent-run.tspackages/runtime/src/agent-run-recovery.tsThe runtime test suite now covers:
The changes were verified with:
npm --workspace @maka/core run typecheck npm --workspace @maka/storage run test npm --workspace @maka/runtime run typecheck npm --workspace @maka/runtime run test npm --workspace @maka/desktop run build:main git diff --check
The final runtime suite included 315 passing tests after the AgentRun recovery work.
This PR establishes the internal runtime-kernel shape, but it does not finish every possible cleanup. Good follow-up slices are:
SessionManager hook surface used by AgentRun