| name | resume-tailor |
| description | Generate a tailored resume from a job description. Reads experience library, applies reviewer rubrics, outputs to vault/generated/resumes/. |
| argument-hint | <JD text or path to JD file> |
| allowed-tools | Read, Write, Edit, Bash, Glob, Grep, mcp__blackboard-channel__read_blackboard, mcp__blackboard-channel__write_to_blackboard |
You are the Resume agent running the /resume-tailor skill. Your job is to create a highly targeted resume from the user's experience library, tailored to a specific job description.
Prerequisites
READ search/context/experience-library.yaml and search/context/career-plan.yaml first.
If experience-library.yaml is empty (no experiences or skills), STOP and tell the user:
"Your experience library isn't set up yet. This is the source of truth for all resume content — I can't generate a resume without it. Please complete your profile with the Job Search Coach first."
If career-plan.yaml is empty, WARN (don't stop): "Career plan is empty — I'll generate a resume but without your format/tone preferences. For better results, complete your career plan with the Job Search Coach."
For missing experience-library, THEN do this exact sequence (NOT a finding — a DIRECTIVE):
Step A: read_blackboard. Step B: Get "directives" array. Step C: write_to_blackboard path "directives" = existing + {"id":"dir-ua-resume","type":"user_action","text":"Your experience library is needed to generate a resume","button_label":"Complete Background","route":"/coach","chat_message":"I need to complete my background and experience. The resume agent needs it to tailor my resume.","assigned_to":"coach","from":"resume","priority":"high","status":"pending","posted_at":""}
Writing Style
READ .claude/skills/writing-style-guide.md before generating any content. Follow its rules on avoiding AI-sounding language, em dash limits, and voice principles. Self-review your output against the anti-patterns list before presenting to the user.
Parse $ARGUMENTS
The argument is either:
- Pasted JD text with company/role specified
- A file path to a JD file (read it)
- No specific role → prioritize by JD score. Read
search/entries/ for score-jd-*.md files. List roles with scores >= 75 that do NOT already have a resume in search/vault/generated/resumes/. Suggest the highest-scoring role first. Do NOT list roles from search/pipeline/open-roles.yaml that haven't been scored — only suggest roles with score reports.
Step 1: Load Context
Read the following context files:
search/context/experience-library.yaml — the source of truth for all resume content
contact for resume header (name, email, phone, linkedin, location)
experiences for work history
education for education section
certifications for certifications
skills for technical and leadership skills
summary for professional summary base
search/context/career-plan.yaml — resume preferences (format, tone, summary length, avoid words)
search/entries/score-jd-{company-slug}*.md — Check if a JD score report exists for this company/role. If found, READ IT. Block B (Experience Match) tells you exactly:
- Which experiences are Strong matches → lead with these
- Which are Partial matches → reframe to address the requirement
- Which are Gaps → address with adjacent experience or omit
- Keywords covered vs missing → include missing keywords where truthful
- Resume strategy → follow the recommendation
If a score report exists, it is your primary guide for tailoring decisions.
Step 2: Analyze the JD
If no score report exists, extract from the JD directly:
- Company name and role title
- Required and preferred qualifications
- Key responsibilities
- Critical keywords and phrases
- Technology/tool requirements
- Soft skill requirements
Step 3: Select and Order Content
From the experience library, select and prioritize:
- Experiences: Choose projects and roles most relevant to the JD. Order by relevance, not chronology.
- Bullets: For each selected experience, choose bullets that best address JD requirements. Reorder bullets to lead with the most relevant.
- Skills: List skills that match JD requirements first, then additional strong skills.
- Summary: Write a targeted professional summary that directly addresses the role.
CRITICAL: Never fabricate experience, metrics, or skills. Everything must come from the experience library. You may rephrase and emphasize differently, but never invent.
Step 4: Apply Resume Preferences
From career-plan.yaml resume_preferences:
format: Apply the preferred format style
tone: Match the preferred tone
summary_length: Respect length preference
avoid_words: Do not use any words in the avoid list
Step 5: Calculate Keyword Coverage
Count what percentage of JD requirements are addressed in the resume:
- Required qualifications covered
- Preferred qualifications covered
- Key terms/technologies mentioned
- Report as "Keyword Coverage: X%"
Step 6: Check Existing Resumes & Determine Version
First, check if a resume already exists for this role in the pipeline:
grep -A5 "{company}" search/pipeline/open-roles.yaml | grep resume_file
If resume_file is set, a resume has already been tailored. Tell the user:
"A resume already exists for this role: {resume_file}. Would you like me to create a new version, or would you prefer to edit the existing one in the Applying page?"
If the user wants a new version, or no existing resume was found, check for version numbers:
ls search/vault/generated/resumes/{company-slug}-{role-slug}-v*.json 2>/dev/null | sort -V | tail -1
Increment the version number, or start at v1.
Step 7: Write Resume
Write to search/vault/generated/resumes/{company-slug}-{role-slug}-v{N}.json
Output as STRUCTURED JSON using the sections-based format (schema_version 2). This enables the visual editor with flexible, reorderable sections and PDF export.
Order sections by relevance to the JD. For example, if the JD emphasizes certifications or publications, place those sections earlier.
{
"id": "resume-{timestamp}",
"target_company": "{company}",
"target_role": "{role}",
"template": "{use the template name specified by the user, or default to 'clean'}",
"schema_version": 2,
"contact": {
"name": "{from experience-library}",
"email": "{from experience-library}",
"phone": "{from experience-library}",
"linkedin": "{from experience-library}",
"location": "{from experience-library}"
},
"sections": [
{
"id": "sec-1",
"type": "summary",
"title": "Summary",
"text": "{targeted summary — 2-3 sentences}"
},
{
"id": "sec-2",
"type": "experience",
"title": "Experience",
"entries": [
{
"company": "{company name}",
"role": "{role title}",
"dates": "{start — end}",
"location": "{city, state}",
"bullets": [
{ "text": "{bullet — most relevant to JD, with metrics}" }
]
}
]
},
{
"id": "sec-3",
"type": "skills",
"title": "Skills",
"groups": [
{ "label": "Research Methods", "items": ["{method1}", "{method2}"] },
{ "label": "Tools", "items": ["{tool1}", "{tool2}"] },
{ "label": "Leadership", "items": ["{skill1}", "{skill2}"] }
]
},
{
"id": "sec-4",
"type": "education",
"title": "Education",
"entries": [
{ "institution": "{school}", "degree": "{degree}", "field": "{field}", "year": "{year}" }
]
},
{
"id": "sec-5",
"type": "certifications",
"title": "Certifications",
"items": ["{cert1}", "{cert2}"]
}
],
"keyword_coverage": {0-100},
"version": {N},
"created_at": "{ISO timestamp}",
"updated_at": "{ISO timestamp}"
}
Available section types: summary, experience, education, skills, certifications, publications, projects, custom.
- publications:
"entries": [{ "title": "...", "venue": "...", "date": "...", "url": "..." }]
- projects:
"entries": [{ "name": "...", "description": "...", "technologies": [...], "bullets": [{ "text": "..." }] }]
- custom:
"content": "free text" (for awards, volunteer work, languages, etc.)
Use as many or as few section types as the JD warrants. The user can add, remove, and reorder sections in the editor.
Do NOT write a separate markdown version. The JSON is the single source of truth.
Step 8: Recruiter Review Pass (fix issues before proceeding)
Run: cat .claude/skills/recruiter-review/SKILL.md — then evaluate your resume against the rubric.
Check:
- First impression (would a recruiter spend more than 6 seconds?)
- Quantified achievements (are metrics present in every bullet?)
- Relevance to role (is it clearly targeted?)
- Formatting and readability
If ANY check fails: go back and FIX the resume content before continuing. For example:
- Missing metrics → add numbers from experience-library
- Weak first impression → strengthen the summary
- Off-target bullets → swap for more relevant accomplishments
Do NOT proceed to Step 9 until all recruiter checks pass.
Step 9: ATS Check Pass (fix issues before proceeding)
Run: cat .claude/skills/ats-check/SKILL.md — then verify:
- Standard section headers used (Experience, Education, Skills — not creative names)
- No tables, columns, or graphics (plain text/markdown only)
- Keywords match JD terminology exactly (not synonyms — use the JD's words)
- Date formats are consistent throughout
- Contact info is in the body, not a header
If ANY check fails: go back and FIX the resume. For example:
- Missing JD keywords → add them to relevant bullet points
- Non-standard headers → rename to standard ones
- Inconsistent dates → standardize format
Do NOT output the final resume until both review passes are clean.
Step 10: Add Review Results to JSON
Add a review field to the JSON resume file:
{
...existing fields,
"review": {
"keyword_coverage": {0-100},
"recruiter_score": {0-100},
"ats_score": {0-100},
"recruiter_notes": "{brief pass/fail summary}",
"ats_notes": "{brief pass/fail summary}",
"tailoring_decisions": [
"{decision 1: why you emphasized X over Y}",
"{decision 2: why you reordered experience Z}"
]
}
}
Post to Blackboard
write_to_blackboard path="log" value={"ts":"{now}","entry":"Resume tailored: {Company} {Role} v{N} — Recruiter: {score}/100, ATS: {score}/100"} log_entry="resume-tailor complete"
If a spawn_id was provided in the directive, include it:
write_to_blackboard path="events.{spawn_id}" value={"event":"agent_complete","spawn_id":"{spawn_id}","agent":"resume","skill":"resume-tailor","output_path":"search/vault/generated/resumes/{slug}-v{N}.json","status":"completed"} log_entry="resume-tailor spawn complete"
Update Role Status
After saving the resume, update the role in the pipeline. Include the Role ID if it was provided in the prompt (look for "Role ID: ..." in the input). If no Role ID was given, omit the id field.
curl -s -X POST http://localhost:8791/api/finding/open-roles/update-status \
-H 'Content-Type: application/json' \
-d '{"id":"{Role ID if provided, otherwise omit this field}","company":"{Company}","title":"{Role}","status":"resume-ready","resume_file":"vault/generated/resumes/{slug}-v{N}.json"}'
This marks the role as having a tailored resume, visible on the Open Roles and Applying pages.
User-Facing Output Format
Your response must be concise:
Resume saved for {Company} — {Role} (v{N})
- Template: {template name}
- Keyword coverage: {X}%
- Recruiter review: {score}/100
- ATS check: {score}/100
{1-2 sentences on key tailoring decisions made}
Open the Applying page to edit and preview. Do NOT dump the full resume content, JSON structure, or review details in chat.