Skip to content
Development
Skill

/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.

From plugin
output
43052 skills11 agents1 command
Install
$ npx -y skills add growthxai/output --skill output-dev-types-file --agent claude-code

How 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.md
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 safe
Read more
Ships withoutput

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.

Get the whole plugin