--- name: api2cli description: Generate a working CLI from any API, then wrap it in a Claude Code skill. Point it at API docs, a live URL, or a peek-api capture and get a dual-mode Commander.js CLI (human + agent output) plus a ready-to-use skill folder. Use when user wants to wrap an API in a CLI, generate a CLI from API docs, turn an API into a command-line tool, scaffold a CLI from discovered endpoints, or create a skill for an API. --- # api2cli Generate a working Node.js CLI from any API, then wrap it in a Claude Code skill. Discovers endpoints, scaffolds a dual-mode Commander.js CLI with a full-featured API client, and creates a skill folder so Claude knows how to use it. ## Workflow 1. **Identify the API** -- user provides a docs URL, a live API base URL, or a peek-api capture 2. **Discover endpoints** -- parse docs, probe the API, or read a peek-api catalog 3. **Build endpoint catalog** -- normalize all discovered endpoints into a standard format 4. **Generate CLI** -- scaffold Commander.js CLI from the catalog 5. **User chooses destination** -- scaffold into current project or create standalone project 6. **Generate skill** -- create a SKILL.md that teaches Claude how to use the generated CLI ## Step 1: Identify the API Ask the user: - "What API do you want to wrap? Share a docs URL, a base URL, or point me at a peek-api capture." Determine which discovery paths to use based on what they provide: | Input | Discovery Path | |-------|---------------| | Docs URL (e.g., `https://docs.stripe.com/api`) | Docs parsing + active probing | | Base URL (e.g., `https://api.example.com/v1`) | Active probing | | peek-api capture dir (e.g., `./peek-api-linkedin/`) | Read existing catalog | | Live website URL | Suggest running peek-api first, then active probing | Also ask: - "What auth does this API use?" (API key, Bearer token, cookies, OAuth, none) - "Do you want this CLI in your current project or as a standalone project?" ## Step 2: Discover Endpoints Use all applicable discovery paths. Combine results into a single catalog. ### Path A: Docs Parsing 1. Fetch the docs URL with WebFetch 2. Extract endpoint information: method, path, description, parameters, request/response examples 3. Look for pagination patterns, auth requirements, rate limit info 4. Follow links to sub-pages for individual endpoint docs if the main page is an index ### Path B: Active Probing 1. Check well-known paths for API specs: - `/.well-known/openapi.json`, `/.well-known/openapi.yaml` - `/openapi.json`, `/openapi.yaml`, `/swagger.json`, `/swagger.yaml` - `/api-docs`, `/docs`, `/api/docs` - `/graphql` (with introspection query) 2. Try `OPTIONS` on the base URL and common resource paths 3. Probe common REST patterns: `/api/v1/`, `/api/v2/`, `/v1/`, `/v2/` 4. For each discovered resource, try standard CRUD: `GET /resources`, `GET /resources/:id`, `POST /resources`, etc. 5. Parse response shapes to understand data models 6. Check response headers for rate limit info (`X-RateLimit-*`, `Retry-After`) 7. Check for pagination patterns in responses (`next`, `cursor`, `page`, `offset`) See `references/discovery-strategies.md` for detailed probing patterns. ### Path C: peek-api Capture 1. Read the capture directory: `endpoints.json`, `auth.json`, `CAPTURE.md` 2. Parse endpoints into the standard catalog format 3. Extract auth headers and cookies from `auth.json` If peek-api is not installed or no capture exists, tell the user: ``` To capture endpoints from a live site, install peek-api: git clone https://github.com/alexknowshtml/peek-api cd peek-api && npm install node bin/cli.js https://example.com ``` ## Step 3: Build Endpoint Catalog Normalize all discovered endpoints into this format: ```typescript interface EndpointCatalog { service: string; // e.g., "stripe", "nexudus" baseUrl: string; auth: { type: 'api-key' | 'bearer' | 'cookies' | 'oauth' | 'none'; headerName?: string; // e.g., "Authorization", "X-API-Key" envVar: string; // e.g., "STRIPE_API_KEY" }; pagination?: { style: 'cursor' | 'offset' | 'page' | 'link-header'; paramName: string; // e.g., "starting_after", "offset", "page" responseField: string; // e.g., "has_more", "next", "next_page_url" }; rateLimit?: { requests: number; window: string; // e.g., "1m", "1h" }; resources: ResourceGroup[]; } interface ResourceGroup { name: string; // e.g., "customers", "invoices" description: string; endpoints: Endpoint[]; } interface Endpoint { method: 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE'; path: string; // e.g., "/v1/customers/:id" description: string; parameters: Parameter[]; requestBody?: object; // JSON schema or example responseExample?: object; } interface Parameter { name: string; in: 'path' | 'query' | 'header'; required: boolean; type: string; description: string; } ``` Present the catalog to the user for review before generating: ``` Found 24 endpoints across 5 resources: customers (6 endpoints): list, get, create, update, delete, search invoices (5 endpoints): list, get, create, send, void ... Ready to generate the CLI? ``` ## Step 4: Generate CLI Generate a dual-mode CLI using Commander.js. The CLI auto-detects human vs agent output via `process.stdout.isTTY`. ### File Structure **In-project scaffold:** ``` scripts/ {service}.ts # Entry point with shebang {service}/ lib/ client.ts # API client (auth, pagination, retry, caching) envelope.ts # Agent JSON envelope helpers commands/ {resource}.ts # One file per resource group ``` **Standalone project:** ``` {service}-cli/ package.json tsconfig.json bin/ {service}.ts # Entry point with shebang src/ lib/ client.ts envelope.ts commands/ {resource}.ts ``` ### Code Generation Patterns See these references for the patterns to apply during generation: - `references/api-client-template.md` -- API client class with pagination, retry, rate limiting, caching - `references/agent-first-patterns.md` -- JSON envelope, HATEOAS next_actions, context-safe output, error fix suggestions - `references/commander-patterns.md` -- Commander.js subcommands, global options, interactive prompts, colored output ### Key Generation Rules **Entry point (`{service}.ts`):** - Shebang: `#!/usr/bin/env npx tsx` - Self-documenting root command (no args → prints full command tree as JSON) - Global options: `--json` (force JSON output), `--verbose`, `--config ` **API client (`lib/client.ts`):** - Constructor takes base URL + auth config - Auth from env var (name based on `catalog.auth.envVar`) - Built-in pagination matching the API's pattern - Retry with exponential backoff for 5xx and 429 errors - Rate limiting based on discovered limits - Optional response caching **Envelope helpers (`lib/envelope.ts`):** ```typescript const isAgent = !process.stdout.isTTY; function respond(command: string, result: any, nextActions: Action[] = []) { if (isAgent) { console.log(JSON.stringify({ ok: true, command, result, next_actions: nextActions })); } else { return result; // caller handles human rendering } } function respondError(command: string, message: string, code: string, fix: string, nextActions: Action[] = []) { if (isAgent) { console.log(JSON.stringify({ ok: false, command, error: { message, code }, fix, next_actions: nextActions })); } else { console.error(`Error: ${message}`); console.error(`Fix: ${fix}`); } process.exit(1); } ``` **Command files (`commands/{resource}.ts`):** - One file per resource group - Each endpoint becomes a subcommand: `mycli customers list`, `mycli customers get ` - `list` commands: support `--limit`, `--offset`/`--cursor`, `--status` (if filterable) - `get` commands: take ID as argument - `create`/`update` commands: accept `--data ` or individual `--field` flags - Every command includes contextual `next_actions` for agent mode - Errors include `fix` suggestions **Standalone project extras:** - `package.json` with `commander`, `tsx` as dependencies, `bin` field pointing to entry - `tsconfig.json` for TypeScript - `.env.example` with the required env var ## Step 5: Verify After generating the CLI: 1. **Verify it runs:** Execute with no args, confirm the self-documenting root works 2. **Test one endpoint:** Pick a simple GET endpoint, run it, verify output 3. **Move on to Step 6** to wrap the CLI in a skill ## Step 6: Generate Skill Create a Claude Code skill folder that teaches Claude how to use the generated CLI. This is the final step -- it turns the CLI into something any Claude session can pick up and use without reading the code. ### Skill Structure ``` .claude/skills/{service}/ SKILL.md # Skill instructions ``` ### SKILL.md Template Generate a SKILL.md with this structure: ```markdown --- name: {service} description: Interact with the {Service} API via CLI. Use when user wants to {list of actions based on discovered resources, e.g., "list customers, create invoices, check order status"}. Commands: {service} {resource} {action}. --- # {Service} CLI CLI wrapper for the {Service} API. ## Setup Set the `{SERVICE_ENV_VAR}` environment variable: \`\`\`bash export {SERVICE_ENV_VAR}=your-api-key-here \`\`\` ## Commands {For each resource group, list commands with examples:} ### {Resource} \`\`\`bash # List {resources} npx tsx {path/to/cli}.ts {resource} list # Get a specific {resource} npx tsx {path/to/cli}.ts {resource} get # Create a {resource} npx tsx {path/to/cli}.ts {resource} create --field value \`\`\` ## Common Workflows {Generate 2-3 practical workflows combining multiple commands:} ### Example: {Workflow name} \`\`\`bash # Step 1: Find the customer npx tsx {path/to/cli}.ts customers list --status=active # Step 2: Get their invoices npx tsx {path/to/cli}.ts invoices list --customer-id=abc123 \`\`\` ## Agent Usage When piped, all commands return JSON with `next_actions`: \`\`\`bash npx tsx {path/to/cli}.ts {resource} list | cat \`\`\` ``` ### Key Rules for Skill Generation 1. **Description is critical** -- include specific trigger phrases and list the actions the CLI supports. This is what Claude reads to decide when to use the skill. 2. **Include real command examples** -- use the actual CLI path and real subcommand names from the generated CLI. 3. **Generate practical workflows** -- combine multiple commands into realistic multi-step scenarios based on how the API's resources relate to each other. 4. **Keep it lean** -- the skill should be a quick reference, not a restatement of `--help`. Focus on what Claude needs to know that it can't infer. ### Tell the User After generating both the CLI and the skill: ``` CLI generated at {cli_path} Skill generated at .claude/skills/{service}/SKILL.md To use the CLI directly: npx tsx {cli_path} # See all commands npx tsx {cli_path} customers list # List customers Claude will now automatically use this skill when you ask about {service}. ``` ## Reference Files - `references/discovery-strategies.md` -- Detailed probing patterns, well-known paths, GraphQL introspection, response parsing - `references/api-client-template.md` -- Full API client class with pagination, retry, rate limiting, caching - `references/agent-first-patterns.md` -- Agent JSON envelope, HATEOAS, context-safe output, error handling - `references/commander-patterns.md` -- Commander.js subcommands, nested commands, interactive prompts, colored output, config files, testing