Workflow API

Purpose and Scope

The Workflow API is the public contract for defining finite, inspectable operations that run through a Flue application. A workflow is different from an ongoing agent conversation: it has a clear admission point, a single durable run, input validation, output handling, and an event history that can be inspected after the work is accepted. Use this API when application code should guide a bounded operation such as summarization, review, transformation, background processing, or continuous integration work rather than keeping an agent active across a long conversation.

Sources: apps/docs/src/content/docs/api/workflow-api.md

The page documents the surface exported by the runtime package and focuses on three developer decisions. First, the workflow must be created as a branded definition value. Second, the workflow must bind to an agent that supplies execution policy and the root harness used while work runs. Third, the work itself is either a reusable Action or an inline run handler that is converted into a workflow-private Action. These distinctions matter because validation, serialization, lifecycle behavior, and discovery all flow from the definition form chosen by the author.

Relevant Source Files

  • apps/docs/src/content/docs/api/workflow-api.md — Defines the reader-facing Workflow API reference, including defineWorkflow overloads, WorkflowDefinition shape, HTTP route exports, invoke semantics, and the execution lifecycle.

Core Definition Contract

The primary entry point is defineWorkflow. It has two supported shapes. In the extracted form, a caller provides an agent and an existing Action. In the inline form, a caller provides an agent, optional input and output contracts, and a run handler. Exactly one work source is allowed: either action or run. The extracted form does not accept separate input or output fields because those contracts belong to the Action. The inline form delegates to the same Action semantics, so schema validation and execution context are intentionally consistent with reusable actions.

Sources: apps/docs/src/content/docs/api/workflow-api.md

function defineWorkflow<TAction extends ActionDefinition>(options: {
  agent: AgentDefinition;
  action: TAction;
}): WorkflowDefinition<TAction>;
 
function defineWorkflow<TInput, TOutput>(options: {
  agent: AgentDefinition;
  input?: TInput;
  output?: TOutput;
  run(context: ActionContext<TInput>): unknown | Promise<unknown>;
}): WorkflowDefinition<ActionDefinition<TInput, TOutput>>;

A workflow definition should be default-exported from a discovered workflow module whose filename provides the workflow name. The definition is intentionally treated as an opaque identity rather than a plain data object to clone or reconstruct. The generated runtime associates the exact discovered default-exported value with the module name, so application code should pass around that value instead of attempting to synthesize an equivalent one. This is also why invocation APIs require the workflow value from the built application discovery graph rather than a structurally similar object.

interface WorkflowDefinition<TAction extends ActionDefinition> {
  readonly agent: AgentDefinition;
  readonly action: TAction;
}

Agents, Actions, and Inline Runs

Every workflow needs an agent, even when the workflow logic looks like ordinary application code. The agent supplies the execution policy and root harness used during the run. That harness is what lets workflow code open sessions, call models, use configured capabilities, and run within the same execution environment as other Flue resources. The agent can be private to the workflow; discovery under an agents directory is only required for persistent agent routes and dispatch use cases, not for a workflow-local harness that exists solely to execute the workflow.

Sources: apps/docs/src/content/docs/api/workflow-api.md

Choose an extracted Action when the finite operation should be shared. A reusable Action can be bound to a workflow and can also appear in an agent action list for model-facing tool use. Choose the inline form when the behavior belongs only to the workflow module and does not need a separate exported identity. Both forms converge on the Action lifecycle, so input schemas are transformed before the handler receives values, output schemas are checked after execution, and schema-invalid data is handled as part of workflow execution rather than as an ad hoc transport concern.

Invocation and Admission

The invoke function admits one workflow run through the configured runtime and returns a receipt after admission. It does not wait for the action body to finish, and it does not run HTTP route middleware. This makes invoke suitable for application code that wants to enqueue or start durable work and then track it by run identifier. The workflow argument must be the exact default export of a discovered workflow module in the current built application, which keeps invocation aligned with the generated routing and persistence model.

