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…
Create shared HTTP clients in src/shared/clients/ for Output SDK workflows. Use when integrating external APIs, creating service wrappers, or standardizing HTTP operations.
Claude Code
$ npx -y skills add growthxai/output --skill output-dev-http-client-create --agent claude-code
Codex
$ npx skills add growthxai/output --skill output-dev-http-client-create -a codex -y
Cursor
$ npx skills add growthxai/output --skill output-dev-http-client-create -a cursor -y
Gemini CLI
$ npx skills add growthxai/output --skill output-dev-http-client-create -a gemini-cli -y
GitHub Copilot
$ npx skills add growthxai/output --skill output-dev-http-client-create -a github-copilot -y
OpenCode
$ npx skills add growthxai/output --skill output-dev-http-client-create -a opencode -y
Windsurf
$ npx skills add growthxai/output --skill output-dev-http-client-create -a windsurf -y
name: output-dev-http-client-create description: Create shared HTTP clients in src/shared/clients/ for Output SDK workflows. Use when integrating external APIs, creating service wrappers, or standardizing HTTP operations. allowed-tools: [Read, Write, Edit, Glob]
This skill documents how to create shared HTTP clients for Output SDK workflows. Clients are stored in `src/shared/clients/` and shared across all workflows to ensure consistent error handling, retry logic, and API integration patterns.
HTTP clients are stored in the shared clients folder:
src/shared/clients/
├── gemini_client.ts # Google Gemini API client
├── jina_client.ts # Jina AI client
├── perplexity_client.ts # Perplexity API client
└── {service}_client.ts # Your new client**Important**: Clients are shared across ALL workflows. Do NOT create per-workflow HTTP clients.
src/shared/ ├── clients/ # API clients (this skill) ├── utils/ # Utility functions & helpers ├── services/ # Business logic services ├── steps/ # Shared step definitions (optional) └── evaluators/ # Shared evaluators (optional)
Use relative imports from workflow files to shared clients:
// CORRECT - Relative path from workflow steps.ts
import { GeminiImageService } from '../../shared/clients/gemini_client.js';
import { parseResumeWithJina } from '../../shared/clients/jina_client.js';
// From shared steps (if used)
import { JinaClient } from '../clients/jina_client.js';// CORRECT - Use @outputai/core/http wrapper
import { createKyClient } from '@outputai/core/http';
// WRONG - Never use axios directly
import axios from 'axios';// CORRECT - Import error types from @outputai/core
import { FatalError, ValidationError } from '@outputai/core';
// WRONG - Custom error classes
class MyCustomError extends Error { ... }// CORRECT - Use @outputai/core/credentials for secrets
import { credentials } from '@outputai/core/credentials';
const apiKey = credentials.require('service.api_key');
// WRONG - Never use process.env for secrets
const apiKey = process.env.SERVICE_API_KEY;// CORRECT - Attach spend to paid API calls with @outputai/core/http
import { addRequestCost, createKyClient } from '@outputai/core/http';
// WRONG - Tracking cost yourself in a side table, or skipping it for paid APIsimport { FatalError, ValidationError } from '@outputai/core';
import { createKyClient } from '@outputai/core/http';
import { credentials } from '@outputai/core/credentials';
const API_KEY = credentials.require('service.api_key');
const BASE_URL = 'https://api.service.com';
const client = createKyClient({
prefix: BASE_URL,
headers: {
Authorization: `Bearer ${API_KEY}`,
Accept: 'application/json'
},
timeout: 30000,
retry: {
limit: 3,
statusCodes: [408, 429, 500, 502, 503, 504]
}
});
/**
* Fetch data from the service
*
* @param query - Search query string
* @returns Processed response data
* @throws {FatalError} If authentication fails or resource not found
* @throws {ValidationError} If temporary error occurs
*/
export async function fetchServiceData(query: string): Promise<ServiceResponse> {
const response = await client.get('endpoint', {
searchParams: { q: query }
});
const data = await response.json();
if (!data.results) {
throw new FatalError('No results returned from service');
}
return data;
}import { FatalError, ValidationError } from '@outputai/core';
import { createKyClient } from '@outputai/core/http';
import { credentials } from '@outputai/core/credentials';
export interface ServiceOptions {
model?: string;
timeout?: number;
}
export class ServiceClient {
private readonly client: ReturnType<typeof createKyClient>;
private readonly model: string;
constructor(apiKey?: string) {
const key = apiKey ?? credentials.require('service.api_key');
this.client = createKyClient({
prefix: 'https://api.service.com',
headers: {
Authorization: `Bearer ${key}`,
'Content-Type': 'application/json'
},
timeout: 30000,
retry: {
limit: 3,
statusCodes: [408, 429, 500, 502, 503, 504]
}
});
this.model = 'default-model';
}
async process(input: ProcessInput): Promise<ProcessOutput> {
try {
const response = await this.client.post('process', {
json: {
model: this.model,
input
}
});
return await response.json();
} catch (error: unknown) {
const err = error as { status?: number; message?: string };
if (err.status === 429) {
throw new ValidationError(`Rate limit exceeded: ${err.message}`);
}
if (err.status === 401 || err.status === 403) {
throw new FatalError(`Authentication failed: ${err.message}`);
}
throw new ValidationError(`Service call failed: ${err.message}`);
}
}
}import { FatalError } from '@outputai/core';
import { createKyClient } from '@outputai/core/http';
import { credentials } from '@outputai/core/credentials';
const JINA_API_KEY = credentials.require('jina.api_key');
const JINA_BASE_URL = 'https://r.jina.ai';
const client = createKyClient({
prefix: JINA_BASE_URL,
headers: {
AuthorizatiThe 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.