/tailor-resume
Choose the best existing resume base/variant for a job, or create a new tailored variant when nothing fits.
Claude Code
$ npx -y skills add suxrobGM/jobpilot --skill tailor-resume --agent claude-code
Codex
$ npx skills add suxrobGM/jobpilot --skill tailor-resume -a codex -y
Cursor
$ npx skills add suxrobGM/jobpilot --skill tailor-resume -a cursor -y
Gemini CLI
$ npx skills add suxrobGM/jobpilot --skill tailor-resume -a gemini-cli -y
GitHub Copilot
$ npx skills add suxrobGM/jobpilot --skill tailor-resume -a github-copilot -y
OpenCode
$ npx skills add suxrobGM/jobpilot --skill tailor-resume -a opencode -y
Windsurf
$ npx skills add suxrobGM/jobpilot --skill tailor-resume -a windsurf -y
SKILL.md
tailor-resume.SKILL.mdname: tailor-resume
description: Choose the best existing resume base/variant for a job, or create a new tailored variant when nothing fits.
argument-hint: "<brief-json | job-url | pasted-jd-text> [--base <resumeId>]"
Tailor resume
Pick a resume for one job: reuse a variant when one fits, create one only when none does.
Follow `../_shared/setup.md`; the profile carries `resumes`.
1. Read the job
- Argument starts with `{`: it is the brief. No browsing.
- Starts with `http`: open it, snapshot the posting body, and build the brief
(`../_shared/job-brief.md`).
- Otherwise: pasted text; build the brief from it.
From the brief, derive:
- `title`; `domain` (fintech, healthtech, devtools, ...); `standouts` (clearance, on-call, onsite).
- `roleFamily`, one of `frontend` (frontend, ui, react, vue, angular), `backend` (backend, api,
services), `fullstack`, `mobile` (ios, android, react native, flutter), `data` (data engineer/scientist, analytics, etl), `ml` (ml, ai engineer, mlops), `devops` (devops, sre, platform, infrastructure), `qa` (qa, sdet, test engineer), or `other`.
- `seniority`, one of `junior` (junior, entry), `senior` (senior, sr.), `staff`, `lead` (lead,
principal), else `mid`. Cross-check `yearsExperience`: 0-2 junior, 3-5 mid, 6-9 senior, 10+ staff or lead.
- `keywords`: the top 10 required skills from `skills` and `requirements`, lowercase, deduped,
must-haves first.
- `responsibilityTerms`: the top 5 terms from `responsibilities` (design, mentor, migrate,
on-call).
2. Pick the base
A resume is usable when it has `hasData` or a `sourceFilename`.
1. `--base <id>` (the feed's resume), if usable. 2. Else `user.primaryResumeId`, if usable. 3. Else score each resume (max 10) and take the highest; ties go to primary, then most recent, then lowest id:
- +4 its `label` names `roleFamily`; or +2 an adjacent family (frontend/fullstack,
backend/fullstack, ml/data, devops/backend);
- +1 `hasData`; +1 `isPrimary`; +1 updated within 90 days;
- +0 to 3 keyword coverage when `hasData`: `round(3 x matched / 10)` over skills, projects and
summary.
Nothing usable: stop with "No usable base resume. Upload a PDF at $JOBPILOT_WEB/resumes, then run this again."
3. Load the base
`GET /api/resumes/$BASE_ID`. `content` null: run the `extract-resume` skill on it, then fetch again.
A non-empty `profileMismatches` means the resume and profile disagree. Say it once, don't block:
> Resume and profile disagree: <field> is "<resume>" on the resume, "<profile>" in the profile. > Fix at $JOBPILOT_WEB/resumes/<baseId>
4. Reuse or create
`GET /api/resumes/$BASE_ID/variants`. Rank by title similarity and fetch only the top 5 (`GET /api/resumes/variants/<id>`). Skip `Suggested rewrite` variants. A variant outside `roleFamily` and its adjacent families scores 0. Otherwise score out of 100:
| Part | Max | How | | --- | --- | --- | | Keywords | 40 | `40 x matched / 10` of `keywords` in skills, project keywords, summary, bullets | | Title | 20 | `20 x` word overlap (Jaccard) of the job title and variant label, ignoring engineer, senior, the, at | | Responsibilities | 15 | `15 x matched / 5` of `responsibilityTerms` in summary and bullets | | Seniority | 15 | exact 15; one step off 8; else 0 | | Domain | 5 | `domain` appears in summary or a bullet | | Recency | 5 | updated within 180 days |
- 60 or more: reuse.
- 45-59: reuse, and name the weakest part in one line.
- Under 45, or nothing passes the family check: create (step 5).
- At 15 or more variants on the base: reuse the best variant that passes the family check, whatever
its score, and say "Reusing variant <id> (<n>/100): the base has <count> variants. Prune at $JOBPILOT_WEB/resumes/<baseId>."
Reuse is the default. A variant is the base with bullets reordered, so a new one gains little and adds a row per application. Recency weighs almost nothing on purpose.
On reuse, print and stop:
Reusing variant <id>: <label> (<n>/100).
RESUME_USED base=<baseId> variant=<id>
5. Create
A variant is the base with the relevant parts moved forward. The reader should see that it fits, not that it was tailored. The server reorders skills and ranks bullets from your hints, so most of the work is choosing terms. Send only what changes something:
- `label`: `"<Company> - <Title>"`.
- `jobUrl`: whenever there is one; it ties the variant to the application.
- `emphasizedTech`: 4-8 lowercase terms from `keywords`; they move to the front of their groups.
- `jobKeywords`: optional, about 10 terms that rank bullets in each entry. Defaults to
`emphasizedTech`.
- `changeNotes`: one or two sentences on what was emphasized and why.
Summary
Leave `summary` out when the base fits; it usually does. When one sentence speaks to the wrong audience, swap only that sentence and keep the rest word for word. The new sentence states one resume fact this job cares about, matching its neighbors in person, tense and length. Keep the base's proof (publications, years, domains, numbers). Never restate the posting, and never open with a title followed by a list of tools.
The server rejects stock phrasing in anything you write (summary, headline, reworded bullets). Don't use: passionate, enjoys, comfortable with, hands-on, results-driven, detail-oriented, self-starter, fast-paced, track record, cutting-edge, state-of-the-art, leverage, spearheaded, seasoned, stakeholders, business requirements, production-grade, best practices, cross-functional, end-to-end, quick learner, eager to, thrives, suited to, the same, downstream.
Headline
Optional: a job title, nothing more. Change it only when the base names a different discipline.
Bullet rewrites
Reordering usually suffices. Reword a bullet only when its relevant fact sits mid-sentence, and at most two or three in the whole resume.
`bulletRewrites` is `[{ entryIndex, bullets: [{ original, tailored }] }]`. `original` is copied verbatim from `experie
Read more
name: tailor-resume description: Choose the best existing resume base/variant for a job, or create a new tailored variant when nothing fits. argument-hint: "<brief-json | job-url | pasted-jd-text> [--base <resumeId>]"
Tailor resume
Pick a resume for one job: reuse a variant when one fits, create one only when none does.
Follow `../_shared/setup.md`; the profile carries `resumes`.
1. Read the job
- Argument starts with `{`: it is the brief. No browsing.
- Starts with `http`: open it, snapshot the posting body, and build the brief
(`../_shared/job-brief.md`).
- Otherwise: pasted text; build the brief from it.
From the brief, derive:
- `title`; `domain` (fintech, healthtech, devtools, ...); `standouts` (clearance, on-call, onsite).
- `roleFamily`, one of `frontend` (frontend, ui, react, vue, angular), `backend` (backend, api,
services), `fullstack`, `mobile` (ios, android, react native, flutter), `data` (data engineer/scientist, analytics, etl), `ml` (ml, ai engineer, mlops), `devops` (devops, sre, platform, infrastructure), `qa` (qa, sdet, test engineer), or `other`.
- `seniority`, one of `junior` (junior, entry), `senior` (senior, sr.), `staff`, `lead` (lead,
principal), else `mid`. Cross-check `yearsExperience`: 0-2 junior, 3-5 mid, 6-9 senior, 10+ staff or lead.
- `keywords`: the top 10 required skills from `skills` and `requirements`, lowercase, deduped,
must-haves first.
- `responsibilityTerms`: the top 5 terms from `responsibilities` (design, mentor, migrate,
on-call).
2. Pick the base
A resume is usable when it has `hasData` or a `sourceFilename`.
1. `--base <id>` (the feed's resume), if usable. 2. Else `user.primaryResumeId`, if usable. 3. Else score each resume (max 10) and take the highest; ties go to primary, then most recent, then lowest id:
- +4 its `label` names `roleFamily`; or +2 an adjacent family (frontend/fullstack,
backend/fullstack, ml/data, devops/backend);
- +1 `hasData`; +1 `isPrimary`; +1 updated within 90 days;
- +0 to 3 keyword coverage when `hasData`: `round(3 x matched / 10)` over skills, projects and
summary.
Nothing usable: stop with "No usable base resume. Upload a PDF at $JOBPILOT_WEB/resumes, then run this again."
3. Load the base
`GET /api/resumes/$BASE_ID`. `content` null: run the `extract-resume` skill on it, then fetch again.
A non-empty `profileMismatches` means the resume and profile disagree. Say it once, don't block:
> Resume and profile disagree: <field> is "<resume>" on the resume, "<profile>" in the profile. > Fix at $JOBPILOT_WEB/resumes/<baseId>
4. Reuse or create
`GET /api/resumes/$BASE_ID/variants`. Rank by title similarity and fetch only the top 5 (`GET /api/resumes/variants/<id>`). Skip `Suggested rewrite` variants. A variant outside `roleFamily` and its adjacent families scores 0. Otherwise score out of 100:
| Part | Max | How | | --- | --- | --- | | Keywords | 40 | `40 x matched / 10` of `keywords` in skills, project keywords, summary, bullets | | Title | 20 | `20 x` word overlap (Jaccard) of the job title and variant label, ignoring engineer, senior, the, at | | Responsibilities | 15 | `15 x matched / 5` of `responsibilityTerms` in summary and bullets | | Seniority | 15 | exact 15; one step off 8; else 0 | | Domain | 5 | `domain` appears in summary or a bullet | | Recency | 5 | updated within 180 days |
- 60 or more: reuse.
- 45-59: reuse, and name the weakest part in one line.
- Under 45, or nothing passes the family check: create (step 5).
- At 15 or more variants on the base: reuse the best variant that passes the family check, whatever
its score, and say "Reusing variant <id> (<n>/100): the base has <count> variants. Prune at $JOBPILOT_WEB/resumes/<baseId>."
Reuse is the default. A variant is the base with bullets reordered, so a new one gains little and adds a row per application. Recency weighs almost nothing on purpose.
On reuse, print and stop:
Reusing variant <id>: <label> (<n>/100). RESUME_USED base=<baseId> variant=<id>
5. Create
A variant is the base with the relevant parts moved forward. The reader should see that it fits, not that it was tailored. The server reorders skills and ranks bullets from your hints, so most of the work is choosing terms. Send only what changes something:
- `label`: `"<Company> - <Title>"`.
- `jobUrl`: whenever there is one; it ties the variant to the application.
- `emphasizedTech`: 4-8 lowercase terms from `keywords`; they move to the front of their groups.
- `jobKeywords`: optional, about 10 terms that rank bullets in each entry. Defaults to
`emphasizedTech`.
- `changeNotes`: one or two sentences on what was emphasized and why.
Summary
Leave `summary` out when the base fits; it usually does. When one sentence speaks to the wrong audience, swap only that sentence and keep the rest word for word. The new sentence states one resume fact this job cares about, matching its neighbors in person, tense and length. Keep the base's proof (publications, years, domains, numbers). Never restate the posting, and never open with a title followed by a list of tools.
The server rejects stock phrasing in anything you write (summary, headline, reworded bullets). Don't use: passionate, enjoys, comfortable with, hands-on, results-driven, detail-oriented, self-starter, fast-paced, track record, cutting-edge, state-of-the-art, leverage, spearheaded, seasoned, stakeholders, business requirements, production-grade, best practices, cross-functional, end-to-end, quick learner, eager to, thrives, suited to, the same, downstream.
Headline
Optional: a job title, nothing more. Change it only when the base names a different discipline.
Bullet rewrites
Reordering usually suffices. Reword a bullet only when its relevant fact sits mid-sentence, and at most two or three in the whole resume.
`bulletRewrites` is `[{ entryIndex, bullets: [{ original, tailored }] }]`. `original` is copied verbatim from `experie
An AI agent that applies to jobs for you, using the Claude or Codex subscription you already have. Open JobPilot → · Docs · How it works · Changelog Watch it full size → Applying for jobs takes hours.
Other skills on jobpilot.
More skills from other plugins.
browser-use
Direct browser control via CDP for web interaction: automation, scraping, testing, screenshots, and site/app work. Also covers…
agent-browser
Browser automation CLI for AI agents. Use when the user needs to interact with websites, including navigating pages, filling…
Questions about tailor-resume.
- Which coding agents can use tailor-resume?
- tailor-resume installs in Claude Code, Codex, Cursor, Gemini CLI, GitHub Copilot, OpenCode and Windsurf with the skills CLI, using each agent's flag shown on this page. Flowy's auto-invocation, which fires a skill when your prompt matches, runs in Claude Code only.

