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

@andy-toolforge/jobscan

v0.3.4

Published

Toolforge domain: freemium job-scan CLI

Readme

@andy-toolforge/jobscan

Freemium job-scan CLI — scan ATS boards (Greenhouse / Lever / Ashby / SmartRecruiters / Workable / Recruitee / Pinpoint / Personio / RemoteOK) against a local resume, report keyword gaps. Local heuristic in free, LLM-tuned bullets in pro.

Install

npm i -g @andy-toolforge/jobscan
# or inside monorepo
npm install

Quick start (no slug needed)

# example resume
cp packages/jobscan/templates/resume.example.json ./resume.json

# 1. save your companies once (paste careers page URLs — provider inferred)
jobscan init
jobscan companies --add https://boards.greenhouse.io/datadog
jobscan companies --list

# 2. scan everything with no args (uses jobscan.yml; no file → RemoteOK board)
jobscan scan --resume ./resume.json

# one-off scan from a URL, no config needed
jobscan scan --url https://jobs.lever.co/lever --resume ./resume.json

# power users: explicit provider + slug still works
jobscan scan --provider greenhouse --company datadog --resume ./resume.json

# pro (single company, valid license)
export JOBSCAN_LICENSE_PUBLIC_KEY="your-server-hmac-secret"
jobscan license verify <key> --sig <hmac> --tier pro --expires 2026-12-31T00:00:00.000Z
jobscan scan --url https://boards.greenhouse.io/datadog --resume ./resume.json --pro

Free vs Pro

| Feature | Free | Pro (--pro + valid license) | |---------|------|-------------------------------| | Heuristic match (score, matched/missing, suggestions) | ✓ | ✓ | | tailoredBullets, coverLetterHint, llmSuggestions | — (placeholder) | ✓ via @andy-toolforge/core LLMClient | | export --format md pro section | stripped | included | | Batch (jobscan batch) | ✓ | ✓ (pro adds LLM fields when licensed) |

Pro uses Groq/Gemini via @andy-toolforge/core LLMClient adapter chain. Cost ~$0.01–0.03 per scan (depends on provider/model). Free never calls LLM — verified by lib/llm.test.js spy.

Providers (9 real, verified live — no stubs)

  • Greenhouse (boards-api.greenhouse.io)
  • Lever (api.lever.co)
  • Ashby (api.ashbyhq.com)
  • SmartRecruiters (api.smartrecruiters.com — list + N+1 detail fetch; IDs case-sensitive, e.g. BoschGroup)
  • Workable (apply.workable.com widget API, ?details=true for inline descriptions)
  • Recruitee ({company}.recruitee.com/api/offers/ — no-auth Careers Site API)
  • Pinpoint ({slug}.pinpointhq.com/postings.json — e.g. workwithus)
  • Personio ({company}.jobs.personio.de/xml — official XML feed, regex-parsed with zero new deps)
  • RemoteOK (remoteok.com/api — board-wide feed, no company slug; --company acts as optional company-name filter, use all for newest)

Each honors User-Agent: jobscan/0.3.4, ≥2s gap + Retry-After / exponential backoff (3 retries). Greenhouse additionally checks robots.txt (best-effort). Research notes for the remaining ATS platforms live in ROADMAP.md — no stub files shipped. Workday and Jobvite are deferred (see ROADMAP).

Data attribution

RemoteOK data requires a dofollow backlink attribution when displayed publicly. CLI matching and local reports are fine, but any public rendering of RemoteOK job descriptions (exported dashboard, website) must credit RemoteOK with a link.

Commands

jobscan init                                        # create jobscan.yml
jobscan companies --add <careers-url>               # add company (provider inferred)
jobscan companies --list                            # list saved companies
jobscan scan [--resume <path>]                      # no args: jobscan.yml or RemoteOK board
jobscan scan --url <careers-url> [--resume <path>]  # one-off URL scan
jobscan scan --provider <name> --company <slug> [--resume <path>] [--pro]
jobscan license verify <key> [--sig <sig>] [--tier pro|free] [--expires <iso>]
jobscan license status
jobscan dashboard [--last]
jobscan batch <file>        # CSV (provider,company) or NDJSON {provider, company}
jobscan update --resume <path>   # 3-way merge, preserves custom, writes *.merge-conflict on conflict
jobscan export --format json|md  # tier-gated via DATA_CONTRACT

Batch is pure Node (no batch-runner.sh) — works on Windows/macOS/Linux.

Dashboard is Ink-style plain renderer (lib/dashboard.js); fallback when Ink ESM not installed.

Data contract

schemas/data-contract.v1.json splits core (always) vs pro (gated):

  • core: score, matchedKeywords, missingKeywords, suggestions, provider, url, fetchedAt, jobTitle, jobId
  • pro: llmSuggestions, tailoredBullets, coverLetterHint

scanner.serialize(result, tier) strips pro keys when tier !== 'pro'.

License grace

~/.config/jobscan/license.json (0600, gitignored) is cache only — signature verified with JOBSCAN_LICENSE_PUBLIC_KEY (HMAC-SHA256 tier|expiresAt|key). Expired within 7 days + valid sig → still pro with warning; expired + 8 days → free. XDG_CONFIG_HOME overrides path for tests. Never commit license.json or plaintext secrets — hygiene check: grep -r JOBSCAN_LICENSE_KEY packages/jobscan --include="*.json" --include="*.md" must be empty (tested in CI).

Update / 3-way merge

jobscan update --resume ./resume.json
  • base = resume.base.json (last pulled)
  • local = current resume.json (user edits, custom preserved)
  • remote = latest scan suggestions

On conflict writes resume.json.merge-conflict (<<<<<<< markers) + resume.json.merge-conflict.json sidecar, does not overwrite original.

Roadmap

See ROADMAP.md — provider research notes, deferred Workday/Jobvite, rejected Breezy (HTML-scrape), + Next.js dashboard v2 (deferred).

Publish

Root .github/workflows/publish.yml checks npm view @andy-toolforge/jobscan version and publishes only on version bump. No per-package workflow.

Testing

npm test -w @andy-toolforge/jobscan   # node --test lib/*.test.js