Aller au contenu

Run ledger protocol

Source candidate for the Run ledger over executor Sessions (maia.run-ledger/v1, S19): the coordinator's durable memory of a task graph whose dispatches are Codex or Claude Code Session turns (decision). The local-v1 terminal Run (run.create and its run.* siblings) is a separate, unchanged record.

Operations

MethodKindExposureReceiptMCP tool
run.ledger.createmutationunsupportedyesrun_ledger_create
run.ledger.listreadunsupportednorun_ledger_list
run.ledger.task.listreadunsupportednorun_ledger_task_list
run.ledger.task.showreadunsupportednorun_ledger_task_show
run.ledger.task.dispatchmutationunsupportedyesrun_ledger_task_dispatch
run.ledger.task.settlemutationunsupportedyesrun_ledger_task_settle

Exposure is Agent-definition eligibility, not a grant: worker Sessions cannot call these until S18 roles exist. A mutation retried with the same commandId and input replays its first receipt; the same commandId with other input conflicts.

Records

  • Run: id, workspaceId, createdAt, taskCounts per Task state and a derived state: succeeded when every Task succeeded, blocked when no Task is ready or active (a stopped Task blocks its dependents), otherwise open.
  • Task: clientKey, dependencyTaskIds, revision, failedDispatches, dispatches (oldest first) and a state derived from them: active while its last dispatch is active, succeeded once one succeeded, stopped after three failed, otherwise ready when every dependency succeeded and blocked when one has not. The full Task adds the objective and every dispatch's evidence.
  • Dispatch: one attempt at a Task on one Session: ordinal 1 to 3, sessionId, the queued turnId, state (active, succeeded, failed) and, once settled, settledTurnId and evidence (1 to 8192 UTF-8 bytes).

The Task revision starts at 1 and advances by one with each dispatch and settlement; both compare it, so two coordinators cannot both dispatch one Task.

Requests

  • run.ledger.create: commandId, workspaceId, tasks (1 to 32 { clientKey, dependsOn, objective }, the local-v1 Task input). The graph keeps the local-v1 bounds (8 direct dependencies and dependents, 128 edges, depth 8, 32 KiB of objectives) without a root or Dispatch Task.
  • run.ledger.list: workspaceId, limit (1 to 100), optional afterCursor.
  • run.ledger.task.list: runId, optional ready: true for the ready Tasks alone.
  • run.ledger.task.show: runId, taskId.
  • run.ledger.task.dispatch: commandId, runId, taskId, expectedTaskRevision, sessionId, expectedSessionRevision. The Node queues the objective as a turn on a running Codex or Claude Code Session of the Run's Workspace in the transaction that records the dispatch; a Session holds at most one active dispatch.
  • run.ledger.task.settle: commandId, runId, taskId, expectedTaskRevision, sessionId (the dispatch's), outcome (succeeded or failed), evidence and optional turnId (a later turn of the same Session; default the dispatched turn). The turn must have settled, and succeeded needs it completed.

Errors

run_task_not_ready (dispatch to a blocked, active, succeeded or stopped Task), run_task_not_active (settle without an active dispatch) and run_turn_unsettled (retryable: the turn is still queued or running), in RUN_LEDGER_ERROR_CODES. A changed revision fails as retryable storage_conflict.

Imported from Maia OS docs at a2175bb