Skip to content

HTTP API

Every operation the server exposes, generated from the OpenAPI document it produces. The credential column is what the operation requires: operator is the operator token (or nothing at all on a loopback bind), task is the per-task token an agent is given. How to authenticate, read the event stream and generate a client is in Using the HTTP API.

Method Path Tag Operation Credential Summary
GET /api/agent/tasks/{task_id} agent get_task_api_agent_tasks__task_id__get taskToken Read this task: its brief and the work log
POST /api/agent/tasks/{task_id}/ask agent ask_api_agent_tasks__task_id__ask_post taskToken Ask the operator a question
POST /api/agent/tasks/{task_id}/log agent append_log_api_agent_tasks__task_id__log_post taskToken Append this attempt's deliverable
GET /api/agent/tasks/{task_id}/requests/{request_id} agent poll_request_api_agent_tasks__task_id__requests__request_id__get taskToken Wait for the answer to a question
POST /api/agent/tasks/{task_id}/submit agent submit_api_agent_tasks__task_id__submit_post taskToken Submit this task's structured result
GET /api/events events events_api_events_get operatorBearer The event stream
GET /api/health system health_api_health_get none Liveness and version
GET /api/me system me_api_me_get none Whether the caller needs a token, and has one
GET /api/plugins plugins manifest_api_plugins_get operatorBearer Everything the registered workflows contribute to the UI
POST /api/plugins/{wf}/actions/{name} plugins run_action_api_plugins__wf__actions__name__post operatorBearer Run one of a workflow's declared actions
GET /api/requests requests list_requests_api_requests_get operatorBearer The inbox: every request still waiting on a person
GET /api/requests/{request_id} requests get_request_api_requests__request_id__get operatorBearer One request and its answer
POST /api/requests/{request_id}/answer requests answer_request_api_requests__request_id__answer_post operatorBearer Answer a request
GET /api/runs runs list_runs_api_runs_get operatorBearer Every run, in dispatch order
DELETE /api/runs/{run_id} runs delete_run_api_runs__run_id__delete operatorBearer Delete a run and everything under it
GET /api/runs/{run_id} runs get_run_api_runs__run_id__get operatorBearer One run, its attempts and its totals
PATCH /api/runs/{run_id} runs edit_run_api_runs__run_id__patch operatorBearer Change a run's title or description
POST /api/runs/{run_id}/cancel runs cancel_run_api_runs__run_id__cancel_post operatorBearer End a run and everything under it
GET /api/runs/{run_id}/events runs get_events_api_runs__run_id__events_get operatorBearer A run's stored events
GET /api/runs/{run_id}/graph runs get_graph_api_runs__run_id__graph_get operatorBearer The workflow's graph, for this run
GET /api/runs/{run_id}/log runs get_log_api_runs__run_id__log_get operatorBearer A run's work log
POST /api/runs/{run_id}/log runs append_log_api_runs__run_id__log_post operatorBearer Append an operator note to the work log
POST /api/runs/{run_id}/pause runs pause_run_api_runs__run_id__pause_post operatorBearer Stop a run dispatching
POST /api/runs/{run_id}/position runs move_run_api_runs__run_id__position_post operatorBearer Move a run in the dispatch list
GET /api/runs/{run_id}/requests runs get_requests_api_runs__run_id__requests_get operatorBearer A run's requests
POST /api/runs/{run_id}/rerun runs rerun_node_api_runs__run_id__rerun_post operatorBearer Run a node again
POST /api/runs/{run_id}/resume runs resume_run_api_runs__run_id__resume_post operatorBearer Let a paused run dispatch again
GET /api/tasks/{task_id} tasks get_task_api_tasks__task_id__get operatorBearer One attempt and what was submitted for it
POST /api/tasks/{task_id}/move tasks move_task_api_tasks__task_id__move_post operatorBearer Move a task's work to another node
POST /api/tasks/{task_id}/retry tasks retry_task_api_tasks__task_id__retry_post operatorBearer Queue another attempt of a task
POST /api/tasks/{task_id}/status tasks set_status_api_tasks__task_id__status_post operatorBearer Write a task's status
GET /api/tasks/{task_id}/stream tasks get_stream_api_tasks__task_id__stream_get operatorBearer A page of a task's agent transcript
GET /api/workflows workflows list_workflows_api_workflows_get operatorBearer Every workflow this server can run
POST /api/workflows workflows register_workflow_api_workflows_post operatorBearer Register a workflow from a target
DELETE /api/workflows/{name} workflows remove_workflow_api_workflows__name__delete operatorBearer Unregister a workflow
GET /api/workflows/{name} workflows get_workflow_api_workflows__name__get operatorBearer One workflow
PUT /api/workflows/{name} workflows reload_workflow_api_workflows__name__put operatorBearer Reload a registered workflow
POST /api/workflows/{name}/runs workflows submit_run_api_workflows__name__runs_post operatorBearer Submit a run
GET /api/workflows/{name}/source workflows get_source_api_workflows__name__source_get operatorBearer The Python a workflow is defined in
POST /mcp/agent agent mcp_agent taskToken Model Context Protocol server (streamable HTTP)

workflows

What this server can run, and how to start a run of it.

GET /api/workflows

Every workflow this server can run

Credential: operatorBearer. Operation id: list_workflows_api_workflows_get.

The registered workflows, by name.

What the New Run overlay's workflow chips and the library's left list are built from. A server with nothing registered answers with an empty list: it runs no workflows, which is a fact rather than a failure.

Responses

Status Body Description
200 array of WorkflowOut Successful Response
401 ApiError No operator token, on a bind that requires one.

POST /api/workflows

Register a workflow from a target

Credential: operatorBearer. Operation id: register_workflow_api_workflows_post.

Load target and register the workflow it names, without a restart.

The name it registers under is the loaded workflow's own. Answers 201 with the workflow as GET /api/workflows/{name} reports it; 409 conflict if that name is already registered; 422 workflow_load_failed when the load stopped — its body carries target, stage (target, import, attribute, finalize, plugins or register) and detail, the underlying error's full message; 422 unknown_pool for a pool the engine does not have, naming the ones it does; 500 persist_failed (path, detail) when persist was asked for and the row could not be written, in which case nothing was registered; 503 registration_unavailable from an application built without a registrar. A response that wrote the row carries X-Athanore-Persisted: <path>.

Request body (required): application/json, RegisterWorkflow

Responses

Status Body Description
201 WorkflowOut Successful Response
401 ApiError No operator token, on a bind that requires one.
422 ApiError The request did not validate. code is validation and errors names each field that failed.

DELETE /api/workflows/{name}

Unregister a workflow

Credential: operatorBearer. Operation id: remove_workflow_api_workflows__name__delete.

Drop the workflow name, interrupting whatever it was running.

Every attempt of it in flight is cancelled and left where it was — no task status is written, and the run reads unregistered: true until the workflow is registered again, at which point those rows are recovered. Nothing is deleted. Answers 200 with the interrupted task ids; 404 unknown_workflow; 500 persist_failed; 503 registration_unavailable. A response that removed the row carries X-Athanore-Persisted: <path>; one that found no row to remove carries no such header.

Parameters

Parameter In Type Required Description
name path string yes The registered workflow's name.
persist query boolean no Remove the [workflows.<name>] row of athanore.toml too; a name with no row is not an error.

Responses

Status Body Description
200 RemovedWorkflowOut Successful Response
401 ApiError No operator token, on a bind that requires one.
422 ApiError The request did not validate. code is validation and errors names each field that failed.

GET /api/workflows/{name}

One workflow

Credential: operatorBearer. Operation id: get_workflow_api_workflows__name__get.

One registered workflow, or 404 unknown_workflow.

Parameters

Parameter In Type Required Description
name path string yes The registered workflow's name.

Responses

Status Body Description
200 WorkflowOut Successful Response
401 ApiError No operator token, on a bind that requires one.
422 ApiError The request did not validate. code is validation and errors names each field that failed.

PUT /api/workflows/{name}

Reload a registered workflow

Credential: operatorBearer. Operation id: reload_workflow_api_workflows__name__put.

Load target — or the registration's recorded one — and replace name.

The next task of every run of the workflow dispatches on the new graph; an attempt already running finishes on the body it started with. Answers 200 with the workflow as GET /api/workflows/{name} now reports it; 404 unknown_workflow; 409 conflict if the target now defines a differently named workflow (that is a new workflow — POST it) or pool would move the workflow while attempts of it are in flight; 422 workflow_load_failed as POST answers, with stage: "target" when target was omitted and the registration has no recorded one; 422 unknown_pool; 500 persist_failed; 503 registration_unavailable. A response that rewrote the row carries X-Athanore-Persisted: <path>.

Parameters

Parameter In Type Required Description
name path string yes The registered workflow's name.

Request body (required): application/json, ReloadWorkflow

Responses

Status Body Description
200 WorkflowOut Successful Response
401 ApiError No operator token, on a bind that requires one.
422 ApiError The request did not validate. code is validation and errors names each field that failed.

POST /api/workflows/{name}/runs

Submit a run

Credential: operatorBearer. Operation id: submit_run_api_workflows__name__runs_post.

Queue a run of this workflow, and return its id.

The run is queued rather than running: waiting for a slot is a state an operator can see, and the first claim of one of its tasks is what flips it.

Parameters

Parameter In Type Required Description
name path string yes The registered workflow's name.

Request body (required): application/json, NewRun

Responses

Status Body Description
201 Created Successful Response
401 ApiError No operator token, on a bind that requires one.
422 ApiError The request did not validate. code is validation and errors names each field that failed.

GET /api/workflows/{name}/source

The Python a workflow is defined in

Credential: operatorBearer. Operation id: get_source_api_workflows__name__source_get.

