Create step functions in steps.ts for Output SDK workflows. Use when implementing I/O operations, error handling, HTTP requests, or LLM calls.
This skill documents how to create step functions in steps.ts for Output SDK workflows. Steps are where all I/O operations happen - HTTP requests, LLM calls, database operations, file system access, etc.
For smaller workflows, use a single steps.ts file:
src/workflows/{workflow-name}/
├── workflow.ts
├── steps.ts # All steps in one file
├── types.ts
└── ...
For larger workflows with many steps, use a steps/ folder:
src/workflows/{workflow-name}/
├── workflow.ts
├── steps/ # Steps split into individual files
│ ├── fetch_data.ts
│ ├── process.ts
│ └── validate.ts
├── types.ts
└── ...
Important: step() calls MUST be in files containing 'steps' in the path:
src/workflows/my_workflow/steps.ts ✓src/workflows/my_workflow/steps/fetch_data.ts ✓src/shared/steps/common_steps.ts ✓src/workflows/my_workflow/helpers.ts ✗ (cannot contain step() calls)Steps are Temporal activities with strict import rules to ensure deterministic replay.
./utils.js, ./types.js, ./helpers.js./clients/pokeapi.js, ./lib/helpers.js../../shared/utils/*.js../../shared/clients/*.js../../shared/services/*.jsExample of WRONG imports:
// WRONG - steps cannot import other steps
import { otherStep } from '../../shared/steps/other.js'; // ✗
import { anotherStep } from './other_steps.js'; // ✗
// CORRECT - Import from @outputai/core
import { step, z, FatalError, ValidationError } from '@outputai/core';
// WRONG - Never import z from zod
import { z } from 'zod';
// CORRECT - Use @outputai/http wrapper
import { httpClient } from '@outputai/http';
// WRONG - Never use axios directly
import axios from 'axios';
Related Skill: output-error-http-client
// CORRECT - Use @outputai/llm wrapper
import { generateText, Output } from '@outputai/llm';
// WRONG - Never call LLM providers directly
import OpenAI from 'openai';
All imports MUST use .js extension:
// CORRECT
import { InputSchema, OutputSchema } from './types.js';
import { GeminiService } from '../../shared/clients/gemini_client.js';
// WRONG - Missing .js extension
import { InputSchema, OutputSchema } from './types';
import { step, z, FatalError, ValidationError } from '@outputai/core';
import { httpClient } from '@outputai/http';
import { generateText, Output } from '@outputai/llm';
import { StepInputSchema, StepOutputSchema } from './types.js';
export const myStep = step({
name: 'myStep',
description: 'Description of what this step does',
inputSchema: StepInputSchema,
outputSchema: StepOutputSchema,
fn: async (input) => {
// Implementation with I/O operations
return { /* output matching outputSchema */ };
}
});
Unique identifier for the step. Use camelCase.