Skip to main content

Workflow API

Table of Contents

Top

upsquad/workflow/v1/workflow.proto

AnswerRunPromptRequest

AnswerRunPromptRequest records an answer to a mid-run user_input prompt. LBE-B2 (#2249).

FieldTypeLabelDescription
prompt_idstringprompt_id is the governance_approvals row id to answer (required).
choicestringchoice is the selected option value. Required unless the prompt is free-text-only (allow_text with no options); when set it must be one of the prompt's option values.
textstringtext is the free-text answer. Permitted only when the prompt has allow_text=true; rejected otherwise.

AnswerRunPromptResponse

AnswerRunPromptResponse reports the outcome of an answer attempt. LBE-B2 (#2249).

FieldTypeLabelDescription
recordedboolrecorded is true when THIS call won the first-write and recorded the answer. False when the prompt was already answered before this call (already_answered is then true) — the answer the client should render is the recorded one.
already_answeredboolalready_answered is true when the prompt was already resolved (this call was a benign no-op — first-write-wins). recorded is then false.
promptGetRunPromptResponseprompt is the prompt's post-answer projection (status flips to "answered" on a successful record), so the client re-renders the card from a single response.

ApproveActionRequest

ApproveActionRequest approves a workflow action.

FieldTypeLabelDescription
action_idstringaction_id is the workflow action UUID (required).
commentstringcomment is optional approval comment.

ApproveActionResponse

ApproveActionResponse contains the approved action result.

FieldTypeLabelDescription
actionWorkflowActionaction is the updated workflow action.
next_actionsWorkflowActionrepeatednext_actions are any new actions created as a result.

CancelRunRequest

CancelRunRequest cancels a workflow run.

FieldTypeLabelDescription
run_idstringrun_id is the workflow run UUID to cancel (required).
reasonstringreason is an optional human-readable note recorded in the audit log.

CancelRunResponse

CancelRunResponse returns the post-cancel run state.

FieldTypeLabelDescription
runWorkflowRunrun is the workflow run with status='cancelled' (or unchanged if the run was already terminal - idempotent).

CreateWorkflowRequest

CreateWorkflowRequest creates a new workflow.

FieldTypeLabelDescription
namestringname is the workflow name (required).
descriptionstringdescription is an optional workflow description.
definitiongoogle.protobuf.Structdefinition is the workflow definition JSON (required, validated against schema).
team_idstringteam_id is optional team scoping.
visibilitystringvisibility is the workflow's audience: "team" (default when empty — visible to its team, today's universal behaviour)

CreateWorkflowResponse

CreateWorkflowResponse contains the created workflow.

FieldTypeLabelDescription
workflowWorkflowworkflow is the created workflow.

DeleteWorkflowRequest

DeleteWorkflowRequest soft-deletes a workflow. #2002.

FieldTypeLabelDescription
workflow_idstringworkflow_id is the workflow UUID (required).

DeleteWorkflowResponse

DeleteWorkflowResponse acknowledges a soft-delete. Empty by design: the workflow is gone from List/Get after this call, so there is nothing useful to echo back. A typed response (rather than google.protobuf.Empty) leaves room to add a deleted_at timestamp or a runs-hidden count later without a breaking change. #2002.

DeliverWorkflowEventRequest

DeliverWorkflowEventRequest delivers one external event to a run parked on a signal-mode wait node. WR2-4 Slice 6 (#2266), LLD #2253 §3.4.

FieldTypeLabelDescription
run_idstringrun_id is the workflow run UUID to deliver into (required). The run is read RLS-scoped: a run owned by another org is NOT_FOUND.
event_keystringevent_key is the correlation handle the waiting node declared (dsl.Step.event_key). It must match for the wait to resolve; a delivery on a key nothing is waiting on is buffered in the run's state and consumed if a wait on that key is reached later. Required.
payloadbytespayload is the OPAQUE event body as JSON bytes. bytes rather than google.protobuf.Struct on purpose: an external event body (CI metadata, a PR number, a vendor webhook) must ride through without a proto-struct constraint. The interpreter never inspects it — it binds it verbatim as the wait node's output envelope, and the SUCCESSOR's WR2-1 expects FieldSpec is what structurally validates the shape.

Optional: an absent payload (and an explicit JSON null) both normalise to {} at the interpreter's drain, so a bare "it happened" event resolves the wait and still binds a valid empty object. | | delivery_id | string | | delivery_id is the PRODUCER-supplied identity of THIS delivery attempt (required). It is what makes an at-least-once caller safe: the platform burns (org, run_id, event_key, delivery_id) durably before signalling, so re-sending the SAME delivery_id is a no-op even after the waiting node already consumed the first one. A genuinely NEW occurrence must carry a NEW delivery_id — a retry and a second occurrence are indistinguishable without it, which is exactly why the field is required rather than optional.

Opaque to the platform: whatever stable id the caller's retry loop re-sends (a webhook delivery id, an outbox row id, a broker message id). Empty is INVALID_ARGUMENT — never a silent fall-through to the non-idempotent path. |

DeliverWorkflowEventResponse

DeliverWorkflowEventResponse reports the outcome of a delivery. WR2-4 Slice 6 (#2266).

FieldTypeLabelDescription
runWorkflowRunrun is the run's CURRENT projection. Delivery is asynchronous — the run's status transitions when the interpreter observes the signal and re-projects (the projection is the single writer of a Temporal run's status) — so this is the state at delivery time, not a post-resume state.
deduplicatedbooldeduplicated is true when this delivery_id had ALREADY been accepted for (run_id, event_key): the call was a benign no-op and NO signal was sent. An at-least-once caller can treat true exactly like a success.

EscalateActionRequest

EscalateActionRequest escalates a workflow action.

FieldTypeLabelDescription
action_idstringaction_id is the workflow action UUID (required).
commentstringcomment is optional escalation comment.

EscalateActionResponse

EscalateActionResponse contains the escalated action result.

FieldTypeLabelDescription
actionWorkflowActionaction is the updated workflow action.

GetNodeIORequest

GetNodeIORequest retrieves the input/output payloads of one workflow_action.

FieldTypeLabelDescription
run_idstringrun_id is the parent run UUID (required, used for tenant scoping).
node_idstringnode_id is the workflow_action UUID (required).

GetNodeIOResponse

GetNodeIOResponse returns the redacted input + output of a node.

FieldTypeLabelDescription
inputgoogle.protobuf.Structinput is the action's input JSON, with sensitive top-level keys stripped per the caller's clearance.
outputgoogle.protobuf.Structoutput is the action's output JSON, with sensitive top-level keys stripped per the caller's clearance. Empty if the node has not produced output yet (queued / running / blocked).
redacted_fieldsstringrepeatedredacted_fields lists every top-level key removed from input or output. Empty when no redaction occurred (caller has full clearance).

GetNodeTranscriptRequest

GetNodeTranscriptRequest retrieves the agent turn transcript of one node.

FieldTypeLabelDescription
run_idstringrun_id is the parent run UUID (required, used for run + tenant scoping).
node_idstringnode_id identifies the node whose transcript is requested (required). It accepts EITHER form (#2021): - the workflow-DAG node id, i.e. the step_name ("architect", "fetch_issue") — this is what the run-view client sends; OR - the workflow_action UUID (back-compat). Both map to the node's step_name, which keys the captured session_events. An unknown or foreign node_id yields an empty transcript (session_missing), never an error.

GetNodeTranscriptResponse

GetNodeTranscriptResponse returns the ordered, redacted transcript events of a node across ALL of its attempts.

FieldTypeLabelDescription
eventsTranscriptEventrepeatedevents are ordered by (session_id, seq, created_at). Multiple attempts interleave by session_id — each event carries its own session_id.
redacted_fieldsstringrepeatedredacted_fields lists every content field removed across all events (stable, deduplicated). Empty when no redaction occurred (caller has full clearance).
session_missingboolsession_missing is true when the node has no captured transcript — a historical / non-agent node, or one whose capture was lost (best-effort). The client renders an empty state rather than an error.

GetRunPromptRequest

GetRunPromptRequest fetches one mid-run user_input prompt's detail. LBE-B2 (#2249).

FieldTypeLabelDescription
prompt_idstringprompt_id is the governance_approvals row id the run parked on — the node's blocked_by / approval_id uuid (required). RLS-scoped to the caller's org.

GetRunPromptResponse

GetRunPromptResponse is the projected spec of a user_input prompt, plus the caller-specific can_answer verdict. LBE-B2 (#2249).

FieldTypeLabelDescription
prompt_idstringprompt_id echoes the requested row id.
questionstringquestion is the human-facing prompt headline (from prompt_spec.question).
optionsRunPromptOptionrepeatedoptions are the structured choices the operator may pick from. Empty for a free-text-only prompt.
allow_textboolallow_text permits a free-text answer in addition to (or instead of) a choice.
text_placeholderstringtext_placeholder is the display hint for the free-text field (display-only).
default_choicestringdefault_choice is the option value recorded on an on_timeout="default" expiry (surfaced so the UI can pre-select it). Empty when the prompt has no default.
required_clearanceint32required_clearance is the clearance floor a caller must clear to answer (0 when the prompt carries no floor — anyone with view access may answer).
expires_atgoogle.protobuf.Timestampexpires_at is when the prompt window closes (the on_timeout policy then fires).
statusstringstatus is the prompt lifecycle: "pending" (awaiting an answer), "answered" (resolved with an answer), or "closed" (denied / expired without an answer).
can_answerboolcan_answer reports whether THIS caller may answer the prompt right now, computed server-side from the required_clearance floor AND the answerable_by scope against the authenticated identity. False on an already-resolved prompt.
answered_bystringanswered_by is the member id (or timeout sentinel) that recorded the answer, set only when status="answered". Empty otherwise.
answered_choicestringanswered_choice is the recorded answer's choice value when status="answered" (so a re-opened card renders "answered: <choice>"). Empty on a pending prompt.
answered_textstringanswered_text is the recorded answer's free text when status="answered". Empty on a pending prompt or a choice-only answer.
asked_by_stepstringasked_by_step is the agent_action step whose agent posed this question (LBE-B3, #2292): either the DSL-declared asked_by or the last-completed agent step on the run's executed path. Empty on a pre-B3 prompt or a prompt reached before any agent turn. Recovered from the prompt row metadata (asked_by_step).
asked_by_rolestringasked_by_role is the asking step's agent_role — the human-legible identity of the agent asking (e.g. "eng"). Recovered from row metadata (asked_by_role).
asked_by_agent_idstringasked_by_agent_id is the CONCRETE deployed-agent uuid the asking step resolved its role to (workflow_actions.resolved_agent_id), so the card can deep-link to the exact agent. Empty when the step never ran a turn or on a legacy row.

GetToolCatalogRequest

GetToolCatalogRequest requests the tool_action whitelist. It carries no parameters: the whitelist is a platform-wide constant, not tenant-scoped. #2067.

GetToolCatalogResponse

GetToolCatalogResponse returns the whitelisted tools a tool_action step may invoke, each with its whitelisted actions and their argument names. #2067.

FieldTypeLabelDescription
toolsToolCatalogEntryrepeatedtools is the set of whitelisted governed tools (today: github only).

GetWorkflowRequest

GetWorkflowRequest retrieves a workflow by ID.

FieldTypeLabelDescription
workflow_idstringworkflow_id is the workflow UUID (required).

GetWorkflowResponse

GetWorkflowResponse contains the requested workflow.

FieldTypeLabelDescription
workflowWorkflowworkflow is the requested workflow.

GetWorkflowStatusRequest

GetWorkflowStatusRequest retrieves workflow run status.

FieldTypeLabelDescription
run_idstringrun_id is the workflow run UUID (required).

GetWorkflowStatusResponse

GetWorkflowStatusResponse contains workflow run status and actions.

FieldTypeLabelDescription
runWorkflowRunrun is the workflow run with status.
actionsWorkflowActionrepeatedactions are the workflow actions for this run.

ListPendingApprovalsRequest

ListPendingApprovalsRequest lists actions awaiting approval.

FieldTypeLabelDescription
agent_idstringagent_id optionally filters by assigned agent.
limitint32limit controls pagination (default: 50, max: 100).
offsetint32offset controls pagination.

ListPendingApprovalsResponse

ListPendingApprovalsResponse contains pending approvals with context.

FieldTypeLabelDescription
approvalsPendingApprovalrepeatedapprovals are the pending approval entries.
total_countint32total_count is the total number of pending approvals (for pagination).

ListRunsRequest

ListRunsRequest pages through past runs of one workflow.

FieldTypeLabelDescription
workflow_idstringworkflow_id is the workflow whose runs to list (required).
page_sizeint32page_size caps the rows in the response. Default 20, max 100. Values outside (0, 100] are clamped silently.
page_tokenstringpage_token is the opaque cursor returned by a previous ListRuns call's next_page_token. Empty starts from the newest run.
status_filterRunStatusFilterstatus_filter narrows the result set; see RunStatusFilter.

ListRunsResponse

ListRunsResponse returns one page of WorkflowRun rows.

FieldTypeLabelDescription
runsWorkflowRunrepeatedruns is the page of WorkflowRun rows ordered (started_at DESC, id DESC). nodes_total / nodes_done are populated; cost_usd reflects the engine's rolled-up cost (zero until #1127 lands the cost-meter wiring).
next_page_tokenstringnext_page_token is the cursor to pass to the next ListRuns call. Empty means no more pages.

ListVisibleRunsRequest

ListVisibleRunsRequest lists the caller's visible runs (QWP-3, #2359). Unlike ListRunsRequest there is NO workflow_id: the visibility predicate (team membership OR private ownership, both keyed off app.member_id) is the scoping.

FieldTypeLabelDescription
page_sizeint32page_size caps the rows in the response. Default 20, max 100. Values outside (0, 100] are clamped silently.
page_tokenstringpage_token is the opaque cursor returned by a previous ListVisibleRuns call's next_page_token. Empty starts from the newest run. Same keyset shape as ListRuns (started_at DESC, id DESC).
status_filterRunStatusFilterstatus_filter narrows the result set; see RunStatusFilter. The panel defaults to RUN_STATUS_FILTER_ACTIVE (pending

ListVisibleRunsResponse

ListVisibleRunsResponse is a page of VisibleRunRow ordered (started_at DESC, id DESC), plus the cursor for the next page.

FieldTypeLabelDescription
runsVisibleRunRowrepeatedruns is the page of VisibleRunRow rows the caller may see.
next_page_tokenstringnext_page_token is the cursor to pass to the next ListVisibleRuns call. Empty means no more pages.

ListWorkflowsRequest

ListWorkflowsRequest lists workflows with optional filtering.

FieldTypeLabelDescription
team_idstringteam_id optionally filters by team.
statusstringstatus optionally filters by workflow status.
limitint32limit controls pagination (default: 50, max: 100).
offsetint32offset controls pagination.

ListWorkflowsResponse

ListWorkflowsResponse contains the workflow list.

FieldTypeLabelDescription
workflowsWorkflowrepeatedworkflows is the list of workflows.
total_countint32total_count is the total number of workflows (for pagination).

NodeIOFrame

NodeIOFrame is one live LLM-I/O frame for an agent node, mirroring the wfio wire contract the orchestrator publisher tees (LBE-A1). Exactly one event arm is set.

FieldTypeLabelDescription
node_idstringnode_id is the step name the frame belongs to.
session_idstringsession_id is the attempt id (groups redos/laps; mirrors TranscriptEvent).
seqint64seq is the publisher's monotonic sequence within (run, node, session). A jump in seq means the publisher dropped frames — the client should expect a gap.
iterationint32iteration is the loop lap (mirrors NodeStatusUpdate.iteration); 0 outside a loop.
token_textstringtoken_text is a coalesced, security-filtered batch of LLM tokens. Suppressed (unset) for callers below clearance 4 (structural-frames-only floor).
tool_callNodeToolCalltool_call is a tool invocation surfaced live.
tool_resultNodeToolResulttool_result is a completed tool result surfaced live.
statusstringstatus is an agent status transition (thinking
user_promptUserPromptFrameuser_prompt is a mid-run elicitation prompt (Capability B / LBE-B). Structural, delivered at every clearance so the "answer needed" card can render.

NodeStatusUpdate

NodeStatusUpdate is a single transition or counter update for one node (workflow_action) inside the subscribed run. The frontend live-DAG keys updates by (run_id, node_id) and replaces the previous projection.

FieldTypeLabelDescription
run_idstringrun_id is the parent run UUID.
node_idstringnode_id is the workflow_action UUID.
statusstringstatus is one of: queued
elapsed_msint64elapsed_ms is wall-clock time spent in running so far for this node. For terminal nodes this is the final duration; for blocked nodes this is the time since the gate was hit.
cost_usddoublecost_usd is the running cost rolled up to this node (sum of LLM / tool costs charged to this action). Convention matches analytics.proto: USD as double.
blocked_bystringblocked_by is the approval UUID this node is waiting on when status=blocked. Empty otherwise. The frontend uses this to deep-link to ApprovalService.GetApproval.
atgoogle.protobuf.Timestampat is the timestamp of the underlying transition.
iterationint32iteration is the loop-lap ordinal for this node (WR2-2, migration 176): 0 for every non-loop step, and the 1-based lap number for a step executed inside a bounded loop's body. The live-DAG uses it to group a loop body step's repeated executions into ordered "round 1 / round 2 / ..." rows instead of collapsing them onto a single node. Additive and back-compatible: an existing consumer that ignores the field sees today's behaviour (a no-loop run streams iteration 0 everywhere). Client rendering of rounds is a separate upsquad-client task.

NodeToolCall

NodeToolCall is the live tool-invocation payload of a NodeIOFrame.

FieldTypeLabelDescription
tool_namestringtool_name is the invoked tool.
tool_call_idstringtool_call_id correlates the call with its later NodeToolResult.
args_summarystringargs_summary is a compact, clamped, redaction-safe rendering of the arguments (structural chrome; the durable + un-clamped truth is the transcript).

NodeToolResult

NodeToolResult is the live tool-result payload of a NodeIOFrame.

FieldTypeLabelDescription
tool_call_idstringtool_call_id correlates the result with its NodeToolCall.
tool_namestringtool_name is the tool that produced the result.
summarystringsummary is a compact, clamped rendering of the result. Suppressed (empty) for callers below clearance 4 — the same free-text floor as token_text.
is_errorboolis_error is true when the tool returned an error.
duration_msint32duration_ms is the tool call's wall-clock duration.

PauseRunRequest

PauseRunRequest pauses a workflow run at the next checkpoint.

FieldTypeLabelDescription
run_idstringrun_id is the workflow run UUID to pause (required).
reasonstringreason is an optional human-readable note recorded in the audit log.

PauseRunResponse

PauseRunResponse returns the post-pause run state.

FieldTypeLabelDescription
runWorkflowRunrun is the workflow run with status='paused' (or unchanged if the run was already paused / terminal - idempotent).

PendingApproval

PendingApproval represents an approval awaiting decision with context.

FieldTypeLabelDescription
actionWorkflowActionaction is the workflow action awaiting approval.
workflow_namestringworkflow_name is the parent workflow name.
agent_namestringagent_name is the assigned agent name (if available).

RejectActionRequest

RejectActionRequest rejects a workflow action.

FieldTypeLabelDescription
action_idstringaction_id is the workflow action UUID (required).
commentstringcomment is optional rejection comment.

RejectActionResponse

RejectActionResponse contains the rejected action result.

FieldTypeLabelDescription
actionWorkflowActionaction is the updated workflow action.

ResumeRunRequest

ResumeRunRequest lifts a pause on a workflow run. WF-16 (#1819).

FieldTypeLabelDescription
run_idstringrun_id is the workflow run UUID to resume (required).
reasonstringreason is an optional human-readable note recorded in the audit log.

ResumeRunResponse

ResumeRunResponse returns the run state after the resume signal is sent. WF-16 (#1819).

FieldTypeLabelDescription
runWorkflowRunrun is the workflow run. Resume is honored asynchronously by the interpreter at the next step boundary, so the returned status reflects the run's current projection (e.g. still 'paused' until the interpreter observes the signal and re-projects 'running').

RunLogLine

RunLogLine is a single log entry emitted during workflow execution.

FieldTypeLabelDescription
run_idstringrun_id is the parent run UUID.
node_idstringnode_id is the workflow_action UUID the log line belongs to. Empty for run-level events (run started, run cancelled, run paused).
levelstringlevel is one of INFO
messagestringmessage is the human-readable log line.
tgoogle.protobuf.Timestampt is the timestamp of the log emission.

RunPromptOption

RunPromptOption is one structured choice in a user_input prompt. value is the machine token that lands in the answer's choice; label/description are display-only. Mirrors the DSL PromptOption (LBE-B1). LBE-B2 (#2249).

FieldTypeLabelDescription
valuestringvalue is the machine token recorded as the answer's choice (required).
labelstringlabel is the display text for the option (optional).
descriptionstringdescription is a longer display hint for the option (optional).

SetWorkflowEnabledRequest

SetWorkflowEnabledRequest configures a workflow's trigger + the enabled gate. WF-24 (#1888), the W4 schedule pre-wiring.

FieldTypeLabelDescription
workflow_idstringworkflow_id is the workflow UUID (required).
enabledboolenabled is the schedule-firing gate (W4). false leaves the workflow manual-only / dormant.
trigger_typestringtrigger_type is "manual" (default when empty) or "schedule".
trigger_configgoogle.protobuf.Structtrigger_config is the schedule cron/interval spec (unset for manual).

SetWorkflowEnabledResponse

SetWorkflowEnabledResponse returns the workflow with its new trigger config and enabled state.

FieldTypeLabelDescription
workflowWorkflowworkflow is the updated workflow.

StreamGap

StreamGap signals that one or more NodeIOFrames were dropped between the last delivered seq and the next one, so the client can render a "stream resynced" marker and optionally refetch the snapshot. from_seq is the last seq the client saw before the gap; to_seq is the next seq it will see.

FieldTypeLabelDescription
node_idstringnode_id is the step whose frames were dropped (empty when not node-specific).
from_seqint64from_seq is the last seq delivered before the gap (0 when unknown).
to_seqint64to_seq is the first seq that will be delivered after the gap.

StreamNodeIORequest

StreamNodeIORequest subscribes to a run's live agent-step LLM I/O.

FieldTypeLabelDescription
run_idstringrun_id is the workflow run UUID to stream (required).
node_idstringnode_id optionally scopes the stream to a single agent node (step name). Empty means every agent node in the run. The snapshot honours this filter too.

StreamNodeIOResponse

StreamNodeIOResponse is one frame of the node-I/O stream. Exactly one of the oneof arms is set on any given message; snapshot_done marks the transition from the replayed transcript snapshot to live frames.

FieldTypeLabelDescription
snapshot_eventTranscriptEventsnapshot_event replays one already-captured transcript event (the verbatim GetNodeTranscript shape, clearance-redacted). Sent before snapshot_done.
liveNodeIOFramelive is a live frame coalesced from the running agent step (after snapshot_done). token_text is present only for clearance >= 4.
gapStreamGapgap signals that frames were dropped (either upstream at the publisher — a jump in seq — or in this hub for a slow subscriber). The client may refetch the snapshot to resync.
snapshot_doneboolsnapshot_done is true on the single marker frame that ends the snapshot replay and precedes the first live frame. All other fields are unset on the marker.

StreamRunLogsRequest

StreamRunLogsRequest subscribes to live log lines for one run.

FieldTypeLabelDescription
run_idstringrun_id is the workflow run UUID to subscribe to (required).

StreamRunLogsResponse

StreamRunLogsResponse wraps a single RunLogLine; same rationale as StreamRunStatusResponse - room for heartbeats / metadata without breaking the stream contract, and satisfies RPC_RESPONSE_STANDARD_NAME.

FieldTypeLabelDescription
lineRunLogLineline is the log entry.

StreamRunStatusRequest

StreamRunStatusRequest subscribes to live status transitions for one run.

FieldTypeLabelDescription
run_idstringrun_id is the workflow run UUID to subscribe to (required).

StreamRunStatusResponse

StreamRunStatusResponse wraps a single NodeStatusUpdate so the stream envelope can grow new fields (e.g. heartbeat, run-level rollup) without a breaking proto change. The wrapper is also what buf v2 lint expects for streaming RPC response naming (RPC_RESPONSE_STANDARD_NAME).

FieldTypeLabelDescription
updateNodeStatusUpdateupdate is the per-node status transition.

StreamVisibleRunsRequest

StreamVisibleRunsRequest opens the caller-scoped live run stream (QWP-3, #2359). It carries no run/workflow id: the caller's allow-set (team units + owned private workflows) is materialized server-side from app.member_id at subscribe. status_filter selects which runs the snapshot replays and which live transitions surface as "in the active set" (a run leaving the filtered set emits a leaving event so the panel drops it).

FieldTypeLabelDescription
status_filterRunStatusFilterstatus_filter narrows the snapshot + the live active set; see RunStatusFilter. The panel defaults to RUN_STATUS_FILTER_ACTIVE.

ToolCatalogAction

ToolCatalogAction is one whitelisted operation on a tool, with the argument names a tool_action step supplies under with. #2067.

FieldTypeLabelDescription
actionstringaction is the operation name (e.g. "get_issue").
descriptionstringdescription is a short human-readable label for the action.
argsToolCatalogArgrepeatedargs are the arguments the action accepts under the step's with block.

ToolCatalogArg

ToolCatalogArg describes one argument a tool_action with block may set. #2067.

FieldTypeLabelDescription
namestringname is the with key (e.g. "repo", "number", "body").
typestringtype is the JSON value type: one of string
requiredboolrequired reports whether the action requires this argument.
descriptionstringdescription is a short human-readable label for the argument.
pinned_literalboolpinned_literal marks a SECURITY-PINNED argument whose with value MUST be an author-committed literal string, never a ${...} runtime template (the WF-30 repo pin). The create-time validator enforces this generically off the SAME catalog flag, so a future pinned arg needs only the flag set — and the client step composer drives its literal-only block from this field instead of inferring it by arg name (#2084). Default false = templatable (today's behaviour for every non-repo arg). #2084.

ToolCatalogEntry

ToolCatalogEntry is one whitelisted governed tool and the actions it exposes to a tool_action step. #2067.

FieldTypeLabelDescription
toolstringtool is the governed tool namespace (e.g. "github").
descriptionstringdescription is a short human-readable label for the tool.
actionsToolCatalogActionrepeatedactions are the whitelisted operations this tool exposes.

TranscriptEvent

TranscriptEvent is one captured turn event (assistant message, tool call, or tool result), redacted per the caller's clearance.

FieldTypeLabelDescription
session_idstringsession_id is the agent session this event belongs to. A node re-run by an acceptance redo produces several sessions (attempts) for the same node; this field is preserved so the client can group events by attempt.
seqint32seq is the monotonic capture order WITHIN a session_id (stable render order for one attempt). It is NOT globally unique across attempts — group by session_id first, then order by seq.
event_typestringevent_type is one of: assistant_message
contentgoogle.protobuf.Structcontent is the event payload, with sensitive fields redacted per the caller's clearance (same discipline as GetNodeIO): assistant_message: { text } tool_call: { tool_name, tool_call_id, arguments } tool_result: { tool_call_id, tool_name, result, is_error, duration_ms }
created_atgoogle.protobuf.Timestampcreated_at is when the event was captured.

TriggerWorkflowRequest

TriggerWorkflowRequest starts workflow execution.

FieldTypeLabelDescription
workflow_idstringworkflow_id is the workflow UUID to execute (required).
contextgoogle.protobuf.Structcontext is optional execution context data.

TriggerWorkflowResponse

TriggerWorkflowResponse contains the started workflow run.

FieldTypeLabelDescription
runWorkflowRunrun is the created workflow run.

UpdateWorkflowDefinitionRequest

UpdateWorkflowDefinitionRequest edits a workflow's stored definition. #2002.

FieldTypeLabelDescription
workflow_idstringworkflow_id is the workflow UUID (required).
definitiongoogle.protobuf.Structdefinition is the new workflow definition JSON (required, validated against the same schema + semantic fences as CreateWorkflow).

UpdateWorkflowDefinitionResponse

UpdateWorkflowDefinitionResponse returns the workflow with its edited definition and bumped updated_at. #2002.

FieldTypeLabelDescription
workflowWorkflowworkflow is the updated workflow.

UpdateWorkflowStatusRequest

UpdateWorkflowStatusRequest transitions a workflow's lifecycle status. WF-24 (#1888).

FieldTypeLabelDescription
workflow_idstringworkflow_id is the workflow UUID (required).
statusstringstatus is the target lifecycle status: draft

UpdateWorkflowStatusResponse

UpdateWorkflowStatusResponse returns the workflow with its new status.

FieldTypeLabelDescription
workflowWorkflowworkflow is the updated workflow.

UserPromptFrame

UserPromptFrame is the live mid-run elicitation payload of a NodeIOFrame. It is structural (no free text is redacted) so the "answer needed" prompt surfaces at every clearance; answering flows through the (LBE-B) AnswerRunPrompt RPC keyed on prompt_id. The full question/options detail is fetched via GetRunPrompt.

FieldTypeLabelDescription
prompt_idstringprompt_id is the governance_approvals row id the answer is recorded against (== the node's blocked_by uuid). The client fetches detail via GetRunPrompt.
questionstringquestion is the prompt headline (already model-authored, not free-text tool output — surfaced at every clearance so the card is legible).
asked_by_stepstringasked_by_step is the agent_action step whose agent is posing the question (LBE-B3, #2292): either the DSL-declared asked_by or the last-completed agent step on the run's executed path. Empty on a pre-B3 run or a run with no agent turn yet. Structural — surfaced at every clearance so the card renders which agent is asking without a GetRunPrompt lookup.
asked_by_rolestringasked_by_role is that step's agent_role — the human-legible identity of the asking agent (e.g. "eng", "reviewer"). Empty when unattributed.

VisibleRunEvent

VisibleRunEvent is one caller-scoped run delta (QWP-3, #2359). It is STRUCTURAL ONLY — every field is chrome the panel renders a row from, at EVERY clearance; NO free text / token content rides this event (that stays gated on StreamNodeIO). A snapshot event and a live event share this shape; is_snapshot distinguishes replay from live, and snapshot_done marks the boundary.

FieldTypeLabelDescription
run_idstringrun_id is the workflow run this event describes.
workflow_idstringworkflow_id is the run's parent workflow.
workflow_namestringworkflow_name is the parent workflow's display name (structural label).
statusstringstatus is the public run status: pending
nodes_totalint32nodes_total is the run's total action count (populated on snapshot rows; a live status delta derived from the StatusHub tee leaves it 0 and the client keeps its last-known count — same zero-default convention as WorkflowRun.nodes_total).
nodes_doneint32nodes_done is the count of actions in a terminal status. Same populate-on- snapshot / zero-on-live-delta convention as nodes_total.
needs_inputboolneeds_input is true when the run is parked on a human user_input prompt (a governance_approvals row with action_type='user_prompt' open on the run). Derived from the StatusHub org tee, NOT from a per-run wfio subscription.
needs_approvalboolneeds_approval is true when the run is parked on an approval/question gate (a governance_approvals row with action_type='approval_gate'
asked_by_rolestringasked_by_role is the human-legible role of the agent posing the prompt/gate (e.g. "eng", "reviewer"), when known. Structural attribution — surfaces at every clearance. Empty when unattributed.
prompt_idstringprompt_id is the governance_approvals row id the panel deep-links to for the prompt/approval detail (GetRunPrompt / RecordDecision). Empty when the run is not currently parked on a prompt or gate.
leavingboolleaving is true when this run has LEFT the caller's filtered active set (it reached a terminal status, or a status filter no longer matches). The panel drops the row. Mutually exclusive with a live status update on the same run.
is_snapshotboolis_snapshot is true on the replay events emitted before snapshot_done; false on every live delta after it.
snapshot_doneboolsnapshot_done is true on the single marker event that ends the snapshot replay and precedes the first live delta. All other fields are unset on the marker.

VisibleRunRow

VisibleRunRow is the panel's list-row shape: the run plus the parent workflow's display name so the panel labels the row without a second fetch (QWP-3, #2359). The run body reuses the frozen WorkflowRun contract (nodes_total/nodes_done are populated, exactly as ListRuns); workflow_name is carried alongside because WorkflowRun itself does not hold the workflow's name.

FieldTypeLabelDescription
runWorkflowRunrun is the WorkflowRun (id, workflow_id, status, node counts, timestamps).
workflow_namestringworkflow_name is the parent workflow's display name (workflows.name).

Workflow

Workflow represents a workflow definition.

FieldTypeLabelDescription
idstringid is the workflow UUID.
org_idstringorg_id is the organization UUID.
team_idstringteam_id is the optional team UUID.
namestringname is the workflow name.
descriptionstringdescription is the workflow description.
definitiongoogle.protobuf.Structdefinition is the workflow definition JSON.
created_bystringcreated_by is the creator UUID.
statusstringstatus is the workflow status (draft, active, archived).
created_atgoogle.protobuf.Timestampcreated_at is the creation timestamp.
deleted_atgoogle.protobuf.Timestampdeleted_at is the optional deletion timestamp.
trigger_typestringtrigger_type is how the workflow is triggered: "manual" (default) or "schedule". Backed by workflows.trigger_type (migration 151, WF-23 #1887).
enabledboolenabled gates schedule firing (W4). Always false for a manual workflow, and false for any workflow until an operator opts in via SetWorkflowEnabled. Backed by workflows.enabled (migration 151); a behavioral no-op until W4.
last_run_statusstringlast_run_status is the status of this workflow's most recent run ("" when it has never run). ROLLUP field — WF-25 computes it; this RPC (WF-24 #1888) lays the field and returns the zero value.
last_run_atgoogle.protobuf.Timestamplast_run_at is when this workflow's most recent run started. ROLLUP — WF-25 computes it; unset here.
run_countint32run_count is the total number of runs this workflow has had. ROLLUP — WF-25 computes it; 0 here.
avg_cost_usddoubleavg_cost_usd is the mean rolled-up cost across this workflow's runs. ROLLUP — WF-25 computes it; 0 here. USD as double (analytics.proto convention).
updated_atgoogle.protobuf.Timestampupdated_at is the last-modification timestamp, maintained by a BEFORE UPDATE trigger (migration 166) that stamps now() on every UPDATE — definition edits (UpdateWorkflowDefinition, #2002), status changes, enable toggles, and the soft-delete write. A client compares it against a cached value to detect staleness. Backfilled to created_at for pre-migration rows so an untouched workflow never looks freshly modified.
visibilitystringvisibility is the workflow's audience, backed by workflows.visibility (migration 187): "team" (default — visible to its team)

WorkflowAction

WorkflowAction represents an individual step within a workflow run.

FieldTypeLabelDescription
idstringid is the action UUID.
run_idstringrun_id is the parent run UUID.
org_idstringorg_id is the organization UUID.
step_namestringstep_name is the workflow step name.
agent_idstringagent_id is the assigned agent UUID.
statusstringstatus is the action status (pending, in_progress, awaiting_approval, approved, rejected, escalated, completed, failed).
inputgoogle.protobuf.Structinput is the step input data.
outputgoogle.protobuf.Structoutput is the step output data.
decided_bystringdecided_by is the decision maker UUID.
decided_atgoogle.protobuf.Timestampdecided_at is the decision timestamp.
created_atgoogle.protobuf.Timestampcreated_at is the creation timestamp.
approval_idstringapproval_id is the governance_approvals row this step is waiting on, populated when the engine creates an approval as part of an approval_gate / escalated step. Empty otherwise. The frontend uses this to deep-link the live-DAG inspector to /approvals/<id> (#1109).
cost_usddoublecost_usd is the rolled-up cost charged to this action (LLM tokens + tool execution). Convention matches analytics.proto: USD as double (#1111). Populated by engine on transition; see #1127 (engine cost-meter wiring is the follow-up that actually writes non-zero values). Until #1127 lands this field is always 0.
elapsed_msint64elapsed_ms is the wall-clock time spent in in_progress for this action. For terminal actions this is the final duration. Engine updates on every transition (#1111).

WorkflowRun

WorkflowRun represents a workflow execution instance.

FieldTypeLabelDescription
idstringid is the run UUID.
workflow_idstringworkflow_id is the parent workflow UUID.
org_idstringorg_id is the organization UUID.
triggered_bystringtriggered_by is the trigger user UUID.
statusstringstatus is the run status: pending
contextgoogle.protobuf.Structcontext is the execution context data.
started_atgoogle.protobuf.Timestampstarted_at is the execution start timestamp.
completed_atgoogle.protobuf.Timestampcompleted_at is the execution completion timestamp.
created_atgoogle.protobuf.Timestampcreated_at is the creation timestamp.
cost_usddoublecost_usd is the rolled-up cost across every action in this run. Populated by engine on transition; see #1127 (engine cost-meter wiring is the follow-up that actually writes non-zero values). Until #1127 lands this field is always 0.
paused_atgoogle.protobuf.Timestamppaused_at is set when the run was last paused via PauseRun (#1110); cleared on resume.
cancelled_atgoogle.protobuf.Timestampcancelled_at is set when the run was cancelled via CancelRun (#1110).
nodes_totalint32nodes_total is the count of workflow_actions rows for this run. Populated by ListRuns (#1074); other RPCs leave it at 0 since they surface action lists directly. Convention: -1 is never used; an unpopulated total is 0 and the consumer falls back to the actions array length when present.
nodes_doneint32nodes_done is the count of workflow_actions in a terminal status ('approved'

RunStatusFilter

RunStatusFilter selects which subset of WorkflowRun rows ListRuns returns. Mirrors the four buckets the redesigned Workflows page renders in its segmented control. UNSPECIFIED maps to ALL (no filtering) so an unset filter on the wire returns the most-permissive response, matching proto3 default-zero ergonomics.

GAP-31 (#1074).

NameNumberDescription
RUN_STATUS_FILTER_UNSPECIFIED0RUN_STATUS_FILTER_UNSPECIFIED returns runs in any status (== ALL).
RUN_STATUS_FILTER_ACTIVE1RUN_STATUS_FILTER_ACTIVE returns runs where status IN ('pending', 'running', 'paused').
RUN_STATUS_FILTER_COMPLETED2RUN_STATUS_FILTER_COMPLETED returns runs where status = 'completed'.
RUN_STATUS_FILTER_FAILED3RUN_STATUS_FILTER_FAILED returns runs where status IN ('failed', 'cancelled'). Cancelled is grouped with failed because the dashboard surfaces both as "did not complete successfully".
RUN_STATUS_FILTER_ALL4RUN_STATUS_FILTER_ALL returns runs in any status. Semantically the same as UNSPECIFIED; provided so callers can be explicit.

WorkflowService

WorkflowService provides lifecycle management for workflows, execution triggering, and approval chain operations.

2026-04-26 redesign extension (tracker #1031): adds streaming RPCs for live-DAG rendering (StreamRunStatus #1046, StreamRunLogs #1107), clearance-gated step I/O (GetNodeIO #1108), an approval_id deep-link on WorkflowAction (#1109), idempotent run-control RPCs (PauseRun + CancelRun #1110), and per-action / per-run cost tracking fields (#1111).

Method NameRequest TypeResponse TypeDescription
CreateWorkflowCreateWorkflowRequestCreateWorkflowResponseCreateWorkflow creates a new workflow with definition validation.
GetWorkflowGetWorkflowRequestGetWorkflowResponseGetWorkflow retrieves a workflow by ID.
ListWorkflowsListWorkflowsRequestListWorkflowsResponseListWorkflows lists workflows for an organization with filtering.
TriggerWorkflowTriggerWorkflowRequestTriggerWorkflowResponseTriggerWorkflow starts execution of a workflow.
GetWorkflowStatusGetWorkflowStatusRequestGetWorkflowStatusResponseGetWorkflowStatus retrieves the current status of a workflow run.
ApproveActionApproveActionRequestApproveActionResponseApproveAction approves a workflow action awaiting approval.
RejectActionRejectActionRequestRejectActionResponseRejectAction rejects a workflow action awaiting approval.
EscalateActionEscalateActionRequestEscalateActionResponseEscalateAction escalates a workflow action to higher clearance.
ListPendingApprovalsListPendingApprovalsRequestListPendingApprovalsResponseListPendingApprovals lists workflow actions awaiting approval.
StreamRunStatusStreamRunStatusRequestStreamRunStatusResponse streamStreamRunStatus opens a server-streaming RPC that emits a NodeStatusUpdate every time a workflow_action row in the given run transitions (queued -> running -> done

Tenant isolation: the stream's org_id is taken from the JWT-derived ambient scope. Events for any other tenant are dropped before reaching the wire. The Hub also validates the requested run_id belongs to the caller's tenant on subscribe.

GAP-29 (#1046). | | StreamRunLogs | StreamRunLogsRequest | StreamRunLogsResponse stream | StreamRunLogs opens a server-streaming RPC that emits RunLogLine messages as workflow execution writes log entries. Backed by the Postgres LISTEN/NOTIFY channel workflow_run_logs (migration 086).

GAP-30 (#1107). | | GetNodeIO | GetNodeIORequest | GetNodeIOResponse | GetNodeIO returns the input and output JSON of a single workflow_action, with sensitive fields redacted based on the caller's clearance level (compared against the workflow's data_classification - workflow_actions is registered as Operational+High in classregistry).

The redacted_fields list names every top-level key that was stripped from input or output so the UI can render a "redacted" placeholder rather than silently lying about completeness.

GAP-32 (#1108). | | GetNodeTranscript | GetNodeTranscriptRequest | GetNodeTranscriptResponse | GetNodeTranscript returns the agent's TURN TRANSCRIPT for one node — the intermediate reasoning/tool trail (assistant messages, tool calls, tool results) that FoldStream discards after keeping only the final output. Reads the session_events captured at fold time (migration 160, #1969 PR-1) by (run_id, step_name), org-scoped and run-scoped fail-closed exactly like GetNodeIO. Content is clearance-redacted on READ via the same RedactStruct discipline (raw at rest, redact at the boundary).

A node re-executed by an acceptance redo (#1966) has MULTIPLE agent sessions (attempts) for the same (run_id, step_name); this RPC returns ALL of their events with each event's session_id preserved, so the client can group the transcript by attempt without losing history.

#1969 PR-3. | | StreamNodeIO | StreamNodeIORequest | StreamNodeIOResponse stream | StreamNodeIO streams a run's agent-step LLM I/O: a snapshot of the already- captured transcript events (clearance-redacted, from session_events, the same read+redact path GetNodeTranscript uses), then a snapshot_done marker, then LIVE frames coalesced from the worker as the agent thinks/acts.

The live frames arrive over a new in-memory NodeIOHub in the context-engine, fed by the Redis pub/sub channel wfio:{org}:{run} the orchestrator publisher tees (LBE-A1). Subscribe-before-snapshot ordering (#1962): the hub subscription opens FIRST so no frame fired during the snapshot read is lost; the client dedups the snapshot↔live overlap by (session_id, seq).

Live redaction floor (byte-consistent with post-hoc GetNodeTranscript): a caller with clearance >= 4 receives full frames including token_text; a caller with clearance < 4 receives STRUCTURAL frames only (status, tool_call name/id, tool_result is_error/timing, user_prompt) — token_text is suppressed server-side in the CE adapter, exactly what GetNodeTranscript would redact for that clearance.

Backpressure: the hub delivers to a per-subscriber buffered channel; on a full buffer (slow client) it REPLACES the overflow with a synthesized StreamGap so the client renders "stream resynced" and may refetch the snapshot rather than silently missing frames. The Redis-subscribe reader never blocks.

Additive to the frozen MVP contract. LBE-A2 (#2240), HLD #2233 §1.2. | | PauseRun | PauseRunRequest | PauseRunResponse | PauseRun marks the run as PAUSED at the next checkpoint. Idempotent - calling PauseRun on an already-paused or terminal run returns the current state without erroring. Audit-logged.

GAP-34 (#1110). | | CancelRun | CancelRunRequest | CancelRunResponse | CancelRun halts the run and marks status=CANCELLED. Idempotent. Audit-logged.

GAP-34 (#1110). | | ResumeRun | ResumeRunRequest | ResumeRunResponse | ResumeRun lifts a pause on a workflow run, letting execution continue from the parked step. This is the Temporal-era counterpart to PauseRun: it sends the resume signal (internal/temporalwf/api.SignalResume) to the run's Temporal execution, which clears the interpreter's pause flag so the walk advances at the next boundary. Idempotent — resuming a run that is not paused is a harmless no-op signal.

Requires Temporal execution (TEMPORAL_ENABLED). On a deployment where Temporal is disabled — or against a terminal run — ResumeRun returns FAILED_PRECONDITION: the legacy engine has no resumable pause state, so there is nothing to resume. Additive to the frozen 16-RPC MVP contract (LLD #1798 §4), WF-16 (#1819). | | ListRuns | ListRunsRequest | ListRunsResponse | ListRuns returns past run metadata for a single workflow, ordered newest-started first. Cursor-paginated on (started_at DESC, id DESC). RLS-scoped — only runs owned by the caller's org are returned.

Powers the Dashboard "Active workflows" panel and the redesigned Workflows page run-history view (workflows.jsx). Per-node detail is intentionally out of scope (use GetWorkflowStatus / StreamRunStatus — GAP-29).

GAP-31 (#1074). | | UpdateWorkflowStatus | UpdateWorkflowStatusRequest | UpdateWorkflowStatusResponse | UpdateWorkflowStatus transitions a workflow's lifecycle status (draft | active | archived). Additive to the frozen MVP contract (LLD #1798 §4). WF-24 (#1888). | | SetWorkflowEnabled | SetWorkflowEnabledRequest | SetWorkflowEnabledResponse | SetWorkflowEnabled configures a workflow's trigger (manual | schedule + schedule config) and the enabled gate that W4 schedule firing reads (LLD #1798 §2.2 disable-race). Behavioral no-op until W4 wires schedules: the RPC writes workflows.enabled / trigger_type / trigger_config, but nothing reads them yet, and manual runs are unaffected. Additive to the frozen MVP contract. WF-24 (#1888), backed by the WF-23 (#1887) store surface. | | UpdateWorkflowDefinition | UpdateWorkflowDefinitionRequest | UpdateWorkflowDefinitionResponse | UpdateWorkflowDefinition edits a workflow's stored definition (the typed DAG). The new definition is validated through the SAME SchemaValidator.ValidateDefinition path as CreateWorkflow — an invalid definition (unknown step type, dangling next/on_approve reference, or a fenced case such as the WF-30 tool_action literal-repo rule) is rejected with INVALID_ARGUMENT and the stored definition is left untouched.

Run-immunity semantics (documented contract): editing the definition does NOT affect in-flight runs. A Temporal-managed run boots its definition from the run's own Temporal history (the interpreter walks the DAG captured at StartWorkflow), so a mid-flight edit cannot mutate a running walk. Runs started AFTER the edit commits pick up the new definition. Each edit bumps workflows.updated_at (migration 166) so a client can detect staleness; the workflow id is stable (this is an in-place edit, not a create-new + archive-old versioning scheme).

Guarded exactly like CreateWorkflow: RLS scopes the write to the caller's org (a foreign/missing workflow reads as NotFound), and the same icsBypassOnly auth surface applies. #2002. | | DeleteWorkflow | DeleteWorkflowRequest | DeleteWorkflowResponse | DeleteWorkflow soft-deletes a workflow: it stamps workflows.deleted_at = now(). After delete the workflow disappears from ListWorkflows / GetWorkflow (both already filter deleted_at IS NULL). Idempotent — deleting an already-deleted (undiscoverable) workflow returns NotFound, matching Get.

Run-data semantics (documented contract): a soft-delete does NOT purge the workflow's runs, actions, or logs. The audit trail is preserved (CLAUDE.md: every action is auditable). The runs become UNDISCOVERABLE through the workflow — ListWorkflows no longer surfaces the parent, so a client cannot reach ListRuns for it without an out-of-band workflow_id — but any run row already known by id remains readable by GetWorkflowStatus until a DB-admin retention sweep hard-deletes it. Hard-delete of run data stays a DB-admin operation; this RPC adds no destructive cascade.

Governed exactly like archive (UpdateWorkflowStatus): RLS scopes the write, same icsBypassOnly auth surface. #2002. | | GetToolCatalog | GetToolCatalogRequest | GetToolCatalogResponse | GetToolCatalog returns the create-time tool_action whitelist (WF-30) — the (tool, action, args) surface a tool_action step may name — from the single Go source of truth shared with the definition validator. The client step composer reads it so it never hard-codes a copy of the whitelist that could drift from what CreateWorkflow accepts. Read-only, tenant-independent (the whitelist is a platform constant), additive to the frozen MVP contract. #2067. | | GetRunPrompt | GetRunPromptRequest | GetRunPromptResponse | GetRunPrompt returns the detail of a mid-run user_input prompt (Track B elicitation, LBE-B2 #2249). prompt_id is the node's blocked_by uuid — the governance_approvals row the run parked on (action_type='user_prompt', migration 181). It projects the typed question the step posed (question, options[], allow_text, text_placeholder, default_choice) plus the row's required_clearance, expires_at, and status, and computes can_answer SERVER-SIDE for THIS caller — the clearance floor AND the answerable_by scope ("" | "anyone" | "requester") are evaluated against the authenticated identity, so the client renders a live "you may answer" affordance without duplicating the authz. The row is RLS-scoped to the caller's org: a foreign prompt_id reads as NotFound.

Additive to the frozen MVP contract. LBE-B2 (#2249), HLD #2233 §2. | | AnswerRunPrompt | AnswerRunPromptRequest | AnswerRunPromptResponse | AnswerRunPrompt records an answer to a mid-run user_input prompt (LBE-B2 #2249). It writes the answer envelope {choice, text, answered_by} through B1's authoritative FIRST-WRITE path (approval.Service.RecordDecision → Store.TryResolveWithPayload — the same CAS that flips the row to answered and fans the DecisionPublisher signal that RESUMES the parked run); it does NOT reinvent the record. Authz is enforced SERVER-SIDE before the write: the caller must clear the row's required_clearance floor AND satisfy its answerable_by scope (answerable_by="requester" ⇒ only the run's triggerer may answer). A second answer to an already-answered prompt is a NO-OP (first-write-wins): the RPC returns already_answered=true carrying the recorded answer rather than erroring. A foreign prompt_id is NotFound; a wrong-clearance / wrong-answerer caller is PermissionDenied.

Additive to the frozen MVP contract. LBE-B2 (#2249), HLD #2233 §2. | | DeliverWorkflowEvent | DeliverWorkflowEventRequest | DeliverWorkflowEventResponse | DeliverWorkflowEvent delivers an external event to a run parked on a signal-mode wait node (WR2-4 Slice 6, #2266; LLD #2253 §3.4). It signals the run's Temporal execution with external_event; the interpreter's drain moves the payload into the wait node's correlation slot and the parked wait resolves, binding the payload as the node's output envelope.

⚠ SCOPE — THIS IS THE CONSUME CONTRACT, NOT INGESTION (founder scope call on HLD #2223, LLD §0). The caller already KNOWS (run_id, event_key). Untrusted webhook INGESTION — a subscription registry that resolves an external correlation key to a waiting (run_id, event_key), HMAC verification, replay protection — is an explicit fast-follow and is OUT of scope. THIS RPC IS THE ENTIRE SEAM it attaches to: that adapter, when built, performs only the resolution and calls this RPC. No signal shape, no drain and no wait-node change is required for it.

IDEMPOTENCY IS BY delivery_id, NOT BY event_key. A wait CONSUMES its slot when it resolves, so a retried delivery that lands after the first was consumed could otherwise satisfy a LATER wait on the same event_key (the next lap of a loop body) — an advance on an event that never occurred twice. This RPC therefore burns (org, run_id, event_key, delivery_id) durably BEFORE signalling: a retry is a no-op that never reaches the run, and deduplicated is true on the response. delivery_id is REQUIRED (an empty one is INVALID_ARGUMENT, never a silent fall-through to the non-idempotent path).

AUTHORIZATION — state precisely what is enforced, because this is a frozen public contract and an overstated control here gets cited later as evidence the surface is covered. What gates this RPC is:

  1. an AUTHENTICATED principal, and 2. ORG-SCOPED ROW-LEVEL SECURITY: the run is read back through the request's RLS-bound scope transaction, so a run owned by another org reads zero rows and the caller gets NOT_FOUND — indistinguishable from "does not exist". Every org this handler then uses (the dedupe-ledger key, the audit row, the derived Temporal execution id) is that authoritative workflow_runs.org_id, NEVER ambient request input.

There is NO per-action RBAC on this RPC, and there is none on PauseRun / CancelRun / ResumeRun either: WorkflowService is mounted with the authenticate-only interceptor (no RBAC interceptor). So any authenticated caller in the owning org may deliver an event to that org's run, exactly as any such caller may pause, cancel or resume it. This RPC introduces no new authority — it is at parity with its siblings, no wider.

⚠ LLD #2253 O4 said this RPC "reuses the run-control entitlement". That premise was false — no such per-action entitlement exists — and the LLD is being corrected. Whether these run-control RPCs SHOULD carry one is tracked separately (#2362); a narrower event-delivery capability remains a future refinement, not something this contract already provides.

unknown / foreign run -> NOT_FOUND terminal run -> FAILED_PRECONDITION empty event_key -> INVALID_ARGUMENT empty delivery_id -> INVALID_ARGUMENT Temporal disabled -> FAILED_PRECONDITION

Additive to the frozen MVP contract. WR2-4 (#2266), LLD #2253 §3.4. | | ListVisibleRuns | ListVisibleRunsRequest | ListVisibleRunsResponse | ListVisibleRuns returns the runs whose parent workflow the CALLER may see — the Quad Workflows Panel's caller-scoped run list (QWP-3, #2359, HLD #2347). Visibility is two arms (HLD §A): a workflow whose team_id is one of the caller's team units, OR a private workflow the caller owns. A caller in NONE of a workflow's teams and NOT its owner sees NOTHING for it. Unlike ListRuns (single workflow) this lists ACROSS workflows; it is RLS-scoped to the caller's org (no cross-org leak) AND filtered by app.member_id (SET LOCAL per request). Cursor-paginated on (started_at DESC, id DESC) — same keyset as ListRuns. The panel defaults status_filter to ACTIVE. | | StreamVisibleRuns | StreamVisibleRunsRequest | VisibleRunEvent stream | StreamVisibleRuns is the live analogue of ListVisibleRuns: a snapshot of the caller's currently-visible runs, a snapshot_done marker, then live VisibleRunEvent deltas (status transition / a run entering or leaving the caller's active set / needs_input / needs_approval). It REUSES the existing StatusHub org tee (Subscribe(org,""), the single process-wide LISTEN on workflow_run_status) filtered per-subscriber against the caller's allow-set — it does NOT open a per-run wfio subscription (that is StreamNodeIO's job for the single selected run). VisibleRunEvent is STRUCTURAL only — name, status, node counts, needs_input/needs_approval, asked_by_role, prompt_id — surfacing at EVERY clearance; no free text / tokens ride this event. QWP-3 (#2359). |

Scalar Value Types

.proto TypeNotesC++JavaPythonGoC#PHPRuby
doubledoubledoublefloatfloat64doublefloatFloat
floatfloatfloatfloatfloat32floatfloatFloat
int32Uses variable-length encoding. Inefficient for encoding negative numbers – if your field is likely to have negative values, use sint32 instead.int32intintint32intintegerBignum or Fixnum (as required)
int64Uses variable-length encoding. Inefficient for encoding negative numbers – if your field is likely to have negative values, use sint64 instead.int64longint/longint64longinteger/stringBignum
uint32Uses variable-length encoding.uint32intint/longuint32uintintegerBignum or Fixnum (as required)
uint64Uses variable-length encoding.uint64longint/longuint64ulonginteger/stringBignum or Fixnum (as required)
sint32Uses variable-length encoding. Signed int value. These more efficiently encode negative numbers than regular int32s.int32intintint32intintegerBignum or Fixnum (as required)
sint64Uses variable-length encoding. Signed int value. These more efficiently encode negative numbers than regular int64s.int64longint/longint64longinteger/stringBignum
fixed32Always four bytes. More efficient than uint32 if values are often greater than 2^28.uint32intintuint32uintintegerBignum or Fixnum (as required)
fixed64Always eight bytes. More efficient than uint64 if values are often greater than 2^56.uint64longint/longuint64ulonginteger/stringBignum
sfixed32Always four bytes.int32intintint32intintegerBignum or Fixnum (as required)
sfixed64Always eight bytes.int64longint/longint64longinteger/stringBignum
boolboolbooleanbooleanboolboolbooleanTrueClass/FalseClass
stringA string must always contain UTF-8 encoded or 7-bit ASCII text.stringStringstr/unicodestringstringstringString (UTF-8)
bytesMay contain any arbitrary sequence of bytes.stringByteStringstr[]byteByteStringstringString (ASCII-8BIT)