A fun AI project that writes cover letters for you!
This little project uses AI to help with job applications. You give it your CV, it finds matching jobs from a list, and then writes a personalized cover letter for the best match. Pretty neat, right?
- Job applications are boring and repetitive 😴
- Writing cover letters takes forever
- I wanted to play with LangChain and Mistral AI
- It's cool to see AI match your skills to jobs
Your CV → AI finds matching jobs → AI ranks them → AI writes cover letter ✨
- Python 3.10+
- A Mistral AI API key (they have free tiers!)
- Your CV in plain text format
# Get the code
git clone <repository-url>
cd IntelliApply_AI
# Make a virtual environment (recommended)
python -m venv venv
venv\Scripts\activate # Windows
# Install stuff
pip install -r requirements.txt
# Setup your API key
copy .env.example .env
# Edit .env and add your MISTRAL_API_KEY# Put your CV text in data/cv.txt, then:
python run_agent.py --cv-path ./data/cv.txt --streamThat's it! It will find jobs, rank them, and write you a cover letter.
📁 data/ # Your CV and job listings go here
📁 scripts/ # Helper scripts
📁 coverletters/ # Generated cover letters saved here
📁 logs/ # App logs
📄 agent.py # The AI agent brain
📄 tools.py # LangChain tools for the agent
📄 run_agent.py # Main script to run everything
AI Agent (agent.py): Uses LangChain to orchestrate everything. It's like a mini AI assistant that knows how to use tools.
Job Matching (retrieval.py): Uses embeddings to find jobs that match your CV semantically (not just keyword matching).
Smart Ranking (ranking.py): Mistral AI looks at all the matching jobs and figures out which ones are actually good fits.
Cover Letter Writer (tools.py): The fun part! Generates personalized cover letters that don't suck.
The project uses Pydantic to define strict data models for everything flowing through the pipeline. Instead of passing raw dicts around and hoping the keys are right, each piece of data has a typed schema that validates itself automatically.
Here's what each schema in schemas.py does:
| Schema | Purpose |
|---|---|
Job |
Represents a full job listing (title, company, description, skills, etc.) |
JobSnippet |
A lightweight preview returned by search — just enough info to display results |
CoverLetterOutput |
The generated cover letter with a title and body |
IngestResult |
Tracks how many jobs were loaded and from where |
RankedJob |
A single job with its rank, score (0–10), and reasoning |
RankingResult |
Wraps the LLM's structured ranking output so we can parse it reliably |
Why bother? Because the LLM returns JSON and we need to trust the shape of that data. Pydantic's model_validate() catches bad/missing fields immediately instead of blowing up somewhere downstream. It also makes the code self-documenting — you can look at the schema and instantly know what data a function expects or returns.
Tech stack:
| Tool / Library | What it's used for |
|---|---|
| LangChain | Agent framework — orchestrates the whole tool-calling workflow |
| Mistral AI | LLM backend for ranking jobs and writing cover letters |
| HuggingFace Sentence Transformers | Generates embeddings for semantic CV↔job matching |
| Pydantic v2 | Data validation and typed schemas (see above) |
| Pinecone | Optional cloud vector DB for scalable job search |
| NumPy | Cosine similarity math for the in-memory fallback search |
| python-dotenv | Loads API keys from .env file |
Environment variables (in .env):
MISTRAL_API_KEY=your_key_here # Required
MISTRAL_MODEL=mistral-medium-latest # Optional, this is default
# Optional Pinecone stuff (for cloud vector storage):
PINECONE_API_KEY=your_pinecone_key
PINECONE_INDEX_NAME=job-search
PINECONE_ENV=us-east-1-awsCommand line options:
python run_agent.py --cv-path ./my_cv.txt --stream
python run_agent.py --cv-text "I'm a developer..." --streamThings I might add when I have time:
- Real job scraping from LinkedIn, Indeed, etc. (right now it uses fake jobs in
data/jobs.json) - PDF CV support (currently needs plain text)
- Web interface instead of command line
- Better job matching with more factors
- Interview prep suggestions
- Different writing styles for cover letters
Right now this is a hobby project with:
- ✅ Hardcoded sample jobs in JSON format
- ✅ Plain text CV input required
- ✅ Works with Mistral AI for intelligence
- ✅ Semantic job matching with embeddings
- ✅ Auto-generated cover letters
- 🚧 No real job platform integration yet
- 🚧 No fancy UI yet
The agent uses these tools to do its magic:
| Tool | What it does |
|---|---|
ingest_jobs() |
Loads jobs from the JSON file |
search_jobs() |
Finds jobs matching your CV |
rank_jobs() |
AI ranks jobs by fit |
get_job_details() |
Gets full info for a job |
generate_cover_letter() |
Writes the cover letter |
"ModuleNotFoundError": Make sure you activated your virtual environment and ran pip install -r requirements.txt
"API Key Error": Check your .env file has MISTRAL_API_KEY=your_actual_key
"No jobs found": The sample jobs are in data/jobs.json. You can run python scripts/sample_jobs.py to generate new ones.
Cover letter seems weird: Make sure your CV is in plain text format, not a PDF or Word doc.
This is just a hobby project I built to learn about AI agents and make job applications less painful. Feel free to experiment with it, break it, and make it better!
The code is pretty straightforward - the agent follows a simple workflow and uses AI to make smart decisions. It's a great example of how you can chain together different AI tools to solve real problems.
Your next job application just got a lot easier! 🚀