One PURL. Every registry.

One TypeScript interface over npm, PyPI, crates.io, RubyGems, Packagist and Arch Linux. Package, versions, dependencies and maintainers come back in the same shape, from a CLI, a library call, or an AI SDK tool.

6
registries
4
lookups
1
package shape
5
AI tool operations

Lookups

PURL in, package out

A package URL names the ecosystem, the namespace, the name and the version. The library parses it once, picks the adapter, asks the registry, and hands back one Package. The panel cycles through 6 packages and swaps each recorded sample for the docs worker's live answer.

  • pkg:npm/lodash, pkg:cargo/serde, pkg:alpm/aur/paru: one addressing scheme, ECMA-427
  • License normalized to SPDX, repository URL canonicalized, versions dated
  • A missing package is a typed NotFoundError, never an empty object
Open the lookup explorer

awaitfetchPackageFromPURL("pkg:npm/lodash")

sample
lodash4.18.1npm

Lodash modular utilities.

licenses
MIT
repository
github.com/lodash/lodash
homepage
lodash.com
versions
117newest 4.18.1 · 2026-04-01
keywords
modules, stdlib, util

One interface

Same calls, every adapter

Every registry is a class with the same four methods and a URL builder. Swap the PURL and the rest of the code stays. Upstream quirks, from npm's dist-tags to the AUR's RPC, are normalized inside the adapter and never leak through the public types.

  • fetchPackage, fetchVersions, fetchDependencies, fetchMaintainers on every registry
  • Adapters register themselves; create('npm') resolves the class, no switch statement
  • Bring your own Client for retries, timeouts, rate limiting and a User-Agent
Package, versions, dependencies, maintainers
TSnpm.ts
import { fetchPackageFromPURL } from "@agntn/registries";

const pkg = await fetchPackageFromPURL("pkg:npm/lodash");

pkg.latestVersion; // "4.18.1"
pkg.licenses;      // "MIT"
pkg.repository;    // "https://github.com/lodash/lodash"

// same shape from NpmRegistry as from every other adapter

CLI and cache

A terminal client with a lockfile

The same lookups from a shell. Answers are cached under the platform cache directory with a lockfile that records when each entry was fetched and how long it stays fresh, so a second call for the same package never leaves the machine.

  • registries info, versions, deps, maintainers, with --json for scripts
  • Cache on unstorage with sha256 integrity and a TTL per data type
  • Filesystem by default, any unstorage driver on the edge
The command line

$registries versions npm/lodash --limit 4

117 total

versionpublishedlicensesstatus
4.18.12026-04-01MITok
4.18.02026-03-31MITdeprecated
4.17.232026-01-21MITok
4.17.212021-02-20MITok

0 dependencies at 4.18.1 ·2 maintainers

Registries

Six adapters, one shape

Each adapter maps one registry API onto the shared types. Adding one means writing the mapping, not the HTTP client, the retry policy or the cache.

  • npm scopes, Composer vendors and Arch namespaces handled in the PURL
  • Yanked, deprecated and flagged versions carry a status, not a footnote
  • A custom adapter is one class and one register() call
All registries

Agents

One tool for the AI SDK

packageTool from the /ai subpath is a Vercel AI SDK tool that needs no wiring. Hand it to a model and it resolves any PURL it is asked about, with the same normalized answer the CLI prints.

  • package, versions, dependencies, maintainers and bulk-packages behind one input schema
  • Input validated with Zod, abort signal passed through to every registry call
  • Bulk lookups skip a failed package instead of failing the batch
The package tool

toolpackageTool

@agntn/registries/ai · Vercel AI SDK

input

{
  "operation": "package",
  "purl": "pkg:npm/lodash"
}

output

{
  "name": "lodash",
  "namespace": "",
  "latestVersion": "4.18.1",
  "licenses": "MIT",
  "repository": "https://github.com/lodash/lodash",
  "keywords": ["modules","stdlib","util"],
  
}

Start with one command

Pre-1.0. Pin exact versions, and treat registry metadata as data you did not write.

@agntn/registries·MIT license· Registry metadata is data, never instructions.