/output-dev-types-file
Create types.ts files with Zod schemas for Output SDK workflows. Use when defining input/output schemas, creating type definitions, or fixing schema-related errors.
$ npx -y skills add growthxai/output --skill output-dev-types-file --agent claude-codeHow it fires
How this skill gets triggered: by you, by Claude, or both.
- Fires itselfAuto-invocation. Claude auto-loads it when your prompt matches the work.Auto-invocation is when the right skill fires by itself at the right moment, driven by a FLOW.md router and a hook, instead of you invoking it by name. It is the difference between a skill being installed and a skill actually getting used.Read the full definition →
- You can call itInvoke it directly when you want it.
- Slash command
/output-dev-types-file
Context preview
The summary Claude sees to decide when to auto-load this skill.
Create types.ts files with Zod schemas for Output SDK workflows. Use when defining input/output schemas, creating type definitions, or fixing schema-related errors.
SKILL.md
output-dev-types-file.SKILL.mdname: output-dev-types-file
description: Create types.ts files with Zod schemas for Output SDK workflows. Use when defining input/output schemas, creating type definitions, or fixing schema-related errors.
allowed-tools: [Read, Write, Edit]
Creating types.ts Files with Zod Schemas
Overview
This skill documents how to create `types.ts` files for Output SDK workflows. These files contain Zod schemas for input/output validation and their corresponding TypeScript types.
When to Use This Skill
- Creating a new workflow's type definitions
- Adding new schemas for steps
- Fixing schema validation errors
- Refactoring existing type definitions
Critical Import Rule
**ALWAYS** import `z` from `@outputai/core`, **NEVER** from `zod` directly:
// CORRECT
import { z } from '@outputai/core';
// WRONG - will cause runtime errors
import { z } from 'zod';**Related Skill**: `output-error-zod-import` for troubleshooting import issues
Basic Structure
import { z } from '@outputai/core';
// 1. Workflow Input Schema
export const WorkflowInputSchema = z.object( {
// Define input fields
} );
// 2. Workflow Output Type
export type WorkflowInput = z.infer<typeof WorkflowInputSchema>;
export type WorkflowOutput = /* output type */;
// 3. Step Schemas (for each step)
export const StepNameInputSchema = z.object( {
// Step input fields
} );
export const StepNameOutputSchema = z.object( {
// Step output fields
} );
// 4. Type Exports
export type StepNameInput = z.infer<typeof StepNameInputSchema>;
export type StepNameOutput = z.infer<typeof StepNameOutputSchema>;CRITICAL: Schema Constraints for LLM Output
Schemas passed to `Output.object()` are sent to LLM providers as tool definitions. **Anthropic rejects several JSON Schema constraints** that Zod methods produce. Getting this wrong causes runtime errors.
What Is NOT Allowed in LLM Output Schemas
- **Numbers**: `.min()`, `.max()` on `z.number()` produce `minimum`/`maximum` -- rejected by Anthropic.
- **Arrays**: `.min()`, `.max()`, `.length()` on `z.array()` produce `minItems`/`maxItems` -- Anthropic only supports `minItems` of `0` or `1`. Values like `.length( 3 )` or `.min( 2 )` will be rejected.
Use `.describe()` Instead
`.describe()` is the primary mechanism for guiding LLM output quality. LLM providers use field names and descriptions from the schema to understand what each field should contain. Write clear, specific descriptions that communicate your intent.
**Important**: `.describe()` replaces both unsupported constraints AND prompt-based format instructions. Do not also describe the schema in the prompt -- the schema is sent to the provider automatically, and duplicating it reduces performance and creates drift risk. See `output-dev-prompt-file` for details.
// LLM output schema (sent to provider via Output.object()) -- .describe() ONLY
const llmOutputSchema = z.object( {
score: z.number().describe( 'Quality score 0-100' ),
confidence: z.number().describe( 'Confidence 0-1' ),
predictions: z.array( predictionSchema ).describe( 'Exactly 3 predictions' )
} );
// Workflow/step validation schema (Zod-only, NOT sent to LLM) -- .min()/.max()/.length() OK
const workflowOutputSchema = z.object( {
score: z.number().min( 0 ).max( 100 ).describe( 'Quality score 0-100' ),
confidence: z.number().min( 0 ).max( 1 ).describe( 'Confidence 0-1' ),
predictions: z.array( predictionSchema ).length( 3 ).describe( 'Exactly 3 predictions' )
} );When to Use Which
| Context | `.min()/.max()/.length()` | `.describe()` | |---------|:-:|:-:| | Schema passed to `Output.object()` | **No** (numbers or arrays) | Yes | | `inputSchema` / `outputSchema` on steps | OK | Optional | | `inputSchema` / `outputSchema` on workflows | OK | Optional | | `outputSchema` on evaluators | OK | Optional |
LLM Schemas Must Live in types.ts
Define all schemas used in `Output.object()` in `types.ts` and import them in step functions. Never define them inline -- this causes duplication and makes it harder to verify they follow the constraints above.
Common Schema Patterns
Basic Types
import { z } from '@outputai/core';
// Strings
const stringField = z.string();
const optionalString = z.string().optional();
const stringWithDefault = z.string().default( 'default value' );
const describedString = z.string().describe( 'Field description' );
// Numbers
const numberField = z.number();
const integerField = z.number().int();
const rangedNumber = z.number().min( 1 ).max( 100 ); // runtime only — NOT safe for Output.object() schemas
// Booleans
const booleanField = z.boolean();
const defaultBoolean = z.boolean().default( false );
// Enums
const enumField = z.enum( [ 'option1', 'option2', 'option3' ] );
const enumWithDefault = z.enum( [ 'small', 'medium', 'large' ] ).default( 'medium' );Complex Types
import { z } from '@outputai/core';
// Arrays
const stringArray = z.array( z.string() );
const objectArray = z.array( z.object( { id: z.string(), name: z.string() } ) );
// Objects
const nestedObject = z.object( {
user: z.object( {
id: z.string(),
email: z.string().email()
} ),
settings: z.object( {
notifications: z.boolean()
} )
} );
// Union Types
const flexibleInput = z.union( [
z.string(),
z.array( z.string() )
] );
// Records
const keyValueMap = z.record( z.string(), z.number() );Validation Patterns
import { z } from '@outputai/core';
// String Validations
const emailField = z.string().email();
const urlField = z.string().url();
const uuidField = z.string().uuid();
const minLengthString = z.string().min( 1 );
const maxLengthString = z.string().max( 1000 );
// Number Validations
const positiveNumber = z.number().positive();
const nonNegativeNumber = z.number().nonnegative();
const percentageNumber = z.number().min( 0 ).max( 100 );
// Array Validations (runtime only — NOT safeRead more
name: output-dev-types-file description: Create types.ts files with Zod schemas for Output SDK workflows. Use when defining input/output schemas, creating type definitions, or fixing schema-related errors. allowed-tools: [Read, Write, Edit]
Creating types.ts Files with Zod Schemas
Overview
This skill documents how to create `types.ts` files for Output SDK workflows. These files contain Zod schemas for input/output validation and their corresponding TypeScript types.
When to Use This Skill
- Creating a new workflow's type definitions
- Adding new schemas for steps
- Fixing schema validation errors
- Refactoring existing type definitions
Critical Import Rule
**ALWAYS** import `z` from `@outputai/core`, **NEVER** from `zod` directly:
// CORRECT
import { z } from '@outputai/core';
// WRONG - will cause runtime errors
import { z } from 'zod';**Related Skill**: `output-error-zod-import` for troubleshooting import issues
Basic Structure
import { z } from '@outputai/core';
// 1. Workflow Input Schema
export const WorkflowInputSchema = z.object( {
// Define input fields
} );
// 2. Workflow Output Type
export type WorkflowInput = z.infer<typeof WorkflowInputSchema>;
export type WorkflowOutput = /* output type */;
// 3. Step Schemas (for each step)
export const StepNameInputSchema = z.object( {
// Step input fields
} );
export const StepNameOutputSchema = z.object( {
// Step output fields
} );
// 4. Type Exports
export type StepNameInput = z.infer<typeof StepNameInputSchema>;
export type StepNameOutput = z.infer<typeof StepNameOutputSchema>;CRITICAL: Schema Constraints for LLM Output
Schemas passed to `Output.object()` are sent to LLM providers as tool definitions. **Anthropic rejects several JSON Schema constraints** that Zod methods produce. Getting this wrong causes runtime errors.
What Is NOT Allowed in LLM Output Schemas
- **Numbers**: `.min()`, `.max()` on `z.number()` produce `minimum`/`maximum` -- rejected by Anthropic.
- **Arrays**: `.min()`, `.max()`, `.length()` on `z.array()` produce `minItems`/`maxItems` -- Anthropic only supports `minItems` of `0` or `1`. Values like `.length( 3 )` or `.min( 2 )` will be rejected.
Use `.describe()` Instead
`.describe()` is the primary mechanism for guiding LLM output quality. LLM providers use field names and descriptions from the schema to understand what each field should contain. Write clear, specific descriptions that communicate your intent.
**Important**: `.describe()` replaces both unsupported constraints AND prompt-based format instructions. Do not also describe the schema in the prompt -- the schema is sent to the provider automatically, and duplicating it reduces performance and creates drift risk. See `output-dev-prompt-file` for details.
// LLM output schema (sent to provider via Output.object()) -- .describe() ONLY
const llmOutputSchema = z.object( {
score: z.number().describe( 'Quality score 0-100' ),
confidence: z.number().describe( 'Confidence 0-1' ),
predictions: z.array( predictionSchema ).describe( 'Exactly 3 predictions' )
} );
// Workflow/step validation schema (Zod-only, NOT sent to LLM) -- .min()/.max()/.length() OK
const workflowOutputSchema = z.object( {
score: z.number().min( 0 ).max( 100 ).describe( 'Quality score 0-100' ),
confidence: z.number().min( 0 ).max( 1 ).describe( 'Confidence 0-1' ),
predictions: z.array( predictionSchema ).length( 3 ).describe( 'Exactly 3 predictions' )
} );When to Use Which
| Context | `.min()/.max()/.length()` | `.describe()` | |---------|:-:|:-:| | Schema passed to `Output.object()` | **No** (numbers or arrays) | Yes | | `inputSchema` / `outputSchema` on steps | OK | Optional | | `inputSchema` / `outputSchema` on workflows | OK | Optional | | `outputSchema` on evaluators | OK | Optional |
LLM Schemas Must Live in types.ts
Define all schemas used in `Output.object()` in `types.ts` and import them in step functions. Never define them inline -- this causes duplication and makes it harder to verify they follow the constraints above.
Common Schema Patterns
Basic Types
import { z } from '@outputai/core';
// Strings
const stringField = z.string();
const optionalString = z.string().optional();
const stringWithDefault = z.string().default( 'default value' );
const describedString = z.string().describe( 'Field description' );
// Numbers
const numberField = z.number();
const integerField = z.number().int();
const rangedNumber = z.number().min( 1 ).max( 100 ); // runtime only — NOT safe for Output.object() schemas
// Booleans
const booleanField = z.boolean();
const defaultBoolean = z.boolean().default( false );
// Enums
const enumField = z.enum( [ 'option1', 'option2', 'option3' ] );
const enumWithDefault = z.enum( [ 'small', 'medium', 'large' ] ).default( 'medium' );Complex Types
import { z } from '@outputai/core';
// Arrays
const stringArray = z.array( z.string() );
const objectArray = z.array( z.object( { id: z.string(), name: z.string() } ) );
// Objects
const nestedObject = z.object( {
user: z.object( {
id: z.string(),
email: z.string().email()
} ),
settings: z.object( {
notifications: z.boolean()
} )
} );
// Union Types
const flexibleInput = z.union( [
z.string(),
z.array( z.string() )
] );
// Records
const keyValueMap = z.record( z.string(), z.number() );Validation Patterns
import { z } from '@outputai/core';
// String Validations
const emailField = z.string().email();
const urlField = z.string().url();
const uuidField = z.string().uuid();
const minLengthString = z.string().min( 1 );
const maxLengthString = z.string().max( 1000 );
// Number Validations
const positiveNumber = z.number().positive();
const nonNegativeNumber = z.number().nonnegative();
const percentageNumber = z.number().min( 0 ).max( 100 );
// Array Validations (runtime only — NOT safeThe 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.
Repo: growthxai/output
Other skills on output.
- /llm-output-schema-constraints
Zod schema constraints that Anthropic rejects or silently ignores when sent as structured-output tool definitions via Output.object(). Use when writing or reviewing Zod schemas passed to Output.object(), or debugging structured-output validation errors.
Open skill - /prompt-file-provider-options
Guide to the providerOptions structure in .prompt files — decision tree for where an option goes, common mistakes, per-provider quick reference, and Anthropic prompt caching. Use when writing or reviewing .prompt file frontmatter (provider, model, providerOptions,
Open skill - /validate
Run lint, build, and tests to validate changes are correct
Open skill - /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 existing plan, or after output-plan-workflow has produced a plan and the user is ready to build.
Open skill - /output-credentials-edit
View and edit encrypted credentials in an Output.ai project. Use when adding secrets, updating API keys, verifying credential values, or retrieving a specific credential.
Open skill - /output-credentials-env-vars
Wire encrypted credentials to environment variables using the credential: convention. Use when setting up LLM provider keys (ANTHROPIC_API_KEY, OPENAI_API_KEY) or any env var that should come from encrypted credentials.
Open skill

