Now liveThe Skillselion MCP - thousands of ranked skills, loaded into your agent mid-task. No install.Get it →
andrelandgraf avatar

Workflow Best Practices

  • 53 installs
  • 18 repo stars
  • Updated June 8, 2026
  • andrelandgraf/fullstackrecipes

Workflow-best-practices is a Claude skill for building durable workflows with the Workflow Development Kit using steps, streaming, agent runs, and persistence.

About

Workflow-best-practices builds durable workflows with the Workflow Development Kit. It covers the 'use workflow' orchestration and 'use step' checkpoint directives, streaming agent runs, and persisting results. A developer uses it when authoring, starting, resuming, or persisting a workflow.

  • Orchestration functions use 'use workflow'; durable checkpoints use 'use step'
  • Wraps agent runs with startStream/finishStream frames for the chat transport
  • Supports starting and resuming runs via start and getRun

Workflow Best Practices by the numbers

  • 53 all-time installs (skills.sh)
  • Ranked #1,063 of 2,715 Automation & Workflows skills by installs in the Skillselion catalog
  • Data as of Jul 28, 2026 (Skillselion catalog sync)
At a glance

workflow-best-practices capabilities & compatibility

Capabilities
orchestration
Use cases
orchestration
From the docs

What workflow-best-practices says it does

Build durable workflows with steps, streaming, and agent execution.
SKILL.md
Steps are durable checkpoints that persist their results.
SKILL.md
npx skills add https://github.com/andrelandgraf/fullstackrecipes --skill workflow-best-practices

Add your badge

Show developers this skill is listed on Skillselion. Paste this into your README.

Listed on Skillselion
Installs53
repo stars18
Last updatedJune 8, 2026
Repositoryandrelandgraf/fullstackrecipes

What it does

Builds durable workflows with the Workflow Development Kit using steps, streaming, agent runs, and persistence.

Who is it for?

Developers building durable, resumable agent workflows with streaming on the Workflow Development Kit.

Skip if: Projects not using the Workflow Development Kit.

When should I use this skill?

Authoring, starting, resuming, or persisting a workflow.

What you get

  • Durable workflow orchestration and step functions
  • Resumable streamed agent runs

Files

SKILL.mdMarkdownGitHub ↗

Workflow Best Practices

Build durable workflows with steps, streaming, and agent execution.

Prerequisites

Complete these setup recipes first:

  • Workflow Development Kit Setup

Folder Structure

Each workflow gets a subfolder under src/workflows/. index.ts orchestrates ("use workflow"); steps/ holds durable checkpoints ("use step"); shared steps live in the top-level steps/.

src/workflows/
  steps/           # shared step functions (e.g. stream helpers)
    stream.ts
  chat/
    index.ts       # orchestration ("use workflow")
    steps/         # workflow-specific steps ("use step")
      history.ts
      logger.ts
      name-chat.ts
    types.ts       # UI message types

Creating a Workflow

The orchestration function carries "use workflow" and calls steps. Always wrap an agent run with startStream(messageId) before and finishStream() after — WorkflowChatTransport needs the start/finish frames to parse the response.

// src/workflows/chat/index.ts
import { getWorkflowMetadata, getWritable } from "workflow";
import { startStream, finishStream } from "../steps/stream";
import { chatAgent } from "@/lib/ai/chat-agent";

export async function chatWorkflow({ chatId, userMessage }) {
  "use workflow";

  const { workflowRunId } = getWorkflowMetadata();

  await persistUserMessage({ chatId, message: userMessage });

  // runId lets clients resume this stream later
  const messageId = await createAssistantMessage({
    chatId,
    runId: workflowRunId,
  });
  const history = await getMessageHistory(chatId);

  await startStream(messageId);
  const { parts } = await chatAgent.run(history, {
    maxSteps: 10,
    writable: getWritable(),
  });
  await persistMessageParts({ chatId, messageId, parts });
  await finishStream();

  await removeRunId(messageId);
}

startStream writes { type: "start", messageId }; finishStream writes { type: "finish", finishReason: "stop" } and closes the writable.

Steps

Steps are durable checkpoints that persist their results.

async function getMessageHistory(chatId: string) {
  "use step";

  const dbMessages = await getChatMessages(chatId);
  return convertDbMessagesToUIMessages(dbMessages);
}

The workflow runtime can't import Node modules, so wrap logger calls in a step.

// src/workflows/chat/steps/logger.ts
import { logger } from "@/lib/logging/logger";

export async function log(
  level: "info" | "warn" | "error" | "debug",
  message: string,
  data?: Record<string, unknown>,
): Promise<void> {
  "use step";

  if (data) {
    logger[level](data, message);
  } else {
    logger[level](message);
  }
}

Starting and Resuming

Start with start from workflow/api; reconnect to an in-progress or completed run with getRun.

import { start, getRun } from "workflow/api";
import { chatWorkflow } from "@/workflows/chat";

const run = await start(chatWorkflow, [{ chatId, userMessage }]);
// run.runId       - unique id for this run
// run.readable    - stream of UI message chunks

const resumed = await getRun(runId);
const readable = await resumed.getReadable({ startIndex });

Persisting Results

Save agent output in a step. assertChatAgentParts narrows the generic UIMessage["parts"] to the app's tool/data types before insert.

// src/workflows/chat/steps/history.ts
import type { UIMessage } from "ai";
import { insertMessageParts } from "@/lib/chat/queries";
import { assertChatAgentParts } from "../types";

export async function persistMessageParts({
  chatId,
  messageId,
  parts,
}: {
  chatId: string;
  messageId: string;
  parts: UIMessage["parts"];
}): Promise<void> {
  "use step";

  assertChatAgentParts(parts);
  await insertMessageParts(chatId, messageId, parts);

  await db
    .update(chats)
    .set({ updatedAt: new Date() })
    .where(eq(chats.id, chatId));
}

---

References

Related skills

FAQ

What directives mark orchestration vs steps?

'use workflow' marks the orchestration function; 'use step' marks durable checkpoints.

How do you resume a run?

Reconnect with getRun(runId) and read from getReadable({ startIndex }).

Automation & Workflowsagentsautomation

This week in AI coding

Five minutes, every Monday - the tools, releases and tactics for developers.

unsubscribe anytime.