workflow

25
0
Source

Creates durable, resumable workflows using Vercel's Workflow DevKit. Use when building workflows that need to survive restarts, pause for external events, retry on failure, or coordinate multi-step operations over time. Triggers on mentions of "workflow", "durable functions", "resumable", "workflow devkit", or step-based orchestration.

Install

mkdir -p .claude/skills/workflow && curl -L -o skill.zip "https://mcp.directory/api/skills/download/1105" && unzip -o skill.zip -d .claude/skills/workflow && rm skill.zip

Installs to .claude/skills/workflow

About this skill

CRITICAL: Always Use Correct workflow Documentation

Your knowledge of workflow is outdated.

The workflow documentation outlined below matches the installed version of the Workflow DevKit. Follow these instructions before starting on any workflow-related tasks:

Search the bundled documentation in node_modules/workflow/docs/:

  1. Find docs: glob "node_modules/workflow/docs/**/*.mdx"
  2. Search content: grep "your query" node_modules/workflow/docs/

Documentation structure in node_modules/workflow/docs/:

  • getting-started/ - Framework setup (next.mdx, express.mdx, hono.mdx, etc.)
  • foundations/ - Core concepts (workflows-and-steps.mdx, hooks.mdx, streaming.mdx, etc.)
  • api-reference/workflow/ - API docs (sleep.mdx, create-hook.mdx, fatal-error.mdx, etc.)
  • api-reference/workflow-api/ - Client API (start.mdx, get-run.mdx, resume-hook.mdx, etc.)
  • ai/ - AI SDK integration docs
  • errors/ - Error code documentation

Related packages also include bundled docs:

  • @workflow/ai: node_modules/@workflow/ai/docs/ - DurableAgent and AI integration
  • @workflow/core: node_modules/@workflow/core/docs/ - Core runtime (foundations, how-it-works)
  • @workflow/next: node_modules/@workflow/next/docs/ - Next.js integration

When in doubt, update to the latest version of the Workflow DevKit.

Official Resources

Quick Reference

Directives:

"use workflow";  // First line - makes async function durable
"use step";      // First line - makes function a cached, retryable unit

Essential imports:

// Workflow primitives
import { sleep, fetch, createHook, createWebhook, getWritable } from "workflow";
import { FatalError, RetryableError } from "workflow";
import { getWorkflowMetadata, getStepMetadata } from "workflow";

// API operations
import { start, getRun, resumeHook, resumeWebhook } from "workflow/api";

// Framework integrations
import { withWorkflow } from "workflow/next";
import { workflow } from "workflow/vite";
import { workflow } from "workflow/astro";
// Or use modules: ["workflow/nitro"] for Nitro/Nuxt

// AI agent
import { DurableAgent } from "@workflow/ai/agent";

Prefer Step Functions to Avoid Sandbox Errors

"use workflow" functions run in a sandboxed VM. "use step" functions have full Node.js access. Put your logic in steps and use the workflow function purely for orchestration.

// Steps have full Node.js and npm access
async function fetchUserData(userId: string) {
  "use step";
  const response = await fetch(`https://api.example.com/users/${userId}`);
  return response.json();
}

async function processWithAI(data: any) {
  "use step";
  // AI SDK works in steps without workarounds
  return await generateText({
    model: openai("gpt-4"),
    prompt: `Process: ${JSON.stringify(data)}`,
  });
}

// Workflow orchestrates steps - no sandbox issues
export async function dataProcessingWorkflow(userId: string) {
  "use workflow";
  const data = await fetchUserData(userId);
  const processed = await processWithAI(data);
  return { success: true, processed };
}

Benefits: Steps have automatic retry, results are persisted for replay, and no sandbox restrictions.

Workflow Sandbox Limitations

When you need logic directly in a workflow function (not in a step), these restrictions apply:

LimitationWorkaround
No fetch()import { fetch } from "workflow" then globalThis.fetch = fetch
No setTimeout/setIntervalUse sleep("5s") from "workflow"
No Node.js modules (fs, crypto, etc.)Move to a step function

