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

vibeledger

v0.4.0

Published

CLI tool for registering applications with Ledger LLM Gateway

Readme

vibeledger CLI

Register your application with the Ledger API Gateway in seconds.

Quick Start

npx vibeledger

That's it. The CLI will walk you through:

  1. Project info — auto-detects name, tech stack, and git repo
  2. Browser auth — opens your browser to approve the registration
  3. Config — writes LEDGER_URL, LEDGER_API_KEY, and LEDGER_APP_ID to your .env

What It Does

  • Detects your project name from package.json
  • Detects your tech stack (Node.js, Python, Ruby, Go, Rust, Java, PHP, etc.)
  • Detects your git repo URL from .git/config
  • Uses a secure device authorization flow (no passwords in the terminal)
  • Writes credentials to .env and ensures .env is in .gitignore

Usage

# Register a new app
npx vibeledger

# If you already have a key, it will ask before overwriting

Interactive Prompts

| Prompt | Default | Required | |--------------------|----------------------|----------| | Project name | From package.json | Yes | | Notification email | — | No | | App URL | — | No |

After Registration

Your app is approved for self-service configuration. You can set up routing, budgets, provider keys, and features programmatically — no dashboard required.

Option 1: SDK (recommended)

import { LedgerClient } from "@ledger/sdk";

const ledger = new LedgerClient({
  apiKey: process.env.LEDGER_API_KEY,
  baseUrl: process.env.LEDGER_URL,
});

// Discover available providers and models
const config = await ledger.setup.getConfig();

// Add your provider key (encrypted immediately, never returned)
await ledger.setup.addProviderKey({
  providerSlug: "openai",
  apiKey: process.env.OPENAI_API_KEY,
  label: "Production",
});

// Register a feature with a primary provider/model + fallbacks
await ledger.setup.createFeature({
  slug: "video-generation",
  name: "Video Generation",
  providerSlug: "openai",
  modelId: "gpt-4o",
  fallbackChain: [
    { provider: "anthropic", model: "claude-sonnet-4-20250514" },
    { provider: "google", model: "gemini-2.0-flash" },
  ],
  keySource: "auto",
});

// Set a spending limit
await ledger.setup.createBudget({
  scopeType: "app",
  limitCents: 50000,
  period: "monthly",
  actionOnExceed: "block",
});

// Now proxy requests through Ledger
const response = await ledger.chat.completions.create({
  model: "gpt-4o",
  messages: [{ role: "user", content: "Hello!" }],
});

Option 2: OpenAI-compatible drop-in

import OpenAI from "openai";

const openai = new OpenAI({
  apiKey: process.env.LEDGER_API_KEY,
  baseURL: process.env.LEDGER_URL + "/v1",
  defaultHeaders: {
    "X-Ledger-Feature": "my-feature",
  },
});

const response = await openai.chat.completions.create({
  model: "gpt-4o",
  messages: [{ role: "user", content: "Hello!" }],
});

Option 3: Python

from openai import OpenAI
import os

client = OpenAI(
    api_key=os.environ["LEDGER_API_KEY"],
    base_url=os.environ["LEDGER_URL"] + "/v1",
    default_headers={
        "X-Ledger-Feature": "my-feature",
    },
)

Self-Service API

After approval, your app can manage its own configuration via the self-service API. Auth: include X-Ledger-Key: {LEDGER_API_KEY} on all requests.

| Endpoint | Method | Description | |----------|--------|-------------| | /api/self-service/config | GET | Current config + available providers/models | | /api/self-service/routing-rules | POST | Create routing rule | | /api/self-service/routing-rules/:id | PUT/DELETE | Update or delete rule | | /api/self-service/budgets | POST | Create budget | | /api/self-service/budgets/:id | PUT/DELETE | Update or delete budget | | /api/self-service/provider-keys | POST | Add provider key (write-only) | | /api/self-service/provider-keys/:id | DELETE | Remove provider key | | /api/self-service/features | POST | Register feature with optional routing config | | /api/self-service/features/:id | PUT/DELETE | Update routing/model/fallbacks or delete feature | | /api/self-service/logs | GET | Recent request logs (provider, model, cost, latency) | | /api/self-service/logs/summary | GET | Routing summary grouped by feature/provider/model |

