Function: executePlan()
function executePlan(
store: PlanStore,
planId: string,
options: RunOptions,
): Promise<RunProjection>;Defined in: src/batteries/orchestration/executor.ts:157
Execute a plan against external input and return the projection folded from the durable event log. External input is materialised as the entry frame's node_settled before any other node runs, so it is addressable by NodeRef exactly like any other node output and is rebuilt from events on resume.
Parameters
| Parameter | Type | Description |
|---|---|---|
store | PlanStore | The plan store backing the run. |
planId | string | The id of the plan to execute. |
options | RunOptions | Per-run input and override dependencies. |
Returns
Promise<RunProjection>
The RunProjection folded from the run's event log.
Remarks
ORDER OF OPERATIONS, because it is observable and load-bearing. Everything that can refuse a request happens BEFORE claimRun: the plan is read and folded, the entry node is located, and RunOptions.input is validated against its DeclaredField[]. Only then is the run claimed.
That ordering is not an optimisation. claimRun is irreversible by design — a plan admits one run EVER and the store exposes no release — so a check that ran after it would burn the plan's only run on a request that never invoked a single tool, leaving it permanently run_already_claimed with clonePlan the only recovery. A rejected request must cost the plan nothing.
So a caller can rely on this: if this function throws on invalid input, the plan is still runnable. Fix the input and call again.
The budget is the PLAN'S bounds.maxSteps, not a library constant — bounds are plan content, digested and approved by the operator. Exhausting it settles the run halted with budget_exhausted{settled}, never process_death: the executor knows why it stopped, and a resume re-reports the same cause rather than looping, because the bound has not changed.
Throws
If RunOptions.input violates the entry node's declared fields — before any claim.