TreeMap
A free, open-source disk-space visualizer. Squarified treemap, duplicate hunting, disk-full forecasting, and cleanup that only ever moves files to the Trash.
Tailor your resume to match the keywords in any job description to boost your chances. Upload your resume, paste a job description, and get a perfectly customized resume instantly.
ProductivityPython · TypeScriptGitHub @ManasAyyalarajuOnlineOwner unconfirmed
Have you tried it? One tap is enough. No sign-in needed.
No updates detected yet. GitHub releases will appear here.
Owners of public repositories under a personal GitHub account can sign in to verify ownership and manage the introduction themselves. No administrator approval is needed.
Sign in, generate a verification file, and commit it to this repository’s default branch within 30 minutes. Files on other branches or forks do not count. Then check the file below to manage the project without administrator approval. Keep the file to retain your access.
If needed, you will go to sign-in. After signing in, return here and press your chosen verification button again.
Run /nomorevibe verify in your project folder to verify ownership and manage the introduction yourself.
Verify in one minuteAsk about other verification options
Using AI to update resume to new job descriptions automatically
Translation pending
Taken from the repository README
Loading the full README. The saved excerpt is shown below.
Tailor your resume to any job in seconds — from a web app, or straight off the job posting.
Upload a resume once. Tailor it against a job description or reformat it into a clean, ATS-friendly PDF — either from the web app or directly on LinkedIn, Indeed, Glassdoor, or Handshake via the refactr Chrome extension.Read the full README ↗Tailor your resume to any job in seconds — from a web app, or straight off the job posting.
Upload a resume once. Tailor it against a job description or reformat it into a clean, ATS-friendly PDF — either from the web app or directly on LinkedIn, Indeed, Glassdoor, or Handshake via the refactr Chrome extension.
Live app: refactrapp.com
refactr is three coordinated pieces, deliberately kept loosely coupled:
| Piece | Stack | Role |
|---|---|---|
Web app (frontend/) | Next.js 16, React 19, TypeScript, Tailwind | Upload, tailor, reformat, dashboard — talks to Supabase directly |
Chrome extension (extension/) | Manifest V3, TypeScript, esbuild | Same tailor/reformat flow, triggered from job board pages |
Backend (backend/) | FastAPI, OpenAI, LaTeX | Stateless — parses, tailors, reformats, and renders PDFs. Nothing else. |
┌──────────────┐
│ Web app │──────┐
│ (Next.js) │ │
└──────────────┘ ▼
┌──────────────────┐
│ Supabase │ Auth · Postgres · private Storage
┌──────────────┐│ (RLS on auth.uid)│
│ Extension │──────┐
│ (Manifest V3) │ │
└───────┬──────┘ ▼
│ (auth/storage is 100% frontend-driven)
│ PDF + JD text only — no credentials, no user data
▼
┌──────────────┐
│ Backend │ Parse → Tailor / Reformat → Render PDF
│ (FastAPI) │ (OpenAI + LaTeX — fully stateless)
└──────────────┘
The backend never talks to Supabase and never sees a service-role key. Auth, persistence, and file storage all happen frontend-driven — the web app and the extension both talk to Supabase directly via supabase-js, protected by row-level security scoped to auth.uid(). This means the extension reuses the exact same auth/storage logic as the web app instead of duplicating it across two codebases, and it keeps the backend's blast radius small: a Supabase outage never takes down the core tailor/reformat pipeline.
The part that actually does the work is built as a small pipeline of specialized steps rather than one giant prompt:
Every stage is timed and surfaced via an X-Pipeline-Timings response header for observability.
brew install --cask mactex-no-guisudo apt-get install texlive-latex-base texlive-fonts-recommended texlive-latex-extracd backend
python -m venv venv
source venv/bin/activate # Windows: venv\Scripts\activate
pip install -r requirements.txt
Create backend/.env (see backend/.env.example):
OPENAI_API_KEY=your_api_key_here
# Optional — model tiering and retry behavior, see .env.example for defaults
# OPENAI_MODEL_FAST=gpt-4o-mini
# OPENAI_MODEL_GENERATE=gpt-4o-mini
# OPENAI_MAX_RETRIES=2
Install LaTeX (see LATEX_SETUP.md), then start the server:
uvicorn app:app --reload
Backend runs on http://localhost:8000 — API docs at http://localhost:8000/docs.
cd frontend
npm install
Create frontend/.env.local:
NEXT_PUBLIC_API_URL=http://localhost:8000
NEXT_PUBLIC_SUPABASE_URL=your_supabase_project_url
NEXT_PUBLIC_SUPABASE_ANON_KEY=your_supabase_anon_key
npm run dev
Frontend runs on http://localhost:3000.
cd extension
npm install
npm run build
Then in chrome://extensions: enable Developer Mode → Load unpacked → select extension/dist. By default the extension points at the deployed backend/web app (see extension/src/lib/config.ts); point it at localhost for local development.
| Endpoint | Purpose |
|---|---|
POST /api/tailor/pdf | Multipart {pdf, jd_text, output: json|pdf, resume_format: regular|technical} — tailor a resume against a job description |
POST /api/reformat/pdf | Multipart {pdf, resume_format} — reformat a resume with no content rewriting |
GET /api/templates/preview?format=regular|technical | Static example resume rendered through the real pipeline — no upload, no AI call |
GET /health | Health check |
Example:
curl -X POST "http://localhost:8000/api/tailor/pdf" \
-F "[email protected]" \
-F "jd_text=$(cat job_description.txt)" \
-F "output=json"
cd backend
python cli_demo.py
refactr/
├── backend/
│ ├── core/
│ │ ├── config.py # Settings (API key, model tiering, retries)
│ │ ├── exceptions.py # TailoringGenerationError
│ │ └── timing.py # Per-stage pipeline timing helper
│ ├── models/
│ │ ├── resume_models.py # Resume data models
│ │ └── job_models.py # Job description models
│ ├── routers/
│ │ ├── tailor_routes.py # POST /api/tailor/pdf
│ │ ├── reformat_routes.py # POST /api/reformat/pdf
│ │ └── template_preview_routes.py
│ ├── services/
│ │ ├── llm_client.py # OpenAI calls (structured outputs, async)
│ │ ├── job_parser.py # JD parsing + domain classification
│ │ ├── domain_prompts.py # Domain-specific tailoring guidance
│ │ ├── bullet_verifier.py # Truthfulness guardrail on tailored bullets
│ │ ├── pdf_resume_parser.py # Resume PDF → structured data
│ │ ├── pdf_writer.py # PDF generation (LaTeX)
│ │ ├── tailor_engine.py # Core tailoring orchestration
│ │ └── reformat_engine.py # Core reformatting orchestration
│ ├── templates/
│ │ └── resume_template.tex # LaTeX resume template
│ ├── app.py # FastAPI application
│ ├── requirements.txt
│ └── Dockerfile
├── frontend/
│ ├── app/
│ │ ├── (landing) page.tsx, login/, signup/, auth/
│ │ ├── dashboard/ # Current resume, history, stats
│ │ ├── resumes/ # Upload → template choice → save
│ │ ├── tailor/, results/ # Tailor flow + results view
│ │ ├── extension/connect/ # Session handoff to the Chrome extension
│ │ └── profile/
│ ├── components/, lib/, types/
│ └── package.json
├── extension/
│ ├── src/
│ │ ├── background.ts, content-script.ts, panel-app.ts
│ │ └── lib/ # Supabase client, API client, config
│ ├── manifest.json # Manifest V3, matches LinkedIn/Indeed/Glassdoor/Handshake
│ └── package.json
├── data/
│ └── sample_jd.txt
├── CLAUDE.md # Architecture reference
├── memory.md # Decision log — the "why" behind non-obvious choices
├── DEPLOYMENT.md # Production deployment guide
├── LATEX_SETUP.md # LaTeX installation guide
└── README.md
backend/Dockerfile and render.yaml)Full step-by-step instructions, environment variable reference, and troubleshooting are in DEPLOYMENT.md.
auth.uid(){user_id}/...Manas Ayyalaraju
Need help? API docs live at http://localhost:8000/docs once the backend is running.