Example - Using fetch in workflow context:

import { fetch } from "workflow";

export async function myWorkflow() {
  "use workflow";
  globalThis.fetch = fetch;  // Required for AI SDK and HTTP libraries
  // Now generateText() and other libraries work
}

Note: DurableAgent from @workflow/ai handles the fetch assignment automatically.

DurableAgent — AI Agents in Workflows

Use DurableAgent to build AI agents that maintain state and survive interruptions. It handles the workflow sandbox automatically (no manual globalThis.fetch needed).

import { DurableAgent } from "@workflow/ai/agent";
import { getWritable } from "workflow";
import { z } from "zod";
import type { UIMessageChunk } from "ai";

async function lookupData({ query }: { query: string }) {
  "use step";
  // Step functions have full Node.js access
  return `Results for "${query}"`;
}

export async function myAgentWorkflow(userMessage: string) {
  "use workflow";

  const agent = new DurableAgent({
    model: "anthropic/claude-sonnet-4-5",
    system: "You are a helpful assistant.",
    tools: {
      lookupData: {
        description: "Search for information",
        inputSchema: z.object({ query: z.string() }),
        execute: lookupData,
      },
    },
  });

  const result = await agent.stream({
    messages: [{ role: "user", content: userMessage }],
    writable: getWritable<UIMessageChunk>(),
    maxSteps: 10,
  });

  return result.messages;
}

Key points:

  • getWritable<UIMessageChunk>() streams output to the workflow run's default stream
  • Tool execute functions that need Node.js/npm access should use "use step"
  • Tool execute functions that use workflow primitives (sleep(), createHook()) should NOT use "use step" — they run at the workflow level
  • maxSteps limits the number of LLM calls (default is unlimited)
  • Multi-turn: pass result.messages plus new user messages to subsequent agent.stream() calls

For more details on DurableAgent, check the AI docs in node_modules/@workflow/ai/docs/.

Starting Workflows & Child Workflows

Use start() to launch workflows from API routes. start() cannot be called directly in workflow context — wrap it in a step function.

import { start } from "workflow/api";

// From an API route — works directly
export async function POST() {
  const run = await start(myWorkflow, [arg1, arg2]);
  return Response.json({ runId: run.runId });
}

// No-args workflow
const run = await start(noArgWorkflow);

Starting child workflows from inside a workflow — must use a step:

import { start } from "workflow/api";

// Wrap start() in a step function
async function triggerChild(data: string) {
  "use step";
  const run = await start(childWorkflow, [data]);
  return run.runId;
}

export async function parentWorkflow() {
  "use workflow";
  const childRunId = await triggerChild("some data");  // Fire-and-forget via step
  await sleep("1h");
}

start() returns immediately — it doesn't wait for the workflow to complete. Use run.returnValue to await completion.

Hooks — Pause & Resume with External Events

Hooks let workflows wait for external data. Use createHook() inside a workflow and resumeHook() from API routes.

Single event

import { createHook } from "workflow";

export async function approvalWorkflow() {
  "use workflow";

  const hook = createHook<{ approved: boolean }>({
    token: "approval-123",  // deterministic token for external systems
  });

  const result = await hook;  // Workflow suspends here
  return result.approved;
}

Multiple events (iterable hooks)

Hooks implement AsyncIterable — use for await...of to receive multiple events:

import { createHook } from "workflow";

export async function chatWorkflow(channelId: string) {
  "use workflow";

  const hook = createHook<{ text: string; done?: boolean }>({
    token: `chat-${channelId}`,
  });

  for await (const event of hook) {
    await processMessage(event.text);
    if (event.done) break;
  }
}

Each resumeHook(token, payload) call delivers the next value to the loop.

Resuming from API routes

import { resumeHook } from "workflow/api";

export async function POST(req: Request) {
  const { token, data } = await req.json();
  await resumeHook(token, data);
  return new Response("ok");
}

Error Handling

Use FatalError for permanent failures (no retry), RetryableError for transient failures:

import { FatalError, RetryableError } from "workflow";