The module a workflow's nodes are defined in, and their line numbers.

The file is the one the start node's body is defined in — the module the author wrote the workflow in — and nodes carries a line for each node whose body is defined in that same file. A node whose function was imported from elsewhere is left out rather than given a line into text that does not contain it.

A workflow whose source Python cannot produce — a body built by exec, or one whose file has been deleted since import — is a 404: the workflow is registered, but this view of it does not exist.

Parameters

Parameter In Type Required Description
name path string yes The registered workflow's name.

Responses

Status Body Description
200 SourceOut Successful Response
401 ApiError No operator token, on a bind that requires one.
422 ApiError The request did not validate. code is validation and errors names each field that failed.

runs

A run's state, its history and the operator verbs that change it.

GET /api/runs

Every run, in dispatch order

Credential: operatorBearer. Operation id: list_runs_api_runs_get.

The run list of 08 §Runs, whole.

Run lists are small and return whole. The order is the dispatch order — position ascending — so the list the operator reads is the order the scheduler will claim in.

An application with no store has no runs and answers with an empty list: "nothing to ask" and "nothing queued" are the same fact for a server that holds no work, unlike /api/health's counts.

Parameters

Parameter In Type Required Description
status query RunStatus | null no Only runs in this status.
workflow query string | null no Only runs of this workflow.

Responses

Status Body Description
200 array of RunSummary Successful Response
401 ApiError No operator token, on a bind that requires one.
422 ApiError The request did not validate. code is validation and errors names each field that failed.

DELETE /api/runs/{run_id}

Delete a run and everything under it

Credential: operatorBearer. Operation id: delete_run_api_runs__run_id__delete.

Cancel what is outstanding, then remove the run.

Both halves are Ops.delete's, in that order and for its reason: the attempts are killed against rows that still exist.

Parameters

Parameter In Type Required Description
run_id path string yes The run id, a ULID.

Responses

Status Body Description
204 empty Successful Response
401 ApiError No operator token, on a bind that requires one.
422 ApiError The request did not validate. code is validation and errors names each field that failed.

GET /api/runs/{run_id}

One run, its attempts and its totals

Credential: operatorBearer. Operation id: get_run_api_runs__run_id__get.

A run with everything the overview pane draws.

current_nodes and pending_requests are the list query's two derived fields, recomputed from this read: the attempts are already in hand, so the in-flight nodes cost nothing, and the pending requests are one indexed query over this run alone.

Parameters

Parameter In Type Required Description
run_id path string yes The run id, a ULID.

Responses

Status Body Description
200 RunDetail Successful Response
401 ApiError No operator token, on a bind that requires one.
422 ApiError The request did not validate. code is validation and errors names each field that failed.

PATCH /api/runs/{run_id}

Change a run's title or description

Credential: operatorBearer. Operation id: edit_run_api_runs__run_id__patch.

Write the fields the body names, and answer with the run.

A field the body omits is left alone, which is why an edit that names neither is accepted and changes nothing (Ops.edit). The response is the whole detail rather than the edited row: the SPA re-renders the overview from it, and a second GET to get the attempts back would be a round trip for nothing.

Parameters

Parameter In Type Required Description
run_id path string yes The run id, a ULID.

Request body (required): application/json, EditRun

Responses

Status Body Description
200 RunDetail Successful Response
401 ApiError No operator token, on a bind that requires one.
422 ApiError The request did not validate. code is validation and errors names each field that failed.

POST /api/runs/{run_id}/cancel

End a run and everything under it

Credential: operatorBearer. Operation id: cancel_run_api_runs__run_id__cancel_post.

Cancel the run and every outstanding attempt; 409 if it has ended.

The note names how many attempts were stopped, because that is the part of the outcome the request could not predict: a run with nothing in flight and a run with three agents mid-turn are the same call and very different events. It is omitted when there were none, rather than sent as "0 attempts".

Parameters

Parameter In Type Required Description
run_id path string yes The run id, a ULID.

Responses

Status Body Description
200 Ok Successful Response
401 ApiError No operator token, on a bind that requires one.
422 ApiError The request did not validate. code is validation and errors names each field that failed.

GET /api/runs/{run_id}/events

A run's stored events

Credential: operatorBearer. Operation id: get_events_api_runs__run_id__events_get.

One page of the run's history, oldest first.

The same typed envelope the SSE feed sends, so a client that caught up from here and then subscribed switches sources without switching shapes. task.stream is ephemeral and is never stored, so it never appears in a page.

Parameters

Parameter In Type Required Description
run_id path string yes The run id, a ULID.
after query integer no Return events after this event id.
limit query integer no How many events to return.

Responses

Status Body Description
200 array of RunCreatedEvent | RunStartedEvent | RunUpdatedEvent | RunReorderedEvent | RunPausedEvent | RunResumedEvent | RunCancelledEvent | RunDeletedEvent | RunCompletedEvent | RunFailedEvent | TaskEnqueuedEvent | JoinArrivedEvent | TaskStartedEvent | TaskDoneEvent | TaskFailedEvent | TaskDeadLetteredEvent | TaskWaitingEvent | TaskResumedEvent | TaskCancelledEvent | TaskMovedEvent | TaskStatusSetEvent | TaskStreamEvent | SubmissionAcceptedEvent | SubmissionRejectedEvent | SubmissionRepairEvent | RequestOpenedEvent | RequestAnsweredEvent | LogAppendedEvent | AgentStatsEvent | EngineRecoveredEvent | EngineStoppingEvent | WorkflowRegisteredEvent | WorkflowReplacedEvent | WorkflowUnregisteredEvent | PluginEvent Successful Response
401 ApiError No operator token, on a bind that requires one.
422 ApiError The request did not validate. code is validation and errors names each field that failed.

GET /api/runs/{run_id}/graph

The workflow's graph, for this run

Credential: operatorBearer. Operation id: get_graph_api_runs__run_id__graph_get.

The registered graph with this run's history projected onto it.

A run whose workflow this server does not have registered is a 404 unknown_workflow: there is no graph to project onto, and the run list already says so with unregistered rather than pretending a shape.

Parameters

Parameter In Type Required Description
run_id path string yes The run id, a ULID.

Responses

Status Body Description
200 GraphOut Successful Response
401 ApiError No operator token, on a bind that requires one.
422 ApiError The request did not validate. code is validation and errors names each field that failed.

GET /api/runs/{run_id}/log

A run's work log

Credential: operatorBearer. Operation id: get_log_api_runs__run_id__log_get.

Every entry of the work log, oldest first and never truncated.

Whole, and unpaged: the log is bounded by the number of stages rather than by agent output. The stats entries an agent never sees are here — token counts are operator information.

Parameters

Parameter In Type Required Description
run_id path string yes The run id, a ULID.

Responses

Status Body Description
200 array of LogEntry Successful Response
401 ApiError No operator token, on a bind that requires one.
422 ApiError The request did not validate. code is validation and errors names each field that failed.

POST /api/runs/{run_id}/log

Append an operator note to the work log

Credential: operatorBearer. Operation id: append_log_api_runs__run_id__log_post.

Write a user entry under the run's current node.

The node is the one node with an attempt in flight, and user when there is not exactly one: a note filed under one branch of a fan-out would claim a context it does not have (Ops.append_log).

Parameters

Parameter In Type Required Description
run_id path string yes The run id, a ULID.

Request body (required): application/json, LogText

Responses

Status Body Description
200 LogRef Successful Response
401 ApiError No operator token, on a bind that requires one.
422 ApiError The request did not validate. code is validation and errors names each field that failed.

POST /api/runs/{run_id}/pause

Stop a run dispatching

Credential: operatorBearer. Operation id: pause_run_api_runs__run_id__pause_post.

Pause a queued or running run; 409 on anything else.

Pause is about the next task: an attempt already in flight runs to its end and enqueues its successor, and that successor waits (04 §Operator operations). Killing running work is /cancel.

Parameters

Parameter In Type Required Description
run_id path string yes The run id, a ULID.

Responses

Status Body Description
200 Ok Successful Response
401 ApiError No operator token, on a bind that requires one.
422 ApiError The request did not validate. code is validation and errors names each field that failed.

POST /api/runs/{run_id}/position

Move a run in the dispatch list

Credential: operatorBearer. Operation id: move_run_api_runs__run_id__position_post.

Swap with a neighbour, or move to a zero-based index.

Both ends are a no-op that still answers 200 with the position the run already had, and an index outside the list is clamped to it: "top" is {"index": 0} and there is nothing for the caller to bounds-check. The body model has already refused neither-or-both of the two fields.

Parameters

Parameter In Type Required Description
run_id path string yes The run id, a ULID.

Request body (required): application/json, Position

Responses

Status Body Description
200 PositionOut Successful Response
401 ApiError No operator token, on a bind that requires one.
422 ApiError The request did not validate. code is validation and errors names each field that failed.

GET /api/runs/{run_id}/requests

A run's requests

Credential: operatorBearer. Operation id: get_requests_api_runs__run_id__requests_get.

Every request the run opened, answered or not, oldest first.

The run's history rather than the inbox: a stale request — one whose attempt is gone — stays here and leaves /api/requests?pending=true.

Parameters

Parameter In Type Required Description
run_id path string yes The run id, a ULID.

Responses

Status Body Description
200 array of RequestView Successful Response
401 ApiError No operator token, on a bind that requires one.
422 ApiError The request did not validate. code is validation and errors names each field that failed.

POST /api/runs/{run_id}/rerun

Run a node again

Credential: operatorBearer. Operation id: rerun_node_api_runs__run_id__rerun_post.

Enqueue a fresh attempt of node with the payload it last had.

