Convert Flow SDK workflow class to Output SDK workflow() function. Use when migrating workflow.ts files from class-based to functional definitions.
Converts Flow SDK class-based workflows to Output SDK functional definitions. Triggers when migrating workflow.ts files from class-based to functional patterns.
/plugin marketplace add growthxai/output-claude-plugins/plugin install growthxai-outputai-flow-migrator-plugins-outputai-flow-migrator@growthxai/output-claude-pluginsThis skill is limited to using the following tools:
This skill guides the conversion of Flow SDK workflow classes to Output SDK functional workflow definitions. Workflows orchestrate step execution and define the overall data flow.
During Migration:
workflow.ts from class-based to functional| Aspect | Flow SDK | Output SDK |
|---|---|---|
| Definition | Class with execute() method | workflow() function |
| Input/Output | TypeScript interfaces | Zod schemas |
| Activity Calls | Direct function calls | Step calls with object params |
| Error Handling | Try-catch blocks | Let errors propagate |
| Imports | @flow/sdk | @output.ai/core |
// workflow.ts
import { Workflow, WorkflowScope } from '@flow/sdk';
import { fetchUser, processData, saveResults } from './activities';
interface WorkflowInput {
userId: string;
processType: string;
}
interface WorkflowOutput {
success: boolean;
resultId: string;
}
export class DataProcessingWorkflow implements Workflow<WorkflowInput, WorkflowOutput> {
async execute( input: WorkflowInput ): Promise<WorkflowOutput> {
try {
// Get user data
const user = await fetchUser( input.userId );
// Process the data
const processed = await processData( user, input.processType );
// Save results
const result = await saveResults( processed );
return {
success: true,
resultId: result.id
};
} catch ( error ) {
throw new Error( `Workflow failed: ${error.message}` );
}
}
}
// workflow.ts
import { workflow, z } from '@output.ai/core';
import { fetchUser, processData, saveResults } from './steps.js';
const WorkflowInputSchema = z.object( {
userId: z.string(),
processType: z.string()
} );
const WorkflowOutputSchema = z.object( {
success: z.boolean(),
resultId: z.string()
} );
export default workflow( {
name: 'dataProcessing',
description: 'Process user data and save results',
inputSchema: WorkflowInputSchema,
outputSchema: WorkflowOutputSchema,
fn: async ( input ) => {
// Get user data
const user = await fetchUser( { userId: input.userId } );
// Process the data
const processed = await processData( { user, processType: input.processType } );
// Save results
const result = await saveResults( { data: processed } );
return {
success: true,
resultId: result.id
};
}
} );
Find the workflow class in workflow.ts:
grep -E "class.*Workflow" src/workflows/my-workflow/workflow.ts
Convert TypeScript interfaces to Zod schemas:
// Before: TypeScript interface
interface WorkflowInput {
userId: string;
count: number;
options?: ProcessOptions;
}
// After: Zod schema
const WorkflowInputSchema = z.object( {
userId: z.string(),
count: z.number(),
options: ProcessOptionsSchema.optional()
} );
Replace class definition with workflow() call:
// Before
export class MyWorkflow implements Workflow<Input, Output> {
async execute( input: Input ): Promise<Output> {
// ...
}
}
// After
export default workflow( {
name: 'myWorkflow',
description: 'Description of what this workflow does',
inputSchema: InputSchema,
outputSchema: OutputSchema,
fn: async ( input ) => {
// ...
}
} );
Change direct function calls to object parameter calls:
// Before (Flow SDK)
const result = await someActivity( param1, param2, param3 );
// After (Output SDK)
const result = await someStep( { param1, param2, param3 } );
Remove error handling wrappers (see flow-error-try-catch-removal):
// Before
async execute( input ) {
try {
const result = await doWork( input );
return result;
} catch ( error ) {
throw new Error( error.message );
}
}
// After
fn: async ( input ) => {
const result = await doWork( { ...input } );
return result;
}
// Before
import { Workflow, WorkflowScope } from '@flow/sdk';
import { z } from 'zod';
// After
import { workflow, z } from '@output.ai/core';
The workflow name must match the legacy name if other systems depend on it:
// Legacy system calls workflow by name 'userOnboarding'
export default workflow( {
name: 'userOnboarding', // Must match!
// ...
} );
Workflows should use export default:
// CORRECT
export default workflow( { ... } );
// WRONG
export const myWorkflow = workflow( { ... } );
Always include .js extension for local imports:
import { fetchUser, processData } from './steps.js';
import { WorkflowInputSchema } from './types.js';
Workflows can invoke other workflows directly:
// parent/workflow.ts
import { workflow, z } from '@output.ai/core';
import childWorkflow from '../child/workflow.js';
export default workflow( {
name: 'parentWorkflow',
inputSchema: z.object( { data: z.string() } ),
outputSchema: z.object( { result: z.string() } ),
fn: async ( input ) => {
// Call child workflow like a step
const childResult = await childWorkflow( { input: input.data } );
return { result: childResult.output };
}
} );
// workflow.ts
import { Workflow, WorkflowScope, FatalError } from '@flow/sdk';
import {
validateInput,
fetchUserProfile,
generateReport,
sendNotification
} from './activities';
interface ReportInput {
userId: string;
reportType: 'daily' | 'weekly' | 'monthly';
includeCharts: boolean;
}
interface ReportOutput {
reportId: string;
downloadUrl: string;
generatedAt: string;
}
export class GenerateReportWorkflow implements Workflow<ReportInput, ReportOutput> {
async execute( input: ReportInput ): Promise<ReportOutput> {
try {
// Validate input
const validated = await validateInput( input );
// Fetch user profile
const profile = await fetchUserProfile( input.userId );
// Generate the report
const report = await generateReport(
profile,
validated.reportType,
validated.includeCharts
);
// Send notification
await sendNotification( profile.email, report.id );
return {
reportId: report.id,
downloadUrl: report.url,
generatedAt: new Date().toISOString()
};
} catch ( error ) {
throw new FatalError( `Report generation failed: ${error.message}` );
}
}
}
// workflow.ts
import { workflow, z } from '@output.ai/core';
import {
validateInput,
fetchUserProfile,
generateReport,
sendNotification
} from './steps.js';
const ReportInputSchema = z.object( {
userId: z.string(),
reportType: z.enum( [ 'daily', 'weekly', 'monthly' ] ),
includeCharts: z.boolean()
} );
const ReportOutputSchema = z.object( {
reportId: z.string(),
downloadUrl: z.string(),
generatedAt: z.string()
} );
export default workflow( {
name: 'generateReport',
description: 'Generate user reports with optional charts',
inputSchema: ReportInputSchema,
outputSchema: ReportOutputSchema,
fn: async ( input ) => {
// Validate input
const validated = await validateInput( {
userId: input.userId,
reportType: input.reportType,
includeCharts: input.includeCharts
} );
// Fetch user profile
const profile = await fetchUserProfile( { userId: input.userId } );
// Generate the report
const report = await generateReport( {
profile,
reportType: validated.reportType,
includeCharts: validated.includeCharts
} );
// Send notification
await sendNotification( {
email: profile.email,
reportId: report.id
} );
return {
reportId: report.id,
downloadUrl: report.url,
generatedAt: new Date().toISOString()
};
}
} );
workflow() function@output.ai/core.js extensionexport default usedflow-convert-activities-to-steps - Step conversionflow-error-try-catch-removal - Try-catch antipatternflow-error-zod-import - Zod import issuesflow-validation-checklist - Complete validationCreating algorithmic art using p5.js with seeded randomness and interactive parameter exploration. Use this when users request creating art using code, generative art, algorithmic art, flow fields, or particle systems. Create original algorithmic art rather than copying existing artists' work to avoid copyright violations.
Applies Anthropic's official brand colors and typography to any sort of artifact that may benefit from having Anthropic's look-and-feel. Use it when brand colors or style guidelines, visual formatting, or company design standards apply.
Create beautiful visual art in .png and .pdf documents using design philosophy. You should use this skill when the user asks to create a poster, piece of art, design, or other static piece. Create original visual designs, never copying existing artists' work to avoid copyright violations.