Use when the user provides a job posting URL or description and wants a tailored resume, asks to analyze job fit, says build/tailor resume or apply for a role, or wants to import an existing resume file into resume.md
Resources
10Install
npx skillscat add redbricksoftware/resume-builder Install via the SkillsCat registry.
Build Resume
Interactive workflow: analyze a job description against the user's base resume (resume.md), identify strongest matches, fill gaps through conversation, and generate an ATS-optimized 2-page Word document.
Prerequisites
resume.mdin working directory (base resume — additive, never remove content)generate_resume.py,import_resume.pyin working directorypython-docxinstalled (pip3 install python-docx)- For PDF import:
pdfplumberinstalled (pip3 install pdfplumber) - For Step 8 (Apply):
playwrightinstalled (pip3 install playwright),apply_to_role.pyin working directory, Google Chrome installed
Importing a Resume
If resume.md does not exist and the user provides a resume file (.docx, .pdf, .txt), run the import flow before the main workflow:
- Extract text from the file:
python3 import_resume.py <resume_file> - Parse the extracted text into structured sections: name, contact info, overview/summary, experience (title, company, location, dates, description, bullets), education, and skills.
- Write
resume.mdin this format:# Full Name phone | email | linkedin ## Overview Summary paragraph... ## Experience ### Job Title **Company | Location** *Dates* Role description... - Bullet 1 - Bullet 2 ## Education Degree — School ## Skills - Skill 1 - Skill 2 - Present
resume.mdto the user for review. Ask:- "Does this look complete? Anything missing or incorrect?"
- "Any achievements, metrics, or skills to add?"
- Apply corrections, then proceed with the main workflow.
Workflow
digraph {
rankdir=TB; node [shape=box];
fetch [label="1. Fetch & parse JD"];
analyze [label="2. Analyze resume vs JD"];
ask [label="3. Ask questions\n(1-2 rounds max)"];
update [label="4. Update resume.md"];
tailor [label="5. Tailor summary,\nbullets, & skills"];
review [label="6. Present selection\nsummary for approval"];
gen [label="7. Generate .docx"];
apply [label="8. Apply to role\n(optional)", style="dashed"];
fetch -> analyze -> ask -> update -> tailor -> review -> gen;
gen -> apply [style=dashed, label="if user\nwants to apply"];
ask -> ask [label="follow-up if needed"];
}Steps
1. Fetch Job Description
- Try
WebFetchon the URL first. - Fallback chain (many job boards block automated fetching):
WebFetchthe URL directly- If blocked/fails:
WebSearchfor the exact job title + company + "job description requirements" to extract JD details from search result snippets - If still insufficient: ask the user to paste the full JD text
- Extract: job title, company, location, hard requirements, preferred qualifications, responsibilities, keywords.
- Distinguish hard requirements from nice-to-haves.
2. Analyze Resume Match
Read resume.md. For each JD requirement, classify resume coverage:
| Category | Meaning |
|---|---|
| Covered | Strong bullet with quantified results directly maps to requirement |
| Partial | Related experience exists but weak fit or missing metrics |
| Gap | No relevant experience in resume.md |
Select top 3-5 strongest matches. Prioritize:
- Quantified achievements directly mapping to JD requirements
- Leadership/scope matching the role level
- Recent experience (last 10-15 years)
- Unique differentiators
3. Ask Questions (batch efficiently, 1-2 rounds max)
Present your analysis first, then ask ALL questions in one round, grouped:
Gaps — "The JD requires X. Do you have experience with this?"
- Only ask where the candidate might plausibly have experience
- Explain why it matters for the role
Clarifications — "Your bullet about X — should this rank higher for Y requirement?"
- Borderline items where ranking could go either way
Deepening — "For [bullet], can you share [specific metric/dollar amount/percentage]?"
- When a number would strengthen a selected or likely-selected bullet
Additional skills — "Do you have experience with [JD-mentioned tools/technologies/certs] not in your resume?"
- Cover tools, frameworks, certifications, domain expertise from JD
If the first round surfaces significant new info, do ONE follow-up. Never more than 2 rounds.
4. Update Base Resume
- Add new bullets to the appropriate role section in
resume.md - Add new skills to the Skills section
resume.mdis additive only — never remove existing content- These additions persist for all future resume builds
5. Tailor Content
Summary: Rewrite targeting THIS role. Mirror JD language. Hit top 3-4 keywords. 3-4 sentences max.
Bullet selection (within 10-15 year range):
- Current role: 4-6 bullets
- Previous 1-2 roles: 2-4 bullets each
- Older roles in range: 1-2 bullets or description only
- Beyond 15 years: title/company/dates under "Additional Experience"
Skills: Reorder with JD-matched skills first. Add user-confirmed skills. Remove irrelevant skills from tailored output only (keep in resume.md).
6. Present Selection Summary
Before generating, show:
- The 3-5 strongest bullets and which JD requirement each addresses
- Tailored summary text
- Ordered skills list
- Notable omissions and why they were cut
- Get user approval or adjustments
7. Generate Word Document
Primary method — if generate_resume.py exists:
python3 generate_resume.py /tmp/resume_input.json resume_[company]_[role].docx- Company and role: lowercase, hyphens for spaces
- Clean up
/tmp/resume_input.jsonafter
Fallback — if generate_resume.py is not found, generate directly using docx-js (preferred) or python-docx:
Using docx-js (npm install docx):
- Follow the docx SKILL.md conventions for creating new documents
- Use US Letter page size (12240 x 15840 DXA) with 0.5" margins for maximum content space
- Use Arial font throughout: name 18pt bold (color #2E75B6), section headers 14pt bold with bottom border, job titles 11pt bold, body 10pt
- Structure: Name (centered) > Contact (centered) > Professional Summary > Professional Experience > Education > Core Competencies
- Use
LevelFormat.BULLETfor bullet points (never unicode bullets) - Use
TabStopType.RIGHTwithTabStopPosition.MAXfor right-aligned dates on job title lines - Validate with
python scripts/office/validate.pyif available
Using python-docx (pip3 install python-docx):
- Create a clean, ATS-friendly single-column layout
- Use
Pt(10)body text,Pt(14)section headers,Pt(18)name - Set narrow margins:
Inches(0.5)all sides for 2-page fit - Add horizontal rules between sections using paragraph borders
8. Apply to Role (Optional)
After generating the resume, ask the user if they want to apply directly. If yes:
Setup (first time only):
pip3 install playwrightAutomation loop — screenshot-driven:
- Launch Chrome to the job URL:
python3 apply_to_role.py launch "<job_url>" - Read the screenshot (
/tmp/apply_screenshot.png) to understand the page state. - If login is required, tell the user: "Please log in to [site] in the Chrome window, then let me know when you're ready." After they confirm, take a new screenshot:
python3 apply_to_role.py screenshot - Click the apply button:
python3 apply_to_role.py click-apply - Read the screenshot to see the application form.
- Upload the resume:
python3 apply_to_role.py upload resume_[company]_[role].docx - Fill known fields from
resume.md(name, email, phone, LinkedIn):python3 apply_to_role.py fill "<selector>" "<value>" - For dropdowns:
python3 apply_to_role.py select "<selector>" "<option text>" - After each action, read the screenshot to verify and decide the next step.
- For fields you can't determine (salary expectations, custom questions, etc.), ask the user.
- If the page has a "Next" or multi-step flow, use
click "text=Next"and repeat. - STOP before clicking Submit — always ask the user to review and confirm.
- When done:
python3 apply_to_role.py close
Other useful commands:
text— extract page text (faster than screenshot for reading form labels)scroll down/scroll up— see more of the pagepages/switch <index>— manage tabs if the site opens new onesurl— check current page URL
Key rules:
- Always read the screenshot after every action — this is your feedback loop
- Never click Submit/Confirm without explicit user approval
- If automation fails for any action, tell the user to do it manually in the Chrome window, then screenshot to continue
- Chrome stays open between commands — the user can interact directly at any time
Job Tracker Integration (Optional)
When running repeated resume builds (especially via scheduled tasks), maintain a job application tracker spreadsheet (job_application_tracker.xlsx) as the single source of truth.
Tracker Schema
| Column | Description |
|---|---|
| Date Found | Date the role was surfaced |
| Company | Company name |
| Job Title | Full job title |
| Location | City, State or Remote |
| Salary (if listed) | Salary range or blank |
| Job Posting URL | Must be a clickable hyperlink (see below) |
| Status | New, In Progress, Applied, Didn't Apply, Rejected, Interviewing, Offer |
| Reason (if Didn't Apply) | Why the user skipped this role |
| Resume File | Filename of the generated .docx |
| Date Applied | User fills this in |
| Last Contacted | Date of last interaction |
| Notes | Brief match summary |
Writing Clickable URLs
When writing URLs to the tracker with openpyxl, always set both the value and the hyperlink:
cell = ws.cell(row=row, column=6, value=url)
cell.hyperlink = url
cell.font = Font(name="Arial", size=10, color="0563C1", underline="single")Deduplication Rules
- Never suggest the same job posting URL twice (exact match against tracker)
- Never suggest a company that appeared in the tracker within the last 30 days
- If a company appears but it's been >30 days, a new role at that company is OK
Batch Search Mode (Scheduled/Multi-Role)
An alternate entry point for automated or scheduled runs that searches for multiple roles and lets the user pick which ones to build resumes for.
Workflow
- Load tracker — read the job tracker spreadsheet to check for duplicates
- Search — use
WebSearchacross multiple job titles, locations, and boards - Filter — enforce posting age (e.g., last 10 days), salary floor (e.g., $300K+), and deduplication against the tracker
- Present — show the top N roles to the user with title, company, location, salary, and a 1-3 sentence summary of the role AND why it matches their background. Let user multi-select.
- Log all — add every surfaced role to the tracker (selected = "New", skipped = "Didn't Apply")
- Build — for each selected role, run the full Steps 1-7 workflow above (including Q&A — never skip it)
- Update tracker — fill in the Resume File column and update status for completed builds
Search Strategy
- Search job boards: LinkedIn, Indeed, Greenhouse, Lever, Glassdoor, company career pages
- Prioritize roles posted within the last 48 hours
- Focus on roles matching the user's strongest differentiators (check
resume.mdfor themes) - Exclude roles clearly outside the user's domain unless the user has indicated interest
Scheduling
This mode can be configured as a scheduled task (e.g., 3x daily) using the schedule skill. The scheduled task prompt should include all search criteria, filtering rules, file paths, and the full build-resume workflow instructions so it runs autonomously.
ATS Content Rules
- Mirror exact JD phrases — if JD says "cross-functional collaboration," use that, not "working across teams"
- Include acronym + spelled-out — "Artificial Intelligence (AI)"
- Front-load keywords — most important keyword in first few words of each bullet
- Quantify everything — "$X revenue", "Y% growth", "Z team members"
- Use standard section names — Professional Summary, Professional Experience, Education, Core Competencies
Common Mistakes
| Mistake | Fix |
|---|---|
| Picking impressive bullets over relevant ones | Score against JD requirements, not general impressiveness |
| Too many Q&A rounds | Batch all questions, max 2 rounds |
| Generic summary | Rewrite per role with JD keywords |
| Forgetting to update resume.md | Always persist new info before generating |
| Ignoring preferred qualifications | Still critical for ATS keyword matching |
| Assuming WebFetch will work on job boards | Most job sites block it — use the fallback chain |
| Writing plain-text URLs in the tracker | Always set cell.hyperlink for clickable links |
| Skipping Q&A in batch/scheduled mode | ALWAYS ask the user enhancement questions, even in batch mode |