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 styles
-
format_cv.py
-
Main formatting script
-
style-mappings.yaml
-
Base semantic inference rules
-
learned-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.json already 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:
- Review the PDF preview
- Make style corrections
- 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