npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

specli

v0.0.39

Published

Run any OpenAPI spec as an Agent optimized executable

Readme

specli

npm version

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 weather

Ask 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 specli

Or use directly with npx/bunx:

npx specli exec ./openapi.json __schema
bunx specli exec ./openapi.json __schema

Commands

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-run

compile

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 BearerAuth

The compiled binary works standalone:

./dist/myapi users list
./dist/myapi users get abc123 --json

CLI Shape

specli generates commands of the form:

<resource> <action> [...positionals] [options]
  • resource: Derived from tags[0], operationId prefix, or first path segment
  • action: Inferred from HTTP method or operationId suffix
  • 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-id

Required 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:

  1. --server <url> flag
  2. Profile server setting
  3. First servers[0].url in the spec

For templated URLs (e.g. https://{region}.api.example.com):

specli ... --server-var region=us-east-1

Authentication

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

  1. --auth <scheme> flag (explicit)
  2. Profile authScheme setting
  3. If operation requires exactly one scheme, use it
  4. 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 --delete

Config 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 actions
  • help - Get details about a specific action
  • exec - 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-token with pre-acquired tokens)

Development

bun install
bun run build
bun test
bun run lint
bun run typecheck