Inside ApplyPilot's six stages, from job scrape to submitted form
AI agent that applies to jobs for you. Any site. Any form.
At a glance
- What is it?
- ApplyPilot is a Python agent that finds jobs across five boards and employer portals, scores them against your resume, rewrites that resume per posting, and lets a browser agent submit the form. The scraping and tailoring half runs on one free Gemini key; the submission half needs Node.js, Chrome and the Claude Code CLI.
- Who is it for?
- ApplyPilot suits a candidate who wants resume and cover letter variants at volume and is willing to read each one before an employer does. It does not suit anyone who needs certainty about what an employer receives, because the score cut-off that decides which jobs get tailored is missing from the README and no command undoes a batch already sent.
- Can I use it commercially?
- Yes, with strict conditions. AGPL-3.0 is a network copyleft licence: if people use a modified version over a network, for example as a hosted service, you must offer them its source code under the same licence.
- Is it still maintained?
- Activity is slowing. The repository last received commits 7 months ago.
- What is it written in?
- Mainly Python, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on September 20, 2026, and from our analysis. They are not legal advice.
Editorial analysis
Six stages from job board scrape to submitted application
ApplyPilot aims at one narrow job: a candidate who wants an agent to carry an application from search to submitted form without touching a browser. The work is split into six stages, and each stage is independent, so you can run all of them or pick the ones you want.
Stage one queries 5 job boards (Indeed, LinkedIn, Glassdoor, ZipRecruiter, Google Jobs) through JobSpy, then walks 48 Workday employer portals and 30 direct career sites, deduplicating by URL. Stage two rebuilds the full description behind each URL through a three-tier cascade: JSON-LD structured data first, CSS selector patterns second, AI extraction last for layouts nobody has written a selector for. Stage three asks the model for a 1-10 fit score against your resume and preferences. Stage four reorganizes that resume for one posting, stage five writes a targeted cover letter, and stage six hands form filling, document uploads and screening answers to Claude Code.
The split is the decision worth noticing. Stages one through five are a scraper and a prompt chain, so they need Python 3.11+ and a Gemini API key. Only stage six pulls in Node.js, Chrome and a second command line tool, which means the expensive and hard to audit half can stay switched off while the part that produces your materials keeps working.
Two pip commands and the numpy pin that forces them
The install path is unusual enough to copy exactly, because the reason for it is written down: `python-jobspy` pins an exact numpy version in its metadata, that pin conflicts with pip's resolver, and the library still runs fine at runtime on any modern numpy.
pip install applypilot
pip install --no-deps python-jobspy && pip install pydantic tls-client requests markdownify regexThe second line does two jobs at once. It forces jobspy past the resolver and then installs its actual runtime dependencies by hand, so you end up with a scraper that pip would have refused to resolve. Everything other than python-jobspy installs normally, and the same explanation is repeated in the requirements section.
Then `applypilot init` writes your working files and `applypilot doctor` prints what is installed and what is missing:
applypilot init # one-time setup: resume, profile, preferences, API keys
applypilot run # discover > enrich > score > tailor > cover letters
applypilot run -w 4 # same but parallel (4 threads for discovery/enrichment)`applypilot run` stops after the cover letters, which is the natural place to keep a human in the loop, and `-w 4` widens discovery and enrichment to four threads. The README opens that whole command block with 'Three commands. That's it.' and then shows seven lines, so count on more than three.
Every job costs a model call on a 15 RPM free tier
Stage three is the cost centre, and its bands are written out plainly: 9-10 means strong match, 7-8 good, 5-6 moderate, 1-4 is skipped. The model rates every posting against your profile and preferences one job at a time, and only the jobs clearing a stated threshold move on to resume tailoring.
That threshold is where the documentation runs out. The Score section ends mid-clause at 'Only jobs above', so the cut-off that promotes a posting into a resume rewrite is not written anywhere in the repository. You can read the bands and you cannot read the gate.
Throughput is the other constraint, and it comes from the same key that does tailoring and cover letters. The requirements table prices the Gemini free tier at 15 RPM / 1M tokens/day and calls that enough. Set that ceiling against the 1,000 jobs in 2 days on the project's own badge and it decides how much of a discovered list ever reaches stage four. Nothing in the repository describes a cheaper local model for the scoring stage in particular, even though `LLM_URL` accepts a llama.cpp or Ollama endpoint and `LLM_MODEL` can override the model name.
profile.json holds the facts the rewrite may not invent
`applypilot init` is where the inputs live. It generates `profile.json` with contact details, work authorization, compensation, experience, skills, the resume facts that must survive tailoring, and EEO defaults used later for form auto-fill. It also writes `searches.yaml` for queries, target titles, locations and board choices, plus a `.env` for keys:
GEMINI_API_KEY= # Gemini 2.0 Flash (recommended, cheapest)
# LLM_MODEL= # Override model name
CAPSOLVER_API_KEY= # For CAPTCHA solving during auto-applyThe `.env.example` file at the repository root tells you to copy that block to `~/.applypilot/.env`, which keeps your key outside the project tree.
Two YAML files ship inside the wheel instead of in your home directory. The build configuration keeps `src/applypilot/config/*.yaml` as artifacts, which is how `config/employers.yaml` with 48 preconfigured Workday employers and `config/sites.yaml` with 30+ direct career sites, blocked sites, base URLs and manual ATS domains reach an installed copy. Both stay editable, and the Workday registry is the one you will end up rewriting for your own target employers.
Stage four's rule is narrow and worth quoting: tailoring reorganizes, emphasizes relevant experience, adds keywords and never fabricates. No validation step between the model output and the saved resume is described anywhere in the repository, so that last promise rests on how the model behaves rather than on a check in the code.
Claude Code drives the browser half of the pipeline
Stage six is the only stage that needs a second toolchain. The requirements table puts Node.js 18+ in the auto-apply column because npx has to run a Playwright MCP server, Chrome or Chromium is auto-detected on most systems, and the Claude Code CLI is what walks the forms, answers questions, uploads documents and submits.
applypilot apply # autonomous browser-driven submission
applypilot apply -w 3 # parallel apply (3 Chrome instances)
applypilot apply --dry-run # fill forms without submitting`-w 3` runs three Chrome instances at once, which is a lot of automated traffic to point at career sites in one go. `--dry-run` is the only review gate the CLI puts in front of a real submission, and no documented command pauses a run, retires an application already sent or throttles per domain.
One packaging detail explains why the browser half feels bolted on. `playwright>=1.40` sits in the core dependency list, so every install pulls the Python binding even on the discovery and tailoring path that never opens a browser, while the driver used for submission is a Playwright MCP server launched through npx:
[project]
name = "applypilot"
version = "0.3.0"
requires-python = ">=3.11"48 Workday portals in one table, 46 in the next
Two parts of this repository disagree about how much of the web the pipeline covers, and the disagreement sits on the page a reader would check first. The pipeline table says discovery scrapes 5 job boards plus 48 Workday employer portals plus 30 direct career sites. The comparison table further down lists supported sites as 46 Workday portals and 28 direct sites. The configuration section then returns to 48 for `config/employers.yaml` and 30+ for `config/sites.yaml`.
Three site counts for one crawler, and only the configuration section matches the files it describes. If your target employer sits on a Workday portal, the registry you can actually edit is the 48-entry `config/employers.yaml`, and the headline number in the marketing table is not something you can audit.
On the state of the code, the last push was on 2026-03-08 while the packaged version 0.3.0 was published on 2026-02-21, so what pip installs is about two weeks behind the branch. Its packaging metadata still labels the build `Development Status :: 4 - Beta`, which sits awkwardly beside a badge claiming the agent is fully autonomous.
Where ApplyPilot stops and AIHawk starts
The comparison table lines ApplyPilot up against AIHawk and against doing it by hand, and the three columns differ in ways that decide adoption.
On discovery, AIHawk covers LinkedIn only, while this pipeline reads 5 boards plus Workday portals plus direct career sites. On submission, AIHawk is limited to LinkedIn Easy Apply, whereas stage six works on any form the browser agent can reach. On tailoring, AIHawk is template-based and this column promises a per-job AI rewrite that reorganizes and reweights your experience. The scoring row is the weakest part of the argument: a 1-10 fit score against basic filtering.
The licence difference settles the integration question: ApplyPilot ships under AGPL-3.0-only in its packaging metadata while the same table lists AIHawk as MIT, so a company that wanted to fold this code into a closed product gets a different answer here. The manual column is the honest baseline it is measured against: hours per application, one board at a time.
CapSolver decides whether a blocked form ever gets sent
The optional component that decides whether a gated application is ever submitted is `CAPSOLVER_API_KEY`. The requirements section lists it as the component that solves CAPTCHAs during auto-apply, naming hCaptcha, reCAPTCHA, Turnstile and FunCaptcha, and states plainly that without it a CAPTCHA-blocked application just fails gracefully. Graceful failure still means no application sent.
That is the first case where this is the wrong tool. A pipeline whose sixth stage is a browser agent pointing three Chrome instances at career sites will meet gates the scraper stages never touch, and `CAPSOLVER_API_KEY` is the documented answer to exactly that wall. `config/sites.yaml` does carry a blocked-sites list, base URLs and manual ATS domains, so there is a blocklist to extend, yet nothing in the repository says who maintains it or how frequently it is refreshed.
The second limitation is quieter: there is no undo. No documented command retracts a submitted application, discards a batch, or reverts a resume already written by a tailoring stage, and the only pre-send control sits on the apply subcommand rather than on run. If you want to read every generated cover letter before it attaches to anything, drive stages one to five yourself and never call apply.
Editorial conclusion
ApplyPilot suits a candidate who wants resume and cover letter variants at volume and is willing to read each one before an employer does. It does not suit anyone who needs certainty about what an employer receives, because the score cut-off that decides which jobs get tailored is missing from the README and no command undoes a batch already sent. Check two things first: that config/employers.yaml still lists the Workday portals you care about, and that your first applypilot apply run ends at --dry-run.
Frequently asked questions
What does ApplyPilot need before it can submit applications on its own?
Auto-apply needs Python 3.11+, Node.js 18+ for npx to run a Playwright MCP server, Chrome or Chromium, the Claude Code CLI, and a Gemini API key for scoring, tailoring and cover letters. The discovery and tailoring path needs only Python 3.11+ and the Gemini key.
Does ApplyPilot require a paid model API to run?
The Gemini free tier at 15 RPM / 1M tokens/day is described as enough. `OPENAI_API_KEY` and a local endpoint set through `LLM_URL` for llama.cpp or Ollama are also supported, and `LLM_MODEL` overrides the model name.
Can ApplyPilot fill an application form without sending it?
Yes, `applypilot apply --dry-run` fills forms without submitting. No equivalent flag is documented for `applypilot run`, which ends after the cover letter stage anyway.
How many job sources does ApplyPilot actually read from?
The pipeline table says 5 job boards plus 48 Workday employer portals plus 30 direct career sites. The comparison table in the same README says 46 Workday portals and 28 direct sites, and the configuration section says 48 and 30+.
What happens to a job application that is blocked by a CAPTCHA?
Without `CAPSOLVER_API_KEY` those applications fail gracefully, which means nothing is submitted. That key is documented as solving hCaptcha, reCAPTCHA, Turnstile and FunCaptcha during auto-apply.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/pickle-pixel-applypilot)Was this useful?