JSON Resume — Authoring Guide for LLMs¶
This document teaches you how to write a valid resume.json that passes schema
validation used by pypi-profile (the schema-resume-validator Python package,
which wraps the JSON Resume schema).
Schema version¶
This project validates against the JSON Resume schema as implemented by
schema-resume-validator. The schema differs from the original v1.0.0 spec in
one important way: work entry location is an object, not a string.
Top-level structure¶
{
"$schema": "https://raw.githubusercontent.com/jsonresume/resume-schema/v1.0.0/schema.json",
"basics": { ... },
"work": [ ... ],
"volunteer": [],
"education": [],
"awards": [],
"certificates": [],
"publications": [],
"skills": [ ... ],
"languages": [ ... ],
"interests": [],
"references": [],
"projects": [ ... ]
}
All top-level arrays are optional and may be empty ([]). Never omit a key
with null — use [] for arrays and omit optional string fields entirely
rather than setting them to "" when the value would fail format validation.
basics¶
"basics": {
"name": "Jane Smith",
"label": "Python Developer",
"image": "",
"email": "jane@example.com",
"phone": "",
"url": "https://github.com/janesmith",
"summary": "One paragraph summary.",
"location": {
"address": "",
"postalCode": "",
"city": "Arlington",
"countryCode": "US",
"region": "Virginia"
},
"profiles": [
{
"network": "GitHub",
"username": "janesmith",
"url": "https://github.com/janesmith"
}
]
}
Rules:
locationis an object withcity,region,countryCode(ISO-3166-1 ALPHA-2, e.g."US"),address,postalCode. All sub-fields are optional strings.urlinbasicsmust be a valid URI or omitted. Never"".image,email,phone,summaryare plain strings and may be"".
work entries¶
{
"name": "Acme Corp",
"position": "Senior Engineer",
"startDate": "2021-03",
"endDate": "2024-09",
"summary": "Led backend platform team.",
"highlights": [
"Reduced API latency by 40%",
"Migrated 20 services to Kubernetes"
],
"location": {
"city": "McLean",
"region": "Virginia",
"countryCode": "US"
}
}
Rules:
locationis an object (same shape asbasics.location), not a string. This is the most common mistake.startDateandendDatemust matchYYYY-MM-DD,YYYY-MM, orYYYY. They cannot be"". OmitendDateentirely for current positions.urlmust be a valid URI or omitted. Never"".highlightsis an array of strings; omit or use[]if none.nameis the company/organization name.description(optional string) is the organization description, rarely used.
Current job pattern — omit endDate:
{
"name": "Booz Allen Hamilton",
"position": "DevOps Engineer",
"startDate": "2025-02",
"summary": "...",
"location": { "city": "McLean", "region": "Virginia", "countryCode": "US" }
}
Past job pattern:
{
"name": "Previous Corp",
"position": "Developer",
"startDate": "2019-01",
"endDate": "2024-12",
"summary": "...",
"location": { "city": "Arlington", "region": "Virginia", "countryCode": "US" }
}
education entries¶
{
"institution": "State University",
"area": "Computer Science",
"studyType": "Bachelor",
"startDate": "1994-09",
"endDate": "1998-05",
"score": "",
"courses": []
}
Same date rules as work. Omit endDate if still enrolled.
skills entries¶
{
"name": "Python",
"level": "Expert",
"keywords": ["packaging", "FastAPI", "pytest"]
}
level is a free string (no enum). Common values: "Beginner", "Intermediate",
"Advanced", "Expert", "Master".
projects entries¶
{
"name": "my-tool",
"description": "A CLI tool for X.",
"highlights": [],
"keywords": ["python", "cli"],
"startDate": "2023-01",
"url": "https://github.com/me/my-tool",
"roles": ["creator"],
"entity": "me",
"type": "application"
}
urlmust be a valid URI or omitted — never"".startDate/endDatefollow the same date pattern.
certificates entries¶
{
"name": "AWS Solutions Architect",
"date": "2022-06",
"issuer": "Amazon Web Services",
"url": "https://www.credly.com/badges/..."
}
languages entries¶
{
"language": "English",
"fluency": "Native speaker"
}
Date format¶
The regex that all date fields must satisfy:
^([1-2][0-9]{3}-[0-1][0-9]-[0-3][0-9]|[1-2][0-9]{3}-[0-1][0-9]|[1-2][0-9]{3})$
| Format | Example | Use when |
|---|---|---|
YYYY |
2023 |
Year only |
YYYY-MM |
2023-06 |
Month precision (most common for jobs) |
YYYY-MM-DD |
2023-06-15 |
Full date (certificates, awards) |
Never use:
""(empty string) — omit the field instead"present"— omitendDatefor current positions"2025-2"— month must be zero-padded:"2025-02"
URI fields¶
Fields typed as "format": "uri" (url in work, projects, certificates,
basics, profiles) must be a syntactically valid URI or omitted entirely.
// WRONG — fails URI format
"url": ""
// CORRECT — omit the field
// (no "url" key at all)
// CORRECT — valid URI
"url": "https://github.com/me/repo"
Common mistakes to avoid¶
| Mistake | Fix |
|---|---|
"location": "Arlington, VA" in work |
Use {"city": "Arlington", "region": "Virginia", "countryCode": "US"} |
"endDate": "" |
Omit endDate entirely |
"url": "" |
Omit url entirely |
"endDate": "present" |
Omit endDate entirely |
"startDate": "2025-2" |
Zero-pad month: "2025-02" |
"highlights": null |
Use [] or omit |
Validating in this project¶
uv run python -c "
import json
from pathlib import Path
from schema_resume import validate_resume
raw = json.loads(Path('data/resume.json').read_text())
result = validate_resume(raw)
print('valid:', result['valid'])
for e in result.get('errors', []):
print(e)
"
Or via the importer (warns on validation failure):
uv run pypi-profile init --from-json-resume data/resume.json --output /tmp/test.toml