cv
Build, tailor, render and approve the CV, then upload the approved version to JobCubby.
Файлы1
Открыть в GitHubSKILL.md.claude/skills/cv/SKILL.md
GitHub/cv
Files: templates/, scripts/, docs/, examples/ and routines/ are in the method root, ${CLAUDE_PLUGIN_ROOT} (the clone holding this skill when that is not replaced by a path); every other relative path is in the workspace, the current folder. Before acting on the person's behalf, read profile.md, docs/rules.md and the workspace rules.md; the workspace one wins on conflict.
The CV is markdown in cv/, rendered to PDF by scripts/render.mjs. cv/base.md is the master; variants are separate files (cv/de.md, cv/backend.md, cv/acme.md). The markdown contract is templates/cv.md: one # Name, header lines, then only these sections: Summary, Technical Skills, Work Experience, Education, Achievements, Certifications, Language Skills, Hobbies. Entries under Work Experience and Education are ### dates | role. The renderer rejects anything else and skips empty sections.
Approval
Every CV file carries approved: in its frontmatter. Empty means not approved. Approved means approved: <YYYY-MM-DD> <hash>, the hash being the output of:
grep -v '^approved:' cv/<file>.md | shasum -a 256 | cut -c1-12
The approval check passes only when the date is set and the hash recomputed now equals the stored one, so any edit after approval, by this skill or by hand, fails it. Every edit this skill makes to a CV file also empties approved: in the same write. Only a CV that passes the check, and the PDF rendered from it, goes to JobCubby, LinkedIn or any board.
Modes:
/cvwith nocv/base.mdyet and a file incv/old/: convert the existing CV into the contract, then fix only what is marked./cvwith no CV at all: full interview, then render./cvwith an existing one: review, propose fixes (including the confirmed "Add now" tags in the latestreports/stack-radar-<date>.mdthat the CV lacks), re-render./cv variant <name> for <posting URL or pasted text>: a tailored copy frombase.md./cv render [file]: just render.
Every mode that changes a CV ends with Showing and approving.
Building from the CV they already have
The old CV's text is in cv/old/<name>.txt, written by /profile step 0. If cv/old/ holds a CV with no .txt beside it, tell the person to run /profile first and stop.
- Read that text and
profile.md. - Write it into the contract as
cv/base.md, starting from a copy oftemplates/cv.md: the same jobs, dates, employers, projects and education; the skills line in the order fromprofile.md; each bullet rewritten into the ABCD shape where its content allows it and kept as written where it does not. Nothing is added that the old CV orprofile.mddoes not say. - Append
(?)to every bullet that has no result and no number, to every technology that only appears in the skills line, and to anything that contradictsprofile.md(a date, a title level, a years figure). - Walk the marks with the person, top to bottom, a few at a time: "what changed because you did it?" for a bullet, "used in real work or a real project?" for a technology, "which one is right?" for a contradiction. Every mark is resolved or the line is removed before rendering; no placeholder survives.
- Apply the defaults below (language, variants, photo, birth date, hobbies), run the checks, render.
A CV that already follows the contract (a base.md from another clone) needs only steps 3 to 5.
Building from scratch
Ask nothing that profile.md already says. Interview section by section, in the person's language, and write the markdown as you go, starting from a copy of templates/cv.md. Defaults to propose:
- Language of the base CV: English (recommended: most postings and all ATS parsers read it); the market's language.
- Variants: base plus one per market language they apply in (recommended); base only.
- Photo: on, casual outdoor headshot (recommended for Germany and most of Europe); off for markets that do not expect one.
- Birth date: on where the market expects it (recommended for Germany); off.
- Bullets per job: by tenure as below (recommended); the person's own count.
- Hobbies: two or three real ones (recommended: they make the person memorable); none.
- Header. Name, title line (role plus main stack in brackets, no level unless
profile.mdsays so), city, birth date, phone, email, links, work authorization line, availability line, languages in brackets if the market expects it. - Technical Skills. One bold group label per line, technologies separated by
|, in the order fromprofile.md. Years in brackets on the first line. Exact ATS spellings:TypeScriptnotTS,Node.jsnotNodeJS,CI/CDwith the slash,React(addReact.jsonly if the person wants both). - Work Experience. Newest first. For every job ask: dates, role, employer with city or "Remote", one-line project definition (where the company is from, what the product is, who uses it, how many), bullets, technologies used. Bullet count follows tenure: two for up to a year, three or four for one to two years, four or five for longer, and the most recent job may carry more. Every bullet has the ABCD shape: an active past-tense verb (built, led, designed, cut), what was done, how or why it was done (the method, tool or reason, whichever matters more), and the result with a number: users, revenue, time saved, load time before and after, components adopted, bugs reduced, team size. Ask "what changed because you did it?" until a number or a concrete outcome appears. Append
(?)to anything the person is unsure about and resolve it before rendering. - Education, Achievements, Certifications, Language Skills, Hobbies. Short lines separated by
|. - Photo. Ask for a file in
photos/. What works: taken by someone else, outdoors in daylight, smart-casual, a real smile, plain or natural background, space around the head so the square crop has room. What does not: selfies, passport photos, sunglasses, other people in frame, old photos. If they have none that fits, say they can generate one from their own photos with ChatGPT or Gemini and drop it in, and nothing more. The template crops to a square, so any ratio works. Photo and birth date are frontmatter switches, off for markets that do not want them. - Market conventions. Read
docs/markets/<market>.mdwhen it exists. For Germany: no summary paragraph, photo and birth date on. A closing line with place, date and signature appears only whensign_placeis set in the frontmatter (withsignaturepointing at an image inphotos/); set it only when the person asks.
Checks before rendering
Every rule in docs/rules.md "Writing on my behalf", plus:
- Every technology confirmed: "Have you used X in real work or a real project?" A "no" means it stays out, however often postings ask for it;
/stack-radarhandles that gap. - A bullet that reads like a posting is rewritten as what they did.
- Metrics present where they exist. Chronology complete (a gap is fine; a wrong date is not).
- Plain text only: no tables, columns, icons or skill bars in the markdown.
- Consistency as a format rule: one date format, one way of writing employers (with or without legal suffixes), one bullet style, the same spacing between jobs. A convention started in the first entry holds to the last.
Rendering
node "${CLAUDE_PLUGIN_ROOT}/scripts/render.mjs" cv/base.md
The output is cv/<Firstname_Lastname>_CV.pdf (suffix from version: for variants, Lebenslauf for German) plus one PNG per page. Open the PNGs and look: two pages at most, no orphan headings, header lines not wrapping, photo present if expected. Fix the markdown (not the template) for content problems; fix templates/cv.html only when the design itself is wrong.
Showing and approving
Show the person the rendered pages (the PNGs) and the PDF path, then ask:
- Approve this CV as rendered (recommended once every mark is resolved and the checks pass)
- Change something first (say what)
On 2, apply the change, re-render and ask again. On 1, compute the hash and write approved: <today> <hash> into that file's frontmatter. Done when the approval check passes for the file.
After approval
Run the approval check on the file; when it fails, go back to Showing and approving.
- Upload the PDF to JobCubby as a labelled resume version (
upload_resume, label = version and date, for exampleLebenslauf 2026-10-10). The file goes in as base64:base64 -i cv/<file>.pdf | tr -d '\n' > /tmp/cv.b64, check its size, thencatit once and pass it asdata. Base64 over about 190 KB exceeds the tool-output limit: shrink the photo inphotos/(a 600 px square is enough), re-render, upload. Every version a sweep may send (per market and language) must exist there. Set it as default when it replaces the master (set_default_resume). Keep the plain-text content current (update_resumewith the markdown text). - For
cv/base.md, push the approved content to the JobCubby profile:update_profilewith headline (the CV title line), summary, skills in the CV's order, work history and education, as the CV states them. Read the existing profile first and send only what changed. - If
.data.git/exists, run"${CLAUDE_PLUGIN_ROOT}/scripts/data" save "cv <name>". - Update "Files" in
profile.mdif a new version should be used for a market. - Tell the person to run
/profilesnext, so LinkedIn and the boards carry the approved CV.
Tailoring a variant
From base.md: reorder technologies within a skills line by the posting, as docs/rules.md "Writing on my behalf" allows; the title is the role's title, translated, never the posting's sentences (same level rule); pick the language. Metrics, chronology and the confirmed technologies stay as in base.md. Save as cv/<slug>.md with version: <slug> and approved: empty, render, then show and approve it like the base. Note in the JobCubby application which version was sent.