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

@thebrubaker/askq

v0.4.0

Published

Ask one question of a whole dataset and get back what to read. Every item is judged twice; code checks that every item came back.

Readme

askq

You have a pile of posts and one question about them.

Three hundred tweets from a search, and you want the ones where someone reports real results. A Discord channel's week, and you want the messages that answer how people set something up. You can't read all of it, so you reach for one of two things. You grep, which finds the word "benchmark" and misses every post that reports one without saying so. Or you hand the pile to a sub-agent and tell it to read everything, and it skims, and nothing tells you what it skipped.

askq has a model judge every item twice and asks for a verdict each time: read, maybe or skip, with a tag and a short reason. An item is read only when both judgements read it; one read or one maybe makes it maybe. Up to 60 items two calls each see the whole pile; past that, overlapping windows do (see Limits). Code checks that every item came back, and prints a roll-up: leads, the read list, the maybe list, and five items it skipped, so you can check it was right to skip them.

jq -c '.[]' tweets.json | npx @thebrubaker/askq \
  "which of these report hands-on results with a local voice model?" \
  --context "tweets from an X search; I care about latency, quality and hardware"

Install with npm i -g @thebrubaker/askq (the command is askq), or run it once with npx @thebrubaker/askq.

Requires Claude Code's claude CLI, installed and signed in: askq runs Sonnet through it, on your Claude subscription. About 30 seconds and 7 calls for 150 tweets. --backend gemini uses GEMINI_API_KEY instead.

What you get back

  • The roll-up, on stdout. Bounded, meant to be read: a header with the records path and the fields askq used, warnings first, the model's leads (labelled as leads to verify, each citing the lines it rests on), the read list, the maybe list (items one judgement read first), a spot-check of five skipped items (one per tag), and a checks line. Every row carries the line, the author, the tag and reason, the item's url and a snippet. A post that others quote is listed with an item you can open, never as a bare internal pointer.
  • The records, in a file. One JSON line per input line (askq_line, askq_id, verdict, tag, reason, item), then one per referenced post (askq_ref), after a first line holding the run (askq_run). A run judged in windows adds askq_windows (the windows that held the item), and an item judged more than once carries askq_votes (each judgement's verdict). The records file goes under your temp directory by default, so scraped content can't land in a repo by accident; --out FILE to choose. The roll-up names the path once, as a shell assignment, and every jq it prints after that reads "$R":
R=/tmp/askq/20260925-141503-a1b2.jsonl
jq -c 'select(.verdict=="read")' "$R"
  • --out - puts the records on stdout and the roll-up on stderr, for pipelines.

How it reads your data

JSONL, one item per line. Fields are recognised by name, so the common scrape shapes need no flags; the roll-up's roles: line shows what was used, and a flag overrides any of them (--text, --author, --time, --id, --reply-to, --quote; --no-roles for none).

  • A reply points to its parent when the parent is in the data, and says whose post it answered when it isn't. A reply to your own earlier post is treated as a thread.
  • A quoted or reposted post is shown once and pointed to: to the item itself when it is in the data (by id, or by matching text), otherwise once in a referenced block, with its author taken from a field such as quoted_author. A quote whose text wasn't captured is still shown as a quote.
  • Items of one thread are shown next to each other.
  • Media shows as a marker such as [2 images, 1 video]. A post that is only an image is still judged. Only an item with no text, no media and no quote is skipped without asking the model.

What it guarantees

  • Every item gets a verdict, or says why not. A pointer the model misses is asked for again once; if it is still missing, its record carries askq_error, the roll-up names the line, and the exit code is 1. In windows, a window whose call fails is sent once more before its items are marked; items another window judged keep that verdict.
  • It flags the model judging groups instead of items. Five or more items sharing one reason word for word (within one window, when there are windows) is a warning, and each of those records carries askq_review.
  • It won't let two kinds of item be skipped: a fragment the model says it can't make sense of, and a post by an account that wrote something in the data and that the overview, or at least two windows, names as the subject's (its creator, company or staff). Both become maybe, with a note.
  • A stalled call doesn't stall the run. A call slower than twice the run's median (45 seconds at least) gets one duplicate, and the first good answer wins; after 150 seconds the call fails.
  • It never prompts. A run that needs more calls than --max-calls (default 100) refuses before sending anything and exits 3, and askq never starts more calls than that. With --backend gemini, --max-cost (default $1.00) does the same by estimated dollars.

What it does not

  • Its verdicts are not facts. They depend on the wording of the question and on the model; two identical runs differ on borderline items.
  • Its leads are not findings. Summaries of a whole set get details wrong, and a model will credit a quoted post to the person who quoted it. Who wrote what, in the roll-up, comes from the data.
  • It is not the last reader. It orders your reading.

How well it holds up

On a 150-tweet set with saved labels (scraped, so not in this repo), three test runs of this design and one run of the built CLI each kept 33 of 33 items marked must-read and 14 of 14 items a blind labelling marked substantive, in 29 to 31 seconds and 7 calls each. One dataset and one question: treat it as direction.

On an 856-item pile the same design took 74 seconds with every window started at once. askq now runs at most 8 calls at a time, so expect a pile that size to take longer.

Limits

Up to 60 items, two parallel calls each see them all. Posts that the items quote or repost are judged as items too, so they count.

Above 60 items, or when the rendered pile is too long for one call, askq judges it in windows of 60 items that overlap by 30, the last one wrapping round to the start, so every item is judged by two windows. Up to 8 calls run at once. A window keeps a thread or a reply chain together where it can, and shows each item the posts it answers or quotes even when those sit in another window. Alongside the windows, one overview call reads every item cut to 120 characters and names the subject's own accounts and the terms your context names; the windows never see it, and askq's checks use it. A last call writes the leads from the read items. The roll-up says when a run was chunked. --window N (60 to 400) forces windows of N at any size of input; smaller windows lost items worth reading in testing, so askq refuses them.

With --backend gemini, one call sees up to 400 items and windows overlap by 15, so an item may be judged only once. The Gemini path shares the vote rule and the own-accounts guard described here, and neither change has been measured on Gemini.

Over 2,000 items askq refuses, naming the cap and the count. Split a larger pile into several runs, by time or by thread, rather than filtering it down: an item dropped to fit is never judged.

Exit codes

| | | | --- | ------------------------------------------------------------------------------------ | | 0 | every item has a verdict | | 1 | coverage incomplete: some items have no verdict (askq_error, named in the roll-up) | | 2 | usage error, over the item cap, or the API refused the request in a way that repeats | | 3 | over --max-calls, or estimated over --max-cost; nothing was sent | | 130 | interrupted |

Status

0.4.0, not published. 0.1.0 asked the question of each item in isolation; that design is in the git history. MIT.