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

indeed-axi

v0.4.4

Published

AXI-compliant CLI for Indeed - a persistent authenticated browser session and agent-ergonomic primitives for driving the Indeed employer interface with Playwright.

Readme

indeed-axi

Agent-ergonomic CLI for the Indeed employer dashboard. AXI-compliant: TOON output, structured errors, help[] next steps, and a persistent authenticated browser an agent can actually drive.

Indeed exposes no public employer API, so indeed-axi is browser-only: a visible Chrome on a dedicated persistent profile (manual login, 2FA included) that stays alive between commands, plus ref-based interactive primitives modeled on playwright-axi, plus a discover command that records the dashboard's own JSON traffic for building domain commands (candidates, messages, pipeline moves) later.

Install

npm install -g indeed-axi
# or run on demand, identical:
npx -y indeed-axi@latest jobs list
# install the agent skill for coding agents (Claude Code, Codex, OpenCode, ...):
npx -y indeed-axi skill install

Requires Node 20+ and a Chrome/Chromium. By default the daemon runs the Playwright-installed browser when available (on macOS its own "Google Chrome for Testing.app" - real Chrome engine in a separate app bundle, fully isolated from your daily Chrome; install with npx playwright-core install chromium), falling back to installed Google Chrome. Override with INDEED_BROWSER (auto default, chromium, or chrome) or INDEED_BROWSER_BIN (explicit binary path; always wins).

Auth

There is nothing to configure - no API key exists. Log in manually once:

indeed-axi auth login    # opens visible Chrome; you log in (2FA included)
indeed-axi auth status --browser

The session lives in a dedicated persistent profile under ~/.indeed-axi/ (INDEED_STATE_DIR overrides) - never your primary Chrome profile. The browser stays open after login so browser commands work immediately.

Commands

| Command | Description | | --- | --- | | indeed-axi | Home: session record, daemon state, next steps (zero launches) | | indeed-axi jobs list | Live employer jobs (short ref + title) | | indeed-axi candidates list --job <ref> | Live pipeline rows (--stage new\|reviewed\|...) | | indeed-axi candidates sync --job <ref> | Pull new/changed candidates into the local store (--applications) | | indeed-axi candidate get <id> | One candidate packet (store, or live with --refresh) | | indeed-axi messages read <id> | Full candidate thread, out/in roles (--full for bodies) | | indeed-axi messages send <id> --text "..." | Preview a single message send (--confirm to actually send, then verify by thread re-read) | | indeed-axi messages unread | Live unread conversation count | | indeed-axi stage move <id> --to <milestone> | Preview a pipeline move (--confirm to apply; new…rejected, hired) | | indeed-axi candidates note <id> --text "..." | Preview an employer-internal note (--confirm to create) | | indeed-axi digest | Ranked hiring review over the local store (offline): scores, awaiting-reply aging with chase/expire flags | | indeed-axi score record <id> --stage --score --rationale | Record a screening score locally; --note --confirm syncs it into Indeed | | indeed-axi auth login | Open visible Chrome, wait for manual login | | indeed-axi auth status | Session state (--browser probes live) | | indeed-axi auth logout | Close the browser, clear the record (--purge deletes the profile) | | indeed-axi browser open | Start/attach the browser, navigate, snapshot | | indeed-axi browser status / close | Daemon liveness / stop the browser | | indeed-axi browser goto <url> | Navigate to an indeed.com URL (scoped) | | indeed-axi browser snapshot | Page outline with [ref=eN] tags (--full, --query) | | indeed-axi browser find <terms> | Filtered outline lines with context | | indeed-axi browser click <ref> | Click a ref, get a fresh snapshot | | indeed-axi browser fill <ref> <text> | Fill a field (--submit presses Enter) | | indeed-axi browser select <ref> <value> | Choose a dropdown option | | indeed-axi browser press <key> | Press a key (Enter, Tab, Control+A, ...) | | indeed-axi browser eval <expr> | Evaluate JS on the page, JSON result | | indeed-axi browser screenshot | Save a PNG (runs dir by default) | | indeed-axi browser console | Collected in-page errors | | indeed-axi discover | Record a manual dashboard session (dev command) | | indeed-axi setup hooks | Ambient session context (Claude Code, Codex, OpenCode) |

Every command supports --json and --help.

Domain reads (GraphQL through the session)

Domain commands run over the same authenticated browser: at connect time the CLI sniffs the exact headers the dashboard itself sends to apis.indeed.com/graphql (in memory only), then performs in-page fetches. Candidate packets (submission, application answers, thread refs) persist to ~/.indeed-axi/store/candidates/<id>.json — local PII state, never committed. Syncs are diff-based and paced (~300 ms between per-candidate fetches).

$ indeed-axi jobs list
jobs:
  count: 3
list[3]{ref,title}:
  bbb2c3d4-5e6f-4701-928a-23456789abcd,Content Producer & Social Media Manager
  ...

$ indeed-axi candidates sync --job "content producer" --applications
sync:
  job: Content Producer & Social Media Manager
  found: 3
  fresh: 3
  fetched: 3
