world.steps

List and inspect workflow step execution data with input/output hydration.

The world.steps interface provides access to individual step execution data within workflow runs. Use it to list steps, inspect their input/output, and build progress dashboards.

Import

import { getWorld } from "workflow/runtime";

const world = getWorld();
const steps = world.steps; 

Methods

get()

Retrieve a single step by run ID and step ID.

const step = await world.steps.get(runId, stepId); 

Parameters:

ParameterTypeDescription
runIdstringThe workflow run ID
stepIdstringThe step ID
params.resolveData'all' | 'none'Whether to hydrate input/output data. Default: 'all'

Returns: Step

list()

List steps with cursor pagination.

const result = await world.steps.list({ 
  runId,
  pagination: { cursor },
}); 

Parameters:

ParameterTypeDescription
params.runIdstringFilter steps by run ID
params.pagination.cursorstringCursor for the next page
params.resolveData'all' | 'none'Whether to hydrate input/output data

Returns: { data: Step[], cursor?: string }

Types

Step

FieldTypeDescription
runIdstringParent workflow run ID
stepIdstringUnique step identifier
stepNamestringMachine-readable step identifier
statusstringStep status: 'running', 'completed', 'failed'
inputanyStep input data (when resolveData: 'all')
outputanyStep output data (when resolveData: 'all')
erroranyError data if the step failed
attemptnumberCurrent retry attempt number
startedAtstringISO timestamp when the step started
completedAtstring | nullISO timestamp when the step completed
retryAfterstring | nullISO timestamp for next retry attempt

Step I/O is serialized using the devalue format. Use hydrateResourceIO() from workflow/observability to deserialize it for display. See Observability Utilities.

Examples

List Steps for a Run without Data

Use resolveData: 'none' to efficiently get step metadata for progress dashboards:

import { getWorld } from "workflow/runtime";
import { parseStepName } from "workflow/observability"; 

export async function GET(req: Request) {
  const url = new URL(req.url);
  const runId = url.searchParams.get("runId");

  if (!runId) {
    return Response.json({ error: "runId required" }, { status: 400 });
  }

  const world = getWorld();
  const steps = await world.steps.list({ 
    runId,
    resolveData: "none", // Skip I/O for performance
  }); 

  const progress = steps.data.map((step) => {
    const parsed = parseStepName(step.stepName); 
    return {
      stepId: step.stepId,
      displayName: parsed?.shortName ?? step.stepName, 
      module: parsed?.moduleSpecifier,
      status: step.status,
      startedAt: step.startedAt,
      completedAt: step.completedAt,
    };
  });

  return Response.json({ progress, cursor: steps.cursor });
}

Get Step with Hydrated Input and Output Data

Retrieve a step with its full serialized data and hydrate it for display:

import { getWorld } from "workflow/runtime";
import { parseStepName } from "workflow/observability";
import { 
  hydrateResourceIO, 
  observabilityRevivers, 
} from "workflow/observability"; 

export async function GET(req: Request) {
  const url = new URL(req.url);
  const runId = url.searchParams.get("runId");
  const stepId = url.searchParams.get("stepId");

  if (!runId || !stepId) {
    return Response.json({ error: "runId and stepId required" }, { status: 400 });
  }

  const world = getWorld();
  const step = await world.steps.get(runId, stepId); 

  const hydrated = hydrateResourceIO(step, observabilityRevivers); 
  const parsed = parseStepName(step.stepName);

  return Response.json({
    stepId: hydrated.stepId,
    displayName: parsed?.shortName ?? step.stepName,
    status: hydrated.status,
    attempt: hydrated.attempt,
    input: hydrated.input, 
    output: hydrated.output, 
  });
}

Calculate Step Duration from Timestamps

import { getWorld } from "workflow/runtime";

const world = getWorld();
const steps = await world.steps.list({ runId });

for (const step of steps.data) {
  if (step.completedAt) {
    const start = new Date(step.startedAt).getTime();
    const end = new Date(step.completedAt).getTime();
    const durationMs = end - start; 
    console.log(`${step.stepName}: ${durationMs}ms`);
  }
}

Parse Step Display Name from Machine-Readable ID

The stepName field contains a machine-readable identifier like step//./src/workflows/order//processPayment. Use parseStepName() to extract display-friendly names:

import { parseStepName } from "workflow/observability"; 

const parsed = parseStepName(step.stepName); 
// parsed.shortName → "processPayment"
// parsed.moduleSpecifier → "./src/workflows/order"

The stepName field is a machine-readable identifier, not a display name. Always use parseStepName() from workflow/observability to extract the shortName for UI display.