DEV Community

Two Skills I Built to Automate My Job Search with Claude Code

I'm a few months into a job search after a layoff, and I kept running into the same two problems: I was spending too long deciding whether a job listing was worth my time, and my resume was drifting out of sync with what was actually landing in interviews. So I built two Claude Code skills, reusable, file-based instructions Claude Code follows every time I invoke a slash command, to close both gaps. This is a walkthrough of how they work, why they're structured the way they are, and what I learned building them. If you haven't used Claude Code skills before: a skill is just a markdown file with YAML frontmatter (name and description ) that lives in .claude/skills/{skill-name}/SKILL.md . The description field is what Claude uses to decide when to trigger the skill automatically, and you can always invoke it explicitly with /skill-name . The problem Job searching produces a lot of repetitive judgment calls: - Is this listing worth 20 minutes of my time? Every JD needs to be read against my actual background, not against wishful thinking. - Once I've scored 30+ listings, what do they add up to? Patterns emerge: the same gap gets flagged five times, the same bullet gets written from scratch in every cover letter, but nobody's collecting those patterns into resume improvements. Two skills, one for each problem: /score-job and /resume-sharpener . They're designed to work as a pair, the first generates raw signal, the second mines it. Skill 1: /score-job Input: paste a JD or give a URL. Output: one markdown file, job-search/scored-listings/YYYY-MM-DD-{company}-{role}.md . Reading the right context every time The skill starts by reading a fixed set of source files in parallel: my resumes (I keep four: engineering, PM, FDE/presales pivot, and a PeopleSoft-specific one), a profile doc, a skills inventory, and a filters doc that encodes what counts as a disqualifier. Critically, it re-reads these every run rather than caching anything, because they evolve as I update my resume or change what I'm filtering for. ## Sources to read (in parallel) 1. me/resume-engineering.md 2. me/resume-pm.md 3. me/resume-fde-presales.md (in progress, skip without erroring if missing) 4. me/resume-peoplesoft.md (read only for PeopleSoft-flavored roles) 5. me/profile.md 6. me/skills-inventory.md 7. me/job-search-filters.md 8. me/preferences.md A scoring rubric, not a vibe The output is a structured scorecard: seniority, domain fit, technical depth, leadership scope, problem-solving complexity, adaptability, and comp signal, each out of 10, followed by an explicit "Ideal Candidate Bar" section. That section forces the model to sketch who the JD is actually written for before scoring me against it, which keeps the scoring honest instead of grading on a curve. The rest of the file is built to be immediately actionable: requirements extracted and matched/partial/gap, top strengths to lead with, gaps with an honest read on whether they're ignorable or a real blocker, 3-5 tailored resume bullets pulled from my actual resume content (never fabricated), a two-sentence cover letter hook, red flags, and a one-line recommended next action. Two lenses when a role is ambiguous One wrinkle: I'm exploring a pivot into Forward Deployed Engineering / presales roles, which is a stretch from my actual track record. Rather than force one verdict, the skill detects presales/FDE-shaped roles by keyword and scores them twice, once against my honest track record, once assuming the pivot is the intentional move, and shows both tables side by side. It also calls out a distinction that matters a lot in this search: "Forward Deployed Engineer" at a product company (Palantir, Anthropic, etc.) is a very different job than "Solutions Engineer" at a staff-augmentation firm, even though the titles look interchangeable on a job board. Closing the loop If the verdict is "Worth applying" or better, the skill offers, never automatically, to add the row to a tracking spreadsheet and to a local submit-queue.md file that feeds my next job-search work block. Nothing gets queued without an explicit yes. Skill 2: /resume-sharpener This is the pattern-mining half. It runs in two phases. Phase 1: analyze and draft It reads every file in job-search/scored-listings/ (by this point, 30+ files) alongside the four base resumes. Then it looks for two signals: - Bullets worth promoting: a tailored bullet that shows up (in substance) in 2+ scored listings, or one the scoring keeps calling a strength while the base resume only gives it a weak line. - Gaps worth addressing proactively: a gap that shows up in 3+ listings and is actually addressable, not something structural like a missing degree. A bullet is a candidate for promotion if it appears (in substance) in 2+ scored listings' "Tailored Resume Bullets" sections, OR it captures something the base resume clearly understates. A gap is a candidate for proactive treatment if it appears in 3+ scored listings AND is addressable (not a hard blocker). The threshold matters here: it's a deliberate filter against overfitting to a single job description. A bullet written for one company's niche stack isn't a candidate; a strength that keeps getting cited across unrelated roles is. The output is a structured draft document, organized per resume, with a star rating showing how many listings each bullet pattern came from, written to Google Drive as a Google Doc so I can mark items KEEP / MODIFY / SKIP before anything touches my actual resume files. Phase 2: apply Only after I've reviewed the draft and say "apply resume improvements" does the skill edit the real *.md resume files, and only the items I approved, using the exact text from the draft. It's an explicit two-step gate: generate a proposal, wait for a human decision, then execute. No autonomous resume rewrites. Build your own version of /score-job The mechanics above are specific to my search, but the shape generalizes. Here's how I'd walk someone through adapting it, as a set of questions to answer before writing a single line of the skill, not a fill-in-the-blanks template. Step 1: How many "lenses" do you actually have? /score-job works for me because I'm evaluating listings through four possible role lenses: engineering leadership, product management, an FDE/presales pivot, and a PeopleSoft specialist track, and a single job can score differently depending on which one it's read through. That's why the skill maintains four separate master resumes instead of one, and why it has a "two-lens scoring" branch for roles that are ambiguous between them. Before you build this, answer honestly: - Am I actually applying from more than one angle, or am I one consistent candidate for one consistent kind of role? If it's the latter, you need one master resume and no lens-switching logic. Don't build the branching for a problem you don't have. - If there is more than one angle, are they truly distinct (different resumes, different framing, different "ideal candidate" bar), or are they the same resume with different bullet ordering? Distinct lenses justify separate files; cosmetic differences don't. - Do any two lenses ever compete for the same listing? That's the case that needs the "score it twice, show both tables" logic; mine is the presales-pivot ambiguity. If your lenses never overlap on the same posting, you don't need that complexity either. Step 2: What are your source-of-truth documents, and what format are they actually in? The skill re-reads a fixed set of files every run rather than caching anything. That's the part worth keeping regardless of your situation. But don't assume everything has to start life as markdown. - Master resumes can be .docx . You don't need to hand-convert them to markdown first. Have the skill flatten each attached resume to a plain.md file as a setup/ingestion step (Claude Code's docx skill can do this extraction), and treat the flattened.md as the source of truth the scoring skill actually reads. This matters because your "real" resume lives in Word for formatting reasons, but the scoring skill wants plain text it can pattern-match and quote from without fighting Word markup. - Your skills-inventory shouldn't be hand-maintained separately. Derive it from the resumes. Rather than writing a skills-inventory doc from scratch (which drifts out of sync the moment you update a resume), have it generated as the union of every skill, tool, and competency mentioned across all your master resumes, one complete list, not per-lens. That way it stays current automatically: update a resume, regenerate the inventory, done. It's the thing that lets the scoring skill say "this is a real match" vs. "this is aspirational" without you maintaining two sources of truth that can disagree. - Export your LinkedIn profile as an additional comparison source. LinkedIn's "Save to PDF" export (Settings โ†’ Get a copy of your data, or the profile page's "More โ†’ Save to PDF") gives you a document that often diverges from your resume in small but telling ways: different framing of the same role, an endorsed skill that never made it onto paper, a summary line that undersells or oversells something. Feed that in as a read-only reference alongside the resumes, not as a resume itself. It's useful for catching inconsistencies and for pulling framing language that's already proven itself in a more public context. Step 3: What's actually disqualifying vs. just undesirable? My job-search-filters.md encodes hard disqualifiers separately from soft preferences, and the scoring skill treats them differently: a filter hit is a "Pass," a soft preference miss just shows up as a red flag. Write these as two explicit lists, not one blended one: - Hard filters: location incompatibility, comp floor, IC-only when you need a leadership scope, industries you've ruled out. These should short-circuit straight to a low verdict. - Soft preferences: things that lower enthusiasm but shouldn't zero out an other

Read on DEV Community ↗ ← Back to News

Comments

No comments yet. Start the discussion.