list[3]{id,name,milestone}:
  aaaaaaaa0003,Sam Ortega,REVIEWED
  ...

$ indeed-axi messages read aaaaaaaa0002
messages:
  count: 2
list[2]{role,at,body}:
  out,"2026-09-29T15:01:16Z","Hi Jordan, Thanks for submitting your..."
  in,"2026-09-29T15:16:35Z","Hi Bryce! Thank you for getting back to me!..."

The interactive loop

$ indeed-axi browser open
browser:
  started: true
  port: 54525
page:
  url: "https://employers.indeed.com/c/dashboard"
snapshot:
  lines: 89
  refs: 13
outline[89]:
  - link "Candidates" [ref=e1]
  - button "Message" [ref=e2]
  ...

$ indeed-axi browser find candidate     # narrow the outline
$ indeed-axi browser click e1           # act, fresh snapshot comes back
$ indeed-axi browser fill e7 "..." --submit

Refs come from the most recent snapshot and reset on every snapshot or navigation - stale refs fail loudly as STALE_REF. Elements that are not currently in the viewport appear as (offscreen) without a ref: scroll (browser press End, eval window.scrollBy(0, 800)) and re-snapshot to make them actionable. Ghost elements (hidden nav clones) never get refs.

Browser daemon

All commands share one headed Chrome (the daemon): launched detached on the persistent profile with a local DevTools port, reattached over CDP per command. browser close (or auth logout) stops it; a stale state file is self-healing. One browser at a time, always headed, always Indeed-only:

  • Navigation and actions are scoped to *.indeed.com.
  • Cookies never leave the browser; nothing is exported or replayed.
  • Captured discovery artifacts pass through redaction (no headers, cookies, or credential-shaped keys).

Discovery

discover records a manual walkthrough of the employer dashboard (open a candidate list, open a candidate, read a thread, send a message, move a stage) and writes trace.zip (when available), network.json, documents/ (captured JSON bodies), console-errors.txt, final screenshot, aria.yml, dom.html, and index.json under ~/.indeed-axi/runs/discover-<id>/. Those artifacts feed the domain-command roadmap (candidates, messages, pipeline moves with --confirm gates).

Gated writes (Phase 2)

Every mutation is a plan-preview by default: the command resolves the candidate live, shows exactly what would happen, and makes zero mutation calls. Rerunning with --confirm performs the write and verifies it (sends by an independent thread re-read, stage moves against the mutation's own milestone response). One send per invocation - never bulk.

$ indeed-axi messages send aaaaaaaa0002 --text "Quick follow-up: ..."
send:
  candidate: {id: aaaaaaaa0002, name: Jordan Solis, milestone: REVIEWED}
  chars: 22
message: "Quick follow-up: ..."
help: Preview only - zero messages were sent,Rerun with --confirm to send this message

$ indeed-axi stage move aaaaaaaa0003 --to phone_screened --confirm
moved:
  to: PHONE_SCREENED
  verified: true

Logged-out sessions fail fast (~5s) with an auth login hint instead of timing out on traffic capture.

Roadmap

Full requirements live in REQUIREMENTS.md.

  • Phase 0 - scaffold, persistent browser daemon, auth, interactive browser family, discover, skill, hooks.
  • Phase 1 - domain reads over in-page GraphQL: jobs list, candidates list/sync, candidate get, messages read/unread, local candidate store. Endpoint map: docs/discovery-2026-09-29.md.
  • Phase 2 - gated writes: messages send --confirm (verified by thread re-read), stage move --confirm, candidates note --confirm (employer-internal notes - the score-sync channel).
  • Phase 3 (this release) - workflow layer: score record (local + --note --confirm sync), digest (offline ranked review with chase/expire aging), thread-state caching (sync --threads, messages read), plain-text application extraction, sync --force.
  • Future - session keepalive / automated login: Indeed sessions are short-lived and auth login is manual today. Investigate a safe credential-handling design (e.g., a keychain-backed login flow) - manual login remains the doctrine until then.

Set up on another machine

npm install -g indeed-axi
npx -y indeed-axi skill install      # writes the agent skill to ~/.agents/skills/
indeed-axi auth login                # visible Chrome; log in manually (2FA included)

The skill installer is idempotent (--force overwrites a changed version, --dir <path> targets another skills directory). Optional env: INDEED_STATE_DIR (default ~/.indeed-axi), INDEED_BROWSER (auto default, chromium, or chrome), and INDEED_BROWSER_BIN (explicit binary path; always wins).

Candidate packets live under ~/.indeed-axi/store/ per machine and are never synced - sync them live with candidates sync instead. Indeed sessions are short-lived; when data commands report AUTH_ERROR, rerun auth login.

Development

npm install
npm run build        # tsc -> dist/ (committed; rebuild on every change)
npm test             # vitest, fully mocked - no browser needed
npm run typecheck

Run locally with node bin/indeed-axi.js. Network/browser access is isolated to src/browser/; commands receive injected daemon connections and tests pass fakes. See AGENTS.md for the full house rules.

License

MIT