A join replays the arrivals the store holds rather than the payload its task was given, which is what makes a rerun the remedy for a branch that arrived late.

Parameters

Parameter In Type Required Description
run_id path string yes The run id, a ULID.

Request body (required): application/json, Rerun

Responses

Status Body Description
200 TaskRef Successful Response
401 ApiError No operator token, on a bind that requires one.
422 ApiError The request did not validate. code is validation and errors names each field that failed.

POST /api/runs/{run_id}/resume

Let a paused run dispatch again

Credential: operatorBearer. Operation id: resume_run_api_runs__run_id__resume_post.

Resume a paused run; 409 on anything else.

Parameters

Parameter In Type Required Description
run_id path string yes The run id, a ULID.

Responses

Status Body Description
200 Ok Successful Response
401 ApiError No operator token, on a bind that requires one.
422 ApiError The request did not validate. code is validation and errors names each field that failed.

tasks

One attempt of one node: what it submitted, what it streamed, and the verbs that re-attempt it.

GET /api/tasks/{task_id}

One attempt and what was submitted for it

Credential: operatorBearer. Operation id: get_task_api_tasks__task_id__get.

The operator view of a task: 08's TaskRow plus submissions.

Every accepted submission, oldest first, because "last valid wins" is a rule about which one the body reads and not about which ones happened: an operator reading a repaired attempt wants the rejected shape and the accepted one.

No token, in this response or any other: a task token is header-only, and TaskDetail has no field that could carry one.

Parameters

Parameter In Type Required Description
task_id path integer yes The task id, unique across runs.

Responses

Status Body Description
200 TaskDetail Successful Response
401 ApiError No operator token, on a bind that requires one.
422 ApiError The request did not validate. code is validation and errors names each field that failed.

POST /api/tasks/{task_id}/move

Move a task's work to another node

Credential: operatorBearer. Operation id: move_task_api_tasks__task_id__move_post.

Cancel the attempt and enqueue its payload at node.

409 conflict when node is a join: a join is dispatched by its arrivals and called with all of them, so a task moved into one would be a join attempt holding a single branch's payload, with no arrival recorded and a run left waiting for branches that already landed.

Parameters

Parameter In Type Required Description
task_id path integer yes The task id, unique across runs.

Request body (required): application/json, Move

Responses

Status Body Description
200 TaskRef Successful Response
401 ApiError No operator token, on a bind that requires one.
422 ApiError The request did not validate. code is validation and errors names each field that failed.

POST /api/tasks/{task_id}/retry

Queue another attempt of a task

Credential: operatorBearer. Operation id: retry_task_api_tasks__task_id__retry_post.

Enqueue the next attempt of a task that has stopped.

Same node, same payload, same branch and the same created, so a retry keeps its place in the dispatch order (Ops.retry). Refused with 409 conflict while the task is still going: a second attempt of a task that already has one is two attempts of one task.

Parameters

Parameter In Type Required Description
task_id path integer yes The task id, unique across runs.

Responses

Status Body Description
200 TaskRef Successful Response
401 ApiError No operator token, on a bind that requires one.
422 ApiError The request did not validate. code is validation and errors names each field that failed.

POST /api/tasks/{task_id}/status

Write a task's status

Credential: operatorBearer. Operation id: set_status_api_tasks__task_id__status_post.

Put the task in one of the three statuses an operator may write.

ready re-dispatches it and re-opens a terminal run, cancelled stops it and dead_letter files it as failed for good; the other four statuses are the engine's record of what happened and are not an operator's to declare, which is why the body's field is a Literal and a fourth value is a 422 before the engine is reached.

Parameters

Parameter In Type Required Description
task_id path integer yes The task id, unique across runs.

Request body (required): application/json, SetStatus

Responses

Status Body Description
200 Ok Successful Response
401 ApiError No operator token, on a bind that requires one.
422 ApiError The request did not validate. code is validation and errors names each field that failed.

GET /api/tasks/{task_id}/stream

A page of a task's agent transcript

Credential: operatorBearer. Operation id: get_stream_api_tasks__task_id__stream_get.

The chunks after after, in transcript order.

after=0 is the whole transcript from the start, which is what a tab opening on a finished attempt asks for; a client following a live one passes the seq_to of the ephemeral task.stream event it just received and appends what comes back.

Parameters

Parameter In Type Required Description
task_id path integer yes The task id, unique across runs.
after query integer no Return chunks after this sequence number.
limit query integer no How many chunks to return.

Responses

Status Body Description
200 StreamOut Successful Response
401 ApiError No operator token, on a bind that requires one.
422 ApiError The request did not validate. code is validation and errors names each field that failed.

requests

The inbox: everything waiting on a person, and the answers.

GET /api/requests

The inbox: every request still waiting on a person

Credential: operatorBearer. Operation id: list_requests_api_requests_get.

The requests of every run, or of one, oldest first.

"Pending" is narrower than "unanswered": a request whose task has ended is stale and leaves the inbox, because an answer to it would reach nobody. It stays in the run's own history, and pending=false here shows it too, with stale: true on it.

An application with no store holds no requests and answers with an empty list; a run that names no run is a filter that matches nothing rather than a 404.

Parameters

Parameter In Type Required Description
pending query boolean no Only requests a person can still act on: unanswered, with the attempt that asked still running.
run query string | null no Only requests of this run.

Responses

Status Body Description
200 array of RequestView Successful Response
401 ApiError No operator token, on a bind that requires one.
422 ApiError The request did not validate. code is validation and errors names each field that failed.

GET /api/requests/{request_id}

One request and its answer

Credential: operatorBearer. Operation id: get_request_api_requests__request_id__get.

One request, answered or not, with the node that asked.

Parameters

Parameter In Type Required Description
request_id path integer yes The request id, unique across runs.

Responses

Status Body Description
200 RequestView Successful Response
401 ApiError No operator token, on a bind that requires one.
422 ApiError The request did not validate. code is validation and errors names each field that failed.

POST /api/requests/{request_id}/answer

Answer a request

Credential: operatorBearer. Operation id: answer_request_api_requests__request_id__answer_post.

Record the one answer this request may have, and return it.

option_id for an options request and value for a text or form one; the request's own mode decides which of the two is read, so a value sent to an options request is not an answer that request could have.

The response is the updated view rather than the answer row (08 §Requests): the SPA re-renders the card it just answered, and pending, answer and answered_by are all part of what changed. The author is user — this route is the operator's, and the other author, engine, belongs to the headless fallbacks that record an answer without a person.

Parameters

Parameter In Type Required Description
request_id path integer yes The request id, unique across runs.

Request body (required): application/json, Answer

Responses

Status Body Description
200 RequestView Successful Response
401 ApiError No operator token, on a bind that requires one.
422 ApiError The request did not validate. code is validation and errors names each field that failed.

agent

What an ACP agent may call, authenticated by the task token of the attempt it is running.

GET /api/agent/tasks/{task_id}

Read this task: its brief and the work log

Credential: taskToken. Operation id: get_task_api_agent_tasks__task_id__get.

Everything the agent needs to start, and nothing else.

The title and the description are the run's — the brief an operator submitted — and input is the payload this node was enqueued with, null when it had none. log is the run's work log, oldest first, uncapped and untruncated: it is the inter-stage channel, it is bounded by the number of stages rather than by agent output, and a retried attempt reads the failure entry that says why the last one failed.

The stats entries are dropped. output_schema is here only while a façade has declared an output_model on this attempt's live context: the native tooling tier reads it to build its submit_result tool, and an agent with no model declared is not required to submit anything.

Parameters

Parameter In Type Required Description
task_id path integer yes The task the token was minted for.
x-athanore-token header string yes The task token, from the claimed attempt.

Responses

Status Body Description
200 AgentTask Successful Response
403 ApiError The task token is not valid for this task.
422 ApiError The request did not validate. code is validation and errors names each field that failed.

POST /api/agent/tasks/{task_id}/ask

Ask the operator a question

Credential: taskToken. Operation id: ask_api_agent_tasks__task_id__ask_post.

Open a request against this attempt, if the agent may ask at all.

403 unless the façade running this attempt declared ask_policy="http": an agent cannot grant itself the right to interrupt a person, and the policy lives on the agent class the workflow chose. The prompt sections that tell an agent how to ask are omitted when it is off, so a 403 here is an agent that went looking.

What was sent decides the mode: options for a pick-one question, schema for a form — whose answer is validated against that very schema where it lands, by the validator registered here (06 §Service) — and neither for free text. The request is opened with source="agent" and no ordinal, because a re-executed attempt does not reproduce a turn statement for statement.

The answer does not come back here: the caller polls /requests/{rid}, which is what lets the agent keep its turn rather than holding this connection open.

Parameters

Parameter In Type Required Description
task_id path integer yes The task the token was minted for.
x-athanore-token header string yes The task token, from the claimed attempt.

Request body (required): application/json, Ask

Responses

Status Body Description
200 AskOut Successful Response
403 ApiError The task token is not valid for this task.
422 ApiError The request did not validate. code is validation and errors names each field that failed.

POST /api/agent/tasks/{task_id}/log

Append this attempt's deliverable

Credential: taskToken. Operation id: append_log_api_agent_tasks__task_id__log_post.

Write one entry to the run's work log, author agent.

The deliverable of a stage, which is what the next stage reads. It is written through the attempt's own LogService, so it carries this task's id and node and emits the log.appended the SPA re-renders on — the same call a node body makes, reached over HTTP.

Parameters

Parameter In Type Required Description
task_id path integer yes The task the token was minted for.
x-athanore-token header string yes The task token, from the claimed attempt.

Request body (required): application/json, LogText

Responses

Status Body Description
200 LogRef Successful Response
403 ApiError The task token is not valid for this task.
422 ApiError The request did not validate. code is validation and errors names each field that failed.

