# Executions

Read executions, follow their lineage, preview calls, rerun, replay, and cancel.

## ActionExecution

| Field                                            | Type                          | Meaning                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                            |
| ------------------------------------------------ | ----------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `id`                                             | `ID!`                         | Global identifier for the `node(id)` query.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                        |
| `executionId`                                    | `UUID!`                       | Unique identifier. Automatic executions derive it from the event and action version; reruns use the `executionId` supplied to `rerunExecution`.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                    |
| `actionId`                                       | `UUID!`                       | Identifier of the action this execution ran.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                       |
| `actionVersion`                                  | `Int!`                        | The action version pinned when the execution was created.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                          |
| `action`                                         | `Action!`                     | That pinned version, fetched when selected.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                        |
| `rerunOf`                                        | `ActionExecution`             | The source execution of a manual rerun. Null for automatic executions.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                             |
| `replayOfId`, `replayOf`                         | `UUID`, `ActionExecution`     | The execution a [replay](https://www.twisp.com/docs/reference/actions/executions.md#replays) reran. Null for an execution that is not a replay.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                              |
| `replay`                                         | `ActionReplay`                | How a replay ran. Null for an execution that is not a replay.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      |
| `parentExecutionId`                              | `UUID`                        | The execution that called this tool, such as an agent or another tool. Null for an execution not called by an execution.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                           |
| `parentInvocationNumber`                         | `Int`                         | The parent invocation that made the call. Null for an execution not called by an execution.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                        |
| `callSequence`                                   | `Int`                         | The call's position among the calls its parent invocation made, from 1. Null when the caller did not number its calls.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                             |
| `callPath`                                       | `[ActionCallFrame!]!`         | The call's position in its call tree, one frame per call from the top of the tree down to this one. Empty for an execution not called by an execution. See [Call paths](https://www.twisp.com/docs/reference/actions/executions.md#call-paths).                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                              |
| `parent`                                         | `ActionExecution`             | The calling execution, subject to your read permissions.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                           |
| `children(invocationNumber, sort, first, after)` | `ActionExecutionConnection!`  | Committed tool calls made by this execution, including native tool calls, ordered by creation time. Pass `invocationNumber` to restrict to one invocation's calls.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                 |
| `event`                                          | `ActionEvent`                 | The [event](https://www.twisp.com/docs/reference/actions/executions.md#the-event) that matched the action, or the tool call, delivered as input. Null for a session turn.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                    |
| `matchedTriggers`                                | `[Int!]!`                     | Positions in the pinned version's `definition.triggers` of every trigger that matched the event, in ascending order; on an [intake record](https://www.twisp.com/docs/reference/actions/executions.md#intake-records), those that failed. Empty for other manual reruns, which do not evaluate triggers.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                     |
| `turn`                                           | `ActionSessionTurn`           | For an execution that runs a session turn: that turn, with its number, status, inputs, and what it committed. For a replay of one, the turn it replays. See [Session turns](https://www.twisp.com/docs/reference/actions/sessions.md#session-turns).                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                            |
| `session`                                        | `ActionSession`               | For an execution that runs a session turn: the session, at its current version.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                    |
| `intake`                                         | `ActionIntake`                | Set on an [intake record](https://www.twisp.com/docs/reference/actions/executions.md#intake-records): the record of an event that failed to start or resume a session, or of a rerun of such a record. Null for any other execution.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                         |
| `draft`                                          | `ActionDefinition`            | For an execution an MCP server's [`invoke`](https://www.twisp.com/docs/reference/actions/mcp.md#invoke) previewed of an unpublished definition: the definition it ran, with its tools and skills resolved as a write resolves them. Its `actionVersion` is then the action's version when it ran. Null when a stored version ran, which is `actionVersion`, and for any other execution. An execution with a `draft` is always `preview`, and is never rerun or replayed.                                                                                                                                                                                                                                                                                                                                                                                                                                       |
| `status`                                         | `ActionExecutionStatus!`      | See [Execution status](https://www.twisp.com/docs/reference/actions/executions.md#execution-status).                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                         |
| `overdue`                                        | `Boolean!`                    | True while a `RUNNING` or `ACCEPTED` invocation is past its deadline.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                              |
| `deadline`                                       | `Timestamp!`                  | When the whole execution expires, from the action's `timeout` setting.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                             |
| `nextInvocationAt`                               | `Timestamp`                   | When a `RETRY_SCHEDULED` execution becomes eligible again.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                         |
| `invocation`                                     | `ActionInvocation`            | The current invocation. Null until the first invocation starts.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                    |
| `skillLoadExecutionId`, `skillLoad`              | `UUID`, `ActionExecution`     | For a call to a tool a skill made available, the load that made it available. Null otherwise. See [Tools a skill makes available](https://www.twisp.com/docs/reference/actions/skills.md#tools-a-skill-makes-available).                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                        |
| `preview`                                        | `Boolean!`                    | True for every execution whose writes were discarded, so that nothing it did committed: a [replay](https://www.twisp.com/docs/reference/actions/executions.md#replays), a request to an MCP server in preview mode, an agent's execution in [preview mode](https://www.twisp.com/docs/reference/actions/executions.md#preview-calls), an execution started in preview mode, a preview, of an MCP [program](https://www.twisp.com/docs/reference/actions/mcp.md#programs) or of an execution an MCP server's [`invoke`](https://www.twisp.com/docs/reference/actions/mcp.md#invoke) ran, with the `invoke` call that started a preview agent, a rerun of any of these, and every call made beneath them. Filter executions on `preview` to find what committed nothing. The marker is about business writes only: the execution's own record still commits, and so does a task's cancellation, such as a `cancel_task` or `tasks/cancel` request to an MCP server in preview mode, which takes effect; the cancelled execution's `cancelledBy` names the request. |
| `writeSet`                                       | `[ActionWrittenRecord!]!`     | For a preview call, each record version it would have written, in write order. Empty for any other execution.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      |
| `writeSetOmitted`                                | `Int!`                        | Writes left out of the end of `writeSet` because it exceeds the size an execution records. Zero when `writeSet` is complete.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                       |
| `writeSetUnreadable`                             | `Int!`                        | Records left out of `writeSet` because you may not read them: a record is listed only when you could read it by its ID as it was written, and a deletion only when you could read the record it removed. Zero when you may read every record.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      |
| `startedBy`                                      | `ActionExecutionStart`        | How the execution was started: by a client with [`startAction`](https://www.twisp.com/docs/reference/actions/tools.md#starting-a-tool), or by another execution, such as an MCP server's request that created a task. Null for an execution that was triggered or called. See [ActionExecutionStart](https://www.twisp.com/docs/reference/actions/executions.md#action-execution-start).                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                  |
| `cancelledBy`                                    | `ActionExecutionCancellation` | Who cancelled the execution: a client with [`cancelExecution`](https://www.twisp.com/docs/reference/actions/executions.md#cancellation); an MCP server's `tasks/cancel` request, with `executionId` and `execution` naming it; for an MCP request's execution, its client going away before the result, recorded as the request's principal; or Twisp stopping the server that ran the request, recorded as the principal `twisp:actions`. Null otherwise, including for an execution cancelled by closing its session.                                                                                                                                                                                                                                                                                                                                                                                                                      |
| `rolledBackByExecutionId`                        | `UUID`                        | For a call made beneath a call that failed, whatever its own status: the failed call's execution, the innermost when several failed, such as a `programmatic_tool_caller` call or an MCP [program](https://www.twisp.com/docs/reference/actions/mcp.md#programs). A failed call's writes roll back with everything beneath it, and its calls stay recorded. Also set on each call a failed invocation of a preview execution an MCP server started made, naming that execution. Null otherwise.                                                                                                                                                                                                                                                                                                                                                                                                                 |
| `created`, `modified`                            | `Timestamp!`                  | When the execution was first created, and the time of its last change.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                             |
| `version`                                        | `Int!`                        | The current version number of this execution. Previous versions are tracked in `history`. Advances on every status change.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                         |
| `_recordId`                                      | `UUID!`                       | Internal Twisp record identifier.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                  |
| `history(first, after)`                          | `ActionExecutionConnection!`  | History of changes to this execution, newest first.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                |

## ActionExecutionStart

| Field              | Type              | Meaning                                                                                                                                                                     |
| ------------------ | ----------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `executionId`      | `UUID`            | The execution that started this one. Null for a client's start.                                                                                                             |
| `execution`        | `ActionExecution` | That execution, subject to your read permissions.                                                                                                                           |
| `invocationNumber` | `Int`             | The starting execution's invocation that made the start. Null for a client's start.                                                                                         |
| `sequence`         | `Int`             | The start's position among the calls and starts that invocation made, from 1. Null for a client's start.                                                                    |
| `notStarted`       | `Boolean!`        | True when a [replay](https://www.twisp.com/docs/reference/actions/executions.md#replays) made the start. A replay starts nothing: the start is recorded, `CANCELLED` and `preview`, with its effective input, and was never queued.   |
| `actionId`         | `UUID`            | The action of the execution that started this one. Null for a client's start.                                                                                               |
| `sessionId`        | `String`          | The session the starting execution ran in, such as the MCP session of the request that created a task. Null for a client's start and for a start made outside a session.    |
| `invoked`          | `Boolean!`        | True when an MCP server's [`invoke`](https://www.twisp.com/docs/reference/actions/mcp.md#invoke) tool made the start: at each invocation, the caller must still be allowed to invoke the started action. |

## ActionInvocation

Each new invocation replaces the previous one. Read earlier invocations through `history`.

| Field                      | Type                               | Meaning                                                                                                                                                                                                                                                                                        |
| -------------------------- | ---------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `number`                   | `Int!`                             | Invocation number, counting from 1.                                                                                                                                                                                                                                                            |
| `startedAt`                | `Timestamp!`                       | When the invocation started.                                                                                                                                                                                                                                                                   |
| `responseDeadline`         | `Timestamp!`                       | When the handler must answer, from the action's `responseTimeout` setting.                                                                                                                                                                                                                     |
| `completionDeadline`       | `Timestamp`                        | When an accepted invocation must report its outcome, from the action's `completionTimeout` setting. Null until acceptance.                                                                                                                                                                     |
| `externalId`               | `String`                           | Correlation identifier supplied by a handler that accepted the work. Null otherwise.                                                                                                                                                                                                           |
| `output`                   | `Value`                            | The handler's result. Null until the invocation succeeds or is accepted, and null for a session turn that ended with the session `WAITING` for approval.                                                                                                                                       |
| `error`                    | `ActionError`                      | Null until the invocation fails.                                                                                                                                                                                                                                                               |
| `dryRun`                   | `Boolean!`                         | True when the invocation succeeded with its business effects rolled back, such as an `invokeAction` call in a `@dryRun` mutation.                                                                                                                                                              |
| `uses`                     | `[ActionOutputUse!]!`              | Tool answers and skill guidance the handler reported supplying to this invocation. See [Output uses](https://www.twisp.com/docs/reference/actions/skills.md#output-uses).                                                                                                                                                   |
| `tools`                    | `[ActionToolReference!]!`          | The action's tool references, each with the version it resolved to when the invocation started in `actionVersion`, followed by the tools skill loads made available to it. For a skill load, the tools the load made available. See [Versions](https://www.twisp.com/docs/reference/actions/tools.md#versions).             |
| `skills`                   | `[ActionSkillReference!]!`         | The action's skill references, each with the version it resolved to when the invocation started in `actionVersion`.                                                                                                                                                                            |
| `approvals`                | `[ActionApprovalRequest!]!`        | The calls the invocation paused before, each waiting for a person's approval, when its session turn ended `WAITING`. For an agent in [preview mode](https://www.twisp.com/docs/reference/actions/executions.md#preview-calls), the calls that would have waited, each marked `grantedInPreview`. See [Approvals](https://www.twisp.com/docs/reference/actions/sessions.md#approvals). |
| `hold`                     | `ActionSessionHold`                | The session turn the invocation held for a person's answer, when it failed with `agent_refused` or `agent_unfinished`. See [Held turns](https://www.twisp.com/docs/reference/actions/sessions.md#held-turns).                                                                                                               |
| `transcriptLastSequence`   | `Int!`                             | The number of the invocation's last transcript event, recorded with its outcome. See [Transcripts](https://www.twisp.com/docs/reference/actions/agents.md#transcripts).                                                                                                                                                     |
| `transcript(first, after)` | `ActionTranscriptEventConnection!` | The invocation's transcript in sequence order. See [Transcripts](https://www.twisp.com/docs/reference/actions/agents.md#transcripts). A call to a built-in model records its exchange with the provider here; see [The call transcript](https://www.twisp.com/docs/reference/actions/models.md#the-call-transcript).                                     |

## ActionError

| Field       | Type       | Meaning                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                       |
| ----------- | ---------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `code`      | `String!`  | Failure code, one of `action_failure`, `action_response_timeout`, `action_completion_failure`, `action_interrupted`, `action_output_too_large`, `action_output_invalid` (including output that fails the tool's output schema), `action_transaction_cannot_wait`, `action_input_invalid`, `action_access_denied`, `action_graphql_error`, `action_cel_error`, `action_call_limit_exceeded`, `action_not_callable` (including a call to a retired model version), for [models](https://www.twisp.com/docs/reference/actions/models.md#errors), `model_not_served`, `model_credential_missing`, `model_unauthorized`, `model_request_invalid`, `model_unavailable`, for [agents](https://www.twisp.com/docs/reference/actions/agents.md), `agent_unfinished`, `agent_limit_exceeded`, `agent_refused`, `agent_runtime_unavailable`, `agent_approval_required`, `fixture_exhausted`, `model_request_rejected`, `model_access_denied`, `model_failed`, or, on an [intake record](https://www.twisp.com/docs/reference/actions/executions.md#intake-records), `session_intake_failed`. |
| `message`   | `String!`  | Description of the failure.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                   |
| `retryable` | `Boolean!` | Whether the failure was classed as retryable. Stays true on an `EXHAUSTED` execution.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                         |
| `hint`      | `String`   | What the caller should change for a failed call to succeed, such as the path and expected shape of a schema violation or the hint passed to `fail()`. Null when there is none.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                |
| `details`   | `Value`    | Structured detail of the failure, such as the errors of a failed `graphql` call. Null when there is none. When the failure is an error of a tool call the execution made and did not handle, whose own record is not kept, `details.cause` describes that call: `tool`, `actionId`, `actionVersion`, `callSequence`, `callPath` (the call's position in its call tree, as a list of frames like [`callPath`](https://www.twisp.com/docs/reference/actions/executions.md#call-paths) on the execution), and its error's `code`, `message`, `hint`, and `details`. A call that failed the same way names its own cause in its `details`.                                                                                                                                                                                                                                                                                                                                                                                  |

## Execution status

| Status            | Terminal | Meaning                                                                                                                         |
| ----------------- | -------- | ------------------------------------------------------------------------------------------------------------------------------- |
| `QUEUED`          | no       | Waiting for its first invocation.                                                                                               |
| `RUNNING`         | no       | An invocation has started and the handler has not answered.                                                                     |
| `ACCEPTED`        | no       | The handler accepted the work and will report its outcome asynchronously.                                                       |
| `RETRY_SCHEDULED` | no       | The last invocation failed with a retryable error or passed its deadline without an outcome. `nextInvocationAt` is set.         |
| `SUCCEEDED`       | yes      | The handler returned a result, or no trigger failed in the rerun of an [intake record](https://www.twisp.com/docs/reference/actions/executions.md#intake-records).                        |
| `FAILED`          | yes      | The handler returned a non-retryable error, or an [intake record](https://www.twisp.com/docs/reference/actions/executions.md#intake-records)'s event failed to start or resume a session. |
| `EXHAUSTED`       | yes      | The invocation budget or `deadline` ran out.                                                                                    |
| `CANCELLED`       | yes      | Cancelled through `cancelExecution`, or a start a replay recorded without starting it.                                          |

Terminal executions never change status again. Only terminal executions can be rerun.

## Listing and filtering

`executions(where: {...})` accepts any combination of the following. Every supplied field must match. Results are ordered by creation time, newest first; pass `sort: ASC` for oldest first. Every list of executions, sessions, and memory records is newest first by default, as the rest of the API's time-ordered lists are; an execution's `children` stay in the order the calls were made, and a session's `inputs` in the order they were delivered. An action's `executions` takes the same filters without `actionId`, a session's turns are its `turns`, and the calls one execution made are its `children`.

| Filter                          | Type                    | Meaning                                                                                                                                                                                             |
| ------------------------------- | ----------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `actionId`                      | `UUID`                  | Executions of one action.                                                                                                                                                                           |
| `eventId`                       | `UUID`                  | Executions created for one event.                                                                                                                                                                   |
| `sessionId`                     | `String`                | Executions of one session: those that run its turns, or for an MCP server, those of the requests recorded in it. Requires `actionId`.                                                               |
| `status`                        | `ActionExecutionStatus` | Executions in one status.                                                                                                                                                                           |
| `createdAfter`, `createdBefore` | `Timestamp`             | Exclusive bounds on execution creation time, not on event time.                                                                                                                                     |
| `intake`                        | `Boolean`               | With `true`, only [intake records](https://www.twisp.com/docs/reference/actions/executions.md#intake-records). With `false`, none.                                                                                                                            |
| `called`                        | `Boolean`               | With `true`, only executions another execution called, which have a `parentExecutionId`. With `false`, only those no execution called, such as calls of `invokeAction`, starts, and triggered runs. |
| `preview`                       | `Boolean`               | With `true`, only executions that committed nothing, which have `preview` set: previews, and those of a server or agent in preview mode, or of a replay. With `false`, only those that committed.   |
| `startedByExecutionId`          | `UUID`                  | Executions one execution started, such as an MCP server's tasks. Cannot be combined with `sessionId`.                                                                                               |
| `startedByInvocationNumber`     | `Int`                   | Executions one invocation of the starting execution started. Requires `startedByExecutionId`.                                                                                                       |

```graphql
query FailedExecutions($actionId: UUID!, $after: String) {
  actions {
    executions(where: { actionId: $actionId, status: FAILED }, first: 20, after: $after) {
      nodes {
        executionId
        created
        event {
          eventId
          occurredAt
        }
        invocation {
          number
          error {
            code
            message
          }
        }
      }
      pageInfo {
        endCursor
        hasNextPage
      }
    }
  }
}
```

Connections follow the [pagination](https://www.twisp.com/docs/reference/api/pagination.md) conventions. `first` is required and accepts 1 to 100. A filtered page can contain fewer nodes than `first`, or none, while `hasNextPage` is still true, so continue from `pageInfo.endCursor` until `hasNextPage` is false. Cursors are valid only with the same filter they were issued for.

## History and exact versions

Every status change writes a new record version. `history` on an action or execution lists those versions newest first, and `action(id, version)` or `execution(id, version)` reads one exactly. Several history entries can share an invocation number, for example the start of an invocation and its outcome. `event` and `invocation.output` on a history node are the payloads as they were at that version.

## Lineage

`lineage` on an execution walks every execution it caused, or that caused it, from any execution in a call tree. Every call is an edge, whatever the caller and the called tool, skill, or native tool, so the walk mirrors exactly what ran. So is every start an execution made, such as an MCP server's request that created a task: a `START` edge leads from the starting execution to the execution it started, which runs on its own, with calls of its own.

| Argument    | Type                     | Meaning                                                                                                                                                                                       |
| ----------- | ------------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `direction` | `ActionLineageDirection` | `DOWNSTREAM` (the default) lists every call and start beneath the execution at any depth. `UPSTREAM` lists its callers to the top, and on through the execution that started the top, if any. |
| `first`     | `Int!`                   | Number of nodes to return, 1 to 100.                                                                                                                                                          |
| `after`     | `String`                 | Cursor to continue from.                                                                                                                                                                      |

Nodes are listed depth first: downstream, each call follows its caller, and a caller's calls and starts are in the order it made them, each followed by its own calls. Upstream, the last node is the top of the call tree, or of the tree of the execution that started it. A client's start has no starting execution, so its upstream walk ends at the top of its own tree. Each execution appears once, and the execution you start from is not listed.

| Field            | Type                     | Meaning                                                                                                                                                   |
| ---------------- | ------------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `executionId`    | `UUID!`                  | Identifier of the execution.                                                                                                                              |
| `execution`      | `ActionExecution`        | The execution, or null when you may not read it.                                                                                                          |
| `depth`          | `Int!`                   | Edges between the starting execution and this one, from 1.                                                                                                |
| `via`            | `ActionLineageEdgeKind!` | `CALL` or `START`. `CAUSE` is reserved for executions started by changes another execution wrote, and is not yet returned.                                |
| `viaExecutionId` | `UUID!`                  | The execution this one was reached from: downstream, its caller or the execution that started it; upstream, the call it made or the execution it started. |
| `viaExecution`   | `ActionExecution`        | The execution identified by `viaExecutionId`, subject to your read permissions.                                                                           |

You must be able to read the execution you start from. The walk continues through executions you may not read: each is listed with its identifier and edge, and a null `execution`, so the shape of the tree is complete without disclosing their content. Each page reflects the executions committed when it is read. Cursors are valid only for the walk they were issued for.

```graphql
query CallTree($id: UUID!, $after: String) {
  actions {
    execution(id: $id) {
      lineage(first: 50, after: $after) {
        nodes {
          executionId
          depth
          viaExecutionId
          execution {
            actionId
            status
            invocation {
              output
            }
          }
        }
        pageInfo {
          endCursor
          hasNextPage
        }
      }
    }
  }
}
```

### Call paths

`callPath` on an execution gives its position in its call tree: one `ActionCallFrame` for each call on the path from the top of the tree down to the execution, which is the last frame. The number of frames is the execution's depth below the top, and a call's path is its caller's path followed by its own frame. A downstream walk lists calls in call path order.

| Field              | Type              | Meaning                                                                                                          |
| ------------------ | ----------------- | ---------------------------------------------------------------------------------------------------------------- |
| `invocationNumber` | `Int!`            | The caller's invocation that made the call.                                                                      |
| `callSequence`     | `Int`             | The call's position among the calls that invocation made, from 1. Null when the caller did not number its calls. |
| `created`          | `Timestamp!`      | When the call was made. A caller's calls that it did not number are ordered by `created`, then by `executionId`. |
| `executionId`      | `UUID!`           | Identifier of the call's execution.                                                                              |
| `execution`        | `ActionExecution` | The call's execution, subject to your read permissions.                                                          |

## Preview calls

An agent whose `config.mode` is `preview` runs on real events and does everything it would do, but changes nothing. Each of its turns runs every call as a live turn would, and each call sees the writes of the calls before it, but the turn's writes are discarded when it ends. The agent's own execution, transcript, and session still commit, so a preview session evolves as a live one would; the execution is marked `preview`, as its calls are. To let the agent act, update its definition's `config.mode` to `live`.

The [memory](https://www.twisp.com/docs/reference/actions/memory.md#agent-memory) and [session history](https://www.twisp.com/docs/reference/actions/memory.md#session-history) a preview turn writes are kept for audit, marked `preview`. Later turns in preview mode read them, as live turns read their own, but a live turn never does: once the agent goes live, it does not act on what it learned of effects that never happened. A preview turn never changes a memory record a live turn wrote. It replaces one with a record of its own whose `replaces` names it, and deletes one with a record of its own of status `DELETED` whose `replaces` names it. Turns in preview mode no longer recall the record it names; live turns still recall it, unchanged. `Action.memories` lists these records with `preview: true`, so you see exactly what the preview turn would have changed.

Each call a preview turn made, and each call beneath one, is recorded with `preview: true`. A call that succeeded lists in `writeSet` every record version it would have written, including those of the tool session it started and of the calls beneath it. A call that failed leaves no writes of its own, as in a live run; it lists only the writes of the tool session it started, which stay in the turn. The calls beneath it are still recorded, each listing what it wrote and marked with `rolledBackByExecutionId`. A `programmatic_tool_caller` or `subagent` call is such a call: it lists the writes of the calls made under it, or none when it failed. A `writeSet` lists only the records you may read, each as a read of it by its ID would be authorized; `writeSetUnreadable` counts the rest, so a write set never shows you a record you could not read.

A call to a tool that requires [approval](https://www.twisp.com/docs/reference/actions/sessions.md#approvals) does not wait in preview mode: it runs at once, with the agent's input, as if a person had approved it. The execution's `invocation.approvals` lists the request a live turn would have made, with `grantedInPreview: true` and an empty `interruptId`, so the record shows that no person approved the call. The session does not wait, and the request cannot be answered.

A tool session that a preview call starts is discarded with the turn's other writes. Later calls in the same turn still find it. A preview call can read other tenants, as `admin` queries do, but it cannot write to them, as `admin` mutations and `branch` do, because the turn could not discard what they write. Nor can it run an operation that acts outside the ledger, such as a warehouse statement or export. Such a call fails with a call error that the tool can handle.

| Field           | Type       | Meaning                                                                               |
| --------------- | ---------- | ------------------------------------------------------------------------------------- |
| `recordType`    | `String!`  | Record name, for example `Journal`.                                                   |
| `recordId`      | `UUID!`    | Row identifier of the record.                                                         |
| `recordVersion` | `Int!`     | Version of the record the write created, or, for a deletion, the version it removed.  |
| `deleted`       | `Boolean!` | True when the write deleted the record.                                               |
| `data`          | `Value`    | The record after the write, in the form an event's `data` takes. Null for a deletion. |

```graphql
query PreviewCalls($id: UUID!) {
  actions {
    execution(id: $id) {
      children(first: 50) {
        nodes {
          actionId
          preview
          invocation {
            output
          }
          writeSet {
            recordType
            recordId
            recordVersion
            deleted
            data
          }
          writeSetOmitted
        }
      }
    }
  }
}
```

## Payloads

`event` is the [event](https://www.twisp.com/docs/reference/actions/executions.md#the-event) as an `ActionEvent` object, and `invocation.output` is whatever the handler returned as a [`Value`](https://www.twisp.com/docs/reference/ledger/kv.md#strong-typing). Records and outputs are stored with their types; the `Value` scalar renders them as JSON only when you read them.

| Kind                                    | JSON rendering                                     |
| --------------------------------------- | -------------------------------------------------- |
| Integers, unsigned integers             | Exact numbers, including values above 2^53.        |
| UUID                                    | Canonical lowercase string.                        |
| Money                                   | `"<amount> <currency>"`, for example `"9.99 USD"`. |
| Decimal                                 | Exact decimal string, for example `"0.125"`.       |
| Timestamp                               | RFC 3339 UTC string.                               |
| Date                                    | `YYYY-MM-DD`.                                      |
| Duration                                | Go duration string, for example `"1h30m0s"`.       |
| Bytes                                   | Standard base64 string.                            |
| Strings, booleans, null, lists, objects | As themselves. Object keys are sorted.             |

Integers arrive with their exact digits. A JSON parser that reads every number as a double, as JavaScript's `JSON.parse` does, still rounds integers above 2^53; use a parser that preserves big integers when you rely on such values.

```graphql
query ExecutionPayloads($id: UUID!, $version: Int) {
  actions {
    execution(id: $id, version: $version) {
      status
      event {
        eventType
        recordType
        recordVersion
        data
        previous
      }
      invocation {
        output
      }
    }
  }
}
```

## The event

The execution's `event`, delivered to the handler as its input and bound to `event` in your triggers, is this event. In a trigger, `event` exposes the same fields with their native types: `event.id` is a UUID, `event.type` a string, `event.occurred_at` a timestamp, and `event.record_version` an unsigned integer.

| Field (`event` key)                | Type             | Meaning                                                                                                                                                                                                                       |
| ---------------------------------- | ---------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `eventId` (`id`)                   | `UUID!`          | Stable identifier of the committed change, the tool call's `executionId`, or an identifier derived from a schedule's firing.                                                                                                  |
| `eventType` (`type`)               | `String!`        | `<record>.inserted`, `<record>.updated`, or `<record>.deleted`, for example `journal.updated`; `action.invoked` for a tool call; `schedule.fired` for a firing of a [schedule](https://www.twisp.com/docs/reference/actions/actions.md#schedule-triggers). |
| `occurredAt` (`occurred_at`)       | `Timestamp!`     | Commit time of the change, the start of the calling transaction, or a firing's scheduled time.                                                                                                                                |
| `recordType` (`record_type`)       | `String`         | Record name, for example `Journal` or `action_session`. Null for a tool call or a firing.                                                                                                                                     |
| `recordId` (`record_id`)           | `UUID`           | Row identifier of the changed record. Null for a tool call or a firing.                                                                                                                                                       |
| `recordVersion` (`record_version`) | `Int`            | Version of the changed record. Null for a tool call or a firing.                                                                                                                                                              |
| `data`                             | `Value`          | The record after the change, the tool call's effective input, or a firing's `{trigger, scheduled_at}` or, for the session's clock, `{schedule, scheduled_at, missed}`. Null for a physical deletion.                          |
| `previous`                         | `Value`          | The record before the change. Null for an insert or a firing.                                                                                                                                                                 |
| `record`                           | `DatabaseEntity` | Not a trigger key. The changed record at `recordVersion`, for an `Account`, `AccountSet`, `Balance`, `Entry`, `Journal`, `KVValue`, `Transaction`, or `TranCode`. Null for other records, a tool call, and a firing.          |

Records inside `data` and `previous` use snake_case field names such as `journal_id` and `dr_balance`, and every field keeps its type: UUIDs are UUIDs, money is money, timestamps and dates keep their kinds, enums are their numeric values, and a KV record's `value` is the same typed document that was written. Each record also carries `version`, its record version. A structured field that was never set, such as a balance with no `encumbrance` or a record with no `entry_id`, is absent rather than zero-valued, so guard it in a trigger with `has(event.data.encumbrance)` or read it with `event.data.?encumbrance.dr_balance.orValue(money("0", "USD"))`; plain strings, numbers, and booleans that were never set read as `""`, `0`, and `false`. Soft deletes such as `deleteJournal` produce an `updated` event.

### Actions records

Changes to actions, executions, transcripts, sessions, session inputs, and agent memory are events too, so an action can respond to them. Their record types are snake_case names, and the event type is the record type and the change, such as `action_execution.updated`. `data` and `previous` hold the record as the API returns it:

| `record_type`            | Event types                                               | `data` and `previous`                                                                                                                                                                                                      |
| ------------------------ | --------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `action`                 | `action.inserted`, `action.updated`, `action.deleted`     | The action. Deleting an action is an `action.updated` event.                                                                                                                                                               |
| `action_execution`       | `action_execution.inserted`, `.updated`, `.deleted`       | The execution, without its `event`, the `event` of each of its `session.inputs`, or its write set (`write_set`, `write_set_omitted`, and `write_set_unreadable`). Read the execution, or the session's inputs, for them.   |
| `action_execution_event` | `action_execution_event.inserted`, `.updated`, `.deleted` | A transcript event's keys only: `action_id`, `execution_id`, `invocation_number`, `sequence`, `kind`, `call_execution_id`, and `session_id`. Read the [transcript](https://www.twisp.com/docs/reference/actions/agents.md#transcripts) for its content. |
| `action_session`         | `action_session.inserted`, `.updated`, `.deleted`         | The session. A large `state` is left out; read the session for it.                                                                                                                                                         |
| `action_session_input`   | `action_session_input.inserted`, `.updated`, `.deleted`   | The session input, without its `event`. Read the session's inputs for it.                                                                                                                                                  |
| `agent_memory`           | `agent_memory.inserted`, `.updated`, `.deleted`           | The [memory record](https://www.twisp.com/docs/reference/actions/memory.md#agent-memory).                                                                                                                                                               |

An answer to an approval request is an `action_session.responded` event; see [Approvals](https://www.twisp.com/docs/reference/actions/sessions.md#approvals).

An update that changes nothing these records show but `version`, `modified`, and `modified_by`, such as a session taking its next inputs, is not an event. Triggers on these records cannot loop; see [Loops](https://www.twisp.com/docs/reference/actions/executions.md#loops).

### Loops

Triggers do not loop. A chain of actions that trigger one another stops before it repeats an action, and after 8 links:

- **A change to an action's own execution never triggers it.**
- **Chains.** A change an execution made, itself or through the tools it called, has a chain: the executions whose changes led to it, oldest first. Each one led to the next because a change it made matched a trigger of the next one's action, or because it started the next one. The last one made the change. A change to a session has the chain of the event that started the session, followed by a link for the session's action, so a change to an action's own session never triggers it either.
- **No repeats.** A trigger never runs its action for a change whose chain includes that action. When A's change triggers B and B's change matches a trigger of A, A does not run, and nothing is recorded.
- **Depth limit.** A change whose chain holds 8 links runs no action. Each action whose triggers match it gets an [intake record](https://www.twisp.com/docs/reference/actions/executions.md#intake-records) with stage `DEPTH_LIMIT` instead.
- **What has a chain.** Changes to executions, transcript events, sessions, session inputs, and agent memory have one. Changes to actions and to your own records do not, so a loop through them, such as an action that writes journals and triggers on journals, is not stopped. Write such a trigger so that it does not match the action's own writes.

## Intake records

An event that matches a [session](https://www.twisp.com/docs/reference/actions/sessions.md) trigger starts or resumes a session. When that fails on the event's data, for example because a `start.input` expression reads a field the event lacks, the mapped input fails `inputSchema`, or `session.id` evaluates to an empty string, the event is recorded as an intake record: a `FAILED` execution of the action with `intake` set. So is an event that matches any of an action's triggers at the end of a chain too long to run (see [Loops](https://www.twisp.com/docs/reference/actions/executions.md#loops)). No handler runs, and the record is not retried: the failure is a fact about the event and the definition. Intake records are listed, filtered, and alarmed on as any failed execution is, and a record can be [rerun](https://www.twisp.com/docs/reference/actions/executions.md#rerunning-an-intake-record) once the definition accepts its event.

- **One record per event and action version.** The record lists every trigger of that version that failed for the event, in `intake.failures`, and their positions in `matchedTriggers`. `event` is the event. `invocation` is invocation 1, whose `error` has the code `session_intake_failed`, is not retryable, and summarizes the failures in its `message`. A repeated delivery of the event finds the same record.
- **Partial failures are recorded.** A record is written when any of the action's triggers failed for the event, even when another of its triggers started or resumed a session with it. `intake.sessionId` then names the session a start or `resume.id` trigger reached, including one the event is held for until it starts. A `resume.input` delivery, which can reach many sessions, is not named.
- **Not failures.** A trigger predicate that fails to evaluate is a non-match, as it is for any trigger. A resume key that fails is a failure only for an event the trigger's predicate can select: one it selects, or cannot decide without the session. An event the predicate rejects, or fails on because the event lacks a field the predicate reads, is not the trigger's event. A resume event that the triggers of the version a session keeps do not match is not delivered to that session. An event for a closed session is not delivered. A resume event for a session that does not exist yet waits for it for 24 hours, and is delivered if the session starts in that time. None of these writes an intake record.

`ActionIntake` describes what failed:

| Field       | Type                      | Meaning                                                                                                                                                                                                                                                                                                                                                                                               |
| ----------- | ------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `failures`  | `[ActionIntakeFailure!]!` | Each trigger that failed, in trigger order. Empty on a `SUCCEEDED` rerun.                                                                                                                                                                                                                                                                                                                             |
| `sessionId` | `String`                  | The session a failure names, such as the open session of an `INPUT_CONFLICT`, or else the session another of the action's triggers reached with the event by a start or `resume.id`: started, resumed, or held the event for until it starts. A `resume.input` delivery, which can reach many sessions, is not named. On a `SUCCEEDED` rerun, the session the rerun reached. Null when there is none. |

Each `ActionIntakeFailure` is one trigger's failure:

| Field         | Type                 | Meaning                                                 |
| ------------- | -------------------- | ------------------------------------------------------- |
| `trigger`     | `Int!`               | Position in the action version's `definition.triggers`. |
| `triggerName` | `String`             | The trigger's name, or null if it has none.             |
| `stage`       | `ActionIntakeStage!` | The step that failed.                                   |
| `message`     | `String!`            | What failed.                                            |

`ActionIntakeStage` names the step that failed:

| Stage            | Meaning                                                                                                                                               |
| ---------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------- |
| `START_MAPPING`  | A `start.input` expression failed, such as on a field the event lacks.                                                                                |
| `INPUT_SCHEMA`   | The mapped input does not satisfy `session.inputSchema`, or is too large.                                                                             |
| `SESSION_ID`     | `session.id` failed, or is not a nonempty string within the size limit.                                                                               |
| `SESSION_ENDS`   | `session.ends` failed, or did not produce a timestamp, for the new session.                                                                           |
| `INPUT_CONFLICT` | Two start triggers map the session to different input, or a start's input differs from that of the open session it names.                             |
| `PINNED_VERSION` | A start names an open session that keeps another version of the action, and matches neither a start nor a resume trigger of that version.             |
| `RESUME_KEY`     | A resume trigger's `resume.id` or `resume.input` value failed or is missing for an event its predicate selects, or cannot decide without the session. |
| `DEPTH_LIMIT`    | The change was made at the end of a chain of 8 executions, the most a chain of triggers runs; see [Loops](https://www.twisp.com/docs/reference/actions/executions.md#loops).                                    |

```graphql
query IntakeRecords($actionId: UUID!, $after: String) {
  actions {
    action(id: $actionId) {
      executions(where: { intake: true, status: FAILED }, first: 20, after: $after) {
        nodes {
          executionId
          actionVersion
          event {
            eventId
            eventType
            occurredAt
          }
          intake {
            sessionId
            failures {
              trigger
              triggerName
              stage
              message
            }
          }
        }
        pageInfo {
          endCursor
          hasNextPage
        }
      }
    }
  }
}

mutation RerunIntake($id: UUID!, $executionId: UUID!) {
  actions {
    rerunExecution(id: $id, input: { executionId: $executionId }) {
      executionId
      status
      actionVersion
      intake {
        sessionId
      }
    }
  }
}
```

## Manual reruns

`rerunExecution` creates a new execution for the same event from a source that is `SUCCEEDED`, `FAILED`, `EXHAUSTED`, or `CANCELLED`. A [replay](https://www.twisp.com/docs/reference/actions/executions.md#replays) is not rerun; replay its original again instead. Nor is a draft's preview, an execution with a `draft`: preview the draft again. The new execution starts `QUEUED` with a fresh invocation and time budget and reuses the source's event unchanged. Triggers are not re-evaluated, so the rerun's `matchedTriggers` is empty. An [intake record](https://www.twisp.com/docs/reference/actions/executions.md#intake-records) is the exception; see [Rerunning an intake record](https://www.twisp.com/docs/reference/actions/executions.md#rerunning-an-intake-record).

A rerun runs the action again, so it needs the `INVOKE` permission on the action, besides `SELECT` and `INSERT` on its execution records, and it cannot be made from inside an execution. A rerun of an execution that has no caller, such as a triggered execution, runs under the action's own policies as the original did, whether or not the action is still active. It reads those policies afresh when it starts, so after an update that adds an operation the original was denied, rerunning the failed execution runs under the update's policies at once. A session turn and an [MCP request](https://www.twisp.com/docs/reference/actions/mcp.md) are not rerun: a turn runs only from its session, and a request only when its endpoint serves it; [replay](https://www.twisp.com/docs/reference/actions/executions.md#replays) them instead.

| Input field     | Type    | Meaning                                                                                                                                                                                                                                                                            |
| --------------- | ------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `executionId`   | `UUID!` | Identifier for the new execution, chosen by you. Repeating a request with the same `executionId`, source, and `actionVersion` returns the same rerun. Reusing it with different values is an error.                                                                                |
| `actionVersion` | `Int`   | Action version to pin. Omit to reuse the source's pinned version or, for an intake record, to use the action's current version. An intake record can be rerun only at a version whose triggers are still published; see [Rerunning an intake record](https://www.twisp.com/docs/reference/actions/executions.md#rerunning-an-intake-record). |

```graphql
mutation Rerun($id: UUID!, $executionId: UUID!) {
  actions {
    rerunExecution(id: $id, input: { executionId: $executionId }) {
      executionId
      status
      actionVersion
      rerunOf {
        executionId
        status
      }
    }
  }
}
```

Automatic retries keep the same `executionId`; a rerun always gets the one you supplied, so downstream deduplication on `executionId` distinguishes deliberate reruns from retries.

A rerun of a call, whoever made it, or of a [started](https://www.twisp.com/docs/reference/actions/tools.md#starting-a-tool) execution is a new start by you: it runs under your authority, in preview mode when the original was a preview, its `caller` is you, and its `startedBy` names no starting execution. As for `startAction`, the action must be callable at the rerun's version: published, enabled, with a `tool` block, and the input must satisfy its schema. A call to a [tool with a session](https://www.twisp.com/docs/reference/actions/sessions.md#tool-sessions) is not rerun, since a start has no call for the session to record; call the tool again instead.

### Rerunning an intake record

A rerun of an [intake record](https://www.twisp.com/docs/reference/actions/executions.md#intake-records) tries the recorded event again: it evaluates every trigger of this action, and no other action's, at `actionVersion`, and starts or resumes sessions as the event would have. No handler runs. The rerun is itself an intake record. It starts `QUEUED`, and is `RUNNING` while the event is tried, when it cannot be cancelled. It then becomes `SUCCEEDED` when no trigger failed, with invocation 1 carrying no error and no output, or `FAILED`, with its own `intake.failures`, `matchedTriggers`, and `session_intake_failed` error.

- **The version.** `actionVersion` defaults to the action's current version, since the fix is usually a new version. An explicit `actionVersion` must be the current version or a replaced version whose triggers are still published: one that sessions still keep, or one replaced less than 24 hours ago. Any other version is refused. Repeating the request with the same `executionId` returns the rerun it made, at the version it resolved then, even if the action's current version has changed since.
- **The session reached.** A `SUCCEEDED` rerun's `intake.sessionId` names the session it reached, as a record does. It is null when the event reached no session: no trigger of the version selects it, its session is closed, or the version the session keeps does not match it. A session keeps its version's triggers, so a resume key fixed in a new version does not reach sessions that keep the old one.
- **Nothing is delivered twice.** An event a session already received, from the original delivery or an earlier rerun, is not delivered to it again.
- **A session's start does not move.** A session a rerun starts keeps the event's commit time as `startedAt`, so its `endsAt` may already have passed; its first turn is then [final](https://www.twisp.com/docs/reference/actions/sessions.md#session-end). A rerun never moves the start or end of a session another event already started: its start is delivered to that session as an input.
- **The rerun runs the recorded event.** Fixing the data the event carried, such as an account's metadata, does not by itself make a rerun succeed; that needs a definition that accepts the event as it was recorded.
- **Waiting resume events expire.** Resume events that arrived before their session existed wait for it for 24 hours. A rerun later than that starts the session without them.
- **Enabled session actions only.** The action must be enabled and not deleted, and the version must have a `session`. A rerun queued before its action was disabled or deleted ends `FAILED` without running, with the code `session_intake_failed` and a message saying it did not run. An intake record cannot be [replayed](https://www.twisp.com/docs/reference/actions/executions.md#replays).

## Replays

`replayExecution` reruns a recorded agent turn with another version of the agent, or with an unpublished definition of it, and records the result as a new execution beside the original, so you can compare the two before you rely on the change. The source must be a finished execution of a kind `agent` action, or a request's execution of an [MCP server](https://www.twisp.com/docs/reference/actions/mcp.md#replay). It cannot be a call that another execution made, including a tool's or an agent's call to an agent, another replay, or a draft's preview, an execution with a `draft`. An agent that a client called directly with `invokeAction` or started with `startAction` can be replayed, and the replay receives the call's input.

A replay needs the `INVOKE` permission on the action it replays, whatever its source. A replay of an execution that had a caller, a client's call or start, or an MCP request, runs under both you and the principal it replays, whose policies are evaluated with the claims it recorded, then the action's policies: it can do nothing either of you could not. A replay of a triggered turn or a session turn runs under the agent's own policies, as the turn did. A replay runs as you, so your principal needs a client in the tenant; without one the replay fails with `action_access_denied`.

A tool can request a replay too, through the `graphql` tool. The replay then also runs under every action on the requesting tool's call path, such as the MCP server that called the tool and the tool itself, before the principal it replays: it can do nothing the requesting tool could not, even when you could. Each invocation checks again that you are still authorized, that the credential you requested it with has not expired, and that the chain may still invoke the replayed action. `replay.requestedBy` names the requesting execution. A program, such as an MCP server's `program` tool or programmatic tool calling, cannot request a replay.

The replay receives what the original turn received: its event or, for a session turn, the same inputs and the session checkpoint the turn started from, even if later turns have moved the session on. Its tools run as they would live, and each call sees the writes of the calls before it, but every write is discarded when the turn ends, as for a [preview](https://www.twisp.com/docs/reference/actions/executions.md#preview-calls) agent. Each call is recorded with `preview: true` and lists in `writeSet` the records it would have written. The replay has its own transcript, calls, and output uses, which you compare with the original's.

A replay is never part of the live session. It admits no inputs, leaves the session and the agent's memory unchanged, and commits no business writes. For a session turn, `replay.session` shows how the turn would have changed the session, to compare with the session version the original turn committed.

A replay calls the tool and skill versions the original turn used: a reference without a `version` resolves to the version the original invocation recorded in its `tools` and `skills`, and to the latest version only for a tool or skill the original did not use. A pinned reference, in the replayed version or in `definition`, uses its `version`. A replay's tools read the data current when it runs, not the data the original turn saw, and `replay.data` is `CURRENT` to say so. Records the original turn read may have changed since. The replay's `invocation.created` is the snapshot it read. While it runs, the replay's writes conflict with other writes to the same records as any transaction's writes do, although they never commit. A write that meets a record the replay has written fails with a write conflict and can be retried once the replay's turn ends. A replay that meets another transaction's write, uncommitted or committed after the replay's invocation started, fails that invocation with a write conflict, and the invocation is retried with the replayed version's execution settings.

The replay starts `QUEUED` and runs as any execution does, with the replayed version's execution settings. Its triggers are not evaluated, so `matchedTriggers` is empty.

| Input field        | Type                    | Meaning                                                                                                                                                                                                                                                                                                                                                                                                                                                                                     |
| ------------------ | ----------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `executionId`      | `UUID!`                 | Identifier for the new execution, chosen by you. Repeating a request with the same `executionId`, source, and other fields returns the same replay. Reusing it with different values is an error.                                                                                                                                                                                                                                                                                           |
| `actionVersion`    | `Int`                   | Version of the agent to run. Omit to run the source's pinned version. A session turn is replayed only by a version with a session, and a turn without one only by a version without one.                                                                                                                                                                                                                                                                                                    |
| `definition`       | `ActionDefinitionInput` | An unpublished definition of the agent to run instead of a stored version: replay a change before you write it. It is a whole definition, with `kind` and `config`, not a patch. It is validated as `createAction` validates a definition, and its tools and skills resolve as that write would resolve them. Running one requires permission to update the action, and the replay's `actionVersion` is the agent's version when you requested it. Cannot be combined with `actionVersion`. |
| `invocationNumber` | `Int`                   | The source invocation whose turn is replayed. Omit for its last invocation.                                                                                                                                                                                                                                                                                                                                                                                                                 |
| `model`            | `ActionReplayModel`     | `LIVE` (default): the model the replayed version configures. `RECORDED`: the model outputs the source invocation recorded, in order for each purpose, so a change of tools or skills is compared without the model's variability. A `RECORDED` replay that needs more outputs of a purpose than were recorded fails with `fixture_exhausted`.                                                                                                                                               |

`ActionReplay` describes how a replay ran:

| Field              | Type                    | Meaning                                                                                                                                                                                 |
| ------------------ | ----------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `invocationNumber` | `Int!`                  | The source invocation whose turn was replayed.                                                                                                                                          |
| `model`            | `ActionReplayModel!`    | What answered the replay's model calls.                                                                                                                                                 |
| `data`             | `ActionReplayData!`     | `CURRENT`: the replay's tools read the data current when it ran.                                                                                                                        |
| `session`          | `ActionReplaySession`   | For a replay of a session turn that succeeded: the `status`, `reason`, and `state` the turn would have given the session. It was not applied.                                           |
| `definition`       | `ActionDefinition`      | For a replay of an unpublished definition: the definition the replay ran. Its invocation's `tools` and `skills` name the versions it called. Null when the replay ran a stored version. |
| `requestedBy`      | `ActionReplayRequester` | For a replay a tool requested: the requesting execution's `executionId` and `execution`, its `invocationNumber`, and its `actionId`. Null for a replay a client requested.              |

```graphql
mutation Replay($id: UUID!, $executionId: UUID!, $version: Int!) {
  actions {
    replayExecution(
      id: $id
      input: { executionId: $executionId, actionVersion: $version, model: RECORDED }
    ) {
      executionId
      status
      replayOfId
    }
  }
}

query Compare($id: UUID!) {
  actions {
    execution(id: $id) {
      status
      invocation {
        output
      }
      replay {
        model
        data
        session {
          status
          state
        }
      }
      children(first: 50) {
        nodes {
          actionId
          invocation {
            output
          }
          writeSet {
            recordType
            recordId
            data
          }
        }
      }
      replayOf {
        invocation {
          output
        }
      }
    }
  }
}
```

A fixture model can also replay recorded outputs outside a replay: `{"provider": "fixture", "replay": {"execution_id": "...", "invocation_number": 1}}` in an agent's config answers its model calls with the outputs recorded in that invocation of an execution of the same agent.

## Cancellation

`cancelExecution` cancels an execution that has not finished, and records you in its `cancelledBy`. When an execution cancels it, such as an MCP server's `tasks/cancel` request, `cancelledBy` names that execution too. You need permission to update the execution.

- **`QUEUED`, `RETRY_SCHEDULED`, or `ACCEPTED`.** The execution is `CANCELLED` at once. It runs no further invocation, and a later completion report for an accepted invocation is ignored.
- **`RUNNING`.** An invocation that has only just begun is cancelled at once: the execution is returned `CANCELLED`, and the invocation's outcome cannot commit. Otherwise the execution is returned still `RUNNING`, with its cancellation requested. Once the cancellation commits, the running invocation's outcome never commits, so its writes roll back; its handler is stopped, and an agent stops at its next step. The execution becomes `CANCELLED`, with `cancelledBy` set, when the invocation ends, within its `responseTimeout`. Read it again to see it `CANCELLED`. Work an invocation started outside Twisp, such as a request to another system, is not undone.
- **Finishing.** If the invocation's outcome commits at the same moment, the cancellation fails with a retriable conflict, and retrying it returns the execution with its outcome. A cancellation that commits is always honoured: either the outcome or the cancellation wins, never both.
- **Finished.** A terminal execution is returned unchanged.

An execution processing a session turn cannot be cancelled; close its session instead. Cancelling does not stop new matches; disable the action for that.

```graphql
mutation Cancel($id: UUID!) {
  actions {
    cancelExecution(id: $id) {
      executionId
      status
    }
  }
}
```
