scaffold-client
Skill0 starsChanged 5 months agoMITView on GitHub
Add a new API client with built-in rate limiting, retry, and timeout. Generates from the base client template and adds config entries. Use when integrating a new external API.
- Reads credentials
In this repository8 other files it gives its agents.
- CLAUDE.mdCLAUDE.md
- browseSkill
- discoverSkill
- onboardSkill
- rememberSkill
- scaffold-projectSkill
- scaffold-taskSkill
- scaffold-viewerSkill
The file
We split this skill into the rules it gives an agent
5 rules. About 0 are common, 1 is distinctive, and 4 are very specific to this project.
≈0
Common · estimate
Many files like this have a rule of this kind.
≈1
Distinctive · estimate
This author's own choices. Worth a look.
4
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Very specific: line 16
If $ARGUMENTS provides an API name, use it as a starting point.
- Very specific: line 29
Read ${CLAUDE_SKILL_DIR}/../../imp_doc/api-clients/patterns.md for client architecture patterns.
- Very specific: line 164
Read .outbound-builder-plugin-memory.json (create with {"version":1,"entries":[],"proven_patterns":[]} if missing)
- Distinctive: line 175
Always include BOTH token bucket (per-second smoothing) AND sliding window (per-minute ceiling)
- Very specific: line 178
Every HTTP call must be preceded by rateLimiter.acquire("<api-name>")
≈ “Common” is an estimate: at least 1 in 5 of the 350,495 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
Scaffold a New API Client
You create a production-ready API client with rate limiting, retry logic, and timeout handling, plus register it in pipeline config.
Process
Step 1: Gather API Details
If $ARGUMENTS provides an API name, use it as a starting point. Ask the user:
- API name (e.g., "twitter", "hubspot", "stripe") — used for file name and rate limiter key
- Base URL (e.g.,
https://api.twitter.com/2) - Auth type:
- API key in header (e.g.,
X-Api-Key: <key>) - Bearer token (e.g.,
Authorization: Bearer <token>) - Query parameter (e.g.,
?api_key=<key>)
- API key in header (e.g.,
- Rate limits from the provider's docs:
- Requests per second (or per 10 seconds)
- Requests per minute (or per hour — convert to per minute)
- Typical response time (for timeout configuration)
Read ${CLAUDE_SKILL_DIR}/../../imp_doc/api-clients/patterns.md for client architecture patterns.
Step 2: Generate Client File
Copy from ${CLAUDE_SKILL_DIR}/../../templates/base-api-client.ts and customize.
Create src/clients/<api-name>.ts with:
- Class name:
<ApiName>Client(PascalCase) - Base URL from Step 1
- Auth header/param configured from environment variable
rateLimiter.acquire("<api-name>")before every HTTP call- Retry logic: 3 attempts, linear backoff (1s, 2s, 3s) for 429/5xx
- Non-transient errors (400, 401, 403, 404) fail immediately
- Timeout via
AbortSignal.timeout() - 2-3 example methods matching common API patterns:
export class <ApiName>Client {
private baseUrl: string;
private apiKey: string;
constructor() {
this.baseUrl = "<base-url>";
this.apiKey = process.env.<API_NAME>_API_KEY!;
}
async getResource(id: string): Promise<ResourceResponse> {
await rateLimiter.acquire("<api-name>");
// fetch with retry, timeout, auth
}
async listResources(params: ListParams): Promise<ListResponse> {
await rateLimiter.acquire("<api-name>");
// fetch with retry, timeout, auth
}
}Step 3: Add Rate Limit Config
Edit src/lib/pipeline-config.ts, add to RATE_LIMITS:
<apiName>: {
tokensPerSecond: <N>, // Provider limit: <actual>/s — using 85% safety margin
maxBurst: <burst>, // Allow short bursts above sustained rate
windowMaxRequests: <N>, // Provider limit: <actual>/min — using 85%
windowSeconds: 60,
},Safety margin rule: Set token bucket and window limits to ~85% of the provider's documented limits. This accounts for clock drift, concurrent consumers, and measurement differences.
Step 4: Add Timeout Config
Edit src/lib/pipeline-config.ts, add to FETCH_TIMEOUTS:
<apiName>: <milliseconds>, // Typical response: <N>ms, timeout at 3xSet timeout to ~3x the typical response time. Minimum 5000ms, maximum 30000ms.
Step 5: Add Environment Variable
Append to .env.example:
# <API Display Name>
<API_NAME>_API_KEY=<YOUR_<API_NAME>_API_KEY>Step 6: Generate Test File
Create tests/unit/<api-name>-client.test.ts:
import { describe, it, expect, vi } from "vitest";
describe("<ApiName>Client", () => {
it("should include auth header in requests", async () => {
// Verify auth is attached to every request
});
it("should retry on 429 and 5xx errors", async () => {
// Mock fetch to return 429, then 200 — verify retry
});
it("should not retry on 4xx client errors", async () => {
// Mock fetch to return 400 — verify immediate failure
});
it("should respect timeout", async () => {
// Mock fetch to hang — verify abort after timeout
});
});Step 7: Report
API client "<api-name>" scaffolded:
src/clients/<api-name>.ts — Client class with rate limiting + retry
tests/unit/<api-name>-client.test.ts — Unit tests
Config updates:
src/lib/pipeline-config.ts — Added RATE_LIMITS.<apiName>
src/lib/pipeline-config.ts — Added FETCH_TIMEOUTS.<apiName>
.env.example — Added <API_NAME>_API_KEY
Rate limits configured:
Token bucket: <N>/s (burst <M>) — 85% of provider's <actual>/s
Window: <N>/min — 85% of provider's <actual>/min
Timeout: <T>ms
Next steps:
1. Add your API key to .env
2. Implement the specific methods you need in the client
3. Import the client in your task file: import { <ApiName>Client } from "../src/clients/<api-name>"
4. Run tests: npm test -- tests/unit/<api-name>-client.test.tsStep 8: Record Learnings
Reflect on the scaffolding process. If you encountered any of the following, record them to .outbound-builder-plugin-memory.json:
- Errors or workarounds (e.g., dependency conflicts, config issues)
- Non-obvious behaviors (e.g., a template needed unexpected modifications)
- API quirks or platform-specific gotchas
- Schema decisions that differed from the template defaults
For each learning:
- Determine the category:
error-fix,api-quirk,schema-pattern,config-gotcha,build-pattern, ordomain-insight - Generate a deterministic ID:
mem-+ first 8 chars of MD5 hash ofcategory:title(use python3) - Read
.outbound-builder-plugin-memory.json(create with{"version":1,"entries":[],"proven_patterns":[]}if missing) - Dedup by ID -- if the same ID exists, increment
success_countand updatedate - Otherwise append a new entry with
success_count: 1,source: "scaffold", andcontext.stage: "scaffold-client" - Rebuild
proven_patternsfrom entries withsuccess_count >= 2 - Write the file
Skip this step if nothing noteworthy happened during scaffolding.
Rules
- Rate limits must use 85% of provider limits (safety margin for clock drift and concurrent consumers)
- Always include BOTH token bucket (per-second smoothing) AND sliding window (per-minute ceiling)
- Auth credentials must come from environment variables — never hardcoded
- Retry only on transient errors (429, 5xx) — fail immediately on 4xx client errors
- Every HTTP call must be preceded by
rateLimiter.acquire("<api-name>") - Rate limiting is centralized in
src/lib/pipeline-config.ts— never configure limits in client files - Reference
${CLAUDE_SKILL_DIR}/../../imp_doc/api-clients/patterns.mdfor client patterns
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
No reviews yet
People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.
- It worked
- Partly
- It didn't
Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