GET /api/agent/tasks/{task_id}/requests/{request_id}

Wait for the answer to a question

Credential: taskToken. Operation id: poll_request_api_agent_tasks__task_id__requests__request_id__get.

The answer, waiting up to wait seconds for one to land.

wait is clamped to MAX_WAIT rather than refused, so 19's instruction — poll with ?wait=60 and repeat until it says answered — is a loop that costs one request per minute and not a spin. The wait ends the moment the answer is recorded, not when the clamp expires.

A request of another task is a 404, not someone else's answer: a token names one attempt and this route reads only what that attempt opened.

Nothing is claimed. An agent that lost a response and asked again gets the same answer again, which is what makes a dropped connection cost nothing.

Parameters

Parameter In Type Required Description
task_id path integer yes The task the token was minted for.
request_id path integer yes A request this task opened.
wait query number no Seconds to wait for an answer before reporting that there is none yet. Clamped to [0, 120].
x-athanore-token header string yes The task token, from the claimed attempt.

Responses

Status Body Description
200 AnswerPoll Successful Response
403 ApiError The task token is not valid for this task.
422 ApiError The request did not validate. code is validation and errors names each field that failed.

POST /api/agent/tasks/{task_id}/submit

Submit this task's structured result

Credential: taskToken. Operation id: submit_api_agent_tasks__task_id__submit_post.

Record a value for this attempt, if it fits what was asked for.

With an output_model declared, a misfit is a 422 carrying errors and schema and nothing is stored: the agent reads the two in its own tool output and can fix the shape inside the same turn. The rejection is also left on the context as ctx.last_rejection, which is what 19's repair turn quotes back if the turn ends without a valid submission.

With none declared, any JSON is stored as it arrived.

Submitting twice is not an error: the latest valid payload wins, and a body reads it with submissions.latest(). A submission never routes anything — the node body decides — so an agent cannot move its own task.

Parameters

Parameter In Type Required Description
task_id path integer yes The task the token was minted for.
x-athanore-token header string yes The task token, from the claimed attempt.

Request body (required): application/json, any

Responses

Status Body Description
200 Ok Successful Response
403 ApiError The task token is not valid for this task.
422 ApiError The request did not validate. code is validation and errors names each field that failed.

POST /mcp/agent

Model Context Protocol server (streamable HTTP)

Credential: taskToken. Operation id: mcp_agent.

The agent surface as MCP tools: get_task, append_log, submit_result, and — when the attempt's ask_policy is httpask_operator and wait_answer. Authenticated by the same X-Athanore-Token header as /api/agent/; the task is the token's, so no tool takes a task id. The request and response bodies are MCP's own JSON-RPC and are opaque to this document.

Parameters

Parameter In Type Required Description
X-Athanore-Token header string yes The task token, from the claimed attempt.

Request body (required): application/json, any

Responses

Status Body Description
200 any One MCP response, as JSON or as an SSE stream.
403 ApiError The task token is not valid for a live attempt.

plugins

The manifest a workflow's declarations publish, and the routes and actions behind it.

GET /api/plugins

Everything the registered workflows contribute to the UI

Credential: operatorBearer. Operation id: manifest_api_plugins_get.

The plugin manifest: panels, actions and assets, per workflow.

Builtins first, then the workflows in registration order. The SPA fetches this at boot, again whenever the SSE stream reconnects onto a server with a new started_at, and on every workflow.* event, because a manifest changes when a workflow is registered, replaced or removed.

Responses

Status Body Description
200 array of PluginManifestEntry Successful Response
401 ApiError No operator token, on a bind that requires one.

POST /api/plugins/{wf}/actions/{name}

Run one of a workflow's declared actions

Credential: operatorBearer. Operation id: run_action_api_plugins__wf__actions__name__post.

Validate the input, resolve the scope, run the handler.

The one way an action is invoked. It answers with whatever the handler returned, as JSON.

Parameters

Parameter In Type Required Description
wf path string yes The workflow that declared the action.
name path string yes The action's name.

Request body (required): application/json, ActionCall

Responses

Status Body Description
200 any Successful Response
401 ApiError No operator token, on a bind that requires one.
422 ApiError The request did not validate. code is validation and errors names each field that failed.

events

The live feed: one server-sent event per event of the vocabulary.

GET /api/events

The event stream

Credential: operatorBearer. Operation id: events_api_events_get.

Missed history, then live events, on one connection.

access_token is accepted here as a query parameter and on no other route, because a browser's EventSource cannot set a header (08 §Authentication); the query string is never logged.

Parameters

Parameter In Type Required Description
after query integer | null no Replay stored events after this event id, then go live. Takes precedence over the Last-Event-ID header.
run query string | null no Only events of this run.
names query string | null no Comma-separated event-name globs; a * matches one dotted segment, so run.* selects run.created. Omitted means every event.
last-event-id header string | null no A browser's reconnect cursor, set by EventSource.

Responses

Status Body Description
200 empty An SSE stream. Each message is id: <event id>, event: <event name>, data: <EventEnvelope as JSON>. Ephemeral events (task.stream) carry no id:, and the resync control frame — sent when the replay overran sse_replay_cap or the server dropped events for a slow reader — carries neither an id: nor an event envelope.
401 ApiError No operator token, on a bind that requires one.
422 ApiError The request did not validate. code is validation and errors names each field that failed.

system

Liveness and the caller's own standing. Unauthenticated, and carrying no ids.

GET /api/health

Liveness and version

Credential: none. Operation id: health_api_health_get.

Whether the server is up, which version it is, and what it is doing.

Pausing every run and then waiting for tasks_in_progress to reach zero here is how an operator drains a server before stopping it.

Responses

Status Body Description
200 Health Successful Response

GET /api/me

Whether the caller needs a token, and has one

Credential: none. Operation id: me_api_me_get.

Whether this server wants a token, and whether this request has one.

Never requires one itself: a request with no credential on a server that wants one gets a 200 saying {"auth": "token", "authenticated": false}, which is the client's cue to ask for a token.

Responses

Status Body Description
200 Me Successful Response

Schemas

ActionCall

The body of POST /api/plugins/{wf}/actions/{name}.

input is whatever the action's form produced, and it is validated against the action's own model on arrival rather than described here: the model is the plugin's, so no schema this application generates could name it ("the model is the form"). An action that declares none takes none, and whatever was sent is ignored.

Field Type Required Description
input any no The form's value. Validated against the action's model; a misfit is the 422 of 08 §Conventions, naming each field.
scope ActionScope no The ids the handler's context is resolved from.

ActionOut

One action of the manifest, and the form the SPA renders for it.

Field Type Required Description
confirm boolean yes Whether the SPA asks for confirmation before calling it.
name string yes The action's name, as its URL spells it.
schema object yes JSON Schema of the input model — the form itself.
scope Slot yes What has to be resolved before it can run.
title string yes What the button and the palette entry say.

ActionScope

Where an action was invoked.

The three ids a plugin route reads off its query string, sent in the body because an action is a POST. All three are optional here: what an action needs resolved is the scope it declared, and mount_actions is what holds the body to it.

Field Type Required Description
node string | null no The node the action was invoked on.
run_id string | null no The run the action was invoked on.
task_id integer | null no The attempt the action was invoked on.

AgentStats

The stats entry of 05 §Stats entry verbatim.

Every measurement is optional because 05 omits what it cannot determine rather than zero-filling it.

Field Type Required Description
attempt integer yes
cost number | null no
denied_permissions integer | null no
duration_s number yes
input_tokens integer | null no
model string | null no
node string yes
output_tokens integer | null no
reason 'refusal', 'cancelled', 'truncated', 'timeout', 'shutdown', 'transport', 'no_submission' | null no
repair_turns integer | null no
session_id string | null no
status 'ok', 'failed' yes
tool_calls integer | null no
total_tokens integer | null no

AgentStatsEvent

Field Type Required Description
created string (date-time) yes
data AgentStats yes
id integer | null no
name 'agent.stats' yes
run_id string | null no
task_id integer | null no

AgentTask

One attempt as the agent running it sees it.

The identity of the attempt, the run's title and description, the payload the node was called with, and the work log that is the inter-stage channel. Everything an agent needs to start, and nothing an operator route would add.

Field Type Required Description
attempt integer yes Which attempt of this node this is, from 1.
description string yes The operator's longer brief for the run.
input any no The payload the node was enqueued with; null when it had none.
log array of LogEntry yes The run's work log, oldest first and never truncated, without the stats entries.
node string yes The node this attempt executes.
output_schema object | null no The JSON Schema a submission must fit, when the agent façade running this attempt declared an output_model.
run_id string yes The run the attempt belongs to.
task_id integer yes This attempt's id; the one the token is for.
title string yes The operator's title for the run.
workflow string yes The workflow being run.

Answer

Answer a request (POST /api/requests/{id}/answer).

option_id for an options request and value for a text or form one. Both are optional here because value may legitimately be any JSON — including null, which is why "which one was given" cannot be decided by looking at the values alone: the request's own mode decides, and the request service refuses the mismatch with the error code 06 §Errors names for it.

Field Type Required Description
option_id string | null no The chosen option, for an options request.
value any no The answer, for a text or form request.

AnswerAuthor

Who answered. engine is a headless fallback: a permission timeout action or a declined elicitation.

  • 'user'
  • 'engine'

AnswerPoll

The result of one long-poll (GET …/requests/{rid}).

answered is the field to branch on. Until it is true the other two are absent, because a request with no answer has no author either; once it is true answer is the chosen option_id of an options request and the value of a text or form one — the same folding RequestView does, so an operator reading the request and the agent reading its answer see the same value.

