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

ownllm

v0.2.0

Published

Self-hostable, subscription-auth, OpenAI-compatible API gateway with real per-request model routing.

Downloads

446

Readme

ownllm

ownllm is an OpenAI-compatible API server that runs on your LLM subscriptions instead of API keys. Point any OpenAI client at it, and it routes each request by the requested model to a backend you've logged into over OAuth:

  • ChatGPT / Codex (openai-codex) — OpenAI Responses API
  • xAI Grok Build / SuperGrok (xai) — OpenAI Responses API
  • GitHub Copilot (copilot) — Chat Completions
  • Qwen (qwen, your qwen.ai login) — Chat Completions
  • MiniMax (minimax) — Anthropic Messages API
  • Google Gemini (gemini, via Cloud Code Assist) — Gemini API

Each backend speaks its own wire format; ownllm translates between Chat Completions (what your client sends) and whatever the provider expects — Responses, Anthropic Messages, or Gemini. Your existing tooling keeps working, streaming and tool calls included, and token usage passes straight through.

Why this exists

Key-based gateways like LiteLLM can't touch a ChatGPT or SuperGrok subscription, because those are OAuth logins, not API keys. The gateways that do speak that OAuth (Hermes, for example) pin a single model per server, so the request's model field is cosmetic.

ownllm routes per request. A YAML table maps each model name you expose to a {provider, upstream} pair, and a model that isn't in the table gets a normal OpenAI model_not_found 404. So one server can serve gpt-5 and grok side by side.

Quickstart

You need Node.js 22 or newer. No install or build step — run it straight from npm with npx:

npx ownllm config init                 # writes ~/.ownllm/config.yaml
npx ownllm auth login openai-codex     # device code; prints a URL to open
npx ownllm auth login xai              # prints a URL to open; loopback catches it (--manual to paste, headless/Docker)
npx ownllm doctor                      # checks token health + reachability before you rely on it
npx ownllm serve                       # binds 127.0.0.1:8787; no client key needed on loopback

Reaching for it often? npm install -g ownllm puts ownllm on your PATH, so you can drop the npx from every command below. (To run from a checkout instead, see Development.)

Now call it like any OpenAI endpoint:

curl http://127.0.0.1:8787/v1/chat/completions \
  -H "content-type: application/json" \
  -d '{"model":"gpt-5","messages":[{"role":"user","content":"hello"}]}'
from openai import OpenAI

# Loopback needs no key, but the SDK insists on a non-empty string.
client = OpenAI(base_url="http://127.0.0.1:8787/v1", api_key="local")
reply = client.chat.completions.create(
    model="grok",
    messages=[{"role": "user", "content": "hi"}],
)
print(reply.choices[0].message.content)

gpt-5 and grok here are names from your routing table, not upstream model ids. Rename them, point them wherever you want, and run ownllm models to see the table. Add --remote to fetch the live upstream names (Grok Build's churn often, so it's worth checking).

Configuration

The config lives at ~/.ownllm/config.yaml. Override the directory with OWNLLM_HOME, or pass serve --config <path>. There's a commented reference in config.example.yaml, and more detail in docs/configuration.md.

server:
  host: 127.0.0.1            # a non-loopback host requires api_key, or the server won't start
  port: 8787
  # api_key: ${OWNLLM_API_KEY}   # client auth (timing-safe); uncomment to require it
  request_timeout_ms: 600000
  strict_params: false        # true rejects unsupported params with 400 instead of ignoring them
providers:
  openai-codex:
    enabled: true
  xai:
    enabled: true
  # also available, once you log in: copilot, qwen, minimax, gemini
models:                       # the routing table: requested model -> upstream provider + model
  gpt-5:
    provider: openai-codex
    upstream: gpt-5
    fallbacks: [grok]         # if gpt-5 fails, retry the request on grok
  grok:
    provider: xai
    upstream: grok-build
    reasoning_effort: medium

The models table is the whole point of ownllm. Model names are matched exactly and case-sensitively. A model can list fallbacks — other models to retry when it fails, even across providers, with a circuit breaker so a model that's down gets skipped (see configuration). String values support ${ENV_VAR} interpolation (resolved after the YAML parses, so it's safe to use in comments), and a referenced variable that isn't set is a hard startup error.

Going beyond localhost

On loopback the client key is optional. The moment you bind anywhere else it becomes mandatory, and the server refuses to start without it. That's deliberate, so you can't accidentally expose an unauthenticated proxy to your subscriptions.

export OWNLLM_API_KEY=$(openssl rand -hex 32)   # referenced as ${OWNLLM_API_KEY} in config
ownllm serve --host 0.0.0.0
# clients then send:  Authorization: Bearer $OWNLLM_API_KEY

CLI

ownllm config init                       write a starter config
ownllm serve [--config p] [--host h] [--port n]
ownllm auth login <provider>             OAuth login, store the credential (openai-codex, xai, copilot, qwen, minimax, gemini)
ownllm auth status                       validity, identity, expiry (tokens redacted)
ownllm auth logout <provider>
ownllm auth import openai-codex          reuse the official Codex CLI login (~/.codex); see the warning it prints
ownllm models [--remote]                 routing table (what clients can request); --remote also lists each provider's live catalog
ownllm doctor                            token health + Codex Cloudflare probe + xAI tier check

Docker

The container binds beyond loopback, so it needs a client key:

export OWNLLM_API_KEY=$(openssl rand -hex 32)
docker compose up --build

Then log in straight into the running container — the image puts ownllm on PATH:

docker compose exec ownllm ownllm auth login openai-codex
docker compose exec ownllm ownllm auth login xai

This works headless: Codex prints a device code, and Grok auto-detects the container and falls back to a paste-the-code flow (force it with --manual). Open the printed URL on any machine, approve, and paste the callback URL or code back. You can also log in on your host and mount ~/.ownllm into the container instead. See docs/configuration.md.

When something breaks

Start with ownllm doctor. The errors you're most likely to hit:

  • codex_cloudflare_blocked (502): chatgpt.com sits behind Cloudflare, and your request got challenged. This happens most on datacenter and Docker IPs; a residential or home-server IP usually sails through. It's a transport block, not a bad token.
  • xai_tier_denied (403): your xAI account isn't allowlisted for programmatic access. Logging in again won't change it; it's a tier gate on xAI's side.
  • credential_expired (401): run ownllm auth login <provider> again.
  • model_not_found (404): the model isn't in your models table. Check ownllm models.

Development

Working from a checkout instead of npm. Requires Node.js 22+ and pnpm (corepack enable if you don't have it).

git clone <this-repo> && cd ownllm
pnpm install
pnpm dev -- serve   # run the CLI through tsx, no build (e.g. pnpm dev -- auth login xai)
pnpm build          # bundle dist/main.js, the published `ownllm` CLI

Before sending a change: pnpm format && pnpm lint && pnpm typecheck && pnpm test. The full contributor guide is AGENTS.md.

Documentation

The guides in docs/:

  • Authentication — logging in, including headless servers and Docker.
  • Configuration — the config file and the model routing table.
  • HTTP API — endpoints, clients, and the errors you may hit.

For how it works under the hood, see architecture, adding a provider, and translation. Hacking on ownllm (with or without an AI agent)? Start with AGENTS.md.

Disclaimer

This is a personal-use tool for reaching your own subscriptions programmatically. It isn't affiliated with or endorsed by OpenAI or xAI. Subscription terms aren't the same as platform or API terms and can change without notice, and xAI gates programmatic access by tier, so it may not work on your account at all. Complying with each provider's terms is on you. Don't run ownllm as a multi-tenant service or resell access to it.

License

Apache-2.0