output-build-workflow
Implement an Output SDK workflow from a plan document. Use when the user asks to build, implement, or code a workflow from an…
Fix direct I/O in Output SDK workflow functions. Use when workflow hangs, returns undefined, shows "workflow must be deterministic" errors, or when HTTP/API calls are made directly in workflow code.
Claude Code
$ npx -y skills add growthxai/output --skill output-error-direct-io --agent claude-code
Codex
$ npx skills add growthxai/output --skill output-error-direct-io -a codex -y
Cursor
$ npx skills add growthxai/output --skill output-error-direct-io -a cursor -y
Gemini CLI
$ npx skills add growthxai/output --skill output-error-direct-io -a gemini-cli -y
GitHub Copilot
$ npx skills add growthxai/output --skill output-error-direct-io -a github-copilot -y
OpenCode
$ npx skills add growthxai/output --skill output-error-direct-io -a opencode -y
Windsurf
$ npx skills add growthxai/output --skill output-error-direct-io -a windsurf -y
name: output-error-direct-io description: Fix direct I/O in Output SDK workflow functions. Use when workflow hangs, returns undefined, shows "workflow must be deterministic" errors, or when HTTP/API calls are made directly in workflow code. allowed-tools: [Bash, Read]
This skill helps diagnose and fix a critical error pattern where I/O operations (HTTP calls, database queries, file operations) are performed directly in workflow functions instead of in steps. This violates Temporal's determinism requirements.
You're seeing:
Workflow functions must be **deterministic** - they should only orchestrate steps, not perform I/O directly. When you make HTTP calls, database queries, or any external operations directly in a workflow function:
1. **Hangs**: The workflow may hang because I/O isn't properly handled 2. **Determinism violations**: Temporal replays workflows, and I/O results differ 3. **No retry logic**: Direct calls bypass Output SDK's retry mechanisms 4. **No tracing**: Operations aren't recorded in the workflow trace
// WRONG: I/O directly in workflow
export default workflow( {
fn: async input => {
const response = await fetch( 'https://api.example.com/data' ); // BAD!
const data = await response.json();
return { data };
}
} );// WRONG: Database I/O in workflow
export default workflow( {
fn: async input => {
const user = await db.users.findById( input.userId ); // BAD!
return { user };
}
} );// WRONG: File I/O in workflow
import fs from 'fs/promises';
export default workflow( {
fn: async input => {
const data = await fs.readFile( input.path, 'utf-8' ); // BAD!
return { data };
}
} );Move ALL I/O operations to step functions. Steps are designed to handle non-deterministic operations.
export default workflow( {
fn: async input => {
const response = await fetch( 'https://api.example.com/data' );
const data = await response.json();
return { data };
}
} );import { z, step, workflow } from '@outputai/core';
import { createKyClient } from '@outputai/core/http';
// Create a step for the I/O operation
export const fetchData = step( {
name: 'fetchData',
inputSchema: z.object( {
endpoint: z.string()
} ),
outputSchema: z.object( {
data: z.unknown()
} ),
fn: async input => {
const client = createKyClient( { prefix: 'https://api.example.com' } );
const data = await client.get( input.endpoint ).json();
return { data };
}
} );
// Workflow only orchestrates steps
export default workflow( {
inputSchema: z.object( {} ),
outputSchema: z.object( { data: z.unknown() } ),
fn: async input => {
const result = await fetchData( { endpoint: 'data' } );
return result;
}
} );export default workflow( {
fn: async input => {
const user = await prisma.user.findUnique( {
where: { id: input.userId }
} );
const orders = await prisma.order.findMany( {
where: { userId: input.userId }
} );
return { user, orders };
}
} );import { z, step, workflow } from '@outputai/core';
import { prisma } from '../lib/db';
export const fetchUser = step( {
name: 'fetchUser',
inputSchema: z.object( { userId: z.string() } ),
outputSchema: z.object( {
user: z.object( {
id: z.string(),
name: z.string(),
email: z.string()
} ).nullable()
} ),
fn: async input => {
const user = await prisma.user.findUnique( {
where: { id: input.userId }
} );
return { user };
}
} );
export const fetchOrders = step( {
name: 'fetchOrders',
inputSchema: z.object( { userId: z.string() } ),
outputSchema: z.object( {
orders: z.array( z.object( {
id: z.string(),
total: z.number()
} ) )
} ),
fn: async input => {
const orders = await prisma.order.findMany( {
where: { userId: input.userId }
} );
return { orders };
}
} );
export default workflow( {
inputSchema: z.object( { userId: z.string() } ),
outputSchema: z.object( {
user: z.unknown(),
orders: z.array( z.unknown() )
} ),
fn: async input => {
const { user } = await fetchUser( { userId: input.userId } );
const { orders } = await fetchOrders( { userId: input.userId } );
return { user, orders };
}
} );Search for common I/O patterns in workflow files:
# Find fetch calls grep -rn "await fetch" src/workflows/ # Find axios calls grep -rn "axios\." src/workflows/ # Find database operations grep -rn "prisma\.\|db\.\|mongoose\." src/workflows/ # Find file system operations grep -rn "fs\.\|readFile\|writeFile" src/workflows/
Then review each match to see if it's in a workflow function vs a step function.
Workflow functions should contain:
Workflow functions should NOT contain:
After moving I/O to steps:
1. **Run the workflow**: `npx output workflow run <name> --input '<input>'` 2. **Check the trace**: `npx output workflow debug <id> --json` 3. **Ve
The open-source TypeScript framework for building AI workflows and agents. Designed for Claude Code — describe what you want, Claude builds it, with all the best practices already in place. One framework.
Implement an Output SDK workflow from a plan document. Use when the user asks to build, implement, or code a workflow from an…
View, edit, and set encrypted credentials in an Output.ai project. Use when adding secrets, updating API keys, verifying…
Wire encrypted credentials to environment variables using the credential: convention. Use when setting up LLM provider keys…
Initialize encrypted credentials for an Output.ai project. Use when setting up credentials for the first time, adding…
Debug Output SDK workflow issues. Use when user reports a workflow failing, erroring, hanging, producing wrong results, or asks…
Use the Agent class for multi-step tool loops, conversation history, streaming progress, and reusable LLM agents. Use when…
You MUST use this before any creative work - creating features, building components, adding functionality, modifying behavior, or…
Ask which skill or flow fits your situation. A router over the skills in this repo.