Skip to content

Controlled tool execution

Meaningful tool effects fail closed. executeControlledTool does not call a tool until the action is bound, the durable receipt is reserved, required policy and approval checks succeed, and a concurrency lease is acquired.

ts
import {
  executeControlledTool,
  type ExecuteControlledToolInput,
} from "@geekist/llm-core/tools/runtime";

declare const input: ExecuteControlledToolInput;

const outcome = await executeControlledTool(input);

switch (outcome.status) {
  case "succeeded":
  case "failed":
    console.log(outcome.receipt.state, outcome.result.status);
    break;
  case "conflict":
    console.log(outcome.existingReceiptId);
    break;
  default:
    console.log(outcome.receipt.state);
}

One authority chain

sequenceDiagram
  participant Host
  participant Control as executeControlledTool
  participant Journal as ToolReceiptJournal
  participant Policy as PolicyEvaluationPort
  participant Approval as ToolApprovalPort
  participant Gate as ConcurrencyGate
  participant Tool as ExecutableTool
  participant Events as EventSink

  Host->>Control: tool, call, security domain, ports
  Control->>Control: bind action and compute digest
  Control->>Journal: reserve idempotency identity
  Journal-->>Control: authoritative receipt
  Control-->>Events: schedule reservation event
  Control->>Journal: append awaiting_policy
  Control-->>Events: schedule transition event
  Control->>Policy: evaluate exact action digest
  opt approval required
    Control->>Approval: request and authenticate decision
    Control->>Journal: append awaiting_approval or ready
    Control-->>Events: schedule transition event
  end
  Control->>Gate: acquire lease
  Control->>Journal: append started
  Control-->>Events: schedule started event
  Control->>Tool: execute once
  Tool-->>Control: ToolExecutionResult
  Control->>Journal: append terminal disposition
  Control-->>Events: schedule terminal event
  Control-->>Host: ControlledToolExecutionOutcome

The journal and gate solve different problems. The ToolReceiptJournal establishes durable identity and recovery state. The ConcurrencyGate limits overlapping live work. An EventSink projects evidence, but it is neither persistence nor execution authority.

Outcomes

ControlledToolExecutionOutcome makes coordination visible:

StatusMeaning
succeeded, failedThe executable tool returned a terminal ToolExecutionResult.
awaiting-approval, cancelled, deniedControl stopped before execution or followed an authoritative decision.
existingThe reservation resolved to an existing terminal receipt.
indeterminateExecution may have started, but completion is not authoritative.
conflictThe idempotency identity is already bound to a different receipt.

Completed receipt outcomes also report event delivery as scheduled, failed, or not-configured. Delivery failure does not erase a durable receipt.

Redaction and native data

Supply explicit RedactionMetadata for sensitive categories. Canonical ToolExecutionEvent values contain action digests, receipt state, safe control facts, and optionally already-redacted extensions. They do not carry raw tool arguments or results.

Runtime integration

A qualified runtime may compose these contracts into its native intervention and resume lifecycle. It remains responsible for native checkpoint claims, decision consumption, workflow state, and recovery semantics. If a recorded effect is started or indeterminate, automatic replay is not authorized; the integration must reconcile it against authoritative external state.