Install any skill in seconds. Free to start, no credit card required.
Get Started Free →Comprehensive guide to Output.ai Framework for building durable, LLM-powered workflows orchestrated by Temporal. Covers project structure, workflow patterns, steps, LLM integration, HTTP clients, CLI commands, and the full inventory of available agents and skills.
.claude/skills/growthxai-output-meta-project-context/SKILL.md| Test case | Without → With | Effect | Δ tokens | Δ turns |
|---|---|---|---|---|
| case-02 | ✗→✓ | ▲ Improved | 121% | 0% |
| case-01 | ✗→✓ | ▲ Improved | 117% | 0% |
| case-03 | ✗→✓ | ▲ Improved | 144% | 0% |
| case-04 | ✗→✓ | ▲ Improved | 159% | 0% |
| case-05 | ✗→✓ | ▲ Improved | 289% | 0% |
Output.ai provides infrastructure for building production-grade AI workflows: fact checkers, content generators, data extractors, research assistants, and multi-step agents. Built on Temporal, it guarantees durable execution - if execution fails mid-run, it resumes from the last successful step.
Separation of orchestration from I/O:
This separation enables automatic retries, resumption, and debugging.
| Component | Purpose | Key Rule | |-----------|---------|----------| | Workflow | Orchestrates step execution | Must be deterministic (no I/O, no Date.now(), no Math.random()) | | Step | Handles all I/O operations | Where HTTP, LLM, DB calls happen | | Evaluator | Quality assessment | Returns confidence-scored results for validation loops | | Scenario | Test input data | JSON files matching workflow's inputSchema | | Prompt | LLM templates | Liquid.js templating with YAML frontmatter config | | Eval Test | Offline quality testing | Dataset-driven verification with verify() from @outputai/evals |
config/
├── credentials.yml.enc # Global encrypted credentials
├── credentials.key # Global decryption key (DO NOT COMMIT)
└── credentials/ # Environment-specific credentials
├── production.yml.enc
└── production.key
src/
├── shared/ # Shared code across workflows
│ ├── clients/ # API clients (e.g., jina.ts, stripe.ts)
│ └── utils/ # Utility functions (e.g., string.ts)
└── workflows/ # Workflow definitions
└── {workflow_name}/
├── workflow.ts # Orchestration logic (deterministic)
├── steps.ts # I/O operations
├── types.ts # Zod schemas (input, output, internal)
├── evaluators.ts # Quality checks (optional)
├── utils.ts # Local utilities (optional)
├── credentials.yml.enc # Workflow-specific credentials (optional)
├── prompts/ # LLM templates (optional)
│ └── generate@v1.prompt
├── scenarios/ # Test inputs (optional)
│ └── happy_path.json
└── tests/ # Offline eval tests (optional)
├── datasets/ # YAML test datasets
│ └── happy_path.yml
└── evals/ # Eval evaluators and workflow
├── evaluators.ts
└── workflow.tsShared directory (src/shared/):
shared/clients/ - API clients using @outputai/http for external servicesshared/utils/ - Helper functions and utilitiesAllowed imports:
../../shared/clients/*.js and ../../shared/utils/*.js./types.js, ./utils.js)Forbidden:
../other_workflow/steps.js)| Rule | Correct | Incorrect | |------|---------|-----------| | Zod import | import { z } from '@outputai/core' | import { z } from 'zod' | | HTTP client | import { createKyClient } from '@outputai/http' | import axios from 'axios' | | HTTP bodies | Read with .json()/.text() or cancel unused non-HEAD bodies | Read only response.url/status and leave body open | | Credentials | import { credentials } from '@outputai/credentials' | process.env.SECRET | | LLM calls | import { generateText, Output } from '@outputai/llm' | Direct provider SDK | | ES imports | import { fn } from './file.js' | import { fn } from './file' | | Workflow I/O | Call steps for any I/O | Direct fetch/http in workflow |
Determinism violations (never in workflows):
Date.now(), new Date()Math.random(), crypto.randomUUID()| Agent | Purpose | |-------|---------| | workflow-planner | Designs workflow architecture, creates implementation blueprints | | workflow-debugger | Analyzes workflow execution traces, identifies issues | | workflow-quality | Reviews code quality, validates implementations | | workflow-prompt-writer | Creates and optimizes LLM prompt templates | | workflow-context-fetcher | Gathers documentation and existing patterns |
| Skill | Purpose | |-------|---------| | output-plan-workflow | Plan workflow architecture - ALWAYS FIRST, creates implementation blueprint | | output-build-workflow | Build/implement workflows from a plan, or for modifications | | output-debug-workflow | Debug workflow issues when workflows fail or behave unexpectedly | | output-migrate | Upgrade a project between Output framework versions |
| Skill | Purpose | |-------|---------| | output-workflow-run | Synchronous workflow execution (waits for result) | | output-workflow-start | Asynchronous workflow execution (returns ID) | | output-workflow-list | List available workflows | | output-workflow-status | Check async workflow status | | output-workflow-result | Get async workflow result | | output-workflow-reset | Rerun a workflow from after a completed step |
| Skill | Purpose | |-------|---------| | output-workflow-stop | Stop running workflow | | output-workflow-trace | Trace workflow execution | | output-workflow-trace-file | Render a local trace file as readable markdown | | output-workflow-runs-list | List workflow run history | | output-dev-workflow-cost | Calculate cost of a workflow run | | output-services-check | Verify Output services status |
| Skill | Catches | |-------|---------| | output-error-zod-import | Wrong zod import source | | output-error-nondeterminism | Date.now, Math.random in workflows | | output-error-try-catch | Workflow try/catch patterns and typed step-error checks | | output-error-missing-schemas | Incomplete Zod schema exports | | output-error-direct-io | I/O operations in workflow files | | output-error-http-client | Using axios instead of @outputai/http |
| Skill | Purpose | |-------|---------| | output-meta-pre-flight | Pre-operation validation checks | | output-meta-post-flight | Post-operation verification | | output-meta-project-context | Load full project context (this skill) |
| Skill | Purpose | |-------|---------| | output-dev-folder-structure | Project and workflow directory layout | | output-dev-code-style | Code style conventions for workflow projects | | output-dev-workflow-function | Writing deterministic workflow files | | output-dev-step-function | Writing step functions for I/O | | output-dev-agent-class | Build multi-step tool-loop agents with the Agent class | | output-dev-types-file | Zod schema definitions | | output-dev-evaluator-function | Quality assessment functions | | output-dev-eval-testing | Offline eval tests with @outputai/evals | | output-dev-prompt-file | LLM prompt templates with Liquid.js | | output-dev-model-selection | Pick a current LLM model via the AI Gateway listing | | output-dev-upgrade-prompt-models | Bulk-upgrade model: fields across .prompt files | | output-dev-scenario-file | Test input JSON files | | output-dev-http-client-create | Shared HTTP API client patterns | | output-dev-skill-file | Author .md skill files for the framework's lazy-loaded instructions | | output-dev-create-skeleton | Generate workflow skeleton |
| Skill | Purpose | |-------|---------| | output-eval-error-analysis | Review traces to identify failure modes before building evaluators | | output-eval-dataset-design | Design diverse eval datasets via dimension-based variation | | output-eval-judge-prompt | Design effective LLM judge .prompt files | | output-eval-validate-judge | Validate LLM judges against human labels (TPR/TNR) | | output-eval-audit | Audit an existing eval suite for trustworthiness |
| Skill | Purpose | |-------|---------| | output-dev-credentials | Full credentials system reference (API, scopes, merging, custom providers) | | output-credentials-init | Initialize encrypted credentials files for the first time | | output-credentials-edit | View and edit credential values with show/get/edit commands | | output-credentials-env-vars | Wire credentials to env vars using the credential: convention |
bash# Development npx output dev # Start dev environment # List & inspect npx output workflow list # List available workflows # Execute npx output workflow run <name> --input '{}' # Run synchronously (waits) npx output workflow start <name> --input '{}' # Run async (returns ID) npx output workflow status <id> # Check async status npx output workflow result <id> # Get async result # Debug npx output workflow debug <id> # Debug failed workflow npx output workflow debug <id> --json # Machine-readable output # Rerun from a step (replays up to <stepName>, re-executes everything after) npx output workflow reset <id> --step <stepName> npx output workflow reset <id> --step <stepName> --reason "why" # Eval Testing npx output workflow test <name> # Run eval tests against datasets npx output workflow test <name> --cached # Use cached output (fast) npx output workflow test <name> --save # Run fresh and save results npx output workflow dataset list <name> # List datasets for a workflow npx output workflow dataset generate <name> --input '{}' # Generate dataset # Credentials npx output credentials init # Initialize encrypted credentials npx output credentials edit # Edit credentials (decrypts, opens $EDITOR) npx output credentials show # Show decrypted credentials npx output credentials get <path> # Get single credential value
| Element | Convention | Example | |---------|------------|---------| | Workflow folder | snake_case | fact_checker/ | | Workflow name | snake_case | name: 'fact_checker' | | Step functions | camelCase | fetchArticle(), analyzeContent() | | Schema names | PascalCase | InputSchema, ArticleData | | Prompt files | snake_case@version.prompt | analyze_claim@v1.prompt | | Scenario files | snake_case.json | happy_path.json |
typescriptimport { workflow, z } from '@outputai/core'; import { fetchData, processData } from './steps.js'; export const inputSchema = z.object( { url: z.string().url() } ); export const outputSchema = z.object( { result: z.string() } ); export default workflow( { name: 'my_workflow', description: 'Processes data from URL', inputSchema, outputSchema, fn: async input => { const data = await fetchData( input.url ); const result = await processData( data ); return { result }; } } );
See output-dev-workflow-function for comprehensive patterns.
typescriptimport { step, z } from '@outputai/core'; import { createKyClient } from '@outputai/http'; export const fetchData = step( { name: 'fetchData', inputSchema: z.string(), outputSchema: z.any() }, async url => { const client = createKyClient( { prefix: url } ); const response = await client.get( '' ); return response.json(); } );
See output-dev-step-function for comprehensive patterns.
Clients live in src/shared/clients/ and are shared across all workflows.
typescript// src/shared/clients/example.ts import { FatalError, ValidationError } from '@outputai/core'; import { createKyClient } from '@outputai/http'; import { credentials } from '@outputai/credentials'; const API_KEY = credentials.require( 'example.api_key' ); const client = createKyClient( { prefix: 'https://api.example.com', headers: { Authorization: `Bearer ${API_KEY}` }, timeout: 30000, retry: { limit: 3, statusCodes: [ 408, 429, 500, 502, 503, 504 ] } } ); export async function fetchFromExample( query: string ): Promise<ExampleResponse> { try { const response = await client.get( 'endpoint', { searchParams: { q: query } } ); return response.json(); } catch ( error: unknown ) { const err = error as { status?: number; message?: string }; if ( err.status === 401 || err.status === 403 ) { throw new FatalError( `Auth failed: ${err.message}` ); } throw new ValidationError( `Request failed: ${err.message}` ); } }
Error type guidelines:
FatalError: 401, 403, 404 (won't succeed on retry)ValidationError: 429, 5xx (may succeed on retry)See output-dev-http-client-create for comprehensive patterns.
Evaluators return confidence-scored results. Three result types available:
typescriptimport { evaluator, z, EvaluationBooleanResult, EvaluationNumberResult, EvaluationStringResult } from '@outputai/core'; // Boolean evaluator - pass/fail checks export const evaluateCompleteness = evaluator( { name: 'evaluate_completeness', description: 'Check if content meets minimum length', inputSchema: z.object( { content: z.string(), minLength: z.number() } ), fn: async ( { content, minLength } ) => { return new EvaluationBooleanResult( { value: content.length >= minLength, confidence: 1.0, reasoning: `Content has ${content.length} chars (min: ${minLength})` } ); } } );
See output-dev-evaluator-function for comprehensive patterns.
Prompts use YAML frontmatter + Liquid.js templating. Location: src/workflows/{name}/prompts/
---
provider: anthropic
# current as of 2026-05-04 — run output-dev-model-selection for the latest
model: claude-sonnet-4-6
temperature: 0.7
maxTokens: 4096
---
<system>
You are an expert content analyzer.
{% if context %}
Additional context: {{ context }}
{% endif %}
</system>
<user>
Analyze the following content:
<content>
{{ content }}
</content>
Provide {{ numberOfPoints | default: 3 }} key insights.
</user>Using in steps:
typescriptimport { generateText, Output } from '@outputai/llm'; import { z } from '@outputai/core'; // Structured output const { output } = await generateText( { prompt: 'analyze@v1', variables: { content: 'Article text...', numberOfPoints: 5 }, output: Output.object( { schema: z.object( { insights: z.array( z.string() ) } ) } ) } ); // Text output const { result } = await generateText( { prompt: 'summarize@v1', variables: { content: 'Article text...' } } );
Provider & model selection: the SDK supports anthropic, openai, google-vertex, amazon-bedrock, azure, and perplexity (the registered list lives in the SDK's provider registry, sdk/llm/src/ai_provider.js). Don't pin specific model IDs in docs — they drift. To pick a current model, run output-dev-model-selection, which queries the AI Gateway model index live.
See output-dev-prompt-file for comprehensive patterns.
docker restart <project>-worker-1docker logs -f output-worker-1output-services-check skillnpx output workflow debug <id> --json| Case | Status | Duration (ms) | Turns | Tokens | Tool calls | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Without | With | Δ | Without | With | Δ | Without | With | Δ | Without | With | Δ | ||
case-02 | fail→pass | 20,533 | 15,158 | -26% | 1 | 1 | 0% | 3,206 | 7,098 | +121% | 0 | 0 | — |
case-01 | fail→pass | 18,912 | 13,498 | -29% | 1 | 1 | 0% | 3,173 | 6,880 | +117% | 0 | 0 | — |
case-03 | fail→pass | 14,657 | 8,212 | -44% | 1 | 1 | 0% | 2,377 | 5,803 | +144% | 0 | 0 | — |
case-04 | fail→pass | 11,170 | 2,908 | -74% | 1 | 1 | 0% | 1,831 | 4,734 | +159% | 0 | 0 | — |
case-05 | fail→pass | 7,977 | 5,384 | -33% | 1 | 1 | 0% | 1,358 | 5,277 | +289% | 0 | 0 | — |
case-06 | fail→pass | 13,013 | 5,627 | -57% | 1 | 1 | 0% | 2,141 | 5,261 | +146% | 0 | 0 | — |
case-07 | pass→pass | 10,513 | 2,737 | -74% | 1 | 1 | 0% | 1,661 | 4,696 | +183% | 0 | 0 | — |
case-08 | fail→pass | 10,077 | 5,782 | -43% | 1 | 1 | 0% | 1,544 | 5,250 | +240% | 0 | 0 | — |
case-09 | fail→pass | 13,305 | 8,014 | -40% | 1 | 1 | 0% | 2,158 | 5,513 | +155% | 0 | 0 | — |
case-10 | pass→pass | 14,510 | 9,530 | -34% | 1 | 1 | 0% | 2,214 | 5,923 | +168% | 0 | 0 | — |
case-11 | fail→pass | 16,661 | 4,750 | -71% | 1 | 1 | 0% | 2,484 | 5,024 | +102% | 0 | 0 | — |
case-12 | fail→pass | 13,368 | 3,446 | -74% | 1 | 1 | 0% | 2,179 | 4,881 | +124% | 0 | 0 | — |
case-13 | fail→pass | 11,151 | 3,320 | -70% | 1 | 1 | 0% | 1,708 | 4,794 | +181% | 0 | 0 | — |
case-14 | fail→pass | 6,660 | 2,207 | -67% | 1 | 1 | 0% | 1,104 | 4,634 | +320% | 0 | 0 | — |
case-15 | fail→pass | 14,613 | 2,784 | -81% | 1 | 1 | 0% | 2,388 | 4,703 | +97% | 0 | 0 | — |
case-16 | fail→fail | 10,411 | 5,073 | -51% | 1 | 1 | 0% | 1,638 | 5,152 | +215% | 0 | 0 | — |
case-17 | fail→pass | 10,321 | 2,040 | -80% | 1 | 1 | 0% | 1,775 | 4,590 | +159% | 0 | 0 | — |
case-18 | fail→pass | 11,889 | 2,900 | -76% | 1 | 1 | 0% | 1,919 | 4,733 | +147% | 0 | 0 | — |
case-19 | fail→pass | 16,025 | 1,692 | -89% | 1 | 1 | 0% | 2,508 | 4,554 | +82% | 0 | 0 | — |
case-20 | pass→pass | 12,454 | 11,970 | -4% | 1 | 1 | 0% | 2,267 | 6,469 | +185% | 0 | 0 | — |
case-21 | pass→pass | 12,571 | 9,340 | -26% | 1 | 1 | 0% | 2,353 | 5,933 | +152% | 0 | 0 | — |
case-22 | pass→pass | 11,603 | 10,082 | -13% | 1 | 1 | 0% | 2,012 | 6,038 | +200% | 0 | 0 | — |
DecimalAI ran this skill against gemini-3.6-flash twice over the same eval suite — once with the skill loaded and once without — and compared the two runs case by case. 22 cases were attempted. The headline lift of +73 percentage points is the difference between those two pass rates over the 22 comparable cases.
Without the skill loaded, the model failed this case. With it loaded, the same prompt on the same model passed. This is one improved case from the latest verified run; every case, including any that regressed, is in the table above.
Other measured skills in the registry, with their headline benchmark lift.