if (res.status >= 400 && res.status < 500) {
  throw new FatalError(`Client error: ${res.status}`);
}
if (res.status === 429) {
  throw new RetryableError("Rate limited", { retryAfter: "5m" });
}

Serialization

All data passed to/from workflows and steps must be serializable.

Supported types: string, number, boolean, null, undefined, bigint, plain objects, arrays, Date, RegExp, URL, URLSearchParams, Map, Set, Headers, ArrayBuffer, typed arrays, Request, Response, ReadableStream, WritableStream.

Not supported: Functions, class instances, Symbols, WeakMap/WeakSet. Pass data, not callbacks.

Streaming

Use getWritable() to stream data from workflows. getWritable() can be called in both workflow and step contexts, but you cannot interact with the stream (call getWriter(), write(), close()) directly in a workflow function. The stream must be passed to step functions for actual I/O, or steps can call getWritable() themselves.

Get the stream in a workflow, pass it to a step:

import { getWritable } from "workflow";

export async function myWorkflow() {
  "use workflow";
  const writable = getWritable();
  await writeData(writable, "hello world");
}

async function writeData(writable: WritableStream, chunk: string) {
  "use step";
  const writer = writable.getWriter();
  try {
    await writer.write(chunk);
  } finally {
    writer.releaseLock();
  }
}

Call getWritable() directly inside a step (no need to pass it):

import { getWritable } from "workflow";

async function streamData(chunk: string) {
  "use step";
  const writer = getWritable().getWriter();
  try {
    await writer.write(chunk);
  } finally {
    writer.releaseLock();
  }
}

Debugging

# Check workflow endpoints are reachable
npx workflow health
npx workflow health --port 3001  # Non-default port

# Visual dashboard for runs
npx workflow web
npx workflow web <run_id>

# CLI inspection (use --json for machine-readable output, --help for full usage)
npx workflow inspect runs
npx workflow inspect run <run_id>

# For Vercel-deployed projects, specify backend and project
npx workflow inspect runs --backend vercel --project <project-name> --team <team-slug>
npx workflow inspect run <run_id> --backend vercel --project <project-name> --team <team-slug>

# Open Vercel dashboard in browser for a specific run
npx workflow inspect run <run_id> --web
npx workflow web <run_id> --backend vercel --project <project-name> --team <team-slug>

# Cancel a running workflow
npx workflow cancel <run_id>
npx workflow cancel <run_id> --backend vercel --project <project-name> --team <team-slug>
# --env defaults to "production"; use --env preview for preview deployments

Debugging tips:

  • Use --json (-j) on any command for machine-readable output
  • Use --web to open the Vercel Observability dashboard in your browser
  • Use --help on any command for full usage details
  • Only import workflow APIs you actually use. Unused imports can cause 500 errors.

More by vercel

View all →

web-design-guidelines

vercel

Review UI code for Web Interface Guidelines compliance. Use when asked to "review my UI", "check accessibility", "audit design", "review UX", or "check my site against best practices".

453

turborepo

vercel

Turborepo monorepo build system guidance. Triggers on: turbo.json, task pipelines, dependsOn, caching, remote cache, the "turbo" CLI, --filter, --affected, CI optimization, environment variables, internal packages, monorepo structure/best practices, and boundaries. Use when user: configures tasks/workflows/pipelines, creates packages, sets up monorepo, shares code between apps, runs changed/affected packages, debugs cache, or has apps/packages directories.

351

list-npm-package-content

vercel

List the contents of an npm package tarball before publishing. Use when the user wants to see what files are included in an npm bundle, verify package contents, or debug npm publish issues.

240

ai-sdk

vercel

Answer questions about the AI SDK and help build AI-powered features. Use when developers: (1) Ask about AI SDK functions like generateText, streamText, ToolLoopAgent, embed, or tools, (2) Want to build AI agents, chatbots, RAG systems, or text generation features, (3) Have questions about AI providers (OpenAI, Anthropic, Google, etc.), streaming, tool calling, structured output, or embeddings, (4) Use React hooks like useChat or useCompletion. Triggers on: "AI SDK", "Vercel AI SDK", "generateText", "streamText", "add AI to my app", "build an agent", "tool calling", "structured output", "useChat".

