Sub2API Admin
Wei-Shaw/sub2api
Manages a Sub2API deployment from the command line: accounts, redeem and invitation codes, groups, proxies, imports, exports and raw admin API calls.
Create shared HTTP clients in src/shared/clients/ for Output SDK workflows.
$ npx skills add growthxai/output --skill output-dev-http-client-create -a claude-codeProject install by default; add -g for ~/.claude/skills/.
$ gh skill install growthxai/output output-dev-http-client-create --agent claude-codeProject scope by default; add --scope user for a personal install. Needs GitHub CLI 2.90.0 or later (public preview).
$ git clone --depth 1 https://github.com/growthxai/output.git skills-src && mkdir -p .claude/skills && cp -r skills-src/coding_assistants/claude/plugins/outputai/skills/output-dev-http-client-create .claude/skills/output-dev-http-client-create && rm -rf skills-srcUse ~/.claude/skills/ instead of .claude/skills for a personal install. The folder must contain SKILL.md.
Claude Code skills documentation · loads skills from .claude/skills/
Install the "output-dev-http-client-create" agent skill from https://github.com/growthxai/output/tree/main/coding_assistants/claude/plugins/outputai/skills/output-dev-http-client-create into .claude/skills/output-dev-http-client-create/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "output-dev-http-client-create", then confirm the skill loads.Claude Code copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$skill-installer install https://github.com/growthxai/output/tree/main/coding_assistants/claude/plugins/outputai/skills/output-dev-http-client-createType this inside Codex. $skill-installer <name> installs a curated skill from openai/skills. The installer writes to $CODEX_HOME/skills (default ~/.codex/skills). Restart Codex if the skill does not show up.
$ npx skills add growthxai/output --skill output-dev-http-client-create -a codexProject install goes to .agents/skills/; add -g for ~/.codex/skills/.
$ gh skill install growthxai/output output-dev-http-client-create --agent codexProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/growthxai/output.git skills-src && mkdir -p .agents/skills && cp -r skills-src/coding_assistants/claude/plugins/outputai/skills/output-dev-http-client-create .agents/skills/output-dev-http-client-create && rm -rf skills-srcUse ~/.agents/skills/ instead of .agents/skills for a personal install.
Codex skills documentation · loads skills from .agents/skills/
Install the "output-dev-http-client-create" agent skill from https://github.com/growthxai/output/tree/main/coding_assistants/claude/plugins/outputai/skills/output-dev-http-client-create into .agents/skills/output-dev-http-client-create/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "output-dev-http-client-create", then confirm the skill loads.Codex copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ npx skills add growthxai/output --skill output-dev-http-client-create -a cursorProject install goes to .agents/skills/; add -g for ~/.cursor/skills/.
$ gh skill install growthxai/output output-dev-http-client-create --agent cursorProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/growthxai/output.git skills-src && mkdir -p .cursor/skills && cp -r skills-src/coding_assistants/claude/plugins/outputai/skills/output-dev-http-client-create .cursor/skills/output-dev-http-client-create && rm -rf skills-srcUse ~/.cursor/skills/ instead of .cursor/skills for a personal install.
Cursor skills documentation · loads skills from .cursor/skills/, .agents/skills/, .claude/skills/, .codex/skills/
Install the "output-dev-http-client-create" agent skill from https://github.com/growthxai/output/tree/main/coding_assistants/claude/plugins/outputai/skills/output-dev-http-client-create into .cursor/skills/output-dev-http-client-create/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "output-dev-http-client-create", then confirm the skill loads.Cursor copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ gemini skills install https://github.com/growthxai/output.git --path coding_assistants/claude/plugins/outputai/skills/output-dev-http-client-create--scope user (default) or --scope workspace; --path is the subfolder of the repo that holds the skill; --consent skips the security confirmation prompt.
$ npx skills add growthxai/output --skill output-dev-http-client-create -a gemini-cliProject install goes to .agents/skills/; add -g for ~/.gemini/skills/.
$ gh skill install growthxai/output output-dev-http-client-create --agent gemini-cliProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/growthxai/output.git skills-src && mkdir -p .gemini/skills && cp -r skills-src/coding_assistants/claude/plugins/outputai/skills/output-dev-http-client-create .gemini/skills/output-dev-http-client-create && rm -rf skills-srcUse ~/.gemini/skills/ instead of .gemini/skills for a personal install, then run /skills reload.
Gemini CLI skills documentation · loads skills from .gemini/skills/, .agents/skills/
Install the "output-dev-http-client-create" agent skill from https://github.com/growthxai/output/tree/main/coding_assistants/claude/plugins/outputai/skills/output-dev-http-client-create into .gemini/skills/output-dev-http-client-create/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "output-dev-http-client-create", then confirm the skill loads.Gemini CLI copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ gh skill install growthxai/output output-dev-http-client-createInstalls for Copilot at project scope by default; add --scope user for a personal install. Preview a skill first with gh skill preview. Needs GitHub CLI 2.90.0 or later (public preview).
$ npx skills add growthxai/output --skill output-dev-http-client-create -a github-copilotProject install goes to .agents/skills/; add -g for ~/.copilot/skills/.
$ git clone --depth 1 https://github.com/growthxai/output.git skills-src && mkdir -p .github/skills && cp -r skills-src/coding_assistants/claude/plugins/outputai/skills/output-dev-http-client-create .github/skills/output-dev-http-client-create && rm -rf skills-srcUse ~/.copilot/skills/ instead of .github/skills for a personal install. Commit .github/skills so cloud agent and code review can use it.
GitHub Copilot skills documentation · loads skills from .github/skills/, .claude/skills/, .agents/skills/
Install the "output-dev-http-client-create" agent skill from https://github.com/growthxai/output/tree/main/coding_assistants/claude/plugins/outputai/skills/output-dev-http-client-create into .github/skills/output-dev-http-client-create/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "output-dev-http-client-create", then confirm the skill loads.GitHub Copilot copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ npx skills add growthxai/output --skill output-dev-http-client-create -a opencodeOpenCode documents no install command of its own. Project install goes to .agents/skills/; add -g for ~/.config/opencode/skills/.
$ gh skill install growthxai/output output-dev-http-client-create --agent opencodeProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/growthxai/output.git skills-src && mkdir -p .opencode/skills && cp -r skills-src/coding_assistants/claude/plugins/outputai/skills/output-dev-http-client-create .opencode/skills/output-dev-http-client-create && rm -rf skills-srcUse ~/.config/opencode/skills/ instead of .opencode/skills for a personal install.
OpenCode skills documentation · loads skills from .opencode/skills/, .claude/skills/, .agents/skills/
Install the "output-dev-http-client-create" agent skill from https://github.com/growthxai/output/tree/main/coding_assistants/claude/plugins/outputai/skills/output-dev-http-client-create into .opencode/skills/output-dev-http-client-create/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "output-dev-http-client-create", then confirm the skill loads.OpenCode copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
output-dev-http-client-createCreate shared HTTP clients in src/shared/clients/ for Output SDK workflows.
Output Dev HTTP Client Create is an agent skill from growthxai/output. Create shared HTTP clients in src/shared/clients/ for Output SDK workflows. Use when integrating external APIs, creating service wrappers, or standardizing HTTP operations.
Its SKILL.md is about 4.9k tokens, which your agent loads only when the skill is triggered. It is a single SKILL.md file with no bundled scripts.
It sits in Backend & APIs, covering Third-party API integration. The repository describes itself as: 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… The licence is Apache-2.0.
5 steps, taken from the step headings in SKILL.md.
Read from SKILL.md and the folder at commit 52b51ac. It shows what the files ask for, not the result of running them.
Pre-approves these tools, so the agent can use them without asking each time:
ReadWriteEditGlobFrom allowed-tools in the SKILL.md frontmatter.
Shell commands in SKILL.md call:
npxFrom the folder's file list and the shell code blocks in SKILL.md.
Hosts in commands or code, which the agent is likely to contact:
api.service.comr.jina.aiFrom URLs in SKILL.md, links to its own repository left out.
Names these keys or tokens, usually read from environment variables:
API_KEYJINA_API_KEYSERVICE_API_KEYFrom names ending in _API_KEY, _TOKEN, _SECRET, _KEY or _PASSWORD in SKILL.md.
Output Dev HTTP Client Create loads about 4.9k tokens when it runs. Until then it costs about 51 tokens; SKILL.md has 896 words of instructions outside code blocks.
Estimates: characters ÷ 4, the usual rule of thumb; real counts depend on the model's tokenizer. Scripts and assets cost tokens only if the agent reads them.
The automated check found no risky patterns in SKILL.md.
Automated static check — not a guarantee. Review scripts before installing. It scans the text of SKILL.md for risky patterns (piping downloads into a shell, reading credential files, hidden Unicode, destructive commands); files beside SKILL.md are not scanned.
The full file from growthxai/output at commit 52b51ac, republished under its Apache-2.0 licence (© growthxai). 896 words, ~4,937 tokens.
.claude/skills/output-dev-http-client-create/SKILL.md (or your agent's skills folder).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 clientImportant: 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/http wrapper
import { createKyClient } from '@outputai/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/http
import { addRequestCost, createKyClient } from '@outputai/http';
// WRONG - Tracking cost yourself in a side table, or skipping it for paid APIsimport { FatalError, ValidationError } from '@outputai/core';
import { createKyClient } from '@outputai/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/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/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: {
Authorization: `Bearer ${JINA_API_KEY}`,
Accept: 'application/json'
},
timeout: 30000,
retry: {
limit: 3,
statusCodes: [408, 413, 429, 500, 502, 503, 504]
}
});
/**
* Parse PDF resume using Jina Reader API
*/
export async function parseResumeWithJina(base64Pdf: string): Promise<string> {
const response = await client.post('', {
json: { pdf: base64Pdf },
headers: {
'Content-Type': 'application/json'
}
});
const data: {
data: {
content: string;
title?: string;
};
} = await response.json();
if (!data.data?.content) {
throw new FatalError('No content returned from Jina PDF parser');
}
return data.data.content;
}
/**
* Scrape text content from URL using Jina Reader
*/
export async function scrapeTextWithJina(url: string): Promise<string> {
const response = await client.get(url, {
headers: {
'X-Return-Format': 'text',
'X-No-Cache': 'true',
'X-Timeout': '30'
}
});
const data: {
data: {
text?: string;
content?: string;
};
} = await response.json();
const textContent = data.data?.text || data.data?.content;
if (!textContent) {
throw new FatalError(`No text content returned from URL: ${url}`);
}
return textContent;
}import { GoogleGenerativeAI } from '@google/generative-ai';
import { FatalError, ValidationError } from '@outputai/core';
import { credentials } from '@outputai/core/credentials';
export interface GeminiImageGenerationOptions {
prompt: string;
referenceImages?: Array<{
inlineData: {
mimeType: string;
data: string;
};
}>;
aspectRatio?: string;
resolution?: string;
numberOfImages?: number;
}
export class GeminiImageService {
private readonly client: GoogleGenerativeAI;
// current as of 2026-05-04 — run output-dev-model-selection for the latest
private readonly model: string = 'gemini-3-pro-image';
constructor(apiKey = credentials.require('google.api_key')) {
if (!apiKey) {
throw new FatalError(
'GeminiImageService: No API Key provided (google.api_key credential).'
);
}
this.client = new GoogleGenerativeAI(apiKey);
}
async generateImage(options: GeminiImageGenerationOptions): Promise<string[]> {
const { prompt, referenceImages = [], aspectRatio = '1:1', resolution = '1K', numberOfImages = 1 } = options;
try {
const model = this.client.getGenerativeModel({ model: this.model });
const parts: Array<{ text: string } | { inlineData: { mimeType: string; data: string } }> = [];
if (referenceImages.length > 0) {
referenceImages.forEach(img => parts.push(img));
}
const finalPrompt = `${prompt}\n\nGenerate this as a ${aspectRatio} aspect ratio image at ${resolution} resolution.`;
parts.push({ text: finalPrompt });
const result = await model.generateContent({
contents: [{ role: 'user', parts }],
generationConfig: {
temperature: 1.0,
topP: 0.95,
candidateCount: numberOfImages,
maxOutputTokens: 8192
}
});
const images: string[] = [];
const candidates = result.response.candidates || [];
for (const candidate of candidates) {
if (candidate.content?.parts) {
for (const part of candidate.content.parts) {
if (part.inlineData?.data) {
images.push(part.inlineData.data);
}
}
}
}
if (images.length === 0) {
throw new ValidationError('No images were generated by Gemini');
}
return images;
} catch (error: unknown) {
const err = error as { status?: number; message?: string };
if (err.status === 429) {
throw new ValidationError(`Gemini rate limit exceeded: ${err.message}`);
}
if (err.status === 401 || err.status === 403) {
throw new FatalError(`Gemini authentication failed: ${err.message}`);
}
throw new ValidationError(`Gemini image generation failed: ${err.message}`);
}
}
}const RETRY_STATUS_CODES = [408, 429, 500, 502, 503, 504];
const FATAL_STATUS_CODES = [401, 403, 404];
const client = createKyClient({
retry: {
limit: 3,
statusCodes: RETRY_STATUS_CODES
},
hooks: {
beforeError: [
( { error } ) => {
const status = error.response?.status;
const message = error.message;
if (status && FATAL_STATUS_CODES.includes(status)) {
throw new FatalError(`HTTP ${status} error: ${message}`);
}
throw new ValidationError(`HTTP request failed: ${message}`);
}
]
}
});| Status Code | Error Type | Reason |
|---|---|---|
| 401, 403 | FatalError | Auth failures won't succeed on retry |
| 404 | FatalError | Resource doesn't exist |
| 408 | ValidationError | Timeout, may succeed on retry |
| 429 | ValidationError | Rate limit, will succeed after wait |
| 500+ | ValidationError | Server errors may be temporary |
If the service a client wraps charges money per request, attach that cost to the request's trace so it shows up in npx output workflow cost (see output-dev-workflow-cost) and in any cost:http:request hook handlers (see output-dev-cost-hooks).
Do this on the client itself, in an afterResponse hook — not at each call site. That way every function or method that goes through the client is costed automatically, and nobody integrating with the client later has to remember to do it.
addRequestCost(response, totalUsd) only works on a response that came from outputFetch or createKyClient — including a response.clone() of one, so it's safe to call from inside an afterResponse hook (ky passes hooks a clone). If the response didn't originate from @outputai/http, addRequestCost no-ops with a console warning.
There are two common pricing shapes for paid third-party APIs:
Some APIs report what a specific call cost — in a response header or a JSON field (credits used, units billed, etc). Read that field and pass it straight to addRequestCost. Guard against free or cached responses that legitimately report zero cost.
import { addRequestCost, createKyClient } from '@outputai/http';
import { credentials } from '@outputai/core/credentials';
const API_KEY = credentials.require('service.api_key');
const client = createKyClient({
prefix: 'https://api.service.com',
headers: { Authorization: `Bearer ${API_KEY}` },
timeout: 30000,
retry: { limit: 3, statusCodes: [408, 429, 500, 502, 503, 504] },
hooks: {
afterResponse: [
async (_request, _options, response) => {
// Errored responses (4xx/5xx) and retried attempts aren't billed the
// same as a successful call — skip them rather than over-counting.
if (!response.ok) {
return;
}
try {
const body = await response.clone().json() as { creditsUsed?: number; cached?: boolean };
// Skip cached or free responses that legitimately cost nothing.
if (body.cached || !body.creditsUsed) {
return;
}
const usdPerCredit = 0.01;
addRequestCost(response, body.creditsUsed * usdPerCredit);
} catch {
// Never let cost tracking break the request.
}
}
]
}
});When a service is billed as a flat monthly fee or subscription tier, there's no true marginal cost per call — but recording some per-call figure keeps spend comparable across services in workflow cost and any cost dashboards. Assign a notional per-call USD rate as a constant, overridable by a non-secret environment variable so it can be tuned without a code change.
import { addRequestCost, createKyClient } from '@outputai/http';
import { credentials } from '@outputai/core/credentials';
const API_KEY = credentials.require('service.api_key');
// Notional per-call cost for a flat-rate subscription. Not a secret, so a
// plain env var is fine here — unlike API keys, which must go through
// @outputai/core/credentials.
const NOTIONAL_COST_USD = Number(process.env.SERVICE_NOTIONAL_COST_USD ?? 0.005);
const client = createKyClient({
prefix: 'https://api.service.com',
headers: { Authorization: `Bearer ${API_KEY}` },
timeout: 30000,
retry: { limit: 3, statusCodes: [408, 429, 500, 502, 503, 504] },
hooks: {
afterResponse: [
(_request, _options, response) => {
// Errored responses (4xx/5xx) and retried attempts aren't billed the
// same as a successful call — skip them rather than over-counting.
if (!response.ok) {
return;
}
addRequestCost(response, NOTIONAL_COST_USD);
}
]
}
});The constant above is a placeholder — config/costs.yml (see output-dev-workflow-cost) can override the actual dollar figure per service afterward, without another code change. Add a services.<name> entry with type: request, a matching url_pattern, and an endpoints.<name> block giving pattern + price for the call. (default_price only applies inside a models/model_path entry, for picking a fallback price when the request's model isn't in models — it does nothing paired with a bare url_pattern.) Prefer that file over inventing more env vars once you have more than one or two notional rates to tune.
Rules:
throw from an afterResponse cost hook — a throw there fails the request itself. Wrap body parsing in try/catch and silently skip on parse failure.!response.ok attempts unless you know the API bills failed requests too (the framework itself does count a recorded cost event "regardless of HTTP status" once one exists — the event is proof of a charge). When in doubt, check the provider's billing docs before adding the guard.llm:generation:metering. addRequestCost is for non-LLM HTTP calls only.output-dev-cost-hooks.Prefer @outputai/core/credentials over process.env for secrets management. See output-dev-credentials skill for details.
import { credentials } from '@outputai/core/credentials';
// credentials.require() throws MissingCredentialError if not found
const apiKey = credentials.require('service.api_key');
// credentials.get() returns undefined or default if not found
const region = credentials.get('aws.region', 'us-east-1');/**
* Fetch user profile from external service
*
* @param userId - Unique user identifier
* @returns User profile data
* @throws {FatalError} If user not found or auth fails
* @throws {ValidationError} If temporary error occurs
*
* @example
* const profile = await fetchUserProfile('user-123');
*/
export async function fetchUserProfile(userId: string): Promise<UserProfile> {
// ...
}// Standard timeout: 30 seconds
timeout: 30000
// Long-running operations: 60 seconds
timeout: 60000createKyClient follows Fetch response-body semantics: callers own returned response bodies. Prefer body readers like .json() or .text()
when the payload is needed. If a request only reads metadata such as response.url, response.status, or headers, cancel the
unused body in a finally block.
const response = await client.get( url );
try {
return response.url;
} finally {
await response.body?.cancel();
}HEAD requests do not have response bodies, so this is only needed for methods that can return one.
// Export interfaces for consumers
export interface ServiceResponse {
data: {
id: string;
content: string;
};
metadata: {
processedAt: string;
};
}src/shared/clients/ directory{service}_client.tscreateKyClient imported from @outputai/http (not axios)FatalError and ValidationError imported from @outputai/coreaddRequestCost in an afterResponse hookoutput-dev-step-function - Using clients in step functionsoutput-dev-evaluator-function - Using clients in evaluatorsoutput-dev-folder-structure - Understanding project layoutoutput-dev-credentials - Encrypted secrets managementoutput-dev-cost-hooks - Subscribing to cost events (cost:http:request, llm:generation:metering) for observabilityoutput-error-http-client - Troubleshooting HTTP issuesoutput-error-try-catch - Proper error handling patterns© growthxai, Apache-2.0. Rendered from Markdown: HTML in the file is shown as text, images as links, and headings moved down two levels. Raw file
Just SKILL.md in coding_assistants/claude/plugins/outputai/skills/output-dev-http-client-create of growthxai/output.
Open the folder on GitHubat commit 52b51ac
Output Dev HTTP Client Create next to the 5 skills that share the most tags, products or categories with it. Stars are the repository's; “used in” counts other GitHub owners with a copy.
| Skill | Stars | Used in | Tokens | Auto-check | Licence | Repo updated |
|---|---|---|---|---|---|---|
| Output Dev HTTP Client Create this skillgrowthxai/output | 440 | — | ~4.9k | Automated safety check: Pass | Apache-2.0 | |
| Sub2API AdminWei-Shaw/sub2api | 43k | 1 repos | ~717 | Automated safety check: Pass | LGPL-3.0 | |
| Firecrawl Build Onboardingfirecrawl/firecrawl | 190k | 1 repos | ~1.4k | Automated safety check: Notes | ISC | |
| ToolJet Marketplace Plugin BuilderToolJet/ToolJet | 41k | — | ~2.1k | Automated safety check: Pass | AGPL-3.0 | |
| Firecrawl Search Integrationfirecrawl/firecrawl | 190k | 1 repos | ~1.1k | Automated safety check: Pass | ISC | |
| CoinGecko API Reference2025Emma/vibe-coding-cn | 23k | 2 repos | ~646 | Automated safety check: Pass | MIT |
Wei-Shaw/sub2api
Manages a Sub2API deployment from the command line: accounts, redeem and invitation codes, groups, proxies, imports, exports and raw admin API calls.
firecrawl/firecrawl
Gets Firecrawl working in a project: signs you in through the browser, saves FIRECRAWL_API_KEY to .env and picks the first SDK or REST path.
ToolJet/ToolJet
Turns an API description, such as an OpenAPI file or a Postman collection, into a connector plugin for ToolJet's marketplace and checks it with the repo's validator.
firecrawl/firecrawl
Guidance for adding Firecrawl's /search endpoint to product code and agent workflows when a feature starts from a query rather than a URL.
2025Emma/vibe-coding-cn
CoinGecko API documentation - cryptocurrency market data API, price feeds, market cap, volume, historical data. Use when integrating CoinGecko API, building…
internet-court/internet-court-skill
Builds cross-chain token swaps and bridge flows with the NEAR Intents 1Click API: quotes, deposit addresses, per-chain deposits and status polling.
growthxai/output
Zod schema constraints that Anthropic rejects or silently ignores when sent as structured-output tool definitions via aiSdk.Output.object().
growthxai/output
Implement an Output SDK workflow from a plan document. An agent skill from growthxai/output.
growthxai/output
View, edit, and set encrypted credentials in an Output.ai project.
growthxai/output
Wire encrypted credentials to environment variables using the credential: convention.
growthxai/output
Initialize encrypted credentials for an Output.ai project. An agent skill from growthxai/output.
growthxai/output
Debug Output SDK workflow issues. An agent skill from growthxai/output.
Categories
Create shared HTTP clients in src/shared/clients/ for Output SDK workflows. Output Dev HTTP Client Create is an agent skill from growthxai/output. Create shared HTTP clients in src/shared/clients/ for Output SDK workflows.
Output Dev HTTP Client Create fits situations like: integrating external APIs; creating service wrappers; standardizing HTTP operations.
Run `npx skills add growthxai/output --skill output-dev-http-client-create -a claude-code`. Or copy the skill folder (coding_assistants/claude/plugins/outputai/skills/output-dev-http-client-create in growthxai/output) into .claude/skills/output-dev-http-client-create in your project. Claude Code loads it when a task matches its description.
Run `npx skills add growthxai/output --skill output-dev-http-client-create -a codex`. Or copy the skill folder (coding_assistants/claude/plugins/outputai/skills/output-dev-http-client-create in growthxai/output) into .agents/skills/output-dev-http-client-create in your project. Codex loads it when a task matches its description.
Cursor, Gemini CLI, GitHub Copilot and OpenCode also load SKILL.md folders. With the skills CLI, run `npx skills add growthxai/output --skill output-dev-http-client-create -a cursor` (or -a gemini-cli, github-copilot or opencode for the others). To copy it by hand, put the folder in .cursor/skills/output-dev-http-client-create, .gemini/skills/output-dev-http-client-create, .github/skills/output-dev-http-client-create and .opencode/skills/output-dev-http-client-create in your project.
Going by SKILL.md and its folder, Output Dev HTTP Client Create needs the command-line tools its instructions call (npx) and credentials named API_KEY, JINA_API_KEY and SERVICE_API_KEY. Our summary lists: Node.js; A credential in SERVICE_API_KEY; A credential in API_KEY. Its frontmatter pre-approves these tools: Read, Write, Edit, Glob.
SKILL.md names 2 domains. In commands or code: api.service.com and r.jina.ai; the agent is likely to contact these when it follows the instructions. This is read from the text; nothing was executed.
Our automated static check of SKILL.md found no risky patterns, such as piping downloads into a shell, reading credential files or hidden Unicode. It is not a guarantee. Review the folder before installing.
Output Dev HTTP Client Create is published under the Apache-2.0 licence (the repository's licence). It allows redistribution, so the full SKILL.md is shown on this page.
About 4.9k tokens (SKILL.md is roughly 20k characters). Agents keep only the skill's name and description in context until a task matches; then they load SKILL.md in full.
Skills that share tags, products or a category with Output Dev HTTP Client Create: Sub2API Admin (Wei-Shaw/sub2api, 43k stars), Firecrawl Build Onboarding (firecrawl/firecrawl, 190k stars), ToolJet Marketplace Plugin Builder (ToolJet/ToolJet, 41k stars) and Firecrawl Search Integration (firecrawl/firecrawl, 190k stars). The comparison table on this page puts their stars, adoption, token cost, safety result and licence side by side.
growthxai (a GitHub organization) maintains it in growthxai/output, which has 440 GitHub stars. The repository holds 52 skills in this directory. The repository was last updated on October 7, 2026.
Source: growthxai/output on GitHub. Facts on this page come from the repository at the commit we read; the author's words are quoted as theirs.