specli
v0.0.39
Published
Run any OpenAPI spec as an Agent optimized executable
Readme
specli
Turn any OpenAPI spec into a CLI.
Demo
Compile this weather OpenAPI spec to an executable:
npx specli compile https://raw.githubusercontent.com/open-meteo/open-meteo/refs/heads/main/openapi.yml --name weatherAsk an agent what the current weather is:
opencode run 'Using ./out/weather what is the current weather in new york city'Install
npm install -g specliOr use directly with npx/bunx:
npx specli exec ./openapi.json __schema
bunx specli exec ./openapi.json __schemaCommands
exec
Run commands dynamically from any OpenAPI spec URL or file path. Works with both Node.js and Bun.
specli exec <spec> <resource> <action> [args...] [options]Examples:
# Inspect available commands
specli exec ./openapi.json __schema
# Machine-readable schema output
specli exec ./openapi.json __schema --json
# Minimal schema (best for large specs)
specli exec ./openapi.json __schema --json --min
# Run an operation
specli exec ./openapi.json users list
# Run with path parameters
specli exec ./openapi.json users get abc123
# Preview the curl command without executing
specli exec ./openapi.json users list --curl
# Dry run (show request details without executing)
specli exec ./openapi.json users list --dry-runcompile
Bundle an OpenAPI spec into a standalone executable. Requires Bun.
specli compile <spec> [options]Options:
| Option | Description |
|--------|-------------|
| --name <name> | Binary name (default: derived from spec title) |
| --outfile <path> | Output path (default: ./out/<name>) |
| --target <target> | Cross-compile target (e.g. bun-linux-x64) |
| --minify | Enable minification |
| --bytecode | Enable bytecode compilation |
| --no-dotenv | Disable .env autoload |
| --no-bunfig | Disable bunfig.toml autoload |
| --server <url> | Bake in a default server URL |
| --server-var <k=v> | Bake in server variables (repeatable) |
| --auth <scheme> | Bake in default auth scheme |
Examples:
# Compile with auto-derived name
specli compile ./openapi.yaml
# Creates: ./out/my-api
# Compile with explicit name
specli compile ./openapi.yaml --name myapi
# Creates: ./out/myapi
# Cross-compile for Linux
specli compile ./openapi.json --target bun-linux-x64 --outfile ./out/myapi-linux
# Bake in defaults
specli compile https://api.example.com/openapi.json \
--name myapi \
--server https://api.example.com \
--auth BearerAuthThe compiled binary works standalone:
./dist/myapi users list
./dist/myapi users get abc123 --jsonCLI Shape
specli generates commands of the form:
<resource> <action> [...positionals] [options]- resource: Derived from
tags[0],operationIdprefix, or first path segment - action: Inferred from HTTP method or
operationIdsuffix - Name collisions are disambiguated automatically
Use __schema to see the command mapping for any spec.
Global Options
| Option | Description |
|--------|-------------|
| --server <url> | Override server/base URL |
| --server-var <name=value> | Server URL template variable (repeatable) |
| --profile <name> | Profile name |
| --auth <scheme> | Select auth scheme by key |
| --bearer-token <token> | Set Authorization: Bearer <token> |
| --oauth-token <token> | Alias for --bearer-token |
| --username <user> | Basic auth username |
| --password <pass> | Basic auth password |
| --api-key <key> | API key value |
| --json | Machine-readable output |
Per-Operation Options
Every operation command includes:
| Option | Description |
|--------|-------------|
| --header <header> | Extra headers (repeatable, Name: Value or Name=Value) |
| --accept <type> | Override Accept header |
| --timeout <ms> | Request timeout in milliseconds |
| --dry-run | Print request details without sending |
| --curl | Print equivalent curl command without sending |
For operations with request bodies:
| Option | Description |
|--------|-------------|
| --data <data> | Inline request body |
| --file <path> | Read request body from file |
| --content-type <type> | Override Content-Type |
Parameters
Path Parameters
Path parameters become positional arguments in order:
/users/{id}/keys/{key_id} → <id> <key-id>Query/Header/Cookie Parameters
These become kebab-case flags:
limit → --limit
X-Request-Id → --x-request-idRequired parameters are enforced by the CLI.
Arrays
Array parameters are repeatable:
# All produce ?tag=a&tag=b
specli ... --tag a --tag b
specli ... --tag a,b
specli ... --tag '["a","b"]'Request Bodies
Body Field Flags
For JSON request bodies, specli generates convenience flags matching schema properties:
specli exec ./openapi.json contacts create --name "Ada" --email "[email protected]"Produces:
{"name":"Ada","email":"[email protected]"}Nested Objects
Use dot notation for nested properties:
mycli contacts create --name "Ada" --address.city "NYC" --address.zip "10001"Produces:
{"name":"Ada","address":{"city":"NYC","zip":"10001"}}Servers
Server URL resolution order:
--server <url>flag- Profile
serversetting - First
servers[0].urlin the spec
For templated URLs (e.g. https://{region}.api.example.com):
specli ... --server-var region=us-east-1Authentication
Supported Schemes
- HTTP Bearer (
type: http,scheme: bearer) - HTTP Basic (
type: http,scheme: basic) - API Key (
type: apiKey,in: header|query|cookie) - OAuth2 (
type: oauth2) - treated as bearer token - OpenID Connect (
type: openIdConnect) - treated as bearer token
Scheme Selection
--auth <scheme>flag (explicit)- Profile
authSchemesetting - If operation requires exactly one scheme, use it
- If spec defines exactly one scheme, use it
Providing Credentials
# Bearer/OAuth2/OIDC
specli ... --bearer-token <token>
# Basic auth
specli ... --username <user> --password <pass>
# API key
specli ... --api-key <key>Profiles
Store configuration for automation:
# List profiles
specli profile list
# Create/update profile
specli profile set --name dev --server https://api.example.com --auth bearerAuth --default
# Switch default profile
specli profile use --name dev
# Delete profile
specli profile rm --name dev
# Manage tokens
specli auth token --name dev --set "..."
specli auth token --name dev --get
specli auth token --name dev --deleteConfig location: ~/.config/specli/profiles.json
Output Modes
Default (Human Readable)
- Success: Pretty JSON for JSON responses, raw text otherwise
- HTTP errors:
HTTP <status>+ response body, exit code 1 - CLI errors:
error: <message>, exit code 1
--json (Machine Readable)
// Success
{"status":200,"body":{...}}
// HTTP error
{"status":404,"body":{...}}
// CLI error
{"error":"..."}--curl
Prints equivalent curl command without sending the request.
--dry-run
Prints method, URL, headers, and body without sending.
Programmatic API
Use specli as a library to execute OpenAPI operations programmatically:
import { specli } from "specli";
const api = await specli({
spec: "https://api.example.com/openapi.json",
bearerToken: process.env.API_TOKEN,
});
// List available resources and actions
const resources = api.list();
// Get help for a specific action
const help = api.help("users", "get");
// Execute an API call
const result = await api.exec("users", "get", ["123"], { include: "profile" });
if (result.type === "success" && result.response.ok) {
console.log(result.response.body);
}Options
| Option | Description |
|--------|-------------|
| spec | OpenAPI spec URL or file path (required) |
| server | Override server/base URL |
| serverVars | Server URL template variables (Record<string, string>) |
| bearerToken | Bearer token for authentication |
| apiKey | API key for authentication |
| basicAuth | Basic auth credentials ({ username, password }) |
| authScheme | Auth scheme to use (if multiple are available) |
Methods
| Method | Description |
|--------|-------------|
| list() | Returns all resources and their actions |
| help(resource, action) | Get detailed info about an action |
| exec(resource, action, args?, flags?) | Execute an API call |
CommandResult
The exec() method returns a CommandResult which is a discriminated union:
// Success
{
type: "success";
request: PreparedRequest;
response: {
status: number;
ok: boolean;
headers: Record<string, string>;
body: unknown;
rawBody: string;
};
timing: { startedAt: string; durationMs: number };
}
// Error
{
type: "error";
message: string;
response?: ResponseData; // If HTTP error
}Type guards are available for convenience:
import { isSuccess, isError } from "specli";
if (isSuccess(result)) {
console.log(result.response.body);
}AI SDK Integration
specli exports an AI SDK tool for use with LLM agents:
import { specli } from "specli/ai/tools";
import { generateText } from "ai";
const result = await generateText({
model: yourModel,
tools: {
api: await specli({
spec: "https://api.example.com/openapi.json",
bearerToken: process.env.API_TOKEN,
}),
},
prompt: "List all users",
});The specli() function is async and fetches the OpenAPI spec upfront, so the returned tool is ready to use immediately without any additional network requests.
The tool supports three commands:
list- Show available resources and actionshelp- Get details about a specific actionexec- Execute an API call
Limitations
- OpenAPI 3.x only (Swagger 2.0 not supported)
- Array serialization uses repeated keys only (
?tag=a&tag=b) - OpenAPI
style/explode/deepObject not implemented - Body field flags only support JSON with scalar/nested object properties
- Multipart and binary uploads not implemented
- OAuth2 token acquisition not implemented (use
--bearer-tokenwith pre-acquired tokens)
Development
bun install
bun run build
bun test
bun run lint
bun run typecheck