AI-Assisted Setup (Claude, Cursor, etc.)

If your project uses an AI coding assistant, add the Ledger instructions to your project's CLAUDE.md (or equivalent) so the assistant knows how to configure and use the gateway.

The CLI outputs a template after registration. Key rules for AI assistants:

  • Always read provider keys from environment variables — never hardcode or log them
  • Call GET /api/self-service/config first to see what's already configured
  • Ask the user before adding provider keys — the assistant should not guess or invent keys
  • Provider keys are write-only — once submitted, they cannot be read back (encrypted at rest)

Environment Variables

After registration, these are written to .env:

| Variable | Description | |------------------|------------------------------------------| | LEDGER_URL | Gateway URL (e.g. https://vibeledger.replit.app) | | LEDGER_API_KEY | Your app's API key (starts with ldgr_) | | LEDGER_APP_ID | Your app's unique ID |

Security

  • .env is never committed — the CLI ensures .env is in .gitignore
  • LEDGER_API_KEY (ldgr_*) grants access only to your app's own resources. It cannot read or modify other apps, org-level settings, or platform keys.
  • Provider API keys submitted via the self-service API are encrypted immediately using AES-256-GCM envelope encryption. They are never returned in API responses, never logged, and are only decrypted in memory at proxy time.
  • If a key is compromised, an admin can immediately suspend the app via the dashboard (POST /api/apps/:appId/suspend), which revokes all self-service access.
  • Do not put LEDGER_API_KEY or provider keys in CLAUDE.md or any committed file. Always reference environment variables.

Feature Routing

Each feature can be configured with a primary provider/model and an ordered fallback chain. When a request includes the X-Ledger-Feature header, the gateway checks the feature's routing config first.

Routing priority: Feature config > App routing rules > Default model pass-through

Configure via SDK

// Create a feature with routing
await ledger.setup.createFeature({
  slug: "image-generation",
  name: "Image Generation",
  providerSlug: "openai",
  modelId: "gpt-4o",
  fallbackChain: [
    { provider: "anthropic", model: "claude-sonnet-4-20250514" },
  ],
  keySource: "auto", // "auto" | "byok" | "platform" | "profile:{slug}"
});

// Update routing for an existing feature
await ledger.setup.updateFeature("feature-id", {
  providerSlug: "anthropic",
  modelId: "claude-sonnet-4-20250514",
  fallbackChain: [
    { provider: "openai", model: "gpt-4o" },
    { provider: "google", model: "gemini-2.0-flash" },
  ],
});

// Clear routing (fall back to routing rules)
await ledger.setup.updateFeature("feature-id", {
  providerSlug: null,
  modelId: null,
  fallbackChain: [],
});

Configure via API

PUT /api/self-service/features/:id
Content-Type: application/json
X-Ledger-Key: $LEDGER_API_KEY

{
  "providerSlug": "openai",
  "modelId": "gpt-4o",
  "fallbackChain": [
    { "provider": "anthropic", "model": "claude-sonnet-4-20250514" }
  ],
  "keySource": "auto"
}

How fallback works

  1. Gateway receives request with X-Ledger-Feature: image-generation
  2. Looks up the feature's providerSlug + modelId (primary)
  3. If primary provider is unhealthy (circuit breaker open) or has no valid key, tries each entry in fallbackChain in order
  4. If all feature-level options are exhausted, falls through to app-level routing rules
  5. If no routing rules match, uses default model-based routing

Observability: Tracking Routing Decisions

Every request through Ledger is logged with full routing metadata. Apps can query their own logs via the self-service API to see which provider, model, and key source handled each request — making it easy to detect when fallbacks are triggered.

Self-Service Logs API

GET /api/self-service/logs?feature=image-generation&limit=50
X-Ledger-Key: $LEDGER_API_KEY

Returns paginated request logs scoped to your app. Each log entry includes:

  • provider — which provider actually handled the request
  • model — which model was used
  • keySource — how the key was resolved (byok, platform, auto, etc.)
  • feature — the feature tag from X-Ledger-Feature
  • statusCode — success/failure
  • latencyMs — response time
  • costCents — cost of the request
  • cacheHit — whether a cached response was returned

Optional query params: feature, provider, model, statusCode, limit (max 200), offset, dateFrom, dateTo.

Routing Summary API

GET /api/self-service/logs/summary?feature=image-generation
X-Ledger-Key: $LEDGER_API_KEY

Returns aggregated stats grouped by feature / provider / model / keySource:

  • requestCount, totalCostCents, totalTokens, avgLatencyMs

This is the fastest way to see primary vs fallback distribution without scanning individual logs.

Building a Simple Admin Page

Using the SDK:

// Get routing summary for a feature
const { summary } = await ledger.setup.getLogsSummary({
  feature: "image-generation",
});

for (const row of summary) {
  console.log(
    `${row.provider}/${row.model}: ${row.requestCount} requests, ` +
    `$${(row.totalCostCents / 100).toFixed(2)}, avg ${row.avgLatencyMs}ms`
  );
}

// Get recent individual logs
const { logs, total } = await ledger.setup.getLogs({
  feature: "image-generation",
  limit: 100,
});

const primaryHits = logs.filter(l => l.provider === "openai").length;
const fallbackHits = logs.filter(l => l.provider !== "openai").length;
console.log(`Primary: ${primaryHits}, Fallback: ${fallbackHits}, Total: ${total}`);

With these endpoints you can build a table or chart showing:

  • Primary vs fallback usage — compare provider against the feature's configured providerSlug
  • Fallback frequency — how often the primary provider was unavailable
  • Cost by provider — see if fallbacks are more/less expensive
  • Latency comparison — detect performance differences between providers

Custom Headers

Request Headers

Send these headers with your LLM requests for routing and tracking:

| Header | Description | |---------------------|------------------------------------| | X-Ledger-Feature | Tag requests by feature/workflow — also triggers feature-level routing | | X-Ledger-User-Id | Associate requests with a user | | X-Ledger-Tier | Override tier for this request (economy, standard, premium) | | X-Ledger-Tag | Custom routing tag for matching routing rules |

Response Headers

Every gateway response includes these headers so your app knows what happened:

| Header | Description | |-----------------------|------------------------------------| | X-Ledger-Provider | Which provider handled the request (e.g. openai, anthropic) | | X-Ledger-Model | Which model was used (e.g. gpt-4o, claude-sonnet-4-20250514) | | X-Ledger-Key-Source | How the API key was resolved (auto, byok, platform) | | X-Ledger-Cache | HIT or MISS — whether a cached response was returned |

Use X-Ledger-Provider to detect fallbacks in real time — if it differs from your feature's configured providerSlug, a fallback was used.

Troubleshooting

"Could not connect to server"

  • Check your internet connection
  • Verify the Ledger server is running
  • Set LEDGER_SERVER_URL env var if using a custom server

"Registration was denied"

  • Make sure you approved the registration in your browser
  • Try running npx vibeledger again for a fresh code

"Authorization code expired"

  • The code expires after a few minutes
  • Run npx vibeledger again to get a new code

"App is not approved for self-service"

  • The app's approval status may have been suspended by an admin
  • Contact your organization admin to reinstate access

Browser didn't open automatically

  • Copy the URL shown in the terminal and open it manually

Server Configuration

To point at a different Ledger server:

LEDGER_SERVER_URL=https://your-ledger.example.com npx vibeledger