Re-delivery is idempotent: nothing is claimed by a poll, so an agent that lost a response and asked again gets the same answer again.

Field Type Required Description
answer any no The chosen option_id, or the value of a text or form answer. Null before an answer, and for an answer that was null.
answered boolean yes Whether an answer has been recorded.
answered_by AnswerAuthor | null no Who answered: the operator, or the engine on a headless fallback. Null until answered.
request_id integer yes The request that was polled.

ApiError

The body of every refusal: {error, code, ...extras}.

code is the ErrorCode vocabulary, referenced rather than inlined, which is how the SPA gets a union instead of a bare string. errors is the extra a validation failure and a rejected submission carry, and it is 18's ValidationError rather than a second model of the same three fields: one function (validate_submission) projects pydantic's errors onto loc/msg/type, and the list it returns is what the 422 body carries and what submission.rejected publishes. The rest of 08's "...extras" are open, so the schema allows further properties rather than pretending the two named fields are all a body can hold.

Field Type Required Description
code ErrorCode yes The stable code a client branches on; the wording of error may change, this may not.
error string yes What went wrong, for a person to read.
errors array of ValidationError | null no Per-field detail, on a validation failure or a rejected submission. Absent otherwise.

Arrivals

How much of an open fan-out has reached a join.

The innermost pending fan-out, which is the one the operator is waiting on; the SPA renders it as 2 of 3 arrived.

Field Type Required Description
arrived integer yes Branches that have reached the join.
count integer yes Branches the fan-out opened.

Ask

A question an agent puts to the operator (POST …/ask).

schema is spelled schema_ in Python, as it is in RequestView, and keeps schema as its alias — the name 08 and the curl line of 19 fix on the wire.

Field Type Required Description
options array of string | AskOption | null no The choices, for a pick-one question. A bare string is an option that is its own id and label.
prompt string yes The question, as the operator will read it.
schema object | null no A JSON Schema the answer must fit, for a form question.

AskOption

One choice an agent offers the operator.

option_id is what an answer names and what comes back from the long-poll; name is what the operator is shown and defaults to the id, which is what a bare string in options is short for.

Field Type Required Description
kind string | null no A label for the option; carried through as given.
name string | null no What to show the operator; the option_id when omitted.
option_id string yes The id an answer names.

AskOut

The request an ask opened.

mode is reported back because the agent did not choose it directly: it sent options, a schema or neither, and this is what that was read as — which is also what tells it what shape of answer to expect from the long-poll.

Field Type Required Description
mode RequestMode yes The shape of the answer expected.
request_id integer yes The id to poll for an answer.

BranchRef

Which branch an output came out of.

The index and the key of each frame, and not the frame's fanout or count: an output names its branch so a consumer can group by it, and the task it came from is in the same entry for anything more.

Field Type Required Description
index integer yes The branch's zero-based index in its fan-out.
key any no The payload that branch was given.

ChunkKind

The kinds of the agent transcript.

text and thought are the assistant's message and reasoning chunks, tool_call/tool_result the ACP tool updates, notice a line the façade itself wrote.

  • 'text'
  • 'thought'
  • 'tool_call'
  • 'tool_result'
  • 'notice'

Created

The 201 body of POST /api/workflows/{name}/runs.

Field Type Required Description
run_id string yes The id of the run that was queued.

EdgeKind

What kind of edge one node's arrow to another is.

  • 'forward'
  • 'back'
  • 'join'

EditRun

Change a run's title, its description, or both (PATCH /api/runs/{id}).

Both fields are optional and a field that is absent is left alone — which is why they are optional rather than defaulted: an edit that sent no description must not blank one. An edit that names neither is accepted and changes nothing, which is what Ops.edit does with it: a patch is not the place to refuse a caller for being redundant.

Field Type Required Description
description string | null no The new description, if changing.
title string | null no The new title, if changing.

EngineRecovered

Rows reset to ready at startup. No run_id.

Field Type Required Description
task_ids array of integer yes

EngineRecoveredEvent

Field Type Required Description
created string (date-time) yes
data EngineRecovered yes
id integer | null no
name 'engine.recovered' yes
run_id string | null no
task_id integer | null no

EngineStopping

Attempts interrupted by a shutdown. No run_id.

Field Type Required Description
task_ids array of integer yes

EngineStoppingEvent

Field Type Required Description
created string (date-time) yes
data EngineStopping yes
id integer | null no
name 'engine.stopping' yes
run_id string | null no
task_id integer | null no

ErrorCode

The stable code of an error body — 08 §Conventions, in full.

A code is a contract with the SPA and the CLI: it is what a client branches on, so it outlives any wording change to error. Adding one is a change to 08 and to the TypeScript mirror, never to this module alone.

  • 'not_found'
  • 'conflict'
  • 'forbidden'
  • 'unauthorized'
  • 'validation'
  • 'invalid_option'
  • 'already_answered'
  • 'stale_request'
  • 'graph_error'
  • 'unknown_workflow'
  • 'unknown_node'
  • 'payload_too_large'
  • 'plugin_error'
  • 'workflow_load_failed'
  • 'unknown_pool'
  • 'registration_unavailable'
  • 'persist_failed'

EventName

Every event name in the vocabulary, one member per row of 03.

Values are subject.verb. Adding one is a change to 03 and to the TypeScript mirror, never to this module alone.

  • 'run.created'
  • 'run.started'
  • 'run.updated'
  • 'run.reordered'
  • 'run.paused'
  • 'run.resumed'
  • 'run.cancelled'
  • 'run.deleted'
  • 'run.completed'
  • 'run.failed'
  • 'task.enqueued'
  • 'join.arrived'
  • 'task.started'
  • 'task.done'
  • 'task.failed'
  • 'task.dead_lettered'
  • 'task.waiting'
  • 'task.resumed'
  • 'task.cancelled'
  • 'task.moved'
  • 'task.status_set'
  • 'task.stream'
  • 'submission.accepted'
  • 'submission.rejected'
  • 'submission.repair'
  • 'request.opened'
  • 'request.answered'
  • 'log.appended'
  • 'agent.stats'
  • 'engine.recovered'
  • 'engine.stopping'
  • 'workflow.registered'
  • 'workflow.replaced'
  • 'workflow.unregistered'

GraphBranch

The tasks of one node that belong to one branch of a fan-out.

from_task is the fan-out that produced the branch — the lineage.from of the first task in the branch chain whose parent returned a list — and is null for a node reached by a single path, which has exactly one branch.

Field Type Required Description
from_task integer | null no The fan-out task this branch came out of.
tasks array of integer no This node's attempts in that branch, oldest first.

GraphEdge

One arrow of the finalized graph, and how often this run took it.

from is a Python keyword, so the field is from_ and carries from as its alias — the name 08 fixes on the wire.

Field Type Required Description
from string yes The node the arrow leaves.
kind EdgeKind yes Forward, a loop back, or an arrow into a join.
to string yes The node it points at.
traversed integer yes How often this run took the edge: task.enqueued reason=transition between the two nodes, plus join.arrived for a join edge.

GraphNode

One node of the graph, with this run's history on it.

Field Type Required Description
arrivals Arrivals | null no For a join with a fan-out still open, how much of it has arrived; absent otherwise.
attempts integer yes How many task rows this node has in this run.
branches array of GraphBranch no The node's tasks grouped by the fan-out that produced them.
generation integer yes BFS depth from the start node.
join boolean yes Whether the node waits for a fan-out to complete.
last_task_id integer | null no The highest task id of the node, the one the task drawer opens; null when the node has no task.
live boolean yes Whether a node-slot plugin panel should show: the node is in progress or waiting, or it has at least one done attempt.
name string yes The node's name.
state NodeState yes What the node is doing, by 08's precedence.

GraphOut

The graph of one run (/graph).

Field Type Required Description
edges array of GraphEdge yes Every edge of the finalized graph.
nodes array of GraphNode yes Every node of the workflow.

Health

Liveness, version and counts. Unauthenticated, and carries no ids.

Field Type Required Description
ok boolean yes True whenever the server answers at all.
pools object of PoolHealth | null no Every registered pool by name. Omitted when this application has no engine; empty when the engine has no pools.
runs_running integer | null no Runs in the running status. Omitted when this application has no store to ask.
tasks_in_progress integer | null no Attempts in the in_progress status; a task parked on a human is waiting and is not counted. Omitted when this application has no store to ask.
version string yes The running Athanore version.

JoinArrived

One per branch reaching a join.

arrived == count means the join task was enqueued in the same transaction.

Field Type Required Description
arrived integer yes
count integer yes
fanout_task integer yes
index integer yes
join string yes
late boolean yes

JoinArrivedEvent

Field Type Required Description
created string (date-time) yes
data JoinArrived yes
id integer | null no
name 'join.arrived' yes
run_id string | null no
task_id integer | null no

LogAppended

preview is the first 200 characters of the entry.

Field Type Required Description
author string yes
kind string | null no
log_id integer yes
node string yes
preview string yes

LogAppendedEvent

Field Type Required Description
created string (date-time) yes
data LogAppended yes
id integer | null no
name 'log.appended' yes
run_id string | null no
task_id integer | null no

LogAuthor

Who wrote a work-log entry.

  • 'agent'
  • 'engine'
  • 'user'

LogEntry

One entry of a run's work log, append-only.

The work log is the inter-stage channel: the engine's failures, the operator's notes and every agent deliverable, in one ordered list. kind is absent on a plain entry.

Field Type Required Description
author LogAuthor yes Who wrote it.
created string (date-time) yes When it was written.
id integer yes The entry id; the log is ordered by it.
kind LogKind | null no What it is, for filtering; absent on a plain entry.
node string yes The node it was written under; user for an operator note with no node in flight.
run_id string yes The run the entry belongs to.
task_id integer | null no The attempt that wrote it, when one did.
text string yes The entry itself, never truncated.

