DromioWorkflow SDK
Workflow SDKAuthoringAPIWorkflow Apps & Harnesses

Design the graph

Decision treeStepsWorkflowsCompositionModels and judgmentHuman boundaries
Design the graph
Decision tree
Steps
Workflows
Composition
Models and judgment
Human boundaries

Authoring

Good workflow graphs make ownership visible. Start by deciding whether a node is a closed operation over known workflow state or an open-ended assignment that must leave that state to do its work.

Use step.model() when everything needed to answer is already in the step input. Use step.delegate() when the performer must go outside that input.

Without an external harnessYour application owns execution. Use step.model() for one closed reasoning operation.
With an external harnessThe harness owns agentic work. Use step.delegate() for a durable external assignment.

These paths can coexist in one workflow. Choose the owner separately for each piece of work; operating the workflow through a harness does not force every AI operation to become a delegation.

Decision tree​

“Use a normal function” means the work is immediate and does not need durable workflow state. “Use an agent loop” means one autonomous performer should own the whole task; a chain of model calls with no meaningful durable boundaries is not improved merely by drawing it as a workflow.

Without an external harness​

Use this path when application code and Workflow App surfaces operate the workflow directly. The application injects the model worker, starts runs, and presents durable questions or approvals through its SDK, CLI, TUI, GUI, HTTP, or other product surface.

Application-owned model work​

step.model() resolves one injected model worker, makes exactly one structured operation, supplies a JSON Schema from its declared output, and validates the returned object before the graph advances. It does not itself own browsing, tool use, conversation state, planning, subagents, or a hidden evaluator.

That boundary is an authoring rule, not a security sandbox: an injected custom worker can do arbitrary work. For new workflows, keep the model worker non-agentic and make open-ended work a visible delegation. Models and evaluation owns provider setup, worker behavior, and model lifecycle events.

Human boundaries remain available without a harness. Application code or a Workflow App surface presents step.ask() and step.approval() to the human, then submits the response so the durable graph can continue. No model router is needed merely to handle a human interaction.

Do not use step.delegate() for application-owned work when no external performer will service the resulting handoff. The run will correctly remain waiting for that contracted external result.

With an external harness​

Use this path when Codex, Claude, OpenCode, Shimex, or another harness should research, browse, use tools, manage context, or coordinate subagents. Register the workflow in a Workflow App and expose its control plane to the harness; the harness triggers or observes runs and services pending interactions.

Harness-owned delegated work​

step.delegate() does not run an agent inside Dromio. It creates a durable handoff_requested suspension containing the selected work context and output contract. The external harness owns inference, tools, context management, subagents, and its internal approvals; Dromio owns validation and graph resumption. External harnesses owns the MCP connection and lifecycle; the API reference owns every option on the handoff contract.

Release status: step.delegate() and dromio.resume_hook are public in @dromio/workflow 0.2.5. See API status for compatibility and current limits.

import { step } from "@dromio/workflow";
import { z } from "zod";

export const revisePlan = step.delegate({
id: "fundraising.revise-plan",
input: {
gaps: z.array(z.string()),
plan: z.string(),
},
artifacts: ({ input }) => [{
artifactId: "fundraising-plan",
kind: "document",
title: "Current fundraising plan",
}],
capabilities: ["browser", "document-reading"],
context: ({ input }) => ({ gaps: input.gaps, plan: input.plan }),
instructions: "Research the identified gaps and revise the plan.",
output: {
revisedPlan: z.string(),
sources: z.array(z.string().url()),
},
title: "Revise the fundraising plan",
});

The harness reads the handoff, performs the work, and submits the typed result through dromio.resume_hook. Dromio validates the result before advancing. A validation failure preserves the pending handoff so the harness can correct and retry it.

step.ask() and step.approval() still represent human boundaries. The harness may present them to the human, but it must not infer the human's answer or approval. An application-owned step.model() also remains valid inside a harness-operated workflow when all evidence for that one operation is already present in its input.

Choose the boundary​

The work needsUse
Reasoning over complete, explicit inputstep.model()
One schema-constrained classification, extraction, transformation, or scorestep.model()
Browsing, external research, files not already supplied, or arbitrary toolsstep.delegate()
Context management, multiple inference passes, or subagentsstep.delegate()
A durable human answer or decisionstep.ask() or step.approval()
A deterministic score-policy decision to route onstep.gate() or an ordinary deterministic step()

Do not add tools to step.model() merely to avoid a delegation boundary. Once the performer must discover context, choose tools, or manage its own work, it is acting as an agent and should be visible as delegated work.

Judging results​

A judge remains a good step.model() use when the plan, evidence, rubric, and threshold inputs are all supplied to it. The model returns a typed assessment. step.gate() then computes and emits a typed score-policy decision; workflow composition or routing acts on that decision. The gate does not branch by itself.

If judging requires browsing, independent verification, tool use, or multiple specialist reviewers, make the judge another step.delegate() instead. The score belongs in that delegate's output contract so Dromio can validate it and route deterministically.

An execution kind controls how a node runs. A role such as assess, revise, or judge explains what it means inside a larger workflow. The canonical definition and table are in Composition.

On this page

  • Decision tree
  • Without a harness
  • With a harness
  • Choose the boundary
  • Judging results