AI-powered job hunting automation that discovers relevant vacancies from your curated company list, scores them against your profile, asks for approval in Telegram, and generates tailored application documents (CV, cover letter, answers) for approved roles.
This project helps you run a structured, human-in-the-loop job search pipeline:
- Discover new roles from curated company career pages.
- Score each role for fit.
- Ask you to approve/decline vacancies via Telegram.
- Generate application assets for approved jobs.
- Track all artifacts locally in
data/.
The following ATS domains are working 100% in this project:
jobs.ashbyhq.comjob-boards.greenhouse.iojobs.lever.cojobs.personio.combamboohr.com
⚠️ IMPORTANT: Custom career pages are also supported, but can be handled differently by AI and potentially can't be properly processed
For a non-code setup walkthrough, see docs/setup-guide.md.
Example knowledge/ files are available in examples/knowledge/.
Requires Python >=3.10,<3.14.
curl -LsSf https://astral.sh/uv/install.sh | sh
source $HOME/.cargo/env
# or just
source ~/.bashrc
uv sync
source .venv/bin/activateIf uv sync fails on Intel macOS because of onnxruntime, run:
uv sync --no-install-package onnxruntime
source .venv/bin/activateSelenium vacancy extraction also requires a Chrome-compatible browser on the
host. On Linux servers, install Chromium or Google Chrome before starting
job_hunting_bot or job_hunting_discover. Install a matching ChromeDriver as
well; the browser and driver major versions must match.
sudo apt-get update
sudo apt-get install -y chromium chromium-driverPDF generation for tailored CVs and cover letters also requires pdflatex:
sudo apt-get install -y texlive-latex-base texlive-latex-recommended texlive-latex-extra texlive-fonts-recommended
pdflatex --versionIf Ubuntu installed Chromium as a Snap, use the Snap-provided browser and driver together:
export CHROME_BINARY=/snap/bin/chromium
export CHROMEDRIVER_PATH=/snap/bin/chromium.chromedriverThe launch commands check these prerequisites and return a clear error if the
browser or driver is not found. The scraper uses modern headless mode and a
temporary Chrome profile directory for VPS/server environments. If modern
headless Chromium exits before creating a WebDriver session, the scraper
automatically retries with legacy --headless and returns the ChromeDriver log
tail with the browser and driver paths it used.
cp .env.example .envSet values in .env:
OPENAI_API_BASEOPENAI_API_KEYMODELTELEGRAM_BOT_TOKENTELEGRAM_CHAT_IDTELEGRAM_ALLOWED_USERS(optional, comma-separated)MIN_SCORE(default:70)CHROME_BINARY(optional, for example/usr/bin/chromium)CHROMEDRIVER_PATH(optional, for example/snap/bin/chromium.chromedriver)
Create a knowledge folder in the project root and fill all necessary files. Examples are in examples/knowledge/; the guide for files is in docs/setup-guide.md.
Copy examples/knowledge/profile.yaml to knowledge/profile.yaml and edit it for the candidate. This private YAML file controls identity, optional candidate summary and languages, Discovery search filters, and the allowlisted structured YAML profile sections used for scoring and generated artifacts. Section examples live as examples/knowledge/profile/*.yaml and are referenced from knowledge/profile.yaml.profile_sections.
Supported profile section keys are work_experience, projects, education, skills, public_speaking, and values. Point each key at a .yaml file under knowledge/profile/; Markdown section files and a summary / profile-summary section are no longer supported. Discovery scoring builds its profile summary from the structured scoring sections.
Links inside profile section YAML must use HTTPS URLs. Clickable links in rendered CV PDFs are underlined. show_on_cv is optional and defaults to true; set it to false to exclude an item or group from the CV while keeping it available as source context. For work experience, show_on_cv applies at the role level.
Edit knowledge/companies.csv with company name + career page URL.
Start the Telegram bot (terminal 1):
job_hunting_botPrepare one vacancy URL directly from Telegram:
/prep_vacancy
Then send the vacancy URL to the bot. It extracts the vacancy, generates the application artifacts, and sends them back to the same chat.
Run discovery (terminal 2, cron-friendly entrypoint):
job_hunting_discoverOptional: start the local advisor chat UI (Chainlit):
job_hunting_advisor- Run discovery periodically (manual or cron).
- Receive Telegram approval cards for high-score roles.
- Click
Approveto trigger document generation. - Review generated artifacts in
data/<date>/applications/<vacancy_id>/. - Mark status back in Telegram (
applied,not_applied, etc.).
Generated application files use company and position names, for example Kraken-SeniorProductManager-CV.pdf, Kraken-SeniorProductManager-QA.md, and Kraken-SeniorProductManager-CoverLetter.pdf.
Generated files are stored under:
data/<YYYY-MM-DD>/vacancies/*.jsondata/<YYYY-MM-DD>/scores/*.jsondata/<YYYY-MM-DD>/applications/<vacancy_id>/...data/<YYYY-MM-DD>/discovery_coverage.csvknowledge/profile.yamlknowledge/profile/*.yaml
Activate the environment first:
source .venv/bin/activatejob_hunting_bot— Starts the Telegram bot. Output: waits for Telegram actions and handles approvals/status updates.job_hunting_discover— Readsknowledge/profile.yamlandknowledge/companies.csv, discovers vacancies, scores them, and sends suitable roles to Telegram. Output:data/<YYYY-MM-DD>/discovery_coverage.csv,data/<YYYY-MM-DD>/vacancies/,data/<YYYY-MM-DD>/scores/, and application files after approval.job_hunting_advisor— Starts the Chainlit advisor UI. Output: local web chat for career/application questions.
Without activating .venv, prefix commands with uv run, for example:
uv run job_hunting_discoverThis project is licensed under the MIT License. See LICENSE.