harrier-ai
v1.0.1
Published
Autonomous job-application agent: discovers, scores, tailors resumes for, and submits applications to Greenhouse/Jobot/Ashby/Workday boards, with a live dashboard and Gmail-based confirmation tracking.
Downloads
208
Maintainers
Readme
Harrier
npm install -g harrier-ai
An autonomous job-application pipeline. It discovers roles from configured job boards, scores them against your profile, tailors a résumé per role, fills and submits the application form with a real (stealthed) Chrome browser, and tracks the outcome by reading your Gmail for confirmation / rejection / interview emails. A live web dashboard shows everything in real time.
Status: v1.0.0, published. You run it on your own machine with your own Anthropic API key — nothing is hosted, and no application data leaves your computer. The free tier submits 3 applications; a licence removes the cap.
At a glance (auto-updated September 8, 2026) — 35 discovery sources · 4 auto-submit platforms (Greenhouse, Jobot, Ashby, Workday) · 602 company playbooks · 819 engine modules · 4204 automated tests. See EXECUTIVE_SUMMARY.html for the full overview.
🚀 Quickstart — install Harrier (this is the one you want)
Start here if you bought Harrier or installed it from npm. Three commands, then it runs. Everything self-creates — no repository to clone, no database migration, no build step.
Prereqs: Node 22+, Google Chrome, and an Anthropic API key from https://console.anthropic.com (add ~$5–10 of credit and set a monthly usage limit in the console — that's your hard cap; Harrier gates spend in-app too, and every AI feature starts off ($0) until you switch it on).
npm install -g harrier-ai
harrier init # asks for your Anthropic API key, then builds your profile — it never asks for a license
harrier start # self-creates the DB, builds the dashboard, opens http://localhost:3001Then open http://localhost:3001 and finish your Profile (the gear, top-right): About you / Résumé / Job search / Take-home — no YAML editing needed. Do Job search first (target titles, minimum salary, home city, remote preference); it overrides the starter defaults so you get roles relevant to you.
- Every command is
harrier <cmd>—harrier status,harrier stop,harrier doctor(a read-only preflight that tells you what's wrong),harrier sync,harrier support. - Optional inbox tracking:
harrier connect-email(Gmail App Password / IMAP) so confirmations, interviews, and rejections show up on the dashboard. - The free tier. A packaged install is free for the first 3 submitted applications; after that the
drain holds and the dashboard shows an upsell card. Unlock with
harrier activate <key>— notharrier init— thenharrier stop && harrier start. - Something wrong? Run
harrier doctorfirst, then see Something broken? Report it from inside Harrier.
The
git clonesections below are not for you. This repository is private, so a clone will fail with a permission error. Everything from the next heading down to Install paths is for collaborators and beta testers who have been granted access to the repo — it is a second, separate way to run Harrier.
🚀 Quickstart — collaborators with repo access (clone + your Claude subscription)
Requires access to the private repository. If you installed from npm, use the section above instead.
The fastest path if you are a collaborator with a Claude subscription (uses the claude CLI, so
no license key and no API key). Everything self-creates — no DB migration, no build step.
Prereqs: Node 22+, Google Chrome, and the claude CLI signed into your Claude
subscription (npm i -g @anthropic-ai/claude-code, then run claude once to log in).
git clone https://github.com/TylerRussell/job-applier-agent.git harrier && cd harrier
npm run setup # installs deps + Chrome, seeds config, creates .env + config/profile.yaml
npm start # self-creates the DB, builds the dashboard, opens http://localhost:3001(You need to be a repo collaborator and authenticated to GitHub for that clone to succeed.)
Then open http://localhost:3001 and fill your Profile (the gear, top-right): About you / Résumé / Job search / Take-home — no YAML editing needed. That's it.
npm run setupdetects theclaudeCLI and leaves.envon the subscription path (no API key).- The Schedule tab stays blank until you connect your own Google Calendar (optional).
- Optional inbox tracking:
npx tsx src/harrier.ts connect-email(Gmail App Password / IMAP). - Stop:
npm stop· Status:npm run status· Foreground (for systemd/launchd):npm run serve. - No application cap on a source/clone install — the 3-application free tier only applies to the
packaged (
npm install -g harrier-ai) build. - Don't run
harrier initon a clone. Two reasons: there's noharriercommand in a clone (thebinentry is only linked by an npm install — from source it'snpx tsx src/harrier.ts <cmd>), andinitwritesHARRIER_DISTRIBUTION=npm+HARRIER_LLM_MODE=anthropic-apiinto.env, which flips your clone onto the metered API-key path and turns on the 3-application free-tier cap.
🐳 Run with Docker — collaborators (optional)
Prefer a container? Harrier ships a Dockerfile + docker-compose.yml. This is purely optional — the
npm path above is unchanged — but if you'd rather not install Node/Chrome on your host, it's one command.
The container runs the same headed stealth browser (inside a virtual display), and your config/data live on
the host via bind-mounts, so nothing personal is baked into the image.
git clone https://github.com/TylerRussell/job-applier-agent.git harrier && cd harrier
docker compose up # builds the image, then serves http://localhost:3001Power the AI either way (same flexibility as the non-Docker paths):
- Claude subscription (free): in
docker-compose.yml, uncomment the~/.claudevolume, thendocker compose up. Uses your existingclaudeCLI login — no API key. - API key: create a
.envwithHARRIER_LLM_MODE=anthropic-apiandANTHROPIC_API_KEY=sk-…(see the beta-tester section below), thendocker compose up.
Everything else works the same: open http://localhost:3001, fill your Profile, and go. Stop with
docker compose down. (Requires Docker Desktop / Engine; first build pulls ~1–2 GB and takes a few minutes.)
The Docker path is aimed at dev/beta users running from a repo clone (the npm package ships no Docker or
test files). From a clone, prove the container path end-to-end with npm run smoke:docker — it builds the
image and boots a throwaway, credential-less container on empty mounts, asserting the dashboard serves.
🚀 Quick start — beta testers with repo access (clone + your own Anthropic API key)
New here? Start with GETTING-STARTED.md — a plain-language, 20-minute walkthrough (including exactly how to get your Claude API key and put a $5 spending cap on it). The condensed version is below.
Also a clone path — it needs repo access, same as the section above; the npm install at the top of this file is the one that doesn't. You run Harrier on your own machine with your own Anthropic API key. Your profile, résumés, and applications live only in your local DB. ~10 minutes.
One thing a beta clone does that the packaged build cannot: beta diagnostics. A clone can send detailed usage diagnostics (pipeline events, logs, state snapshots including
config/profile.yaml) to the maintainer, so a bug is diagnosable without a week of email. It captures nothing until you accept the dashboard's consent gate, a permanent header chip shows while it is on, andHARRIER_TELEMETRY=offortouch state/TELEMETRY_OFFstops it for good. Full field list: docs/beta-setup.md → Data sharing during the beta. Released/packaged builds cannot send diagnostics at all.
Before you start: Node 22+, git, and an Anthropic API key from https://console.anthropic.com (add ~$5–10 of credit and set a monthly usage limit in the console — that's your hard cap; Harrier also gates spend in-app: every AI feature starts off ($0) until you turn it on, plus a daily-spend cap, a daily application cap, and a lifetime budget that all auto-pause when reached). Harrier never bills you; the Anthropic API does, per token.
Estimated AI cost per application (the presets in src/lib/ai-usecases.ts, costed by totalCostPerApplication()) — Free $0.00/app · Lean ≈$0.06/app (≈$6 per 100) · Standard ≈$0.10/app (≈$10 per 100) · Max quality ≈$0.52/app (≈$52 per 100). The AI models chip on the dashboard shows the live estimate for your own picks.
# 1) Clone + install (also installs the dashboard + seeds starter config)
git clone https://github.com/TylerRussell/job-applier-agent.git harrier
cd harrier
./setup.sh # or: npm run setup — installs deps + Chrome and creates .env2) Your résumé — you don't need one to start. Open the dashboard's Résumé tab and fill in your
experience, skills, and education; Harrier builds an ATS-safe résumé from it and tailors a fresh one per
job. Edit it anytime and future résumés pick up the changes. (Prefer your own? Drop a real résumé —
.pdf / .docx / .md — into the reference/ folder instead; Harrier uses it as the source of truth.)
3) Your API key — setup.sh already created a .env in the repo root with the two lines you need;
paste your key after the =. .env starts with a dot, so Finder hides it — open it from the terminal:
open -e .env # macOS TextEdit (or: code .env · nano .env · $EDITOR .env)# the two lines that must end up in .env
ANTHROPIC_API_KEY=sk-ant-...your key...
HARRIER_LLM_MODE=anthropic-api# 4) Start — dashboard opens at http://localhost:3001
npm start5) Set up your profile via the dashboard's Profile button (the gear, top-right) — no file editing. Its sub-nav is About you / Résumé / Job search / Take-home:
- About you — name, current title, years of experience, contact, location, LinkedIn/GitHub.
- Job search — target titles, work eligibility, minimum salary, home city, remote preference, interview style, résumé voice, AI spend budget, email connection. Do this first — it overrides the starter defaults so you get roles relevant to you.
(This is a clone, so there is no harrier command and you should not run harrier init — it would
mark the install as a packaged build and apply the 3-application free-tier cap. Run source commands as
npx tsx src/harrier.ts <cmd>, e.g. npx tsx src/harrier.ts doctor.)
On your first run, Harrier protects you (because it's your pay-per-token key):
- Spend-consent gate — shows the estimate ("~$X for N matches") and asks you to set a budget or confirm. Nothing spends on AI until you do.
- First-run confidence sample — while discovery, scoring and tailoring run (a few minutes) the dashboard shows a "Setting up your first run" strip with live counts, so you can see it working and know there's nothing to do yet. It then prepares your first 3 applications and holds (submits nothing); click Approve & continue on the dashboard to proceed. If you've connected an inbox it also emails you a preview of exactly what it would submit in your name.
- Profile banner — flags anything still missing so you're never half-configured.
Optional — track responses: node --import tsx src/harrier.ts connect-email connects your inbox
(read-only) so confirmations / interviews / rejections show on the dashboard (and the preview email above can
reach you). Full walkthrough: docs/beta-setup.md.
Install paths: which commands are yours
Two ways to run Harrier, and they use different commands. Pick one and stick to its column.
| | Source / git clone (this repo) | Packaged install (npm install -g harrier-ai) |
|---|---|---|
| Install | git clone … then ./setup.sh | npm install -g harrier-ai |
| First-run setup | .env + the dashboard's Profile page | harrier init (API key + profile, interactive) |
| Run a CLI command | npx tsx src/harrier.ts <cmd> | harrier <cmd> |
| Start / stop | npm start / npm stop | harrier start / harrier stop |
| AI provider | your Claude subscription or your own API key | your own Anthropic API key |
| Application cap | none — uncapped | free for the first 3 submitted applications |
License & free tier — Harrier Pro is $49. One-time purchase — license valid for one year. A packaged install (npm install -g harrier-ai) runs free until 3 submitted applications, then the drain holds and the dashboard shows an upsell card. A source/clone install is never capped.
harrier …is not a command in a clone. Theharrierbin comes from the npmbinfield, which only a package install links; a clone has nonode_modules/.bin/harrier. Everywhere a doc saysharrier <cmd>, the clone equivalent isnpx tsx src/harrier.ts <cmd>(doctor,connect-email,status, …).harrier initbelongs to the packaged path only. It writesHARRIER_DISTRIBUTION=npmandHARRIER_LLM_MODE=anthropic-apiinto.env, which is right for a package install and wrong for a clone (it switches the AI to a metered key and switches the free-tier cap on). It never asks for a license.- The free tier. The upsell card above links to checkout when a purchase link is configured, and the key
arrives by email. Unlock with
harrier activate <key>— notharrier init— then restart (npm stop && npm start).
What it does (end to end)
- Discover — probe Greenhouse (and Eightfold/Netflix) boards plus the
LinkedIn and Indeed job-search aggregators listed in
config/sources.yamlfor matching titles. Each source emits the same canonical match shape (src/lib/<source>-normalize.ts) intodocs/discovery/, deduped across sources. LinkedIn/Indeed are discovery-only — matches still apply through each role's real ATS. Toggle withLINKEDIN_DISCOVERY=0/INDEED_DISCOVERY=0. - Score — rank each role A+–F on a weighted rubric (level, stack overlap, comp, geo tier, interview style, etc.); deterministic first, Claude only for ambiguous cases. Geo/comp/title hard-filters applied.
- Stage — write a per-role folder under
output/staged/<co>_<role>/with a tailored résumé,application.json(pre-filled fields), and the JD. - Submit — launch real Chrome with anti-detection shims, fill standard fields + résumé upload + react-select dropdowns + employment-history blocks (truthful dates from the profile; "current role" checkbox convention), handle emailed security codes, click submit, and poll Gmail to confirm.
- Repair — once the staged backlog is drained, deep-retry previously failed roles one company at a time (up to 1 hour/role, Claude + screenshots); companies whose forms can't be cracked go to an icebox for manual review.
- Track — scan Gmail for confirmations, rejections, and interview requests;
surface cooldowns (e.g. "too many applications in 180 days") and counts on
the dashboard. An interview request also pauses further applications to that
company — a recruiter sees every application you have open with them, and a
new one landing mid-loop is yours to explain. The hold lifts on a rejection or
after
application_policy.active_interview_window_days(profile.yaml).
The dashboard (where to look)
Once running, the dashboard at http://localhost:3001 has seven content tabs — Dashboard · Pipeline ·
Roles · Schedule · Prep · Stats · Guide — plus a Profile button (top-right, in the settings gear). On a
phone, Roles, Prep and Schedule are hidden (a wide table, a code editor and a calendar grid aren't
usable at that width), so the mobile nav shows four.
- Dashboard — the live pipeline: roles moving through discover → staged → submitting → sent → confirmed, with per-company lanes and system-status. Its filter bar holds the AI models control with a live estimated cost-per-application — the main dial on a metered key. One-click presets (Free / Lean / Standard / Max) or tune each step (Opus/Sonnet/Haiku, or Off for any of them); on a BYO key everything starts Off and a first-run gate makes you open it before continuing. (Vision is unavailable on a BYO API key, shown as such.) Turned Résumé tailoring on after roles were already staged?
npx tsx src/retailor-staged.tsre-writes the résumés of your best staged roles at the new tier — dry-run by default (shows targets + estimated cost),--apply --limit Nto run; your spend caps still apply. - Pipeline — the full-lifecycle per-company view: one track per company, each expandable to its roles and the live step in flight, filtered by Active / Waiting / Stalled. This is where you watch what's moving right now.
- Roles — every role Harrier has seen, as a sortable/searchable table (filter by search, grade, stage, timeframe) above a funnel strip, with a column picker. This is where you go to answer "what happened to that job".
- Stats — charts over time (scored, submitted, confirmed, interviews, rejections), plus three all-time diagnostics that answer "where is this pipeline losing work": good roles we never sent and why (the largest loss bucket — mostly application sites Harrier has no autonomous path to, listed by site so you know which adapter is worth building), which job sources are worth running (postings found against applications actually sent, per discovery source — a source can be the biggest supplier of postings and produce almost nothing), and what an application costs (measured AI spend per sent application, split into finding-the-work and sending-it, with the repair lane's share called out because it is a switch you can turn off).
- Prep — interview practice: a problem bank (Easy→Hard, filterable by difficulty), an AI coach (graduated hints / full explanation / mock interviewer), and a multi-language code runner (JavaScript in-browser; Python/Java/C++/Ruby compiled server-side). The editor has live syntax checking in every runner language (squiggles + error messages as you type — JavaScript via the TypeScript language service in a lazily-loaded chunk; Python/Java/C++/Ruby via their real toolchains server-side) and hover documentation (signatures + stdlib docs + param docs, IDE-style; JavaScript first). The language picker shows the detected runtime each language executes against (e.g.
Python · 3.9.6,C++ · clang 17.0.0 · c++17). Prep has two nested tabs: Practice (the problem-bank workspace above) and Screen — a faithful reproduction of CoderPad's AI Assist interview environment (the "AI turned on in CoderPad" screen), with a right-docked assistant offering Ask / Plan / Edit modes over an honest Claude model picker, an interviewer-observer that probes how you use the AI, a 60-minute timer, and a post-session scorecard on the four competencies (Problem-Solving, Code Quality, Verification, Communication) that flags the documented anti-patterns. - Schedule — your interviews on a 4-week calendar synced from your Google Calendar (interviews only; blank until you connect Google). Click any meeting for its details + an on-demand AI gameplan. Comp/take-home planning lives under Profile → Take-home (federal + FICA + state tax → net pay, feeding your search floor).
- Guide — a built-in "How Harrier works" explainer (the six stages: discover → score → tailor → stage → submit → track); the place to start on day one.
- Profile (top-right button) — a gear (with a pending-actions count badge when the action-items source is enabled) opening a page with an About you / Résumé / Job search / Take-home sub-nav. About you is your identity and contact details; Résumé is the experience/skills/education intake Harrier writes your résumé from; Job search is what to chase (target titles, work eligibility, minimum salary, home city, remote preference, interview style, résumé voice, AI spend budget, and the Email & notifications connection); Take-home is the tax/net-pay math behind your salary floor. On a packaged install,
harrier initdoes the same first-time setup from the terminal (your API key + profile — it never asks for a license); the first 3 applications are free, thenharrier activate <key>unlocks unlimited. On a clone, use the Profile page and skipinitentirely.
New here? Start with docs/beta-setup.md — the full from-scratch walkthrough.
Prerequisites
System requirements at a glance: macOS or Linux · Node.js 22+ · Google Chrome ·
~2 GB free RAM while it's actively submitting (it drives a real Chrome) · ~5 GB free disk — a live
install settles around 2 GB (~850 MB node_modules + ~1 GB state/, most of it the per-employer browser
profiles), and the rest is headroom for the temporary submission recordings; see
Disk space.
Any modern laptop handles it; on a small drive the disk figure is the one to watch.
- ~5 GB of free disk space. Harrier keeps everything on your own computer — see Disk space & what's stored below. On a small drive (e.g. a base MacBook Air), this is the requirement to watch.
- Node.js 22–26 (validated through 26; uses built-in ESM auto-detection and
node:test). - Google Chrome (Playwright drives a real Chrome for submissions).
- (Optional) a Gmail account + Google App Password to track interview/rejection replies — connected in the dashboard (Profile → Job search → Email & notifications), no OAuth setup. Everything else runs without it.
- An Anthropic API key (your own, from https://console.anthropic.com) for the AI scoring +
résumé tailoring. Put
ANTHROPIC_API_KEYandHARRIER_LLM_MODE=anthropic-apiin.env, and set a monthly usage limit in the console. The deterministic paths work without it, at lower quality.
Platforms — macOS and Linux. macOS is where Harrier is developed and run
daily. Linux is verified from a clean room: docs/beta-validate.Dockerfile
builds on node:22-bookworm (Debian) and only exits 0 if npm install, the
native better-sqlite3 compile, npx playwright install --with-deps chromium,
the dashboard SPA build and the full npm test all pass there. Windows is
not supported — it has never been tested (there's no Windows runner to test it
on), and setup.sh is bash, so the install path doesn't exist on it. Claiming it
without a test would be a guess, so the docs don't. Revisit when there's a
Windows runner to build and run the container suite against.
npm start / npm stop / npm run status are one Node launcher
(src/harrier.ts, no bash) that runs the whole worker tree as a single
supervised process and stops it together. The credential vault is portable too —
the master key auto-provisions to the macOS Keychain when available, otherwise to
a 0600 key file under ~/.harrier (set CREDENTIALS_KEY, base64 32 bytes, for
the strongest headless option). For auto-restart + start-on-boot, point your OS
service manager (launchd / systemd --user / Docker / pm2) at npm run serve
(the supervisor in the foreground); the bundled launchd plist is the macOS
shortcut.
Install JS dependencies:
npm install
npx playwright install chromeDisk space & what Harrier stores on your computer
Harrier runs entirely on your own machine — nothing is stored in the cloud — so it needs room to work. Plan to keep about 5 GB free. Here's what that space is for, in plain terms:
What gets installed (one-time, ~1–1.3 GB)
Everything lives inside the project folder plus one browser — no system-wide services, no background OS daemons, nothing in the cloud.
- Harrier and its libraries — ~770 MB, installed into the project's
node_modulesbynpm install. This is the bulk: the browser-automation engine (Playwright), the local dashboard, the SQLite database driver, and the Google/Gmail API client. (npm installalso generates the database client and installs the dashboard's own ~24 MB of dependencies — both included in that figure.) - A browser for submissions — ~280 MB, via
npx playwright install chrome. Harrier drives a real Google Chrome to fill and submit applications. If you already have Chrome, it reuses it and this is ~0. Where Google ships no Chrome (notably Linux on ARM) or the download is blocked, setup falls back to Playwright's own bundled Chromium (~110 MB) so résumé rendering and submissions still work.
To remove Harrier later, you just delete the folder (Chrome, if you want it gone, uninstalls separately).
What Harrier stores as you use it (grows slowly)
Three things accumulate permanently on disk:
- The job database (
state/pipeline.db) — every job it has found and scored. Grows ~10–15 KB per role; tens of MB after thousands of jobs. - A logged-in browser profile per employer portal (
state/browser-profiles/) — Workday-style portals require an account, so Harrier keeps one Chrome profile per employer rather than logging in from scratch every time. This is the largest thing instate/: ~650 MB on a live install after two months of daily applying. It grows with the number of employers you've applied to, not the number of jobs. - A kept application packet per applied job — your tailored résumé (a ~125 KB PDF, plus a durable
archived copy under
output/resume-archive/), the answers it filled into that company's form, and a saved copy of the job posting. About 0.2–0.3 MB per applied job. (One résumé is written per role — not several — so this is the dominant per-job cost, and it's small.)
Rough durable footprint (résumés + postings + answers + database), excluding the browser profiles above and the temporary recordings below:
| Applied jobs | Kept on disk | |---|---| | 100 | ~25 MB | | 1,000 | ~250 MB | | 5,000 | ~1.2 GB |
The part that can spike — temporary submission recordings
Each time Harrier submits an application it makes a detailed recording of that attempt (mostly full-page screenshots before/after submit) so it can diagnose and retry anything that didn't go through. These are large — usually around 20 MB each, up to ~100 MB on the heaviest career portals (big sites like Twilio, MongoDB, or StackAdapt push the most data). Harrier auto-deletes each recording once that application settles (a confirmation/rejection arrives, or it gives up), so in normal use they don't pile up. While a batch is actively submitting, expect a few hundred MB to a couple of GB of these in use at once — this does not scale with your total job count, only with how many are submitting right now.
If you're on a small drive, watch this. If a batch stalls and applications never settle, the recordings can build up until the automatic cleanup catches them. A quick way to see Harrier's footprint:
du -sh output state # the two folders that grow with useYour logins are kept in a local encrypted vault. Some application sites (Workday-based career
portals — Home Depot, Target, and many large employers) require an account before you can apply.
Harrier creates one per employer with a unique random password and stores those passwords encrypted
on your machine (AES-256-GCM). The key that unlocks them lives in your macOS Keychain when
available, otherwise in a locked-down (0600) key file in your home folder (~/.harrier) — kept
separate from the data, so the database, a backup, or a synced file never exposes a password on its
own. Nothing is ever sent over the network; the vault is local-only.
Setup (clone → running)
Quick start: run ./setup.sh — it checks Node, installs dependencies +
Chrome, scaffolds config/profile.yaml/.env from the examples (never
clobbering existing files), validates your profile, and prints the remaining
steps (your API key in .env, adding a résumé). Your whole profile — identity,
work eligibility, and search preferences — is set via the dashboard's Profile
button (the gear, top-right), not in a file. (harrier init is the packaged
install's equivalent — don't run it here; see
Install paths.) The steps below are the
same flow done by hand.
1. Set your API key
setup.sh already put the two lines in .env; paste your key after ANTHROPIC_API_KEY=.
It's a dotfile, so Finder won't show it — open it from the terminal:
open -e .env # macOS TextEdit (or: code .env · nano .env · $EDITOR .env)
# ANTHROPIC_API_KEY=sk-ant-... HARRIER_LLM_MODE=anthropic-apiThat's the only file you must touch. After npm start, click the dashboard's Profile
button (the gear, top-right) and fill in everything else — no YAML editing. The page has an
About you / Résumé / Job search / Take-home sub-nav:
- About you — name, current title, years of experience, contact, location, LinkedIn/GitHub.
- Résumé — experience, skills, education (what Harrier writes your résumé from).
- Job search — target roles, work eligibility, minimum salary, home city, remote preference, interview style, résumé tone, AI spend budget, Email & notifications.
- Take-home — the tax/net-pay math behind your salary floor.
These persist to the local database and overlay config/profile.yaml live (a saved value
wins; anything you leave blank falls back to the YAML). config/profile.yaml still exists
for power-user fields the UI doesn't cover yet — detailed stack, education, full mailing
address — and npm run check validates it, but it's optional to start.
2. (Optional) Connect your email
To track submission confirmations, rejections, and interview replies — and get run summaries — connect a Gmail inbox with a Google App Password (no OAuth, no Google Cloud project):
- Turn on 2-Step Verification on your Google account, then create an App Password at https://myaccount.google.com/apppasswords.
- Connect it either way:
- Dashboard: Profile → Job search → Email & notifications → paste your address + App Password.
- CLI:
npx tsx src/harrier.ts connect-email
The credential is verified over IMAP and stored encrypted in a local vault; reading and sending both use it. Skip this entirely and everything else still runs — you just won't get reply tracking or summary emails.
3. Initialize the database
The SQLite database (state/pipeline.db) is created automatically on first run
from src/db/schema.ts. Nothing to do — it self-initializes.
4. Run
npm start # start the whole supervised tree in the background; dashboard → http://localhost:3001
npm run status # is the supervisor running? is the dashboard up?
npm stop # stop everything together (safe + resumable — state is in SQLite/JSONL)
npm run serve # run the supervisor in the FOREGROUND (for systemd/launchd/Docker/a terminal)npm start/stop/status/serve are one Node launcher
(src/harrier.ts) — no bash — so they behave identically on macOS and Linux.
app.ts is the single supervisor: one process that spawns + keep-alives
every worker (dashboard, discovery, drain, …) and tears the whole tree down
together on stop.
Individual stages can also be run directly, e.g.
npx tsx src/discover-greenhouse.ts, npx tsx src/submit.ts --concurrency 6.
Configuration reference
Everything user-specific lives in config/profile.yaml (see
config/profile.example.yaml for the full annotated template): identity/contact,
application_answers (EEOC/work-eligibility), prompt_summary (one-line
phrasings for Claude prompts), target_comp, geo_preferences,
interview_preferences, stack, domains, experience, education.
Runtime tuning is via environment variables (see .env.example for the full
annotated list), including: NOTIFY_EMAIL, PROFILE_PATH, LOG_LEVEL,
MAX_DAILY_INPUT_TOKENS (Claude budget), ITERATION_ENGINE_HARD_CAP,
ATTEMPT_WATCHDOG_MS, the REPAIR_* deep-repair settings, and PORT (dashboard).
Other config files: config/sources.yaml (boards to scan), config/filters.yaml
(hard skips, captcha/skip companies), config/learned_answers.yaml (cross-role
answer cache), config/strategies.yaml (submission strategy bank).
Useful commands
npm run check # validate config/profile.yaml
npm test # unit tests (config loader, geo filter, learned answers, verifier)
RUN_DASHBOARD_RENDER=1 node --test src/test/test-dashboard-render.ts # Playwright dashboard render tests (the e2e CI gate; needs a built bundle + browsers)
npm run report -- dashboard # pipeline metrics (today/week/all-time)
npm run report -- backlog # staged-but-not-confirmed breakdown
npx tsx src/cooldown.ts list # company application cooldowns
npm run report -- interviewing # companies paused because an interview is in progressArchitecture (high level)
discover → score → stage → submit → (repair) → tracksrc/discover-*.ts— board probing.src/score-fast.ts+src/classify-jd-fit.ts— scoring.src/stage-*.ts— write staged role folders.src/submit.ts+src/core/*— the submission engine (browser, field-filler, form-solver, iteration-engine, verifier).src/harrier.ts— thestart/stop/status/servelauncher.src/app.ts— the single-process supervisor it launches: spawns + keep-alives every worker (dashboard, discovery, drain + repair lanes) and stops them together.src/dashboard/server.ts+index.html— live dashboard (port 3001).src/db/— SQLite schema + access helpers.src/lib/config.ts— single config loader;src/lib/logger.ts— logging.
Data persists in state/pipeline.db (SQLite, source of truth) plus JSONL
mirrors under state/. Generated artifacts live in output/staged/.
Something broken? Report it from inside Harrier
Open the gear in the dashboard header and pick Report a problem. Describe what happened and press Send — Harrier attaches the technical detail itself (version, install type, Node/npm, operating system, the built-in preflight results, which settings are switched on, and the tail of its own logs).
Three things are worth knowing about it:
- Your credentials and personal data never go. API keys, passwords, OAuth tokens, your résumé, your job list, your name, email, phone and home directory are stripped before the report is even written to disk. Settings are reported as set or unset, never by value.
- You can read the exact payload first. "Show me the exact report" prints the precise bytes that would be sent. Nothing leaves your machine until you press Send.
- It sends through the inbox you already connected. If you have not connected one, the report is
still saved to
output/support/and Harrier hands you a prefilled draft instead — it will never tell you a report went out when it did not.
If the dashboard itself will not start, the same report can be produced from a terminal:
harrier support # writes output/support/HR-<date>-<id>.txt and prints where to email it
harrier support --open # …and opens a prefilled draft in your mail appLimitations
- Single-user. One profile, one Gmail account, runs on one machine.
- Four autonomous ATSes. The drain auto-submits only to Greenhouse, Jobot, Ashby and
Workday (
DEFAULT_ALLOWLISTinsrc/lib/submit-ats.ts), and Workday only for tenants inPROVEN_WORKDAY_TENANTS. Eightfold/Netflix has its own dedicated submitter outside that drain. Lever and Workable have working adapters but were removed from the allowlist on 2026-07-26 — measured 0/106 and 0/9 real confirmations against their captcha wall — so they stage for the human-assist lane instead. Every other ATS is discovered but skipped at submit. - Selector fragility. Form-filling depends on current ATS DOM structure; ATS UI changes can break field detection until strategies/learned-answers adapt.
- CAPTCHA / anti-bot. Some companies (tracked in
config/filters.yaml) can't be auto-submitted and are skipped or iceboxed. - No CI/CD. Runs locally via
npm start; no hosted deployment. - Credential vault is local + key-bound. The encrypted login vault has two honest caveats: (1)
on a headless install (a server/CI box with no OS keychain) you must provide the master key
yourself via the
CREDENTIALS_KEYenv var; (2) the key lives in your machine's secure store, so wiping or migrating the machine loses it — the encrypted passwords then can't be decrypted. That's recoverable, not catastrophic: Harrier simply re-creates the employer accounts (they're also password-resettable via your email). Back up the key (or export/import it) if you want a clean migration.
See docs/ for recon notes and per-company playbooks.
