Hirable is a two-phase agentic app that builds a rich profile of your professional background through a conversational interview, then generates a tailored resume and cover letter for any job you apply to — improving with every session.
Phase 1 — Build your profile (do this once)
Upload your resume and Hirable will interview you to fill in what a CV can't capture: scale, impact metrics, private context per role, career goals. Your profile is saved to disk and enriched over time — the more detail you add, the better your tailored resumes become.
Phase 2 — Generate for each job
Paste a job URL or description. Choose:
- Quick mode — generate immediately from your profile
- Ask follow-ups mode — Hirable first identifies gaps between your profile and the JD (e.g. technologies mentioned in the job you haven't discussed), asks a few targeted questions, then generates
Output: a tailored resume (editable YAML + PDF) and a cover letter.
- Persistent profile — built up incrementally through chat; never re-asks what you've already answered
- Private context — per-role notes and impact metrics inform the LLM but never appear on the PDF
- Parallel LLM adaptation — 6 resume sections adapted concurrently against the job description
- JD keyword highlighting — extracted keywords are bolded in the PDF
- Editable YAML — review and tweak the resume before rendering
- Professional PDF — rendered via RenderCV
- Multiple input formats — resume as PDF, DOCX, TXT, or TEX; job as URL or pasted text
You'll need uv for package management.
# Install uv if you don't have it
curl -LsSf https://astral.sh/uv/install.sh | sh
uv sync
uv pip install "rendercv[full]" # installed separately — strict deps conflict with uv resolverHirable works with OpenAI, Google Gemini, Anthropic, or any LangChain-supported provider.
Set the relevant environment variable:
export OPENAI_API_KEY="sk-..." # OpenAI
export GOOGLE_API_KEY="..." # Gemini
export ANTHROPIC_API_KEY="sk-ant-..." # AnthropicThen edit src/config/__init__.py to select your provider and model names. The config has a small and large model slot — large is used for experience bullets and cover letter, small for everything else.
streamlit run streamlit_app.pyGo to Profile Setup in the sidebar. Upload your resume (PDF, DOCX, TXT, or TEX) and click Load resume into profile. Hirable will automatically start a gap-analysis interview — answer as briefly or in as much detail as you like. Type done at any point to stop.
Your profile is saved to data/user_profile.json after every answer. You can re-open Profile Setup at any time to add more context.
Go to Generate Resume. Paste the job URL or description, choose Quick or Ask follow-ups mode, and click Start.
Once generated:
- Edit keywords to adjust bold highlighting in the PDF
- Expand the YAML editor to tweak any section
- Click Generate PDF to render and preview
- Download the YAML or PDF
| Setting | File | Description |
|---|---|---|
| Model provider & names | src/config/__init__.py |
Switch between OpenAI / Gemini / Anthropic and set model IDs |
| Resume adaptation prompts | src/prompts/adaptation_prompts.py |
Edit to tune resume output quality |
| Interview prompts | src/prompts/interview_prompts.py |
Edit to change how gap analysis or Q&A extraction works |
| PDF style | src/config/rendercv_config.yaml |
RenderCV theme and layout settings |
hirable/
├── streamlit_app.py # Home page
├── pages/
│ ├── 1_Profile_Setup.py # Chat-based profile interview
│ └── 2_Generate_Resume.py # Job input + generation UI
├── src/
│ ├── models/ # Pydantic data models
│ │ ├── user_profile.py # Persistent profile (UserProfile, RoleContext, ProfilePatch)
│ │ ├── resume.py # Output schema for PDF generation
│ │ ├── job_desc.py # Parsed job description
│ │ └── cover_letter.py
│ ├── nodes/
│ │ ├── profile_nodes.py # Gap analysis, interview Q&A extraction
│ │ └── generation_nodes.py # Resume adaptation, cover letter generation
│ ├── graphs/
│ │ └── generation_graph.py # LangGraph pipeline
│ ├── prompts/
│ │ ├── adaptation_prompts.py
│ │ └── interview_prompts.py
│ └── utils/
│ ├── persistence.py # load/save user_profile.json
│ ├── export.py # Resume → RenderCV → PDF
│ ├── parse.py # File and URL parsing
│ └── llm.py # LLM initialisation with rate limiting
└── data/
└── user_profile.json # Your persisted profile (gitignored)
Your profile (data/user_profile.json) is stored locally only — nothing is sent anywhere except the LLM API calls you configure. Add data/ to your .gitignore if you're pushing to a public repo.