A Chainlit chat app that turns your resume and a job posting into a tailored cold email or cover letter — drafted in your voice, not an AI's.
- Onboarding — paste your resume (text or PDF). It's parsed into a structured profile (skills, experience, education, social links) and enriched with your GitHub bio and top repos. Saved locally so you only do this once.
- Apply — paste a job posting URL or description. It extracts the company, role, requirements, and posting tone, then streams a drafted email or cover letter live in the chat.
- Refine — say things like "more casual", "more formal", "simpler vocab", or "richer vocabulary" to redraft in a different tone or word choice, reusing the same extracted job facts (no re-scraping).
Tone is asked once via action buttons and remembered for next time (data/preferences.json); say a tone name again to change it.
(Windows / PowerShell)
.venv\Scripts\Activate.ps1
pip install -r requirements.txt
Copy .env.example to .env and fill in OPENAI_API_KEY (and GROQ_API_KEY if/when the Groq branch in utils/llm.py is wired up).
chainlit run app.py -w
-w enables auto-reload on file changes.
app.py— Chainlit handlers (on_chat_start/on_message) and the session state machine (resume onboarding, job detection, tone/vocab follow-ups)graphs/— compiled LangGraph flows:profile_graph(resume → structured profile → GitHub enrichment → save) andapply_graph(job input → fetch → structured job facts)nodes/— graph nodes:extract.py(structuredProfile/JobFactsvia LLM),scrape.py(job fetching + GitHub enrichment),draft.py(streaming email/cover-letter generation)prompts/—system.py(voice/tone fragments, list of AI-sounding patterns to avoid) andtemplates.py(composed system prompts) — tweak these to change output styleutils/—llm.py(single LLM provider factory — seeget_llm),scraper.py(httpx + BeautifulSoup page fetching, PDF text extraction viapypdf, GitHub API lookups)memory/— flat-JSON persistence layer for the user's profile and preferences (data/profile.json,data/preferences.json; gitignored)
For a deeper architectural walkthrough (state machine details, LLM task routing, prompt composition), see CLAUDE.md.
- Only OpenAI is wired up by default (
gpt-4o-minifor extraction,gpt-4ofor drafting); a Groq branch is sketched inutils/llm.py. - LinkedIn profile enrichment is intentionally skipped (LinkedIn blocks scraping) — that data comes from your resume text only.
- There is no test suite, lint config, or CI in this repo.