LogKind

What a work-log entry is, for filtering (the agent view drops stats).

  • 'deliverable'
  • 'note'
  • 'stats'
  • 'failure'

LogRef

The id of a work-log entry that was appended.

Field Type Required Description
log_id integer yes The id of the entry that was written.

LogText

Append an entry to a run's work log (POST /api/runs/{id}/log).

Field Type Required Description
text string yes The entry, written verbatim and never truncated.

Me

What the caller may do, and which server they are talking to.

Field Type Required Description
auth 'off', 'token' yes token when operator endpoints require a bearer token, off on a plain loopback bind.
authenticated boolean yes Whether this request carries operator rights. Always true when auth is off.
features array of string yes Optional capabilities this server has. Empty in v1.
started_at string (date-time) yes When this process came up. A change means a restart, which is the SPA's cue to refetch the plugin manifest.
version string yes The running Athanore version.

Move

Move a task's work to another node (POST /api/tasks/{id}/move).

Field Type Required Description
node string yes The node to enqueue the work at.

NewRun

Submit a run of a workflow (POST /api/workflows/{name}/runs).

The two fields become the start task's payload, which is why editing either afterwards does not rewrite it.

Field Type Required Description
description string no Longer context for the run; the workflow's input.
title string yes The operator's title for the run.

NodeOut

One node's edges and its options, as 08 §Workflows lists them.

priority and retries of null mean "the server default" and timeout of null means no wall-clock cap on one attempt — the node metadata of 04 §Node options, unresolved, because what the default is belongs to the settings of the server running it.

Field Type Required Description
description string | null no The body's docstring, unless the node overrode it.
edges array of string yes The nodes this one may transition to, in declaration order.
generation integer yes BFS depth from the start node; a loop-back edge targets a generation at or below its source.
label string yes The display name; the function's name by default.
priority integer | null no Dispatch priority, or null for the server default.
retries integer | null no Retry budget, or null for the server default.
timeout number | null no Seconds one attempt may run, or null for no cap.

NodeState

What a node is doing in one run, in 08 §Graph semantics' precedence.

Declared in precedence order, highest first, so the rule is the member order and not a table kept somewhere else. failed outranks done but is itself outranked by ready: a failed attempt whose retry is queued reports ready, because that retry row exists and the node is going to run again. idle means no task of this node was ever created in this run.

The SPA colours by this alone.

  • 'in_progress'
  • 'waiting'
  • 'ready'
  • 'dead_letter'
  • 'failed'
  • 'done'
  • 'cancelled'
  • 'idle'

Ok

An operation that succeeded and has nothing else to report.

note is the one place a router adds a sentence about how it succeeded — 08 §Runs' {ok, note?} — and is omitted when there is nothing to say rather than sent as an empty string.

Field Type Required Description
note string | null no What was unusual about the success, when anything was.
ok boolean no Always true; a failure is an error body.

PanelKind

The renderer vocabulary of 09 §Panel kinds, one member per row.

The kind fixes the shape source must return: markdown a string, kv an object, table {columns, rows}, log a list of entries, chart {series, kind}, dashboard {note?, metrics, table?}, form the name of an action, and custom nothing at all — the plugin's own web component reads what it needs through window.athanore.

A kind the SPA does not know renders a placeholder card rather than crashing the pane, so this enum is the server's vocabulary and not a promise about the browser's.

  • 'markdown'
  • 'kv'
  • 'table'
  • 'log'
  • 'chart'
  • 'dashboard'
  • 'form'
  • 'custom'

PanelOut

One panel of the manifest.

source is the mounted URL of the route the panel's data comes from, or — for a form panel — the name of the action whose model is the form. node is present only on a panel that follows one; whether that node is live travels on the run's graph rather than here, because the manifest changes only when a workflow is registered, replaced or removed, never per run (08 §Graph semantics, 22 §Live mounting).

Field Type Required Description
element string | null no The custom element tag a custom panel renders.
kind PanelKind yes Which renderer draws it, and its data shape.
name string yes The panel's title, unique within its workflow.
node string | null no The node this panel follows, when it follows one.
placement 'pane', 'card' yes A pane of its own, or a card on the run overview.
refresh_on array of string no Event-name globs that invalidate this panel's data.
scope Slot yes What has to be resolved before it can load.
slot Slot yes Where the panel is shown.
source string | null no The URL its data comes from, or the action name for a form.

PluginEvent

plugin.<workflow>.<name>: the vocabulary's open end.

The handler's data is free-form, so the wire carries whatever it passed to ctx.services.events.publish; 18 requires a JSON object, and the registry — not this model — enforces that <workflow> is the publishing workflow.

name is the only one in the union that is not a Literal, and it is declared as the whole vocabulary — EventName | str — rather than as a bare str. The two are the same set of strings, so nothing is widened; what the wider spelling buys is a reference to the enum in the generated document, which is where 08 §OpenAPI wants the event-name enum published and where the SPA's TypeScript union is generated from. The validator below is what actually narrows this field, to the plugin. namespace.

Field Type Required Description
created string (date-time) yes
data object yes
id integer | null no
name EventName | string yes
run_id string | null no
task_id integer | null no

PluginManifestEntry

What one workflow contributes to the UI.

Field Type Required Description
actions array of ActionOut no Its actions, in declaration order.
assets array of string no URLs of the JavaScript modules the SPA injects for it, each carrying a ?v= that changes when the file's bytes do.
panels array of PanelOut no Its panels, in declaration order.
workflow string yes The workflow that declared these, or _builtin for the views the core ships.

PoolHealth

One pool's capacity and what it is spending right now.

Field Type Required Description
capacity integer yes Slots the pool has, in total.
in_flight integer yes Slots leased right now.

Position

Move a run in the dispatch list (POST /api/runs/{id}/position).

Exactly one of the two. direction swaps with the neighbour above (-1) or below (+1) and is a no-op at the ends — still a 200, reporting the position the run already had. index is the zero-based list index to move to, clamped to the list; New Run's "top" is {"index": 0} and "bottom" is the default, which needs no call at all.

Field Type Required Description
direction -1, 1 | null no Swap with the neighbour above (-1) or below (1).
index integer | null no The zero-based list index to move to, clamped.

PositionOut

Where a run sits in the dispatch list after a move.

Field Type Required Description
position integer yes The run's place in the dispatch list after the move, numbered from 1. The index that asked for it is zero-based.

RegisterWorkflow

Register a workflow on the running server (POST /api/workflows).

target names the workflow as athanore serve would: module:attr or path/to/file.py:attr. The name it registers under is the loaded Workflow's own. pool must already exist on the engine — a live registration never creates one — and persist writes the [workflows.<name>] row of athanore.toml before anything is mutated, so a target that does not load is never written down.

Field Type Required Description
persist boolean no Write the registration as a [workflows.<name>] row of athanore.toml; the response then carries X-Athanore-Persisted.
pool string | null no The pool to bind the workflow to; the default pool when omitted.
target string yes The workflow to load: module:attr or path/to/file.py:attr.

ReloadWorkflow

Replace a registered workflow (PUT /api/workflows/{name}).

target omitted re-resolves the registration's recorded target — what athanore serve or an earlier registration loaded it from — and is refused when there is none. A target that now defines a differently named workflow is refused too: that is a new workflow, and POST is how it arrives. pool omitted keeps the binding the name has.

Field Type Required Description
persist boolean no Rewrite the [workflows.<name>] row of athanore.toml; the response then carries X-Athanore-Persisted.
pool string | null no The pool to move the workflow to; the current binding when omitted. Refused while any attempt of the workflow is in flight.
target string | null no The workflow to load; the registration's recorded target when omitted.

RemovedWorkflowOut

What DELETE /api/workflows/{name} did.

A body rather than a 204, because the body is the point: the caller wants to know what it interrupted. Whether a row of athanore.toml was removed is the response's X-Athanore-Persisted header, not a field — a receipt about the request belongs on the response.

Field Type Required Description
task_ids array of integer yes The attempts that were interrupted, in spawn order; empty when nothing of the workflow was in flight.
workflow string yes The name that was unregistered.

RequestAnswered

value is not in the event (may be large or sensitive); fetch it.

Field Type Required Description
author 'user', 'engine' yes
option_id string | null no
request_id integer yes

RequestAnsweredEvent

Field Type Required Description
created string (date-time) yes
data RequestAnswered yes
id integer | null no
name 'request.answered' yes
run_id string | null no
task_id integer | null no

RequestKind

What the request is about. A label for the UI; nothing keys on it.

  • 'permission'
  • 'elicitation'
  • 'question'

RequestMode

The shape of the answer a request expects.

  • 'options'
  • 'form'
  • 'text'

RequestOpened

Field Type Required Description
kind string yes
mode string yes
node string yes
ordinal integer | null no
request_id integer yes
source string yes

RequestOpenedEvent

Field Type Required Description
created string (date-time) yes
data RequestOpened yes
id integer | null no
name 'request.opened' yes
run_id string | null no
task_id integer | null no

RequestOption

One choice an options request offers.

The agent's options verbatim for an ACP permission: the operator picks under the labels the agent used, and the option_id that goes back is the one it will be given.

Field Type Required Description
kind string | null no The ACP permission kind, when the option came from one.
name string yes What to show the operator.
option_id string yes The id an answer names.

RequestSource

Who raised the request: the agent mid-turn, or the node body.

  • 'agent'
  • 'node'

RequestView

A request, its answer, and the node that asked.

schema is spelled schema_ in Python — a field named schema shadows an attribute of BaseModel — and keeps schema as its alias, which is the name 08 fixes on the wire.