380

ai-elements

vercel

Create new AI chat interface components for the ai-elements library following established composable patterns, shadcn/ui integration, and Vercel AI SDK conventions. Use when creating new components in packages/elements/src or when the user asks to add a new component to ai-elements.

160

streamdown

vercel

Implement, configure, and customize Streamdown — a streaming-optimized React Markdown renderer with syntax highlighting, Mermaid diagrams, math rendering, and CJK support. Use when working with Streamdown setup, configuration, plugins, styling, security, or integration with AI streaming (e.g., Vercel AI SDK). Triggers on: (1) Installing or setting up Streamdown, (2) Configuring plugins (code, mermaid, math, cjk), (3) Styling or theming Streamdown output, (4) Integrating with AI chat/streaming, (5) Configuring security, link safety, or custom HTML tags, (6) Using carets, static mode, or custom components, (7) Troubleshooting Tailwind, Shiki, or Vite issues.

200

You might also like

flutter-development

aj-geddes

Build beautiful cross-platform mobile apps with Flutter and Dart. Covers widgets, state management with Provider/BLoC, navigation, API integration, and material design.

276787

drawio-diagrams-enhanced

jgtolentino

Create professional draw.io (diagrams.net) diagrams in XML format (.drawio files) with integrated PMP/PMBOK methodologies, extensive visual asset libraries, and industry-standard professional templates. Use this skill when users ask to create flowcharts, swimlane diagrams, cross-functional flowcharts, org charts, network diagrams, UML diagrams, BPMN, project management diagrams (WBS, Gantt, PERT, RACI), risk matrices, stakeholder maps, or any other visual diagram in draw.io format. This skill includes access to custom shape libraries for icons, clipart, and professional symbols.

203415

godot

bfollington

This skill should be used when working on Godot Engine projects. It provides specialized knowledge of Godot's file formats (.gd, .tscn, .tres), architecture patterns (component-based, signal-driven, resource-based), common pitfalls, validation tools, code templates, and CLI workflows. The `godot` command is available for running the game, validating scripts, importing resources, and exporting builds. Use this skill for tasks involving Godot game development, debugging scene/resource files, implementing game systems, or creating new Godot components.

197279

nano-banana-pro

garg-aayush

Generate and edit images using Google's Nano Banana Pro (Gemini 3 Pro Image) API. Use when the user asks to generate, create, edit, modify, change, alter, or update images. Also use when user references an existing image file and asks to modify it in any way (e.g., "modify this image", "change the background", "replace X with Y"). Supports both text-to-image generation and image-to-image editing with configurable resolution (1K default, 2K, or 4K for high resolution). DO NOT read the image file first - use this skill directly with the --input-image parameter.

210231

ui-ux-pro-max

nextlevelbuilder

"UI/UX design intelligence. 50 styles, 21 palettes, 50 font pairings, 20 charts, 8 stacks (React, Next.js, Vue, Svelte, SwiftUI, React Native, Flutter, Tailwind). Actions: plan, build, create, design, implement, review, fix, improve, optimize, enhance, refactor, check UI/UX code. Projects: website, landing page, dashboard, admin panel, e-commerce, SaaS, portfolio, blog, mobile app, .html, .tsx, .vue, .svelte. Elements: button, modal, navbar, sidebar, card, table, form, chart. Styles: glassmorphism, claymorphism, minimalism, brutalism, neumorphism, bento grid, dark mode, responsive, skeuomorphism, flat design. Topics: color palette, accessibility, animation, layout, typography, font pairing, spacing, hover, shadow, gradient."

168197

rust-coding-skill

UtakataKyosui

Guides Claude in writing idiomatic, efficient, well-structured Rust code using proper data modeling, traits, impl organization, macros, and build-speed best practices.

165173

Stay ahead of the MCP ecosystem

Get weekly updates on new skills and servers.