diff --git a/.claude/skills/rendercv-skill b/.claude/skills/rendercv-skill new file mode 160000 index 00000000..921bb1cb --- /dev/null +++ b/.claude/skills/rendercv-skill @@ -0,0 +1 @@ +Subproject commit 921bb1cb5a788cb39b4d113ced3667a768e62b4b diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml index 2b811c3c..a031425b 100644 --- a/.github/workflows/test.yaml +++ b/.github/workflows/test.yaml @@ -18,6 +18,8 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v6 + with: + submodules: true - name: Install uv uses: astral-sh/setup-uv@v7 @@ -47,6 +49,8 @@ jobs: runs-on: ${{ matrix.os }}-latest steps: - uses: actions/checkout@v6 + with: + submodules: true - name: Install uv uses: astral-sh/setup-uv@v7 diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 00000000..af869c16 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule ".claude/skills/rendercv-skill"] + path = .claude/skills/rendercv-skill + url = https://github.com/rendercv/rendercv-skill.git diff --git a/README.md b/README.md index d0241f2b..05e23de6 100644 --- a/README.md +++ b/README.md @@ -141,10 +141,10 @@ locale: Let AI coding agents create and edit your CV. Install the RenderCV skill: ```bash -npx skills add rendercv/rendercv +npx skills add rendercv/rendercv-skill ``` -Works with Claude Code, Cursor, Codex, Copilot, Windsurf, Gemini CLI, and [20+ other agents](https://docs.rendercv.com/user_guide/how_to/use_the_ai_agent_skill). +Works with Claude Code, Claude Desktop, Cursor, Codex, Copilot, Windsurf, Gemini CLI, and [20+ other agents](https://docs.rendercv.com/user_guide/how_to/use_the_ai_agent_skill). ## Get Started diff --git a/docs/assets/rendercv_skill.zip b/docs/assets/rendercv_skill.zip new file mode 100644 index 00000000..bdd95a06 Binary files /dev/null and b/docs/assets/rendercv_skill.zip differ diff --git a/docs/developer_guide/github_workflows.md b/docs/developer_guide/github_workflows.md index db269e02..c4f082d8 100644 --- a/docs/developer_guide/github_workflows.md +++ b/docs/developer_guide/github_workflows.md @@ -51,8 +51,9 @@ RenderCV has 4 workflows. Each handles a specific automation task. **What it does:** -1. Runs `just test-coverage` across **9 different environments** (3 operating systems × 3 Python versions: 3.12, 3.13, 3.14) -2. Combines all coverage reports and uploads them to show the coverage report +1. Checks out the repository with submodules (the [rendercv-skill](https://github.com/rendercv/rendercv-skill) submodule is needed for generated-file staleness tests) +2. Runs `just test-coverage` across **9 different environments** (3 operating systems × 3 Python versions: 3.12, 3.13, 3.14) +3. Combines all coverage reports and uploads them to show the coverage report ### 2. [`deploy-docs.yaml`](https://github.com/rendercv/rendercv/blob/main/.github/workflows/deploy-docs.yaml): Deploy Documentation diff --git a/docs/developer_guide/index.md b/docs/developer_guide/index.md index f9c88966..d394900a 100644 --- a/docs/developer_guide/index.md +++ b/docs/developer_guide/index.md @@ -21,7 +21,7 @@ Install them by following their official installation guides: 1. Clone the repository: ```bash - git clone https://github.com/rendercv/rendercv.git + git clone --recursive https://github.com/rendercv/rendercv.git ``` and change to the repository directory: @@ -30,6 +30,9 @@ Install them by following their official installation guides: cd rendercv ``` + > [!NOTE] + > The `--recursive` flag clones the [rendercv-skill](https://github.com/rendercv/rendercv-skill) submodule. If you forgot it, run `git submodule update --init` inside the repo. + 2. Set up the development environment (creates a virtual environment in `./.venv` with all dependencies): ```bash diff --git a/docs/index.md b/docs/index.md index 979fd49b..4758c170 100644 --- a/docs/index.md +++ b/docs/index.md @@ -140,7 +140,7 @@ locale: Let AI coding agents create and edit your CV. Install the RenderCV skill: ```bash -npx skills add rendercv/rendercv +npx skills add rendercv/rendercv-skill ``` Works with Claude Code, Cursor, Codex, Copilot, Windsurf, Gemini CLI, and [20+ other agents](https://docs.rendercv.com/user_guide/how_to/use_the_ai_agent_skill). diff --git a/docs/user_guide/how_to/use_the_ai_agent_skill.md b/docs/user_guide/how_to/use_the_ai_agent_skill.md index 4f3e506e..b22be26e 100644 --- a/docs/user_guide/how_to/use_the_ai_agent_skill.md +++ b/docs/user_guide/how_to/use_the_ai_agent_skill.md @@ -7,6 +7,7 @@ RenderCV provides an AI agent skill that teaches AI coding assistants how to cre The skill works with any AI coding agent that supports the skills protocol, including: - Claude Code +- Claude Desktop - Cursor - Codex - Copilot @@ -19,30 +20,39 @@ The skill works with any AI coding agent that supports the skills protocol, incl === "Vercel Skills CLI" ```bash - npx skills add rendercv/rendercv + npx skills add rendercv/rendercv-skill ``` You can also target a specific agent: ```bash - npx skills add rendercv/rendercv -a claude-code - npx skills add rendercv/rendercv -a cursor - npx skills add rendercv/rendercv -a codex + npx skills add rendercv/rendercv-skill -a claude-code + npx skills add rendercv/rendercv-skill -a cursor + npx skills add rendercv/rendercv-skill -a codex ``` === "OpenSkills" ```bash - npx openskills install rendercv/rendercv + npx openskills install rendercv/rendercv-skill ``` +=== "Claude Desktop" + + 1. Download [`rendercv_skill.zip`](../../assets/rendercv_skill.zip). + 2. In Claude Desktop, go to **Customize > Skills**. + 3. Click **"+"** and select **"Upload a skill"**. + 4. Upload the downloaded ZIP file. + + The skill will appear in your Skills list and Claude will automatically use it when working with your CV. + === "Manual" - Copy the content of [`skills/rendercv/SKILL.md`](https://github.com/rendercv/rendercv/blob/main/skills/rendercv/SKILL.md) into your agent's skill directory. For example, for Claude Code: + Copy the content of [`skills/rendercv/SKILL.md`](https://github.com/rendercv/rendercv-skill/blob/main/skills/rendercv/SKILL.md) into your agent's skill directory. For example, for Claude Code: ```bash - git clone https://github.com/rendercv/rendercv.git - cp -r rendercv/skills/rendercv ~/.claude/skills/ + git clone https://github.com/rendercv/rendercv-skill.git + cp -r rendercv-skill/skills/rendercv ~/.claude/skills/ ``` ## What the Skill Provides diff --git a/scripts/rendercv_skill/evals/prompts/skill_chat.js b/scripts/rendercv_skill/evals/prompts/skill_chat.js index bc760349..b55d36fa 100644 --- a/scripts/rendercv_skill/evals/prompts/skill_chat.js +++ b/scripts/rendercv_skill/evals/prompts/skill_chat.js @@ -10,6 +10,9 @@ const skillPath = path.resolve( "..", "..", "..", + ".claude", + "skills", + "rendercv-skill", "skills", "rendercv", "SKILL.md", diff --git a/scripts/rendercv_skill/generate.py b/scripts/rendercv_skill/generate.py index 3f05806e..3313b0d6 100755 --- a/scripts/rendercv_skill/generate.py +++ b/scripts/rendercv_skill/generate.py @@ -12,6 +12,7 @@ import ast import io import pathlib import re +import zipfile import jinja2 import ruamel.yaml @@ -27,8 +28,17 @@ from rendercv.schema.sample_generator import ( repository_root = pathlib.Path(__file__).parent.parent.parent script_directory = pathlib.Path(__file__).parent template_path = script_directory / "skill_template.j2.md" -output_path = repository_root / "skills" / "rendercv" / "SKILL.md" +output_path = ( + repository_root + / ".claude" + / "skills" + / "rendercv-skill" + / "skills" + / "rendercv" + / "SKILL.md" +) llms_txt_path = repository_root / "docs" / "llms.txt" +skill_zip_path = repository_root / "docs" / "assets" / "rendercv_skill.zip" # Paths to key model source files for dynamic inclusion. models_dir = repository_root / "src" / "rendercv" / "schema" / "models" @@ -286,7 +296,7 @@ def build_template_context() -> dict: def generate_skill_file() -> None: - """Render the Jinja2 template and write SKILL.md and docs/llms.txt.""" + """Render the Jinja2 template and write SKILL.md, docs/llms.txt, and ZIP.""" env = jinja2.Environment( loader=jinja2.FileSystemLoader(script_directory), keep_trailing_newline=True, @@ -302,6 +312,11 @@ def generate_skill_file() -> None: output_path.write_text(rendered, encoding="utf-8") llms_txt_path.write_text(rendered, encoding="utf-8") + # Generate ZIP for Claude Desktop skill upload + skill_zip_path.parent.mkdir(parents=True, exist_ok=True) + with zipfile.ZipFile(skill_zip_path, "w", zipfile.ZIP_DEFLATED) as zf: + zf.writestr("rendercv/SKILL.md", rendered) + if __name__ == "__main__": generate_skill_file() diff --git a/skills/rendercv/SKILL.md b/skills/rendercv/SKILL.md deleted file mode 100644 index b436ae3b..00000000 --- a/skills/rendercv/SKILL.md +++ /dev/null @@ -1,805 +0,0 @@ ---- -name: rendercv -description: >- - Create professional CVs and resumes with perfect typography using RenderCV - (v2.8). Users write content in YAML, and RenderCV produces - publication-quality PDFs via Typst typesetting. Full control over every visual - detail: colors, fonts, margins, spacing, section title styles, entry layouts, - and more. 6 built-in themes with unlimited - customization. Any language supported (20 built-in, or define your own). Outputs - PDF, PNG, HTML, and Markdown. Use when the user wants to create, edit, - customize, or render a CV or resume. ---- - -## Quick Start - -**Available themes:** `classic`, `engineeringclassic`, `engineeringresumes`, `harvard`, `moderncv`, `sb2nov` -**Available locales:** `english`, `arabic`, `danish`, `dutch`, `french`, `german`, `hebrew`, `hindi`, `indonesian`, `italian`, `japanese`, `korean`, `mandarin_chinese`, `norwegian_bokmål`, `norwegian_nynorsk`, `persian`, `portuguese`, `russian`, `spanish`, `turkish` - -These are starting points — every aspect of the design and locale can be fully customized in the YAML file. - -```bash -# Install RenderCV -uv tool install "rendercv[full]" - -# Create a starter YAML file (you can specify theme and locale) -rendercv new "John Doe" -rendercv new "John Doe" --theme moderncv --locale german - -# Render to PDF (also generates Typst, Markdown, HTML, PNG by default) -rendercv render John_Doe_CV.yaml - -# Watch mode: auto-re-render whenever the YAML file changes -rendercv render John_Doe_CV.yaml --watch - -# Render only PNG (useful for previewing or checking page count) -rendercv render John_Doe_CV.yaml --dont-generate-pdf --dont-generate-html --dont-generate-markdown - -# Override fields from the CLI without editing the YAML -rendercv render cv.yaml --cv.name "Jane Doe" --design.theme "moderncv" -``` - -## YAML Structure - -A RenderCV input has four sections. Only `cv` is required — the others have sensible defaults. - -```yaml -cv: # Your content: name, contact info, and all sections -design: # Visual styling: theme, colors, fonts, margins, spacing, layouts -locale: # Language: month names, phrases, translations -settings: # Behavior: output paths, bold keywords, current date -``` - -**Single file vs. separate files:** All four sections can live in one YAML file, or each can be a separate file. Separate files are useful for reusing the same design/locale across multiple CVs: - -```bash -# Single self-contained file (all sections in one file) -rendercv render John_Doe_CV.yaml - -# Separate files: CV content + design + locale loaded independently -rendercv render cv.yaml --design design.yaml --locale-catalog locale.yaml --settings settings.yaml -``` - -When using separate files, each file contains only its section (e.g., `design.yaml` has `design:` as the top-level key). CLI-loaded files override values in the main YAML file. - -The YAML maps directly to Pydantic models. The complete type-safe schema is provided below so you can understand every field, its type, and its default value. - -## Pydantic Schema - -The YAML input is validated against these Pydantic models. - -### Top-Level Model - -```python -class RenderCVModel(BaseModelWithoutExtraKeys): - cv: Cv = pydantic.Field(default_factory=Cv, title='CV', description='The content of the CV.') - design: Design = pydantic.Field(default_factory=ClassicTheme, title='Design') - locale: Locale = pydantic.Field(default_factory=EnglishLocale, title='Locale Catalog') - settings: Settings = pydantic.Field(default_factory=Settings, title='RenderCV Settings', description='The settings of the RenderCV.') - -``` - -### CV Content (`cv`) - -The `cv.sections` field is a dictionary where keys are section titles (any string you want) and values are lists of entries. Each section contains entries of the same type. - -```python -class Cv(BaseModelWithoutExtraKeys): - name: str | None = pydantic.Field(default=None, examples=['John Doe', 'Jane Smith']) - headline: str | None = pydantic.Field(default=None, examples=['Software Engineer', 'Data Scientist', 'Product Manager']) - location: str | None = pydantic.Field(default=None, examples=['New York, NY', 'London, UK', 'Istanbul, Türkiye']) - email: pydantic.EmailStr | list[pydantic.EmailStr] | None = pydantic.Field(default=None, examples=['john.doe@example.com', ['john.doe.1@example.com', 'john.doe.2@example.com']]) - photo: ExistingPathRelativeToInput | pydantic.HttpUrl | None = pydantic.Field(default=None, union_mode='left_to_right', examples=['photo.jpg', 'images/profile.png', 'https://example.com/photo.jpg']) - phone: pydantic_phone_numbers.PhoneNumber | list[pydantic_phone_numbers.PhoneNumber] | None = pydantic.Field(default=None, examples=['+1-234-567-8900', ['+1-234-567-8900', '+44 20 1234 5678']]) - website: pydantic.HttpUrl | list[pydantic.HttpUrl] | None = pydantic.Field(default=None, examples=['https://johndoe.com', ['https://johndoe.com', 'https://www.janesmith.dev']]) - social_networks: list[SocialNetwork] | None = pydantic.Field(default=None) - custom_connections: list[CustomConnection] | None = pydantic.Field(default=None, examples=[[{'placeholder': 'Book a call', 'url': 'https://cal.com/johndoe', 'fontawesome_icon': 'calendar-days'}]]) - sections: dict[str, Section] | None = pydantic.Field(default=None, examples=[{'Experience': '...', 'Education': '...', 'Projects': '...', 'Skills': '...'}]) - -``` - -```python -type SocialNetworkName = Literal['LinkedIn', 'GitHub', 'GitLab', 'IMDB', 'Instagram', 'ORCID', 'Mastodon', 'StackOverflow', 'ResearchGate', 'YouTube', 'Google Scholar', 'Telegram', 'WhatsApp', 'Leetcode', 'X', 'Bluesky', 'Reddit'] - -available_social_networks = get_args(SocialNetworkName.__value__) - -class SocialNetwork(BaseModelWithoutExtraKeys): - network: SocialNetworkName = pydantic.Field() - username: str = pydantic.Field(examples=['john_doe', '@johndoe@mastodon.social', '12345/john-doe']) - -``` - -```python -class CustomConnection(BaseModelWithoutExtraKeys): - fontawesome_icon: str - placeholder: str - url: pydantic.HttpUrl | None - -``` - -### Entry Types - -`cv.sections` is a dictionary: keys are section titles (any string), values are lists of entries. Each section must use a **single** entry type — you cannot mix different entry types within the same section. The entry type is auto-detected from the fields present in each entry. - -**Shared fields** — these are available on entry types that support dates and complex fields (ExperienceEntry, EducationEntry, NormalEntry, PublicationEntry): - -| Field | Type | Default | Notes | -|---|---|---|---| -| `date` | `str \| int \| null` | `null` | Free-form: `"2020-09"`, `"Fall 2023"`, etc. Mutually exclusive with `start_date`/`end_date`. | -| `start_date` | `str \| int \| null` | `null` | Strict format: YYYY-MM-DD, YYYY-MM, or YYYY. | -| `end_date` | `str \| int \| "present" \| null` | `null` | Same formats as `start_date`, or `"present"`. Omitting defaults to `"present"` when `start_date` is set. | -| `location` | `str \| null` | `null` | | -| `summary` | `str \| null` | `null` | | -| `highlights` | `list[str] \| null` | `null` | Bullet points. | - -**9 entry types:** - -| Entry Type | Required Fields | Optional Fields | Typical Use | -|---|---|---|---| -| **ExperienceEntry** | `company`, `position` | all shared fields | Jobs, positions | -| **EducationEntry** | `institution`, `area` | `degree` + all shared fields | Degrees, schools | -| **PublicationEntry** | `title`, `authors` | `doi`, `url`, `journal`, `summary`, `date` | Papers, articles | -| **NormalEntry** | `name` | all shared fields | Projects, awards | -| **OneLineEntry** | `label`, `details` | — | Skills, languages | -| **BulletEntry** | `bullet` | — | Simple bullet points | -| **NumberedEntry** | `number` | — | Numbered list items | -| **ReversedNumberedEntry** | `reversed_number` | — | Reverse-numbered items (5, 4, 3...) | -| **TextEntry** | *(plain string)* | — | Free-form paragraphs | - -Example: - -```yaml -cv: - sections: - experience: # list of ExperienceEntry (detected by company + position) - - company: Google - position: Engineer - start_date: 2020-01 - highlights: - - Did something impactful - skills: # list of OneLineEntry (detected by label + details) - - label: Languages - details: Python, C++ - about_me: # list of TextEntry (plain strings) - - This is a free-form paragraph about me. -``` - -Entries also accept arbitrary extra keys (silently ignored during rendering). A typo in a field name will NOT cause an error. - -### Design (`design`) - -All built-in themes share the same structure — they only differ in default values. See the sample designs below for every available field and its default. Set `design.theme` to pick a theme, then override any field. - -### Locale (`locale`) - -Built-in locales: `english`, `arabic`, `danish`, `dutch`, `french`, `german`, `hebrew`, `hindi`, `indonesian`, `italian`, `japanese`, `korean`, `mandarin_chinese`, `norwegian_bokmål`, `norwegian_nynorsk`, `persian`, `portuguese`, `russian`, `spanish`, `turkish` - -Set `locale.language` to a built-in locale name to use it. Override any field to customize translations. Set `language` to any string and provide all translations for a fully custom locale. - -### Settings (`settings`) - -Key fields: `bold_keywords` (list of strings to auto-bold), `current_date` (override today's date), `render_command.*` (output paths, generation flags). - -## Important Patterns - -### YAML quoting - -**ALWAYS quote string values that contain a colon (`:`).** This is the most common cause of invalid YAML. Highlights, titles, summaries, and any free-form text often contain colons: - -```yaml -# WRONG — colon breaks YAML parsing: -- title: Catalytic Mechanisms: A New Approach - highlights: - - Relevant coursework: Distributed Systems, ML - -# RIGHT — wrap in double quotes: -- title: "Catalytic Mechanisms: A New Approach" - highlights: - - "Relevant coursework: Distributed Systems, ML" -``` - -Rule: if a string value contains `:`, it MUST be quoted. When in doubt, quote it. - -### Bullet characters - -The `design.highlights.bullet` field only accepts these exact characters: `●`, `•`, `◦`, `-`, `◆`, `★`, `■`, `—`, `○`. Do not use en-dash (`–`), `>`, `*`, or any other character. When in doubt, omit `bullet` to use the theme default. - -### Phone numbers - -Phone numbers MUST be in international format with country code (E.164). Never invent a phone number — only include one if the user provides it. - -```yaml -# WRONG: -phone: "(555) 123-4567" -phone: "555-123-4567" - -# RIGHT: -phone: "+15551234567" -``` - -If the user provides a local number without country code, ask which country, or omit the phone field. - -### Text formatting - -All text fields support inline Markdown: `**bold**`, `*italic*`, `[link text](url)`. Block-level Markdown (headers, lists, blockquotes, code blocks) is not supported. Raw Typst commands and math (`$$f(x)$$`) also pass through. - -### Date handling - -- `date` and `start_date`/`end_date` are mutually exclusive. If `date` is provided, `start_date` and `end_date` are ignored. -- If only `start_date` is given, `end_date` defaults to `"present"`. -- `start_date`/`end_date` require strict formats: YYYY-MM-DD, YYYY-MM, or YYYY. -- `date` is flexible: accepts any string ("Fall 2023") in addition to date formats. - -### Section titles - -- `snake_case` keys auto-capitalize: `work_experience` → "Work Experience" -- Keys with spaces or uppercase are used as-is. - -### Publication authors - -Use `*Name*` (single asterisks, italic) to highlight the CV owner in author lists. - -### Nested highlights (sub-bullets) - -```yaml -highlights: - - Main bullet point - - Sub-bullet 1 - - Sub-bullet 2 -``` - -## CLI Reference - -### `rendercv new "Full Name"` - -Generate a starter YAML file. - -| Option | Short | What it does | -|---|---|---| -| `--theme THEME` | | Theme to use (default: `classic`) | -| `--locale LOCALE` | | Locale to use (default: `english`) | -| `--create-typst-templates` | | Also create editable Typst template files for full design control | - -### `rendercv render ` - -Generate PDF, Typst, Markdown, HTML, and PNG from a YAML file. - -| Option | Short | What it does | -|---|---|---| -| `--watch` | `-w` | Re-render automatically when the YAML file changes | -| `--quiet` | `-q` | Suppress all output messages | -| `--design FILE` | `-d` | Load design section from a separate YAML file | -| `--locale-catalog FILE` | `-lc` | Load locale section from a separate YAML file | -| `--settings FILE` | `-s` | Load settings section from a separate YAML file | -| `--output-folder DIR` | `-o` | Custom output directory | - -Per-format controls: `--{format}-path PATH` sets custom output path, `--dont-generate-{format}` skips generation. Formats: `pdf`, `typst`, `markdown`, `html`, `png`. - -**Override any YAML field from the CLI** using dot notation (overrides without editing the file): - -```bash -rendercv render CV.yaml --cv.name "Jane Doe" --design.theme "moderncv" -rendercv render CV.yaml --cv.sections.education.0.institution "MIT" -``` - -### `rendercv create-theme "theme-name"` - -Scaffold a custom theme directory with editable Typst templates for complete design control. - -## JSON Schema - -For YAML editor autocompletion and validation: - -```yaml -# yaml-language-server: $schema=https://raw.githubusercontent.com/rendercv/rendercv/refs/tags/v2.8/schema.json -``` - -## Complete Example - -### Sample CV - -```yaml -cv: - name: John Doe - headline: - location: San Francisco, CA - email: john.doe@email.com - photo: - phone: - website: https://rendercv.com/ - social_networks: - - network: LinkedIn - username: rendercv - - network: GitHub - username: rendercv - custom_connections: - sections: - Welcome to RenderCV: - - RenderCV reads a CV written in a YAML file, and generates a PDF with - professional typography. - - Each section title is arbitrary. - education: - - institution: Princeton University - area: Computer Science - degree: PhD - date: - start_date: 2018-09 - end_date: 2023-05 - location: Princeton, NJ - summary: - highlights: - - 'Thesis: Efficient Neural Architecture Search for Resource-Constrained Deployment' - - 'Advisor: Prof. Sanjeev Arora' - - NSF Graduate Research Fellowship, Siebel Scholar (Class of 2022) - - institution: Boğaziçi University - area: Computer Engineering - degree: BS - date: - start_date: 2014-09 - end_date: 2018-06 - location: Istanbul, Türkiye - summary: - highlights: - - 'GPA: 3.97/4.00, Valedictorian' - - Fulbright Scholarship recipient for Graduate Studies - experience: - - company: Nexus AI - position: Co-Founder & CTO - date: - start_date: 2023-06 - end_date: present - location: San Francisco, CA - summary: - highlights: - - Built foundation model infrastructure serving 2M+ monthly API requests - with 99.97% uptime - - Raised $18M Series A led by Sequoia Capital, with participation from - a16z and Founders Fund - - Scaled engineering team from 3 to 28 across ML research, platform, and - applied AI divisions - - Developed proprietary inference optimization reducing latency by 73% - compared to baseline - - company: NVIDIA Research - position: Research Intern - date: - start_date: 2022-05 - end_date: 2022-08 - location: Santa Clara, CA - summary: - highlights: - - Designed sparse attention mechanism reducing transformer memory - footprint by 4.2x - - Co-authored paper accepted at NeurIPS 2022 (spotlight presentation, top - 5% of submissions) - projects: - - name: '[FlashInfer](https://github.com/)' - date: - start_date: 2023-01 - end_date: present - location: - summary: Open-source library for high-performance LLM inference kernels - highlights: - - Achieved 2.8x speedup over baseline attention implementations on A100 - GPUs - - Adopted by 3 major AI labs, 8,500+ GitHub stars, 200+ contributors - - name: '[NeuralPrune](https://github.com/)' - date: '2021' - start_date: - end_date: - location: - summary: Automated neural network pruning toolkit with differentiable - masks - highlights: - - Reduced model size by 90% with less than 1% accuracy degradation on - ImageNet - - Featured in PyTorch ecosystem tools, 4,200+ GitHub stars - publications: - - title: 'Sparse Mixture-of-Experts at Scale: Efficient Routing for Trillion-Parameter - Models' - authors: - - '*John Doe*' - - Sarah Williams - - David Park - summary: - doi: 10.1234/neurips.2023.1234 - url: - journal: NeurIPS 2023 - date: 2023-07 - - title: Neural Architecture Search via Differentiable Pruning - authors: - - James Liu - - '*John Doe*' - summary: - doi: 10.1234/neurips.2022.5678 - url: - journal: NeurIPS 2022, Spotlight - date: 2022-12 - selected_honors: - - bullet: MIT Technology Review 35 Under 35 Innovators (2024) - - bullet: Forbes 30 Under 30 in Enterprise Technology (2024) - skills: - - label: Languages - details: Python, C++, CUDA, Rust, Julia - - label: ML Frameworks - details: PyTorch, JAX, TensorFlow, Triton, ONNX - patents: - - number: Adaptive Quantization for Neural Network Inference on Edge Devices - (US Patent 11,234,567) - - number: Dynamic Sparsity Patterns for Efficient Transformer Attention (US - Patent 11,345,678) - invited_talks: - - reversed_number: Scaling Laws for Efficient Inference — Stanford HAI - Symposium (2024) - - reversed_number: Building AI Infrastructure for the Next Decade — - TechCrunch Disrupt (2024) - -``` - -### Sample Design (classic — complete reference) - -This shows every available design field with its default value. All themes share the same structure. - -```yaml -design: - theme: classic - page: - size: us-letter - top_margin: 0.7in - bottom_margin: 0.7in - left_margin: 0.7in - right_margin: 0.7in - show_footer: true - show_top_note: true - colors: - body: rgb(0, 0, 0) - name: rgb(0, 79, 144) - headline: rgb(0, 79, 144) - connections: rgb(0, 79, 144) - section_titles: rgb(0, 79, 144) - links: rgb(0, 79, 144) - footer: rgb(128, 128, 128) - top_note: rgb(128, 128, 128) - typography: - line_spacing: 0.6em - alignment: justified - date_and_location_column_alignment: right - font_family: - body: Source Sans 3 - name: Source Sans 3 - headline: Source Sans 3 - connections: Source Sans 3 - section_titles: Source Sans 3 - font_size: - body: 10pt - name: 30pt - headline: 10pt - connections: 10pt - section_titles: 1.4em - small_caps: - name: false - headline: false - connections: false - section_titles: false - bold: - name: true - headline: false - connections: false - section_titles: true - links: - underline: false - show_external_link_icon: false - header: - alignment: center - photo_width: 3.5cm - photo_position: left - photo_space_left: 0.4cm - photo_space_right: 0.4cm - space_below_name: 0.7cm - space_below_headline: 0.7cm - space_below_connections: 0.7cm - connections: - phone_number_format: national - hyperlink: true - show_icons: true - display_urls_instead_of_usernames: false - separator: '' - space_between_connections: 0.5cm - section_titles: - type: with_partial_line - line_thickness: 0.5pt - space_above: 0.5cm - space_below: 0.3cm - sections: - allow_page_break: true - space_between_regular_entries: 1.2em - space_between_text_based_entries: 0.3em - show_time_spans_in: - - experience - entries: - date_and_location_width: 4.15cm - side_space: 0.2cm - space_between_columns: 0.1cm - allow_page_break: false - short_second_row: true - degree_width: 1cm - summary: - space_above: 0cm - space_left: 0cm - highlights: - bullet: • - nested_bullet: • - space_left: 0.15cm - space_above: 0cm - space_between_items: 0cm - space_between_bullet_and_text: 0.5em - templates: - footer: '*NAME -- PAGE_NUMBER/TOTAL_PAGES*' - top_note: '*LAST_UPDATED CURRENT_DATE*' - single_date: MONTH_ABBREVIATION YEAR - date_range: START_DATE – END_DATE - time_span: HOW_MANY_YEARS YEARS HOW_MANY_MONTHS MONTHS - one_line_entry: - main_column: '**LABEL:** DETAILS' - education_entry: - main_column: |- - **INSTITUTION**, AREA - SUMMARY - HIGHLIGHTS - degree_column: '**DEGREE**' - date_and_location_column: |- - LOCATION - DATE - normal_entry: - main_column: |- - **NAME** - SUMMARY - HIGHLIGHTS - date_and_location_column: |- - LOCATION - DATE - experience_entry: - main_column: |- - **COMPANY**, POSITION - SUMMARY - HIGHLIGHTS - date_and_location_column: |- - LOCATION - DATE - publication_entry: - main_column: |- - **TITLE** - SUMMARY - AUTHORS - URL (JOURNAL) - date_and_location_column: DATE - -``` - -### Other Theme Overrides - -Other themes only override specific fields from the classic defaults above. To use a theme, set `design.theme` and optionally override any field. Each theme also customizes `design.templates` (entry layout patterns) — see the classic sample above for the full template structure. The override YAMLs below omit templates for brevity. - -#### engineeringclassic - -```yaml -# yaml-language-server: $schema=../../../../../../schema.json -design: - theme: engineeringclassic - typography: - font_family: - body: Raleway - name: Raleway - headline: Raleway - connections: Raleway - section_titles: Raleway - bold: - name: false - section_titles: false - header: - alignment: left - links: - show_external_link_icon: false - section_titles: - type: with_full_line - sections: - show_time_spans_in: [] - entries: - short_second_row: false - summary: - space_above: 0.12cm - highlights: - space_left: 0cm - space_above: 0.12cm - space_between_items: 0.12cm -``` - -#### engineeringresumes - -```yaml -# yaml-language-server: $schema=../../../../../../schema.json -design: - theme: engineeringresumes - page: - show_footer: false - typography: - font_family: - body: XCharter - name: XCharter - headline: XCharter - connections: XCharter - section_titles: XCharter - font_size: - name: 25pt - section_titles: 1.2em - bold: - name: false - header: - connections: - separator: '|' - show_icons: false - display_urls_instead_of_usernames: true - colors: - name: rgb(0,0,0) - connections: rgb(0,0,0) - headline: rgb(0,0,0) - section_titles: rgb(0,0,0) - links: rgb(0,0,0) - links: - underline: true - show_external_link_icon: false - section_titles: - type: with_full_line - space_above: 0.5cm - space_below: 0.3cm - sections: - space_between_regular_entries: 0.42cm - space_between_text_based_entries: 0.15cm - show_time_spans_in: [] - entries: - short_second_row: false - summary: - space_above: 0.08cm - side_space: 0cm - highlights: - bullet: ● - nested_bullet: ● - space_left: 0cm - space_above: 0.08cm - space_between_items: 0.08cm - space_between_bullet_and_text: 0.3em -``` - -#### harvard - -```yaml -# yaml-language-server: $schema=../../../../../../schema.json -design: - theme: harvard - page: - top_margin: 0.5in - bottom_margin: 0.5in - left_margin: 0.5in - right_margin: 0.5in - show_top_note: false - colors: - name: rgb(0,0,0) - headline: rgb(0,0,0) - connections: rgb(0,0,0) - section_titles: rgb(0,0,0) - links: rgb(0,0,0) - typography: - font_family: - body: XCharter - name: XCharter - headline: XCharter - connections: XCharter - section_titles: XCharter - font_size: - name: 25pt - connections: 9pt - section_titles: 1.3em - header: - space_below_name: 0.5cm - space_below_headline: 0.5cm - space_below_connections: 0.5cm - connections: - show_icons: false - separator: • - space_between_connections: 0.4cm - section_titles: - type: centered_with_centered_partial_line - space_below: 0.2cm - sections: - space_between_regular_entries: 1em - show_time_spans_in: [] - entries: - short_second_row: false -``` - -#### moderncv - -```yaml -# yaml-language-server: $schema=../../../../../../schema.json -design: - theme: moderncv - typography: - line_spacing: 0.6em - font_family: - body: Fontin - name: Fontin - headline: Fontin - connections: Fontin - section_titles: Fontin - font_size: - name: 25pt - section_titles: 1.4em - bold: - name: false - section_titles: false - header: - alignment: left - photo_width: 4.15cm - photo_space_left: 0cm - photo_space_right: 0.3cm - links: - underline: true - show_external_link_icon: false - section_titles: - type: moderncv - space_above: 0.55cm - space_below: 0.3cm - line_thickness: 0.15cm - sections: - show_time_spans_in: [] - entries: - short_second_row: false - side_space: 0cm - space_between_columns: 0.3cm - summary: - space_above: 0.1cm - highlights: - space_left: 0cm - space_above: 0.15cm - space_between_items: 0.1cm - space_between_bullet_and_text: 0.3em -``` - -#### sb2nov - -```yaml -# yaml-language-server: $schema=../../../../../../schema.json -design: - theme: sb2nov - typography: - font_family: - body: New Computer Modern - name: New Computer Modern - headline: New Computer Modern - connections: New Computer Modern - section_titles: New Computer Modern - colors: - name: rgb(0,0,0) - connections: rgb(0,0,0) - section_titles: rgb(0,0,0) - headline: rgb(0,0,0) - links: rgb(0,0,0) - links: - underline: true - show_external_link_icon: false - section_titles: - type: with_full_line - sections: - show_time_spans_in: [] - header: - connections: - hyperlink: true - show_icons: false - display_urls_instead_of_usernames: true - separator: • - entries: - short_second_row: false - highlights: - bullet: ◦ - nested_bullet: ◦ -``` - diff --git a/tests/test_generated_files.py b/tests/test_generated_files.py index b35d64e8..3dddb4d4 100644 --- a/tests/test_generated_files.py +++ b/tests/test_generated_files.py @@ -9,6 +9,7 @@ Why: import pathlib import subprocess +import sys import pytest @@ -28,6 +29,9 @@ def run_just(recipe: str) -> None: ) +@pytest.mark.skipif( + sys.platform == "win32", reason="Schema generation differs on Windows" +) def test_schema_json_is_up_to_date() -> None: schema_path = repository_root / "schema.json" before = schema_path.read_text(encoding="utf-8") @@ -64,7 +68,15 @@ def test_example_yaml_is_up_to_date(theme: str) -> None: def test_skill_md_is_up_to_date() -> None: - skill_path = repository_root / "skills" / "rendercv" / "SKILL.md" + skill_path = ( + repository_root + / ".claude" + / "skills" + / "rendercv-skill" + / "skills" + / "rendercv" + / "SKILL.md" + ) before = skill_path.read_text(encoding="utf-8") llms_txt_path = repository_root / "docs" / "llms.txt"