Field Type Required Description
age number yes Seconds since it was opened, when it was read.
answer any no The chosen option_id, or the value of a text or form answer. Null both before an answer and for an answer that was null.
answered_by AnswerAuthor | null no Who answered; the field to test for having an answer at all.
created string (date-time) yes When the request was opened.
id integer yes The request id.
kind RequestKind yes What the request is about; a label.
mode RequestMode yes The shape of the answer expected.
node string yes The node that attempt runs.
options array of RequestOption | null no The choices, for an options request.
pending boolean yes Unanswered, with an attempt still waiting.
prompt string yes What the operator is being asked.
run_id string yes The run it belongs to.
schema object | null no The JSON Schema the answer must fit, for a form request.
source RequestSource yes Whether the agent asked mid-turn or the node body did.
stale boolean yes Unanswered, with no attempt left to consume an answer: in history, out of the inbox, and no longer answerable.
task_id integer yes The attempt that asked.
tool_call object | null no What the agent was about to do, for a permission request.

Rerun

Run a node again (POST /api/runs/{id}/rerun).

The payload and branch it last had are re-used; a rerun of a join replays the arrivals it fired on.

Field Type Required Description
node string yes The node to run again.

RunCancelled

Field Type Required Description
cancelled_tasks array of integer yes

RunCancelledEvent

Field Type Required Description
created string (date-time) yes
data RunCancelled yes
id integer | null no
name 'run.cancelled' yes
run_id string | null no
task_id integer | null no

RunChanges

The fields an edit or an op changed on a run; only those it changed.

Field Type Required Description
description string | null no
status string | null no
title string | null no

RunCompleted

output follows the shape rule of 04 §Routing edge cases.

node and task_id are the last landing task. output is required and may be null: a body that returns None terminates the run with that value, which is not the same as an unknown one.

Field Type Required Description
node string yes
output any yes
task_id integer yes
terminal_tasks array of integer yes

RunCompletedEvent

Field Type Required Description
created string (date-time) yes
data RunCompleted yes
id integer | null no
name 'run.completed' yes
run_id string | null no
task_id integer | null no

RunCreated

Field Type Required Description
position integer yes
title string yes
workflow string yes

RunCreatedEvent

Field Type Required Description
created string (date-time) yes
data RunCreated yes
id integer | null no
name 'run.created' yes
run_id string | null no
task_id integer | null no

RunDeleted

The last event of a run: it is deleted with the run, so SSE only.

Field Type Required Description
title string yes
workflow string yes

RunDeletedEvent

Field Type Required Description
created string (date-time) yes
data RunDeleted yes
id integer | null no
name 'run.deleted' yes
run_id string | null no
task_id integer | null no

RunDetail

A run, its tasks and its totals.

Field Type Required Description
created string (date-time) yes When the run was submitted.
current_nodes array of string no The nodes with an in-progress or waiting attempt right now.
description string no The operator's description.
id string yes The run id, a ULID.
output any no The run's output: one value for a single terminal task, a list in branch order when several branches terminated. Null before the run ends, and also when it ended by returning null.
outputs array of RunOutput no One entry per terminal task, always a list.
pending_requests integer no Unanswered, non-stale requests waiting on a person.
position integer yes The run's place in the dispatch list; runs are numbered 1..n in list order.
stats RunStats no The agent totals of the run.
status RunStatus yes The run state machine of 03.
tasks array of TaskView no Every attempt of the run, oldest first.
title string yes The operator's title for the run.
unregistered boolean no Whether this server has no workflow of that name registered.
updated string (date-time) yes When anything about it last changed.
workflow string yes The workflow this run executes.

RunFailed

code is set when the run stalled on a partial join.

Field Type Required Description
code 'join_incomplete' | null no
error string yes
node string yes
task_id integer yes

RunFailedEvent

Field Type Required Description
created string (date-time) yes
data RunFailed yes
id integer | null no
name 'run.failed' yes
run_id string | null no
task_id integer | null no

RunOutput

One terminal task's value, with the branch it came out of.

Field Type Required Description
branch array of BranchRef no The fan-out stack the attempt was inside, outermost first; empty for a run that never fanned out.
node string yes The node that attempt ran.
task_id integer yes The terminal attempt that produced it.
value any no What the body returned.

RunPaused

Type: object

RunPausedEvent

Field Type Required Description
created string (date-time) yes
data RunPaused yes
id integer | null no
name 'run.paused' yes
run_id string | null no
task_id integer | null no

RunReordered

Field Type Required Description
position integer yes
previous integer yes

RunReorderedEvent

Field Type Required Description
created string (date-time) yes
data RunReordered yes
id integer | null no
name 'run.reordered' yes
run_id string | null no
task_id integer | null no

RunResumed

Type: object

RunResumedEvent

Field Type Required Description
created string (date-time) yes
data RunResumed yes
id integer | null no
name 'run.resumed' yes
run_id string | null no
task_id integer | null no

RunStarted

The first claim of the run.

Field Type Required Description
node string yes
task_id integer yes

RunStartedEvent

Field Type Required Description
created string (date-time) yes
data RunStarted yes
id integer | null no
name 'run.started' yes
run_id string | null no
task_id integer | null no

RunStats

A run's agent totals, summed over its attempts.

Every field is optional and nothing is zero-filled: a provider that reported no cost leaves cost absent rather than claiming zero (01 §Real data only). duration_s is the sum of the attempts' durations and not wall-clock time, which fan-out would make meaningless.

Field Type Required Description
cost number | null no
duration_s number | null no
input_tokens integer | null no
output_tokens integer | null no
tool_calls integer | null no
total_tokens integer | null no

RunStatus

The run state machine of 03.

queued is new in v1: a run that exists but has dispatched nothing, so "waiting for a slot" is visible. The three terminal states are re-openable by retry, rerun and move.

  • 'queued'
  • 'running'
  • 'paused'
  • 'completed'
  • 'failed'
  • 'cancelled'

RunSummary

One row of the run list.

current_nodes is plural because a fan-out puts a run in several nodes at once. unregistered is not stored: it says this server has no workflow of that name registered, so the run is shown but nothing will dispatch it.

Field Type Required Description
created string (date-time) yes When the run was submitted.
current_nodes array of string no The nodes with an in-progress or waiting attempt right now.
id string yes The run id, a ULID.
pending_requests integer no Unanswered, non-stale requests waiting on a person.
position integer yes The run's place in the dispatch list; runs are numbered 1..n in list order.
status RunStatus yes The run state machine of 03.
title string yes The operator's title for the run.
unregistered boolean no Whether this server has no workflow of that name registered.
updated string (date-time) yes When anything about it last changed.
workflow string yes The workflow this run executes.

RunUpdated

Field Type Required Description
changed RunChanges yes

RunUpdatedEvent

Field Type Required Description
created string (date-time) yes
data RunUpdated yes
id integer | null no
name 'run.updated' yes
run_id string | null no
task_id integer | null no

SetStatus

Write one of the three statuses an operator may set.

The other four are the engine's own record of what happened and are not an operator's to declare.

Field Type Required Description
status 'ready', 'cancelled', 'dead_letter' yes ready re-dispatches the task, cancelled stops it, dead_letter files it as failed for good.

Slot

Where a panel is shown — 09 §Slots, one member per row.

run is a pane in the selected run's cycle or a card on its overview, task the task drawer, node a pane live only while the named node has a task in flight or has produced output, workflow the library's detail side, and global a pane shown when no run is selected.

  • 'run'
  • 'task'
  • 'node'
  • 'workflow'
  • 'global'

SourceNode

Where one node's body starts in the returned source.

Field Type Required Description
line integer yes The 1-based line of the body's first decorator or def.

SourceOut

A workflow's module source, and the line each node begins on.

nodes names the nodes whose bodies are defined in this file. A workflow may register a function imported from somewhere else; that node has no line in this source, and it is left out rather than given a number that points at the wrong text.

Field Type Required Description
file string yes The absolute path of the module the source is from.
nodes object of SourceNode yes The line each node's body starts on, for the nodes defined here.
source string yes That module's text, in full.

StreamChunk

One segment of an agent transcript.

Field Type Required Description
created string (date-time) yes When it was recorded.
kind ChunkKind yes What kind of segment this is.
seq integer yes The per-task cursor ?after= pages by.
text string yes The segment itself.

StreamOut

A page of one task's transcript.

last_seq is the highest sequence stored for the task, not the highest in this page, so a client that has caught up can tell. live says the attempt is still running — in_progress or waiting, because a waiting attempt goes on writing once its request is answered — which is what stops the SPA polling a transcript that will never grow again.

Field Type Required Description
chunks array of StreamChunk yes The page, in sequence order.
last_seq integer yes The highest sequence stored for this task.
live boolean yes Whether the attempt is still running (in_progress or waiting), so the transcript may still grow.

SubmissionAccepted

The payload itself is not in the event; fetch the task.

Field Type Required Description
node string yes
submission_id integer yes

SubmissionAcceptedEvent

Field Type Required Description
created string (date-time) yes
data SubmissionAccepted yes
id integer | null no
name 'submission.accepted' yes
run_id string | null no
task_id integer | null no

SubmissionOut

One value an agent submitted for a task.

Field Type Required Description
created string (date-time) yes When it was accepted.
id integer yes The submission id.
payload any no The value, as it was accepted.
task_id integer yes The attempt it was submitted for.

SubmissionRejected

Field Type Required Description
errors array of ValidationError yes
node string yes

SubmissionRejectedEvent

Field Type Required Description
created string (date-time) yes
data SubmissionRejected yes
id integer | null no
name 'submission.rejected' yes
run_id string | null no
task_id integer | null no

SubmissionRepair

