| name | format-resume |
| description | Intelligently format CV/resume content using semantic understanding and visual verification |
Format Resume Skill
Purpose
Format CV/resume content with intelligent style application based on semantic context. Uses a clean template with 19 semantic styles and learns from your corrections over time.
Usage
Format new content:
Format this CV: [paste content]
Format from file:
Format my-cv-draft.txt as a resume
How It Works
Key Principle: Intelligence lives in the skill (Claude analyzes text). Python code is just helpers.
Semantic Analysis: I (Claude) analyze your raw text to understand what each element represents
- I don't use regex patterns - I understand semantic context
- "Anthony Byrnes" at top → CV Name
- "EDUCATION" in caps → Section Header
- "2023 - Present California State University" → Timeline Entry + Institution
- "Romeo & Juliet" in productions → Play Title (not Job Title, even though both are bold italic!)
Create JSON Structure: Convert raw text to structured format with style assignments
User Confirmation: Show you my analysis, get confirmation or corrections
Apply Learned Patterns: Python helpers apply previously learned preferences
Generate Document: Create formatted .docx using template with page headers
Visual Preview: Show PDF preview images for review
Learn from Corrections: If you correct a style choice, I save it to learned-preferences.yaml
The 19 Styles
Paragraph Styles:
- CV Name - Your name at top
- Contact Name - Bold, 10pt (cover letter header)
- Contact Info - Regular, 10pt (phone/email)
- Recipient Address - Regular, 11pt (organization address)
- RE Line - Bold, 13pt, ORANGE (position/subject line)
- Date Line - Right-aligned, 11pt (document date)
- Section Header - Bold, ORANGE (11pt for CV, 13pt for cover letter)
- Body Text - Standard paragraphs, 11pt
- Timeline Entry - Date + institution with hanging indent (CV only)
- Page Header - Bold, 10pt (page 2+ headers)
- Bullet Standard, Bullet Gray, Bullet Emphasis - List variations
Character Styles (inline):
- Play Title - Bold italic for productions (most common!)
- Institution - Bold for school/company names
- Job Title - Bold italic for positions
- Orange Emphasis - Highlight text
- Gray Text - Dates, secondary info
Note: Shares template with format-cover-letter skill (career-documents-template.docx)
Workflow
Step 1: You Provide Raw Text
User: "Format this CV: [pastes raw text]"
Step 2: I (Claude) Analyze and Create JSON
I analyze your content using semantic understanding (not regex):
I see:
- Name: "ANTHONY BYRNES" → CV Name style
- Contact: "T: 213.305.3132" → Contact Info style
- Section: "EDUCATION" → Section Header (orange, 11pt)
- Timeline: "2020-2024 California State University, Long Beach" → Timeline Entry
- inline: "California State University, Long Beach" → Institution (bold)
- Position: "Interim Associate Dean, College of the Arts" → Body Text
- inline: "Interim Associate Dean" → Job Title (bold italic)
- Bullet: "Led $29M budget..." → Bullet Standard
Here's my JSON interpretation:
{
"document_metadata": {
"type": "cv",
"author_name": "ANTHONY BYRNES",
"document_title": "Curriculum Vitae",
"page_header": {
"enabled": true,
"left": "ANTHONY BYRNES - Curriculum Vitae",
"right": "page"
}
},
"content": [
{"text": "ANTHONY BYRNES", "style": "CV Name"},
{"text": "T: 213.305.3132", "style": "Contact Info"},
...
]
}
Looks correct? (yes/show json/corrections)
Step 3: You Confirm or Correct
- Say "yes" → I proceed to formatting
- Say "Line 5 should be Gray Text" → I update JSON
- Say "show json" → I display full JSON for manual editing
Step 4: Apply Learned Patterns
Python helpers load learned-preferences.yaml and apply any previously learned style rules:
from cv_formatting.learning_system import LearningSystem
learning = LearningSystem()
content = learning.apply_learned_patterns(content)
This is simple pattern matching - the intelligence came from your previous corrections.
Step 5: Generate Document
I save the JSON and call Python helpers to create formatted .docx:
import json
import subprocess
from pathlib import Path
# Save JSON structure
mapping_file = "/tmp/cv_mapping.json"
with open(mapping_file, 'w') as f:
json.dump(content_mapping, f, indent=2)
# Format document (Python helper just applies styles from JSON)
result = subprocess.run([
"python3",
"format_cv.py",
mapping_file,
output_path,
"--document-type", "cv",
"--preview"
], capture_output=True, text=True, cwd=str(Path.home() / "PycharmProjects/career-lexicon-builder"))
Step 6: Visual Preview
I convert to PDF and show you page images.
You can request changes: "That committee role should be gray text"
Step 7: Learn (if corrections made)
If you make corrections, I save them to learned-preferences.yaml:
learning.learn_correction(
text="Graduate Studies Advisory Committee",
context="service section",
preferred_style="Gray Text"
)
Next time I analyze a CV, I'll automatically suggest Gray Text for committee roles.
Step 8: Finalize
Once you're happy with the preview, I save the final document (e.g., "anthony-byrnes-cv.docx").
LLM-Based Analysis vs. Regex Patterns
Why LLM analysis (me, Claude) is better:
- ✅ Understands semantic context (not just patterns)
- ✅ Handles variations naturally ("PhD" vs "Ph.D." vs "Doctor of Philosophy")
- ✅ Distinguishes context: "Dean" in experience → Job Title, "Dean" in service → Gray Text
- ✅ Can explain reasoning to you
- ✅ Learns from corrections through conversation
Python helpers only:
- Load defaults from YAML
- Apply previously learned patterns (simple matching)
- Find files, generate dates
- NO semantic analysis in Python code
Example: Bold Italic Context Discrimination
I distinguish based on semantic context, not just formatting:
- "Interim Associate Dean" after "2023 - Present CSULB" → Job Title (follows employer)
- "Romeo & Juliet" in productions list → Play Title (in artistic works context)
Traditional regex can't do this because both are bold italic. I understand the context.
Learning System
Three-layer learning stored in learned-preferences.yaml:
Layer 1: Style Corrections
style_rules:
- pattern: "committee"
context: "service section"
preferred_style: "Gray Text"
learned_date: "2025-11-11"
example: "Graduate Studies Advisory Committee"
Layer 2: Metadata Patterns
metadata_defaults:
document_title: "Curriculum Vitae" # not "Resume"
page_header_enabled: true
date_format: "MMMM YYYY"
Layer 3: Section Patterns
section_patterns:
EDUCATION:
order: ["Timeline Entry", "Body Text", "Bullet Standard"]
inline_institution: true
Corrections are automatically saved. No "save preferences" button needed.
You: "That should be gray text, it's a committee role"
Me: "✓ Updated formatting rules: committee roles → Gray Text"
Next CV: Automatically applies gray to committee roles without asking.
Error Handling
If template missing:
- "Template not found. Run generate_cv_template.py first"
If LibreOffice/Poppler unavailable:
- "PDF preview not available (LibreOffice not installed)"
- "Continuing with .docx only..."
If style mapping unclear:
- "I'm not sure if this is a Job Title or Play Title - can you clarify?"
Files
career-documents-template.docx- Shared template with 19 semantic stylesformat_cv.py- Main formatting scriptstyle-mappings.yaml- Base semantic inference ruleslearned-preferences.yaml- Your accumulated corrections
Page Headers for Multi-Page CVs
CVs spanning multiple pages automatically get professional headers on page 2+:
- Format: "ANTHONY BYRNES - Curriculum Vitae page 2"
- Style: Helvetica 10pt, bold, gray (RGB 128, 128, 128)
- Alignment: Left text aligns with body, right text at 6.5 inches
- Clean first page: No header on page 1
- Same implementation as cover letters (already working!)
Metadata Inference
Python helpers load from defaults.yaml and generate page header config:
from cv_formatting.metadata_inference import MetadataHelper
helper = MetadataHelper()
metadata = helper.infer_cv_metadata(content)
# Returns:
{
"type": "cv",
"author_name": "ANTHONY BYRNES",
"document_title": "Curriculum Vitae",
"last_updated": "November 2025",
"version": "Academic",
"page_header": {
"enabled": true,
"left": "ANTHONY BYRNES - Curriculum Vitae",
"right": "page"
}
}
Detects:
- Contact Information: From defaults.yaml
- Document Title: "Curriculum Vitae", "Resume", or "CV" (from defaults or learned)
- Version: Academic, Industry, Arts, or General (simple keyword detection)
- Page Header Config: Generated automatically from template
Configuration Files
defaults.yaml - Your contact info and preferences:
contact:
name: "ANTHONY BYRNES"
phone: "213.305.3132"
email: "anthonybyrnes@mac.com"
cv_defaults:
document_title: "Curriculum Vitae"
page_header:
enabled: true
format: "{name} - {title}"
preferences:
version: "Academic"
learned-preferences.yaml - Three-layer learning system:
style_rules: [] # Layer 1: Style corrections
metadata_defaults: {} # Layer 2: Metadata patterns
section_patterns: {} # Layer 3: Section structures
JSON Export for Wrapper Application
After successfully formatting the resume and creating the output files, export structured metadata.
Write to: resume-formatted-v1.json (increment version if exists)
Implementation:
- Check if
resume-formatted-v1.jsonalready exists in output directory - If exists, increment version number:
resume-formatted-v2.json,resume-formatted-v3.json, etc. - Extract formatting metadata from the JSON structure and output files
- Write JSON file with proper formatting (2-space indentation)
- Save to same directory as formatted resume
Structure:
{
"metadata": {
"created_at": "YYYY-MM-DDTHH:MM:SSZ",
"version": 1,
"skill": "format-resume",
"input_file": "resume-content.md",
"output_file": "resume-formatted.pdf"
},
"formatting_metadata": {
"template": "career-documents-template.docx",
"document_type": "cv",
"font": "Helvetica",
"font_size": 11,
"margins": {
"top": 0.5,
"bottom": 0.5,
"left": 0.5,
"right": 0.5
},
"line_spacing": 1.15,
"section_spacing": 0.15,
"page_header": {
"enabled": true,
"left": "ANTHONY BYRNES - Curriculum Vitae",
"right": "page"
}
},
"sections": [
{
"name": "Contact Information",
"content_preview": "ANTHONY BYRNES\nT: 213.305.3132\nE: anthonybyrnes@mac.com",
"styles_used": ["CV Name", "Contact Info"],
"validation": "passed",
"issues": []
},
{
"name": "Professional Experience",
"entries": 5,
"styles_used": ["Section Header", "Timeline Entry", "Body Text", "Bullet Standard"],
"validation": "passed",
"issues": []
},
{
"name": "Education",
"entries": 3,
"styles_used": ["Section Header", "Timeline Entry", "Body Text"],
"validation": "passed",
"issues": []
}
],
"validation_results": {
"total_checks": 15,
"passed": 14,
"failed": 0,
"warnings": 1,
"issues": [
{
"type": "warning",
"section": "Professional Summary",
"message": "Summary slightly long (95 words, recommend <90)",
"severity": "low"
}
]
},
"metrics": {
"page_count": 2,
"word_count": 542,
"section_count": 7,
"estimated_read_time_seconds": 130,
"ats_compatibility_score": 0.92,
"readability_score": 0.88,
"visual_appeal_score": 0.90
},
"style_analysis": {
"total_styles_used": 12,
"paragraph_styles": ["CV Name", "Contact Info", "Section Header", "Timeline Entry", "Body Text", "Bullet Standard", "Bullet Gray"],
"character_styles": ["Institution", "Job Title", "Play Title", "Gray Text"],
"learned_corrections_applied": 3,
"manual_overrides": 0
},
"output_files": [
{
"type": "pdf",
"path": "anthony-byrnes-cv.pdf",
"size_bytes": 245632,
"created_at": "YYYY-MM-DDTHH:MM:SSZ"
},
{
"type": "docx",
"path": "anthony-byrnes-cv.docx",
"size_bytes": 123456,
"created_at": "YYYY-MM-DDTHH:MM:SSZ"
}
]
}
Present to user:
Formatting complete! Saved to:
- anthony-byrnes-cv.docx (formatted document)
- anthony-byrnes-cv.pdf (preview)
- resume-formatted-v1.json (formatting metadata)
Formatting summary:
- Pages: 2
- Sections: 7
- Styles used: 12 (7 paragraph, 5 character)
- Validation: 14/15 checks passed (1 warning)
- ATS compatibility: 92%
Would you like to:
1. Review the PDF preview
2. Make style corrections
3. Export a different format
Related
- Design:
docs/plans/2025-11-09-cv-style-extraction-and-formatting-design.md - CV Enhancements:
docs/plans/2025-11-11-cv-formatting-enhancements-design.md - Template generation:
python generate_cv_template.py - Validation:
python validate_template.py