AI-powered CV optimization using CrewAI Flow. This application uses AI agents to iteratively improve your CV to match specific job descriptions.
- Iterative Optimization: AI reviewer and writer agents work together to improve your CV
- Multiple Input Formats: Support for text, markdown, and PDF files
- Web Scraping: Extract job descriptions directly from URLs
- Multi-LLM Support: Works with OpenAI, Anthropic, and Ollama (local models)
- Multi-Language Translation: Translate your optimized CV to any language (German, French, Spanish, etc.)
- Flexible Configuration: Configure via files, environment variables, or CLI arguments
- Detailed Feedback: Get comprehensive feedback history for all iterations
- Production Ready: Clean, professional markdown output
- Python 3.10 or higher (< 3.14)
- pip or uv package manager
# Using pip
pip install -e .
# Or using uv (recommended)
uv pip install -e .Create a .env file in the project root:
# For OpenAI (default)
OPENAI_API_KEY=your_openai_api_key_here
# For Anthropic
ANTHROPIC_API_KEY=your_anthropic_api_key_here
# For Ollama (optional, defaults to localhost)
OLLAMA_BASE_URL=http://localhost:11434Basic usage:
cv-optimizer --job-description job.txt --cv my_cv.mdWith additional options:
cv-optimizer \
--job-description https://example.com/job-posting \
--cv my_cv.pdf \
--additional-docs portfolio.pdf \
--additional-docs certifications.md \
--llm-provider openai \
--max-iterations 5 \
--output-dir ./results--job-description,-j: Job description source (file path or URL)--cv,-c: Path to your CV file
--additional-docs,-a: Additional supporting documents (can be used multiple times)--llm-provider,-p: LLM provider (openai, anthropic, ollama)--llm-model,-m: Specific model name--max-iterations,-i: Maximum number of iterations (default: 3)--config: Path to custom config file--output-dir,-o: Output directory for results--translate-to,-t: Target language code for translation (e.g., 'de', 'fr', 'es')--translation-llm-provider: LLM provider for translation (if different from main)--translation-llm-model: LLM model for translation (if different from main)
- Text:
.txt - Markdown:
.md,.markdown - PDF:
.pdf
- Local files (text, markdown, PDF)
- URLs (web scraping)
Configuration follows a hierarchy (lowest to highest precedence):
- Default values
- Config file (
src/cv_writer/config/cv_optimizer.yaml) - Environment variables
- CLI arguments
Create a custom config file:
llm:
provider: openai
model: gpt-4o
temperature: 0.7
optimizer:
max_iterations: 3
save_intermediate_versions: false
output:
directory: ./output
cv_filename_pattern: "cv_optimized_{timestamp}.md"
feedback_filename_pattern: "cv_review_history_{timestamp}.md"
translation:
enabled: false
target_language: null
llm_provider: null # Uses main LLM if not specified
llm_model: null # Uses main LLM if not specifiedUse it:
cv-optimizer --config my_config.yaml --job-description job.txt --cv cv.mdOverride configuration with environment variables:
export LLM_PROVIDER=anthropic
export LLM_MODEL=claude-sonnet-4-5
export MAX_ITERATIONS=5
export OUTPUT_DIRECTORY=./my_output
cv-optimizer --job-description job.txt --cv cv.md# Enable translation with environment variables
export TRANSLATE_TO=de
export TRANSLATION_LLM_PROVIDER=ollama
export TRANSLATION_LLM_MODEL=llama3.1
cv-optimizer --job-description job.txt --cv cv.md-
Initialization
- Parse job description and CV
- Load supporting documents
- Initialize LLM and configuration
-
Review Phase
- Reviewer agent analyzes CV against job requirements
- Provides detailed, actionable feedback
- Makes APPROVE or REVISE decision
-
Routing Decision
- If APPROVED: Save outputs and complete
- If REVISE and iterations < max: Continue to writing
- If max iterations reached: Save current version
-
Writing Phase
- Writer agent creates improved CV version
- Addresses all reviewer feedback
- Incorporates information from supporting documents
- Returns to review phase
-
Output Generation
- Save final optimized CV (clean markdown)
- Save feedback history with all iterations
- Experienced HR professional persona
- Critically assesses CV alignment with job requirements
- Provides structured, actionable feedback
- Makes binary APPROVE/REVISE decisions
- Professional CV writer persona
- Creates compelling career narratives
- Follows reviewer feedback meticulously
- Optimizes for ATS and human readers
- Professional translator specializing in career documents
- Translates CVs while preserving formatting and impact
- Adapts terminology for target language markets
- Maintains exact markdown structure
The application generates the following files:
-
Optimized CV (
cv_optimized_[timestamp].md)- Clean markdown format
- No explanations or metadata
- Production-ready document
-
Translated CV (
[basename]_[language].md) - Optional- Appears only when
--translate-tois specified - Uses the same basename as English version with language code appended
- Language code suffix (e.g.,
cv_optimized_20251113_123456_de.md) - Preserves exact formatting of original
- Appears only when
-
Feedback History (
cv_review_history_[timestamp].md)- Chronological feedback from all iterations
- Reviewer decisions and comments
- Improvement suggestions
- Timestamps for each iteration
export OPENAI_API_KEY=your_key_here
cv-optimizer \
--job-description job_posting.txt \
--cv my_cv.mdexport ANTHROPIC_API_KEY=your_key_here
cv-optimizer \
--job-description https://example.com/job \
--cv cv.pdf \
--additional-docs portfolio.md \
--additional-docs certifications.pdf \
--llm-provider anthropic \
--max-iterations 5# Start Ollama server first
# ollama serve
cv-optimizer \
--job-description job.txt \
--cv cv.md \
--llm-provider ollama \
--llm-model llama3.1 \
--max-iterations 3export OPENAI_API_KEY=your_key_here
cv-optimizer \
--job-description job.txt \
--cv cv.md \
--translate-to de# Use Claude for translation while using GPT-4o for optimization
cv-optimizer \
--job-description job.txt \
--cv cv.md \
--llm-provider openai \
--translate-to de \
--translation-llm-provider anthropic \
--translation-llm-model claude-sonnet-4-5
# Use local Ollama model for translation to save costs
cv-optimizer \
--job-description job.txt \
--cv cv.md \
--translate-to fr \
--translation-llm-provider ollama \
--translation-llm-model llama3.1cv-optimizer \
--config my_config.yaml \
--job-description job.md \
--cv cv.md \
--output-dir ./custom_output \
--max-iterations 4cv_writer/
├── src/cv_writer/
│ ├── __init__.py
│ ├── main.py # CLI entry point
│ ├── config/
│ │ ├── config_loader.py # Configuration management
│ │ └── cv_optimizer.yaml # Default config
│ ├── crews/
│ │ ├── reviewer_crew/ # Reviewer agent & tasks
│ │ ├── translator_crew/ # Translator agent & tasks
│ │ └── writer_crew/ # Writer agent & tasks
│ ├── flows/
│ │ └── cv_optimization_flow.py # Main optimization flow
│ ├── models/
│ │ └── state_models.py # Pydantic state models
│ ├── tools/
│ │ ├── document_parser.py # Document processing
│ │ ├── pdf_reader.py # PDF extraction
│ │ └── web_scraper.py # Web scraping
│ └── utils/
│ ├── file_handler.py # File I/O operations
│ └── llm_factory.py # LLM instantiation
├── tests/ # Unit tests
├── pyproject.toml # Project dependencies
└── README.md # This file
# Install test dependencies
pip install pytest pytest-mock
# Run tests
pytest tests/
# Run with coverage
pytest --cov=cv_writer tests/Generate a flow diagram:
python -m cv_writer.main plot- Provider:
openai - Default Model:
gpt-4o - Environment Variable:
OPENAI_API_KEY - Other Models:
gpt-5.1,gpt-5,gpt-4,gpt-3.5-turbo, etc.
- Provider:
anthropic - Default Model:
claude-sonnet-4-5 - Environment Variable:
ANTHROPIC_API_KEY - Other Models:
claude-3-5-sonnet-20241022,claude-3-opus-20240229, etc.
- Provider:
ollama - Default Model:
llama3.1 - Environment Variable:
OLLAMA_BASE_URL(optional) - Other Models:
llama2,mistral,codellama, etc. - Note: Requires Ollama server running locally
- max_iterations: Number of review-revise cycles (default: 3)
- temperature: LLM creativity (0.0-1.0, default: 0.7)
- output_directory: Where to save results (default: ./output)
- Ensure you've created a
.envfile with your API key - Or export the variable:
export OPENAI_API_KEY=your_key
- Ensure pypdf is installed:
pip install pypdf - Some PDFs may have image-based text (not supported)
- Try converting to text or markdown first
- Check your internet connection
- Some websites block scraping
- Try saving the job description to a file instead
- Increase iterations:
--max-iterations 5 - Review feedback history to understand issues
- Consider manually incorporating feedback
- Web-based user interface
- Multiple output formats (DOCX)
- Cover letter generation
- A/B testing of CV versions
- Industry-specific templates
- Integration with job boards
- Batch translation to multiple languages simultaneously
This project is licensed under the MIT License - see the LICENSE file for details.
Contributions are welcome! Please ensure:
- Code follows existing style
- Tests are included
- Documentation is updated
- Type hints are used
For issues, questions, or contributions:
- Check existing documentation
- Review troubleshooting section
- Open an issue with detailed information
Built with:
- CrewAI - Multi-agent framework
- LangChain - LLM integrations
- Click - CLI framework
- Pydantic - Data validation
Version: 0.2.0
Status: Production Ready
Python: 3.10-3.13