← Back to projects

Hansel

πŸ€– AI Agent Python Β· LangChain Β· Ollama 2025

I got tired of manually searching for jobs and writing cover letters for every application. So I built a tool that does it β€” reads my CV, finds relevant listings, and drafts personalized emails. 100% local. No paid APIs. No data leaving my machine.

142
Unit tests
3
Job boards scraped
9
Architecture Decision Records
100%
Local β€” no paid APIs

The problem

Most job search tools are generic. They surface hundreds of listings that technically match your keywords but don't actually fit your profile. Then you spend hours reading each one, writing slightly different cover letters, and still not knowing which ones are worth applying to.

I wanted something that reads my actual CV, understands what I do, and only surfaces listings that genuinely match β€” then helps me write the application.

What it does

πŸ“„

CV-aware matching

Reads your CV and uses it as context for all ranking and generation. Not keyword matching β€” semantic understanding.

πŸ”

Parallel search

Searches 3 Swiss job boards simultaneously. Results are deduplicated and ranked by relevance.

🎯

Retrieve & Rerank

Two-stage ranking: fast embeddings for retrieval, then LLM reranker for precision. Best of both worlds.

βœ‰οΈ

Email generation

Drafts personalized application emails grounded in both your CV and the specific job listing.

πŸ›‘οΈ

Hallucination defense

3-layer system to prevent the model from inventing credentials or misrepresenting your profile.

πŸ–₯️

Web UI + streaming

FastAPI backend with a clean web interface. Results stream in real-time as the agent works.

Tech stack

Fully local β€” everything runs on your machine via Ollama. No OpenAI, no Anthropic, no cloud calls.

Python LangChain Ollama Qwen / local LLM RAG Embeddings FastAPI Docker Pydantic pytest (142 tests) uv

What I learned

Building a production-grade RAG pipeline is harder than tutorials make it look. The retrieval step is easy. The reranking, hallucination prevention, and making the whole thing feel coherent is where most of the work went.

Writing 142 tests for an AI agent is also an interesting challenge β€” you can't just assert exact outputs. I had to think about what properties the outputs should have, not what the exact text should be.

The 9 Architecture Decision Records document why I made specific technical choices β€” from the choice of embedding model to how I structured the hallucination defense. It's a habit I picked up from working on real projects and it's genuinely useful.