--- name: output-dev-folder-structure description: Workflow folder structure conventions for Output SDK. Use when creating new workflows, organizing workflow files, or understanding the standard project layout. allowed-tools: [Read, Glob] --- # Workflow Folder Structure Conventions ## Overview This skill documents the standard folder structure for Output SDK workflows. Following these conventions ensures consistency across the codebase and enables proper tooling support. ## When to Use This Skill - Creating a new workflow from scratch - Reorganizing an existing workflow - Understanding where to place different file types - Reviewing workflow structure for compliance ## Standard Project Structure ``` src/ ├── shared/ # Shared code across workflows │ ├── clients/ # API clients (using @outputai/http) │ ├── utils/ # Utility functions & helpers │ ├── services/ # Business logic services │ ├── steps/ # Shared steps (optional) │ └── evaluators/ # Shared evaluators (optional) └── workflows/ └── {workflow-name}/ # Individual workflow directory ├── workflow.ts # Workflow definition (REQUIRED) ├── steps.ts # OR steps/ folder ├── evaluators.ts # OR evaluators/ folder (optional) ├── types.ts # Zod schemas and TypeScript types ├── utils.ts # Workflow-specific utilities (optional) ├── prompts/ # LLM prompt templates (optional) │ └── {promptName}@v1.prompt └── scenarios/ # Test input scenarios (optional) └── {scenario_name}.json ``` ## File Purposes ### workflow.ts (Required) - Contains the main `workflow()` function definition - Default exports the workflow - Must be deterministic - no direct I/O operations - Orchestrates step calls **Related Skill**: `output-dev-workflow-function` ### steps.ts or steps/ folder (Required) - Contains all `step()` function definitions - Handles all I/O operations (HTTP, LLM, file system, etc.) - Named exports for each step function - Includes error handling with FatalError and ValidationError **Related Skill**: `output-dev-step-function` ### evaluators.ts or evaluators/ folder (Optional) - Contains `evaluator()` function definitions - Used for workflow quality assessment and validation - Named exports for each evaluator function ### types.ts (Required) - Contains Zod schemas for input/output validation - Exports TypeScript types derived from schemas - Imports `z` from `@outputai/core` (never from `zod`) **Related Skill**: `output-dev-types-file` ### utils.ts (Optional) - Contains pure helper functions - No I/O operations - those belong in steps - Shared utility logic for the workflow ### prompts/ folder (Optional) - Contains `.prompt` files for LLM operations - File naming: `{promptName}@v1.prompt` - Uses YAML frontmatter and Liquid.js templating **Related Skill**: `output-dev-prompt-file` ### scenarios/ folder (Optional) - Contains JSON test input files - File naming: `{scenario_name}.json` - Matches workflow inputSchema structure **Related Skill**: `output-dev-scenario-file` ## Organization Options ### Option 1: Flat Files (Recommended for smaller workflows) ``` src/workflows/{workflow-name}/ ├── workflow.ts ├── steps.ts # All steps in one file ├── evaluators.ts # All evaluators in one file (optional) ├── types.ts └── ... ``` ### Option 2: Folder-Based (For larger workflows) ``` src/workflows/{workflow-name}/ ├── workflow.ts ├── steps/ # Steps split into individual files │ ├── fetch_data.ts │ ├── process.ts │ └── validate.ts ├── evaluators/ # Evaluators split into individual files │ ├── quality.ts │ └── accuracy.ts ├── types.ts └── ... ``` ## Component Location Rules (Strict) The Output SDK enforces strict rules about where components can be defined: | Component | Must be in | |-----------|------------| | `step()` calls | Files containing 'steps' in path | | `evaluator()` calls | Files containing 'evaluators' in path | | `workflow()` calls | `workflow.ts` file | **Examples:** - `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) ## Import Rules (Activity Isolation) Steps and evaluators are Temporal activities with isolation constraints to ensure deterministic replay. ### Steps CAN import from: - Local workflow files: `./utils.js`, `./types.js`, `./helpers.js` - Local subdirectories: `./clients/pokeapi.js`, `./lib/helpers.js` - Shared utilities: `../../shared/utils/*.js` - Shared clients: `../../shared/clients/*.js` - Shared services: `../../shared/services/*.js` ### Steps CANNOT import: - Other steps (activity isolation) - Evaluators - Workflow files ### Evaluators follow the same rules: - CAN import local files and shared code - CANNOT import other evaluators, steps, or workflows **Import Pattern Examples:** ```typescript // From workflow steps.ts - importing shared client import { GeminiImageService } from '../../shared/clients/gemini_client.js'; // From workflow steps.ts - importing local utility import { formatResponse } from './utils.js'; // From workflow steps.ts - importing types import { InputSchema, OutputSchema } from './types.js'; // WRONG - steps cannot import other steps import { otherStep } from '../../shared/steps/other.js'; // ✗ ``` ## Shared Resources ### src/shared/clients/ HTTP clients shared across workflows: ``` src/shared/clients/ ├── gemini_client.ts # Google Gemini API client ├── jina_client.ts # Jina AI client └── perplexity_client.ts # Perplexity API client ``` Import pattern in workflow steps: ```typescript import { GeminiImageService } from '../../shared/clients/gemini_client.js'; ``` **Related Skill**: `output-dev-http-client-create` ### src/shared/utils/ Utility functions shared across workflows: ``` src/shared/utils/ ├── string_helpers.ts ├── date_formatters.ts └── validators.ts ``` ### src/shared/services/ Business logic services shared across workflows: ``` src/shared/services/ ├── image_service.ts └── content_service.ts ``` ### src/shared/steps/ (Optional) Shared steps that can be imported by workflows: ``` src/shared/steps/ └── common_steps.ts ``` Note: Workflows import shared steps, but steps cannot import other steps directly. ## Naming Conventions ### Folder Names - Use `snake_case` for workflow folder names - Example: `image_infographic_nano`, `resume_parser` ### File Names - Use `camelCase` for `.ts` files (except `workflow.ts`, `steps.ts`, `types.ts`, `evaluators.ts`) - Use `camelCase@v{n}` for `.prompt` files - Use `snake_case` for `.json` scenario files ### Workflow Names - The `name` property in `workflow()` should be camelCase - Example: `imageInfographicNano` ## Example: Complete Workflow Structure ``` src/workflows/image_infographic_nano/ ├── workflow.ts # workflow({ name: 'imageInfographicNano', ... }) ├── steps.ts # generateImageIdeas, generateImages, validateReferenceImages ├── types.ts # WorkflowInputSchema, WorkflowOutput, step schemas ├── utils.ts # normalizeReferenceImageUrls, buildS3Url, etc. ├── prompts/ │ └── generateImageIdeas@v1.prompt └── scenarios/ ├── test_input_complex.json └── test_input_solar_panels.json ``` ## Verification Checklist When reviewing workflow structure, verify: - [ ] `workflow.ts` exists with default export - [ ] `steps.ts` or `steps/` folder exists with all step definitions - [ ] `types.ts` exists with Zod schemas - [ ] All `.ts` imports use `.js` extension - [ ] `prompts/` folder exists if LLM operations are used - [ ] `scenarios/` folder exists with at least one test input - [ ] Folder naming follows `snake_case` convention - [ ] Workflow name in code follows `camelCase` convention - [ ] Steps only import allowed dependencies (local files, shared code) - [ ] No cross-component imports (steps don't import other steps) ## Related Skills - `output-dev-workflow-function` - Writing workflow.ts files - `output-dev-step-function` - Writing step functions - `output-dev-evaluator-function` - Writing evaluators.ts files - `output-dev-types-file` - Creating Zod schemas - `output-dev-prompt-file` - Creating prompt files - `output-dev-scenario-file` - Creating test scenarios - `output-dev-http-client-create` - Creating shared HTTP clients