Field Type Required Description
node string yes
reason 'nothing_submitted', 'rejected' yes
turn integer yes

SubmissionRepairEvent

Field Type Required Description
created string (date-time) yes
data SubmissionRepair yes
id integer | null no
name 'submission.repair' yes
run_id string | null no
task_id integer | null no

TaskCancelled

Field Type Required Description
from string yes
node string yes
reason 'cancel', 'move', 'delete', 'set_status' yes

TaskCancelledEvent

Field Type Required Description
created string (date-time) yes
data TaskCancelled yes
id integer | null no
name 'task.cancelled' yes
run_id string | null no
task_id integer | null no

TaskDeadLettered

Field Type Required Description
attempt integer yes
error string yes
node string yes

TaskDeadLetteredEvent

Field Type Required Description
created string (date-time) yes
data TaskDeadLettered yes
id integer | null no
name 'task.dead_lettered' yes
run_id string | null no
task_id integer | null no

TaskDetail

A task and the values submitted against it.

The operator view: 08 overloads nothing by credential, so an agent reading its own task gets a different model on a different router (/api/agent/), and this one never has a token to omit.

Field Type Required Description
attempt integer yes Which attempt of that node this row is, from 1.
branch array of athanore__api__schemas__tasks__BranchFrame no The fan-out stack this attempt is inside.
created string (date-time) yes When the row was enqueued.
error string | null no Why the attempt failed, when it did.
explicit boolean yes Whether that priority was declared on the node rather than defaulted.
finished string (date-time) | null no When it ended.
id integer yes The task id, unique across every run.
lineage object | null no Where this attempt came from: its reason and its parent.
node string yes The node whose body this attempt runs.
payload any no The value the task was enqueued with.
priority integer yes The dispatch priority this attempt was given.
result any no What the body returned, once it has.
run_id string yes The run this attempt belongs to.
started string (date-time) | null no When it was claimed.
stats object | null no The agent's measurements for this attempt; absent when nothing measured it.
status TaskStatus yes The task state machine of 03.
submissions array of SubmissionOut no Every accepted submission, oldest first.
terminal boolean yes Whether the attempt finished with no transition, making its result a branch output.

TaskDone

Field Type Required Description
attempt integer yes
node string yes
terminal boolean yes
transitions array of string yes

TaskDoneEvent

Field Type Required Description
created string (date-time) yes
data TaskDone yes
id integer | null no
name 'task.done' yes
run_id string | null no
task_id integer | null no

TaskEnqueued

branch omits key; for reason=join from_task is the fan-out task and arrivals lists the arriving tasks.

Field Type Required Description
arrivals array of integer | null no
attempt integer yes
branch array of athanore__events__payloads__BranchFrame yes
from_task integer | null no
node string yes
payload_present boolean yes
reason 'start', 'transition', 'retry', 'rerun', 'move', 'manual_retry', 'set_status', 'join' yes

TaskEnqueuedEvent

Field Type Required Description
created string (date-time) yes
data TaskEnqueued yes
id integer | null no
name 'task.enqueued' yes
run_id string | null no
task_id integer | null no

TaskFailed

Field Type Required Description
attempt integer yes
error string yes
node string yes
retry_task_id integer | null no
retryable boolean yes
will_retry boolean yes

TaskFailedEvent

Field Type Required Description
created string (date-time) yes
data TaskFailed yes
id integer | null no
name 'task.failed' yes
run_id string | null no
task_id integer | null no

TaskMoved

Field Type Required Description
new_task_id integer yes
node string yes
to string yes

TaskMovedEvent

Field Type Required Description
created string (date-time) yes
data TaskMoved yes
id integer | null no
name 'task.moved' yes
run_id string | null no
task_id integer | null no

TaskRef

The id of a task an operator verb queued.

The answer to rerun, retry and move: each of the three ends with a new attempt row, and this is its id (08 §Runs, §Tasks).

Field Type Required Description
task_id integer yes The id of the task that was enqueued.

TaskResumed

Field Type Required Description
node string yes
request_id integer yes
waited_s number yes

TaskResumedEvent

Field Type Required Description
created string (date-time) yes
data TaskResumed yes
id integer | null no
name 'task.resumed' yes
run_id string | null no
task_id integer | null no

TaskStarted

Field Type Required Description
attempt integer yes
node string yes

TaskStartedEvent

Field Type Required Description
created string (date-time) yes
data TaskStarted yes
id integer | null no
name 'task.started' yes
run_id string | null no
task_id integer | null no

TaskStatus

The task state machine of 03.

waiting is a body parked in human_input; it holds no pool slot. failed is the record of one attempt — the retry is a new row — and dead_letter is the attempt that exhausted them.

  • 'ready'
  • 'in_progress'
  • 'waiting'
  • 'done'
  • 'failed'
  • 'dead_letter'
  • 'cancelled'

TaskStatusSet

Field Type Required Description
from string yes
node string yes
to string yes

TaskStatusSetEvent

Field Type Required Description
created string (date-time) yes
data TaskStatusSet yes
id integer | null no
name 'task.status_set' yes
run_id string | null no
task_id integer | null no

TaskStream

Ephemeral; the content is fetched from /api/tasks/{id}/stream.

Field Type Required Description
seq_from integer yes
seq_to integer yes

TaskStreamEvent

Ephemeral: published to the bus and SSE, never stored, no id.

Field Type Required Description
created string (date-time) yes
data TaskStream yes
id integer | null no
name 'task.stream' yes
run_id string | null no
task_id integer | null no

TaskView

One attempt of one node in one run. Never carries a token.

Field Type Required Description
attempt integer yes Which attempt of that node this row is, from 1.
branch array of athanore__api__schemas__tasks__BranchFrame no The fan-out stack this attempt is inside.
created string (date-time) yes When the row was enqueued.
error string | null no Why the attempt failed, when it did.
explicit boolean yes Whether that priority was declared on the node rather than defaulted.
finished string (date-time) | null no When it ended.
id integer yes The task id, unique across every run.
lineage object | null no Where this attempt came from: its reason and its parent.
node string yes The node whose body this attempt runs.
payload any no The value the task was enqueued with.
priority integer yes The dispatch priority this attempt was given.
result any no What the body returned, once it has.
run_id string yes The run this attempt belongs to.
started string (date-time) | null no When it was claimed.
stats object | null no The agent's measurements for this attempt; absent when nothing measured it.
status TaskStatus yes The task state machine of 03.
terminal boolean yes Whether the attempt finished with no transition, making its result a branch output.

TaskWaiting

Field Type Required Description
node string yes
request_id integer yes

TaskWaitingEvent

Field Type Required Description
created string (date-time) yes
data TaskWaiting yes
id integer | null no
name 'task.waiting' yes
run_id string | null no
task_id integer | null no

ValidationError

One pydantic error, as ValidationError.errors() reports it.

Field Type Required Description
loc array of string | integer yes
msg string yes
type string yes

WorkflowOut

One registered workflow: its graph, its capacity, its plugins.

Field Type Required Description
capacity integer yes Slots that pool has, in total.
in_flight integer yes Slots of that pool leased right now, across every workflow bound to it.
name string yes The workflow's name, as it appears in URLs.
nodes object of NodeOut yes Every node of the finalized graph, by name.
plugin WorkflowPlugin yes What this workflow contributes to the UI.
pool string yes The pool this workflow's tasks are dispatched on.
start string yes The node a new run begins at.
target string | null no The target this workflow was loaded from (module:attr or path.py:attr), and what PUT /api/workflows/{name} without a target reloads; null for a programmatic registration.

WorkflowPlugin

The panels and actions a workflow contributes.

Both lists are empty until the plugin registry lands: the field is part of the contract now so the SPA can read a workflow's plugin surface from the workflow itself, and the entries it will carry are the manifest's own.

Field Type Required Description
actions array of object no Action declarations, as /api/plugins lists them.
panels array of object no Panel declarations, as /api/plugins lists them.

WorkflowRegistered

A workflow added to a serving server. No run_id.

target is the string it was loaded from, absent for a programmatic registration.

Field Type Required Description
pool string yes
target string | null no
workflow string yes

WorkflowRegisteredEvent

Field Type Required Description
created string (date-time) yes
data WorkflowRegistered yes
id integer | null no
name 'workflow.registered' yes
run_id string | null no
task_id integer | null no

WorkflowReplaced

A workflow's graph and plugins swapped. No run_id.

Field Type Required Description
pool string yes
target string | null no
workflow string yes

WorkflowReplacedEvent

Field Type Required Description
created string (date-time) yes
data WorkflowReplaced yes
id integer | null no
name 'workflow.replaced' yes
run_id string | null no
task_id integer | null no

WorkflowUnregistered

A workflow removed. No run_id.

task_ids are the attempts the removal interrupted.

Field Type Required Description
task_ids array of integer yes
workflow string yes

WorkflowUnregisteredEvent

Field Type Required Description
created string (date-time) yes
data WorkflowUnregistered yes
id integer | null no
name 'workflow.unregistered' yes
run_id string | null no
task_id integer | null no

athanore__api__schemas__tasks__BranchFrame

One frame of a task's fan-out stack.

Frames nest, outermost first: a branch that fans out again pushes a second frame. key is the payload that branch was given, which is the branch's identity in every list the SPA groups by it.

Field Type Required Description
count integer yes How many branches that fan-out opened.
fanout integer yes The task whose return value fanned out.
index integer yes This branch's zero-based index in that fan-out.
key any no The payload this branch was given.

athanore__events__payloads__BranchFrame

One fan-out frame of a task's branch, without its (large) key.

Field Type Required Description
count integer yes
fanout integer yes
index integer yes

The document all of this is generated from is published beside this page: openapi.json.