jd_optimization
Optimize and enhance AI-generated job descriptions for SEO, readability, and conversion
Install
mkdir -p .claude/skills/jd-optimization && curl -L -o skill.zip "https://agentskills.codes/api/skills/download/13790" && unzip -o skill.zip -d .claude/skills/jd-optimization && rm skill.zipInstalls to .claude/skills/jd-optimization
Activation
This is the description your AI agent reads to decide when to run this skill — the better it matches your request, the more reliably it fires.
Optimize and enhance AI-generated job descriptions for SEO, readability, and conversionAbout this skill
Job Description Optimization Skill
Purpose
This skill helps you optimize AI-generated job descriptions (JDs) for the AARLP platform. It ensures JDs are SEO-optimized, ATS-friendly, and conversion-focused while maintaining the platform's AI-generated quality standards.
When to Use
- After AI generates a new JD
- When a recruiter requests JD improvements
- Before posting jobs to external boards (Indeed, LinkedIn)
- When optimizing for specific industries or roles
Optimization Checklist
1. SEO Optimization
- Include primary keyword in title (role + location)
- Use semantic keywords naturally throughout
- Add location information (city, state, remote options)
- Include salary range if available (increases visibility by 30%)
- Use structured data markup for Google for Jobs
Keywords to Include:
- Job title variations
- Required technologies/tools
- Industry-specific terms
- Location-based keywords
- Remote/hybrid keywords
2. ATS Compliance
- Avoid tables, images, or complex formatting
- Use standard section headers (Responsibilities, Qualifications, Benefits)
- Include exact skill matches from industry standards
- Use common job title formats
- Avoid abbreviations without full terms first
3. Structure & Readability
Standard JD Structure:
1. Hook (1-2 sentences) - Company mission/value prop
2. Role Overview (2-3 sentences) - What they'll do
3. Responsibilities (5-7 bullet points)
4. Qualifications
- Required (3-5 must-haves)
- Preferred (2-4 nice-to-haves)
5. Benefits & Perks (4-6 compelling points)
6. About Company (2-3 sentences)
7. CTA (Apply now with clear next steps)
4. Conversion Optimization
- Start with a compelling hook (not just "We are hiring...")
- Highlight unique selling points (culture, growth, impact)
- Use inclusive language (avoid gendered terms, "rock star", "ninja")
- Include remote/flexible work options prominently
- Add salary transparency (increases applications by 30%)
- Clear call-to-action with application timeline
5. Industry-Specific Enhancements
Tech Roles
- Include tech stack with versions
- Mention engineering practices (CI/CD, code review, testing)
- Highlight learning budget, conference attendance
- Specify remote work policy clearly
Non-Tech Roles
- Focus on impact and growth opportunities
- Include team structure and reporting lines
- Mention training and development programs
- Highlight company culture and values
Implementation in AARLP
Using the API
# Regenerate JD with specific feedback
POST /jobs/{job_id}/regenerate-jd
{
"feedback": "Add more emphasis on remote work options and salary range. Include specific technologies like FastAPI, LangGraph, Pinecone."
}
Manual Editing
# Update specific JD sections
PUT /jobs/{job_id}/jd
{
"title": "Senior Backend Engineer - FastAPI & AI (Remote)",
"responsibilities": [...],
"benefits": [
"Competitive salary: $120k-$160k",
"100% remote work - US timezone",
...
]
}
Validation Steps
-
Run SEO Analysis
- Check keyword density (1-2% for primary keyword)
- Verify meta description length (150-160 chars)
- Ensure title is under 60 characters
-
Readability Check
- Flesch Reading Ease: 60-70 (8th-9th grade level)
- Sentence length: 15-20 words average
- Paragraph length: 2-4 sentences max
-
Bias Detection
- Run through gender decoder tools
- Avoid age-related terms ("digital native", "recent grad")
- Use neutral pronouns or "you/your"
Common Issues & Fixes
| Issue | Fix |
|---|---|
| Too generic | Add company-specific details, tech stack, projects |
| Too formal | Use conversational tone, "you'll" instead of "candidate will" |
| Unclear expectations | Quantify responsibilities ("manage 3-5 direct reports") |
| Missing benefits | Add at least 4 compelling benefits |
| Poor mobile formatting | Break long paragraphs, use bullet points |
AARLP Integration: Workflow & Code Paths
How JD Optimization Fits in the LangGraph Workflow
# app/workflow/nodes.py - generate_jd_node
async def generate_jd_node(state: GraphState) -> GraphState:
"""
Node that generates JD and automatically applies optimization rules.
"""
from app.ai.jd_generator import generate_job_description
from app.jobs.schemas import JobInput
# Extract job input from state
job_input = JobInput(**state.jd.input_data)
# Generate initial JD
generated_jd = await generate_job_description(job_input)
# OPTIMIZATION CHECKPOINT: Apply SEO and ATS rules
optimized_jd = apply_optimization_rules(generated_jd, job_input)
return state.model_copy(
update={
"jd": state.jd.model_copy(
update={
"content": optimized_jd.description,
"title": optimized_jd.job_title,
"status": Status.COMPLETED
}
)
}
)
Feedback Formats That Work with AARLP's AI
The regenerate_job_description() function in app/ai/jd_generator.py expects specific feedback patterns:
✅ Effective Feedback Examples:
# 1. Specific additions
feedback = """
Add emphasis on remote work flexibility and include salary range $120k-$160k.
Mention that we use FastAPI, LangGraph, and Pinecone in the tech stack.
"""
# 2. Tone adjustments
feedback = """
Make the tone more conversational and less corporate.
Replace 'candidate will be responsible for' with 'you'll get to work on'.
"""
# 3. SEO-focused
feedback = """
Include keywords: 'AI engineer', 'machine learning', 'python developer'.
Add location 'San Francisco Bay Area' for better local search visibility.
"""
# 4. Structural changes
feedback = """
Move benefits section before requirements.
Add a 'What You'll Build' section highlighting real projects.
Break requirements into 'Must Have' and 'Nice to Have' subsections.
"""
❌ Ineffective Feedback (Too Vague):
# Won't produce good results
feedback = "Make it better"
feedback = "Sounds too boring"
feedback = "Add more details"
API Integration Points
# 1. Regenerate with optimization feedback (POST /jobs/{id}/regenerate-jd)
async def regenerate_with_seo_focus(job_id: str, auth_headers: dict):
"""
Trigger regeneration with SEO optimization focus.
This updates the workflow state and resumes from checkpoint.
"""
response = await fetch(
f"http://localhost:8000/jobs/{job_id}/regenerate-jd",
method="POST",
headers=auth_headers,
json={
"feedback": """
Optimize for Google for Jobs:
- Add explicit salary range in title
- Include 'Remote' or location in title
- Use job title keywords that match common searches
- Add structured benefits section
"""
}
)
# This triggers the workflow to:
# 1. Load checkpoint from wait_jd_approval state
# 2. Call generate_jd_node with feedback
# 3. Return to wait_jd_approval for re-review
return response.json()
# 2. Manual edit (PUT /jobs/{id}/jd)
async def manual_optimization_edit(job_id: str, auth_headers: dict):
"""
Directly update JD fields without AI regeneration.
Use when recruiter knows exact changes needed.
"""
response = await fetch(
f"http://localhost:8000/jobs/{job_id}/jd",
method="PUT",
headers=auth_headers,
json={
"summary": "Join our mission to revolutionize recruitment...",
"requirements": [
"5+ years Python development (FastAPI, Django, or Flask)",
"Experience with AI/ML frameworks (LangChain, OpenAI SDK)",
"PostgreSQL and vector databases (Pinecone preferred)"
],
"salary_range": "$120,000 - $160,000 + equity"
}
)
# This updates the DB directly, bypassing workflow
# No state change, JD remains in wait_jd_approval
return response.json()
# 3. Check if optimization is needed (GET /jobs/{id}/jd)
async def analyze_jd_quality(job_id: str, auth_headers: dict):
"""
Fetch JD and run optimization checks programmatically.
"""
response = await fetch(
f"http://localhost:8000/jobs/{job_id}/jd",
headers=auth_headers
)
jd = response.json()
# Run checks
issues = []
if not jd.get("salary_range") or jd["salary_range"] == "Competitive":
issues.append("Missing explicit salary range (reduces visibility by 30%)")
if len(jd.get("description", "")) < 200:
issues.append("Description too short for SEO (minimum 200 chars)")
if "remote" not in jd.get("title", "").lower() and "location" not in jd.get("title", "").lower():
issues.append("Title missing location/remote keyword")
return {
"needs_optimization": len(issues) > 0,
"issues": issues,
"suggestion": "Run regenerate with: " + "; ".join(f"Fix: {i}" for i in issues)
}
Workflow State Transitions
graph TB
A[create_job API] --> B[generate_jd_node]
B --> C[wait_jd_approval]
C --> D{Recruiter Action}
D -->|regenerate-jd API| E[generate_jd_node with feedback]
D -->|PUT /jd API| C
D -->|approve-jd API| F[post_job_node]
E --> C
style E fill:#f9f,stroke:#333
style C fill:#bbf,stroke:#333
Key Points:
regenerate-jdtriggers a full workflow state update and resumes graph executionPUT /jdis a direct DB update without workflow interaction- Use regenerate for AI-driven changes, PUT for manual tweaks
Optimization Rules Engine (Code Reference)
# Add to app/ai/jd_generator.py or create app/ai/jd_optimizer.py
from app.jobs.schemas import GeneratedJD, JobInput
---
*Content truncated.*