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

yafette

v0.1.0

Published

Open-access art in your terminal — find one exact work (never a guess), search 11,500 public-domain works from 13 museums, and download full-resolution files with their rights attached. Built for coding agents.

Readme

yafette

Open-access art in your terminal — 11,500 public-domain works from 13 museums (the Met, the Rijksmuseum, the National Gallery of Art, the Getty, the V&A, Wikimedia Commons and more), one catalogue, no key. Built so a coding agent can pull one exact work and never a guess.

npx yafette get "The Starry Night" --artist "van Gogh"     # one work, exit 0
npx yafette get "Night Watch"                              # finds the Rijksmuseum's Nachtwacht
npx yafette get Sunflowers --artist "van Gogh"             # several versions → a numbered list, exit 2
npx yafette search cypress --artist "van gogh" --pd-only   # ranked, forgiving
npx yafette pull wikidata:Q45585 --out ./art               # the museum's file + a .json rights sidecar

The catalogue is published by yafette.com and downloaded once (about 2 MB) into your cache directory; every command then runs locally — no server, no rate limit, works offline.

Install

npm install -g yafette      # installs the `yafette` command
# or run one-off with npx yafette — nothing to install

Requires Node 18.17 or newer. No runtime dependencies.

For coding agents

get is the command to reach for when a person names a work. It answers in exactly one of three ways, and the exit code says which:

| exit | meaning | what to do | |---:|---|---| | 0 | one work — work in the JSON | use it | | 2 | several fit — candidates in the JSON | show the list, or narrow with --museum, --year, --qid, or yafette get <id> | | 4 | nothing fits — didYouMean in the JSON | the suggestions are search results, not answers; ask, or use search |

get never picks from an ambiguous list for you. Titles match exactly (case, accents, punctuation and a leading article aside) in every language the museums use, and studies, copies and fragments are set aside unless you pass --role any. Prints are always a list until a museum or an id names the impression. search is the forgiving one: ranked, prefix and typo tolerant, alias-aware (nachtwacht finds The Night Watch).

yafette get "The Oath of the Horatii" --json --fields id,title,image,licence,web
yafette get wikidata:Q45585 --json              # ids and Q-numbers resolve too
yafette search "still life" --category post-impressionism --json --limit 10
yafette pull --from-search "self-portrait" --artist rembrandt --limit 5 --out ./rembrandt

Add --json to any command for a machine-readable body ({ "ok": true, … } or { "ok": false, "error": { "code", "message", "hint" } }), --format md for a markdown table, --fields a,b.c to trim a record, --quiet for ids only. A ready-made skill file for Claude Code and similar tools is in skills/yafette/SKILL.md.

Commands

| Command | What it does | |---|---| | get <title \| id \| Qnnn> | Exactly one work, or a list to choose from. Filters: --artist --year 1889\|1885..1890 --museum --medium --kind --qid --role any | | search <words…> | Ranked search over titles (every language), artists, tags, museums. Same filters, plus --category <slug> --pd-only --limit --offset | | categories [--family <slug>] | The 16 families and 974 categories, with approximate counts | | category <slug> | The works in one category (--limit --offset) | | artists / artist <key \| Qnnn> | Who is in the catalogue | | random | One work by chance (--artist --category --open) | | pull <id…> | The museum's own file and a rights sidecar. --out <dir> --size full\|display\|thumb --from-search "<q>" --stdin --no-sidecar --overwrite --allow-non-pd --allow-host <h> | | open <id> [--site] | The museum's page, or the yafette page | | cache status\|refresh\|clear\|path | The local catalogue | | doctor | Node version, cache, data URL reachability |

Categories are approximate. A category holds the works that name it and every work by a related artist — the same rule the website uses. Every category response says so ("approximate": true). Use get when you need one particular work.

What a record holds

{
  "id": "rijksmuseum:200107928", "qid": "Q219831",
  "title": "The Night Watch",
  "titles": ["The Night Watch", "Het korporaalschap van kapitein Frans Banninck Cocq … 'Nachtwacht'"],
  "artist": "Rembrandt", "artistQid": "Q5598", "artistDates": "1606–1669",
  "role": "original", "kind": "painting", "attribution": "firm",
  "date": "1642", "year": [1642, 1642], "medium": "canvas",
  "museum": "Rijksmuseum", "museums": ["Rijksmuseum"],
  "pd": true, "licence": { "label": "Public Domain Mark 1.0", "url": "…" },
  "image": { "full": "https://iiif.micr.io/PJEZO/full/max/0/default.jpg", "thumb": "…", "iiif": "…", "blocked": false, "via": "rijksmuseum" },
  "web": "https://www.rijksmuseum.nl/…",
  "members": [ { "id": "rijksmuseum:200107928", … }, { "id": "wikidata:Q219831", … } ]
}

One record is one work. When the same painting reaches the index from its museum and again from Wikidata, the copies are merged; members lists every record, titles every title, and any member id resolves to the work. role says what the record is to the work it names: original, version, study, copy, fragment, or impression (one impression of a print). --json gives the compact record; --json --full the whole thing.

Rights

Only works their museum publishes as public domain or CC0 are offered (pd: true); a Wikimedia Commons photograph is offered only when the file's own Commons page says public domain or CC0. pull refuses anything else unless you pass --allow-non-pd, and writes a .json sidecar beside every file naming the museum, the record, the rights statement, the licence and the source URLs, so provenance travels with the file. Images stream from the museums' own servers; the Art Institute of Chicago serves its files only to a browser on its own site, so those records give you the page instead. Verify before commercial reuse — institutions revise their records.

Security

  • Zero runtime dependencies — the tool is Node built-ins and its own source.
  • HTTPS only. The catalogue comes from one fixed origin and every file is checked against the hash the manifest publishes.
  • Images only from the museums' hosts (an allowlist). Europeana points at thousands of provider servers, so those need --allow-host <host>.
  • Filenames are sanitised and kept inside --out; existing files are never overwritten without --overwrite.
  • No telemetry. Nothing is written outside the cache and output directories.

Environment: YAFETTE_CACHE_DIR (default ~/.cache/yafette, %LOCALAPPDATA%\yafette on Windows), YAFETTE_DATA_URL (the catalogue origin), YAFETTE_OFFLINE=1 (never fetch), NO_COLOR.

Development

The search and resolve engine lives in tools/catalog-core and is copied into src/core/ by bin/sync-core; the catalogue is built by tools/art-api (npx tsx src/cli.ts catalog). npm test builds and runs the golden queries against the fixture in test/fixtures/catalog/ with no network; regenerate the fixture with npm run fixture after the catalogue's shape changes.

Licence

MIT. Museum metadata belongs to the institutions that publish it; every download names its source.