A local-first job application engine that turns a structured experience database and a job description into verified, tailored application materials.
The LLM selects and phrases facts. It does not invent them. Skills, projects, and evidence live in structured storage. Matching is deterministic where possible. Every generated claim can be traced to a source.
How do you tailor resumes to job descriptions with local models without hallucinating experience, while keeping the pipeline inspectable, testable, and usable through a real UI?
- Stores profile, skills, and projects as structured records with explicit evidence lines.
- Parses a pasted job description or listing URL into a validated skill and requirement schema.
- Matches jobs to experience with exact, normalized, and evidence-backed stages, plus explanations.
- Plans resume and cover letter wording from selected evidence only, with provenance on claims.
- Exports DOCX through interchangeable templates (technical, modern, classic).
- Runs ATS-oriented diagnostics as a checklist, not a fake ranking guarantee.
- Tracks applications and surfaces skill-gap analytics across parsed jobs.
- Serves a React UI with light and dark themes for the full workflow.
The repository is a small monorepo: a FastAPI backend for the pipeline and data layer, and a Vite React frontend for interaction.
Architecture
- Experience store: SQLModel models over SQLite for profile, skills, projects, jobs, and applications. List fields are stored simply and exposed as structured JSON through the API.
- Job intake: paste path for raw text, or URL fetch via Playwright with an HTTP fallback, then HTML text extraction.
- Parsing: Ollama when available for structured JSON extraction, validated with Pydantic. Heuristic section parsing when Ollama is offline.
- Matching engine: exact aliases, skill-family normalization, then project evidence attachment. Embeddings are intentionally out of scope for this release.
- Document planning: resume and cover letter planners receive only matched skills and evidence blocks. Bullets without sources are dropped.
- Rendering: python-docx applies template configs (font, density, section style) separately from content generation.
- Analytics: skill demand across parsed jobs, missing skills, and underrepresented skills that lack project evidence.
- Frontend: React + TypeScript + Tailwind pages for profile, skills, projects, jobs, applications, and analytics. Vite proxies
/apito the backend.
Design choices
- Canonical experience is data, not prompt memory, so generation stays grounded and auditable.
- Matching is LLM-free and unit-tested, so fit scores do not depend on model quirks.
- Heuristic fallbacks keep the product usable without a local model.
- Content and presentation are separated: planners decide what to say, templates decide how DOCX looks.
- ATS output is diagnostic. It reports keyword coverage and structure checks without claiming placement success.
- Local Ollama is the default model path. No cloud API key is required.
Stack
| Area | Choice |
|---|---|
| Frontend | React, TypeScript, Vite, Tailwind CSS |
| Backend | Python 3.11+, FastAPI, Uvicorn |
| Data | SQLite, SQLModel, Pydantic Settings |
| Local LLM | Ollama (optional, with heuristic fallback) |
| Scraping | Playwright, BeautifulSoup / lxml |
| Documents | python-docx (LibreOffice optional for PDF) |
| Quality | pytest |
- Python 3.11 or newer
- Node.js 18 or newer and npm
- pip and a virtual environment
- Optional: Ollama and a pulled instruct model such as
llama3.2 - Optional: LibreOffice (
soffice) on PATH for PDF conversion
git clone <this-repo>
cd resume-crafter
python -m venv .venvActivate the environment:
# Windows (PowerShell)
.\.venv\Scripts\activate
# Linux / macOS
source .venv/bin/activateInstall backend dependencies and create local config:
pip install -r backend/requirements.txt
copy .env.example .env
# Linux / macOS: cp .env.example .envInstall frontend dependencies:
cd frontend
npm install
cd ..Optional demo data:
cd backend
python scripts/seed_demo.py
cd ..cd backend
uvicorn app.main:app --reload --port 8000API docs: http://127.0.0.1:8000/docs
Health: http://127.0.0.1:8000/api/health
In a second terminal:
cd frontend
npm run dev- Open Profile, Skills, and Projects. Evidence lines become resume bullets.
- On Jobs, paste a description or URL and run Parse and match.
- Review match explanations, choose a template, then Generate resume and Download DOCX.
- Optionally generate a Cover letter, run ATS checks, and Track application.
- Use Analytics for skill demand and gaps across parsed jobs.
ollama serve
ollama pull llama3.2When Ollama is reachable, job parsing and document wording use the configured model from .env. When it is not, the API stays on heuristic mode.
Generated artifacts and state live under data/ (gitignored):
data/
resume_crafter.db
resumes/
cover_letters/
jobs/
applications/
API responses also include structured match results, provenance-bearing resume and cover letter JSON, ATS reports, and skill-gap analytics.
frontend/ React UI
src/pages/ Overview, profile, skills, projects, jobs, applications, analytics
src/api/ Typed client for /api
backend/
app/api/ FastAPI routers
app/ai/ Ollama client, prompts, matching
app/parsing/ Job, resume, cover letter, ATS, skill-gap parsers
app/documents/ DOCX rendering and template loading
app/models/ SQLModel entities
app/scraping/ URL fetch and HTML extraction
tests/ Unit tests
templates/resumes/ Template configs (technical, modern, classic)
data/ Local SQLite DB and exports
overview.md Architecture notes and longer roadmap
cd backend
pytest -qMatching, heuristic job parsing, ATS diagnostics, cover letter fallback, skill-gap analytics, and template loading are covered without requiring Ollama.
In scope: local experience storage, job parsing, explainable matching, evidence-grounded resume and cover letter generation, DOCX templates, application tracking, skill-gap analytics, and a usable UI.
Out of scope for this codebase: automatic apply-on-your-behalf against real job boards, paid cloud LLM dependency, semantic vector matching, and treating ATS diagnostics as a guarantee of recruiter or ATS ranking success.