Repository navigation
How to automate job applications with Python
AIHawk is written in Python and is MIT licensed, so the honest answer to "how do I automate job applications with Python" is: run it, read it, and change the part you need. This page says what the program is made of, how to run it from source, and where the three things people usually want to change live: the models, the search, and the job sites.
The dependencies in pyproject.toml on 2026-11-06, with what each one does in AIHawk:
| Package | Role |
|---|---|
textual and rich
|
The terminal screen: the job list, the settings, the batch that sends. |
duckdb |
The job index. The database is a Parquet file, searched on your machine. |
pypdf |
Reads a PDF resume. Word and plain text are read too. |
openai |
The client for every model call. The endpoint is OrcaRouter, which serves the OpenAI chat API. |
invisible-playwright-mcp and mcp
|
The browser. A Firefox built to look like a person's, driven through the Model Context Protocol. |
click and pyyaml
|
The command line and aihawk.yaml. |
There is no scraper for job sites in the package. The postings come from a database that a GitHub Actions workflow builds every five hours from 24 public sources; docs/data-sources.md names each source with its licence. What AIHawk automates is the reading of your CV, the ranking, and the form.
Python 3.11 or newer is required.
The published command uses uv, and it is the same one the README gives:
uvx --refresh-package aihawk --from git+https://github.com/feder-cr/Jobs_Applier_AI_Agent aihawkuvx fetches the repository, builds the package, and runs the aihawk entry point, which is aihawk.cli:run. The run.ps1 and run.sh scripts in the repository do nothing more than install uv when it is missing and run that line. To work on the code instead, clone the repository and install it in a virtual environment as an editable package; the dev extra in pyproject.toml adds pytest and ruff.
AIHawk keeps its files in ~/.aihawk (%USERPROFILE%\.aihawk on Windows): aihawk.yaml with the settings, key with the model key, the browser profile, applied.csv with every send, and data/proofs/ with the screenshots.
Every model call goes through one gateway. aihawk.yaml names four models, and e in the program edits them:
| Key | Default | What it does |
|---|---|---|
model |
deepseek/deepseek-v4.1-flash |
Fills the application forms and reads their screenshots. |
quick_model |
google/gemini-3.5-flash |
Writes the search plan from your CV. |
judge_model |
deepseek/deepseek-v4.1-flash |
Writes the score and the report of each shortlisted posting. |
decision_model |
typesafe/jev-1.14 |
Answers the six closed questions that shortlist the postings. |
Any model that OrcaRouter serves can go in the first three, by its id. The page Automate job applications with Claude works through one such change, with the prices. The decision model is better left alone: the code turns its answers into evidence by rules that were checked on that model, and the repository's own comment says another model answers differently.
The search plan is a graph in filters.plan: nodes for the facets of the job (the role, a skill), forms for the wordings a title can use, and arcs that scale a title up or down when a word is present. AIHawk writes the plan from your CV, and you can edit it by hand in aihawk.yaml. The page How matching works has the YAML and the rules, including the whole-word match and the 60-day limit on postings.
This is the part people expect to be code, and it is not. A site is a plugin: a Markdown file with a front matter naming the hosts, and then prose that explains the site's form to the model, in the order the form is met. A plugin for Lever is about twenty lines. Yours goes in ~/.aihawk/plugins/, and a file with the name of a bundled plugin replaces it. The repository's guide, docs/plugins.md, has the full format, a real plugin as an example, and the ways to test one without sending anything to an employer. Sites and plugins says which sites already have one.
The model is told not to send the form and to leave that to AIHawk after your yes, and nothing in the code checks the model's calls. SECURITY.md says why that choice was made. A form AIHawk fills goes out in your name, and the page Limits lists what nobody has verified. Read that before you automate anything that reaches an employer.
-
pyproject.toml,run.ps1,run.sh,docs/configuration.md,docs/plugins.md,docs/data-sources.md,src/aihawk/config.pyandsrc/aihawk/llm.pyof feder-cr/Jobs_Applier_AI_Agent at commit0212a10, read on 2026-11-06.