Sources: apps/docs/src/content/docs/api/workflow-api.md

function invoke<TWorkflow extends WorkflowDefinition>(
  workflow: TWorkflow,
  request: WorkflowInvokeRequest<TWorkflow>,
): Promise<WorkflowInvocationReceipt>;
 
interface WorkflowInvocationReceipt {
  readonly runId: string;
}

Input rules follow the workflow action contract. A workflow with an input schema requires an input value in the request, while a workflow without an input schema accepts no input property. Input is snapshotted as JSON before admission so the detached run has a stable record of what the caller submitted. Runtime validation against the Action schema occurs when the workflow executes. This split is important: admission records the request and returns a run identifier, while execution later validates, transforms, initializes resources, and produces terminal output or error state.

HTTP Exports and Run Resources

HTTP routing is deliberately not part of defineWorkflow options. Instead, a workflow module can export middleware separately. The route export controls POST access for invoking the workflow endpoint. The runs export controls operations on existing runs owned by that workflow, including metadata reads, ordinary reads, HEAD requests, unsupported methods, and future run operations. Both exports are ordinary Hono middleware, so they may return a response or call the next handler depending on authorization, filtering, or application-specific policy.

Sources: apps/docs/src/content/docs/api/workflow-api.md

export default defineWorkflow({ agent, action });
export const route: WorkflowRouteHandler = invokeMiddleware;
export const runs: WorkflowRunsHandler = runMiddleware;

The separation between route and runs prevents accidental exposure of run inspection when an author only intended to expose invocation. Without a runs export, the HTTP run resource returns the same generic not found response used for an unknown or removed workflow run. Unsupported methods return method not allowed only after Flue has resolved an exposed run and the middleware authorizes the request. These details make run routes safe to compose with application authorization because existence and method information are not leaked before the workflow run is properly exposed.

Execution Lifecycle

For each invocation, Flue follows a deterministic lifecycle. It represents omitted input as undefined and rejects non-undefined input for workflows with no input schema. It snapshots caller input, admits the run for detached execution, validates and transforms declared Action input before initializing the agent or sandbox, emits the run start event, initializes the workflow agent and root harness, executes the Action, validates and serializes output, closes invocation resources, and then persists run end with either the terminal result or the terminal error.

Sources: apps/docs/src/content/docs/api/workflow-api.md

This ordering explains several edge cases. Validation happens before expensive agent or sandbox initialization, which keeps malformed inputs from consuming unnecessary execution resources. Output validation happens after the handler completes, so a handler may perform useful work but still fail terminally if it returns a value outside the declared contract. Invocation resources close before the terminal run record is persisted, so cleanup is part of the lifecycle rather than an optional caller responsibility. Readers implementing workflows should therefore keep transport data in input, configure capabilities on the agent, and rely on run records for observation.

Compact Reference

ComponentContractPractical use
defineWorkflowCreates a branded WorkflowDefinition from an agent plus an Action or inline run handler.Default-export from a discovered workflow module.
WorkflowDefinitionContains readonly agent and action fields but should be treated as opaque identity.Pass the discovered value to runtime APIs rather than rebuilding it.
route exportWorkflowRouteHandler middleware for POST workflow invocation.Expose and authorize new HTTP workflow runs.
runs exportWorkflowRunsHandler middleware for existing run operations.Expose and authorize run inspection and run-resource methods.
invokeAdmits a run and returns a receipt with runId.Start workflow work programmatically without waiting for completion.

Next Steps

After defining a workflow, decide how it should be invoked and observed. Use direct invocation when application code controls admission. Add a route export when external HTTP callers should create runs. Add a runs export only when callers should inspect existing workflow run resources through HTTP. If the operation should be reused by agents or other workflows, extract it as an Action first and bind that Action into the workflow. If the work belongs only to one module, keep it inline and let defineWorkflow create the workflow-private Action.