<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Shawn Abernathy</title>
    <description>The latest articles on DEV Community by Shawn Abernathy (@smabernat).</description>
    <link>https://dev.to/smabernat</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3785368%2F79a453d9-7f4a-4ed1-9d2e-35f487801964.png</url>
      <title>DEV Community: Shawn Abernathy</title>
      <link>https://dev.to/smabernat</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/smabernat"/>
    <language>en</language>
    <item>
      <title>Two Skills I Built to Automate My Job Search with Claude Code</title>
      <dc:creator>Shawn Abernathy</dc:creator>
      <pubDate>Sun, 09 Aug 2026 03:04:30 +0000</pubDate>
      <link>https://dev.to/smabernat/two-skills-i-built-to-automate-my-job-search-with-claude-code-1pcn</link>
      <guid>https://dev.to/smabernat/two-skills-i-built-to-automate-my-job-search-with-claude-code-1pcn</guid>
      <description>&lt;p&gt;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.&lt;/p&gt;

&lt;p&gt;So I built two &lt;a href="https://claude.com/claude-code" rel="noopener noreferrer"&gt;Claude Code&lt;/a&gt; &lt;strong&gt;skills&lt;/strong&gt;, 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.&lt;/p&gt;

&lt;p&gt;If you haven't used Claude Code skills before: a skill is just a markdown file with YAML frontmatter (&lt;code&gt;name&lt;/code&gt; and &lt;code&gt;description&lt;/code&gt;) that lives in &lt;code&gt;.claude/skills/{skill-name}/SKILL.md&lt;/code&gt;. The &lt;code&gt;description&lt;/code&gt; field is what Claude uses to decide when to trigger the skill automatically, and you can always invoke it explicitly with &lt;code&gt;/skill-name&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  The problem
&lt;/h2&gt;

&lt;p&gt;Job searching produces a lot of repetitive judgment calls:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Is this listing worth 20 minutes of my time?&lt;/strong&gt; Every JD needs to be read against my actual background, not against wishful thinking.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Once I've scored 30+ listings, what do they add up to?&lt;/strong&gt; 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.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Two skills, one for each problem: &lt;code&gt;/score-job&lt;/code&gt; and &lt;code&gt;/resume-sharpener&lt;/code&gt;. They're designed to work as a pair, the first generates raw signal, the second mines it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Skill 1: &lt;code&gt;/score-job&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Input:&lt;/strong&gt; paste a JD or give a URL. &lt;strong&gt;Output:&lt;/strong&gt; one markdown file, &lt;code&gt;job-search/scored-listings/YYYY-MM-DD-{company}-{role}.md&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Reading the right context every time
&lt;/h3&gt;

&lt;p&gt;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 &lt;strong&gt;every run&lt;/strong&gt; rather than caching anything, because they evolve as I update my resume or change what I'm filtering for.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="gu"&gt;## Sources to read (in parallel)&lt;/span&gt;
&lt;span class="p"&gt;1.&lt;/span&gt; &lt;span class="sb"&gt;`me/resume-engineering.md`&lt;/span&gt;
&lt;span class="p"&gt;2.&lt;/span&gt; &lt;span class="sb"&gt;`me/resume-pm.md`&lt;/span&gt;
&lt;span class="p"&gt;3.&lt;/span&gt; &lt;span class="sb"&gt;`me/resume-fde-presales.md`&lt;/span&gt; &lt;span class="ge"&gt;*(in progress, skip without erroring if missing)*&lt;/span&gt;
&lt;span class="p"&gt;4.&lt;/span&gt; &lt;span class="sb"&gt;`me/resume-peoplesoft.md`&lt;/span&gt; &lt;span class="ge"&gt;*(read only for PeopleSoft-flavored roles)*&lt;/span&gt;
&lt;span class="p"&gt;5.&lt;/span&gt; &lt;span class="sb"&gt;`me/profile.md`&lt;/span&gt;
&lt;span class="p"&gt;6.&lt;/span&gt; &lt;span class="sb"&gt;`me/skills-inventory.md`&lt;/span&gt;
&lt;span class="p"&gt;7.&lt;/span&gt; &lt;span class="sb"&gt;`me/job-search-filters.md`&lt;/span&gt;
&lt;span class="p"&gt;8.&lt;/span&gt; &lt;span class="sb"&gt;`me/preferences.md`&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  A scoring rubric, not a vibe
&lt;/h3&gt;

&lt;p&gt;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 &lt;em&gt;actually&lt;/em&gt; written for before scoring me against it, which keeps the scoring honest instead of grading on a curve.&lt;/p&gt;

&lt;p&gt;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.&lt;/p&gt;

&lt;h3&gt;
  
  
  Two lenses when a role is ambiguous
&lt;/h3&gt;

&lt;p&gt;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 &lt;strong&gt;twice&lt;/strong&gt;, 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.&lt;/p&gt;

&lt;h3&gt;
  
  
  Closing the loop
&lt;/h3&gt;

&lt;p&gt;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 &lt;code&gt;submit-queue.md&lt;/code&gt; file that feeds my next job-search work block. Nothing gets queued without an explicit yes.&lt;/p&gt;

&lt;h2&gt;
  
  
  Skill 2: &lt;code&gt;/resume-sharpener&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;This is the pattern-mining half. It runs in two phases.&lt;/p&gt;

&lt;h3&gt;
  
  
  Phase 1: analyze and draft
&lt;/h3&gt;

&lt;p&gt;It reads every file in &lt;code&gt;job-search/scored-listings/&lt;/code&gt; (by this point, 30+ files) alongside the four base resumes. Then it looks for two signals:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Bullets worth promoting:&lt;/strong&gt; 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.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Gaps worth addressing proactively:&lt;/strong&gt; a gap that shows up in 3+ listings and is actually addressable, not something structural like a missing degree.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;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).
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;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.&lt;/p&gt;

&lt;p&gt;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.&lt;/p&gt;

&lt;h3&gt;
  
  
  Phase 2: apply
&lt;/h3&gt;

&lt;p&gt;Only after I've reviewed the draft and say "apply resume improvements" does the skill edit the real &lt;code&gt;*.md&lt;/code&gt; 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.&lt;/p&gt;

&lt;h2&gt;
  
  
  Build your own version of &lt;code&gt;/score-job&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;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.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 1: How many "lenses" do you actually have?
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;/score-job&lt;/code&gt; works for me because I'm evaluating listings through &lt;strong&gt;four possible role lenses&lt;/strong&gt;: 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 &lt;em&gt;why&lt;/em&gt; 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.&lt;/p&gt;

&lt;p&gt;Before you build this, answer honestly:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Am I actually applying from more than one angle&lt;/strong&gt;, 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.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;If there is more than one angle, are they truly distinct&lt;/strong&gt; (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.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Do any two lenses ever compete for the same listing?&lt;/strong&gt; 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.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Step 2: What are your source-of-truth documents, and what format are they actually in?
&lt;/h3&gt;

&lt;p&gt;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.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Master resumes can be &lt;code&gt;.docx&lt;/code&gt;.&lt;/strong&gt; You don't need to hand-convert them to markdown first. Have the skill flatten each attached resume to a plain &lt;code&gt;.md&lt;/code&gt; file as a setup/ingestion step (Claude Code's docx skill can do this extraction), and treat the flattened &lt;code&gt;.md&lt;/code&gt; 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.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Your skills-inventory shouldn't be hand-maintained separately. Derive it from the resumes.&lt;/strong&gt; 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 &lt;strong&gt;union of every skill, tool, and competency mentioned across all your master resumes&lt;/strong&gt;, 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.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Export your LinkedIn profile as an additional comparison source.&lt;/strong&gt; 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.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Step 3: What's actually disqualifying vs. just undesirable?
&lt;/h3&gt;

&lt;p&gt;My &lt;code&gt;job-search-filters.md&lt;/code&gt; 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:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Hard filters:&lt;/strong&gt; 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.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Soft preferences:&lt;/strong&gt; things that lower enthusiasm but shouldn't zero out an otherwise strong match. These belong in the "Red Flags" section of the output, not the verdict logic.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Step 4: What does "done" look like for one scored listing?
&lt;/h3&gt;

&lt;p&gt;Decide your output contract before you write the skill, not after: one file per listing, a predictable filename pattern (I use &lt;code&gt;YYYY-MM-DD-{company}-{role}.md&lt;/code&gt;), and a fixed section structure every time. This is the detail that makes a second skill (like &lt;code&gt;/resume-sharpener&lt;/code&gt;) possible later. Consistent structure is what makes 30 files parseable as a dataset instead of 30 one-off documents. Even if you never build a second skill, future-you re-reading old scores will thank you for the consistency.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 5: Where's the line between "generate" and "act"?
&lt;/h3&gt;

&lt;p&gt;Decide up front which actions the skill takes automatically and which it always asks about. Mine: writing the scored file is automatic (low cost, easily deleted, no external effect); adding a row to a tracking spreadsheet or a submit queue always requires an explicit yes (it changes what I do next). If you're adapting this, sort your own downstream actions into "safe to automate" and "needs a yes" before you write the prompts. It's much easier to decide that in the abstract than to notice mid-skill that you just want it to stop and ask.&lt;/p&gt;

&lt;h2&gt;
  
  
  Build your own version of &lt;code&gt;/resume-sharpener&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;The promotion/gap thresholds are the most quotable part of this skill, but they're not the part that makes it safe to run. Here's the fuller set of decisions worth making deliberately before you build it.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 1: Decide the two phases are non-negotiable
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;/resume-sharpener&lt;/code&gt; never edits a resume file directly. Phase 1 only ever reads scored listings and base resumes and writes a &lt;em&gt;new&lt;/em&gt; draft document; Phase 2, the only phase that touches &lt;code&gt;*.md&lt;/code&gt; resume files, doesn't run until you've reviewed the draft and said so explicitly. This isn't a nice-to-have, it's the whole safety model for the skill: any automation that mines your own history and rewrites something you depend on (your resume, in this case) should have a proposal step you can reject, wholesale or line by line, before a single character changes. If you're adapting this pattern to a different "mine my history and update a source file" use case (reference docs, a portfolio site, an about-me page), keep this gate. Don't collapse it into one phase for convenience.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 2: Tune your thresholds to your own volume, not mine
&lt;/h3&gt;

&lt;p&gt;My thresholds, 2+ listings for a bullet, 3+ for a gap, are calibrated to scoring 30+ listings over a couple of months. If you're scoring 5 listings a week you'll hit those thresholds fast and get noisy, overfit suggestions; if you score rarely, you may never hit them and the skill will report nothing. Set your threshold as a function of your own pace: enough occurrences that a pattern is clearly not a one-off, but not so many that you're waiting months for signal. It's fine to start conservative and loosen it after the first run tells you whether you're getting too much or too little.&lt;/p&gt;

&lt;p&gt;Also decide explicitly what &lt;em&gt;doesn't&lt;/em&gt; count as a pattern. Mine excludes bullets that are too narrow to a single company or niche domain, because the goal is promoting things that generalize, not copy-pasting one great cover-letter line into a resume where it doesn't belong.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 3: Match the draft's structure to how many "lenses" you built in Step 1 of the scoring skill
&lt;/h3&gt;

&lt;p&gt;If you built &lt;code&gt;/score-job&lt;/code&gt; with a single resume, your draft document is one section. If you built it with multiple lenses (see the &lt;code&gt;/score-job&lt;/code&gt; walkthrough above), the sharpener's draft needs one section per resume/lens, &lt;em&gt;plus&lt;/em&gt; a cross-cutting section for anything that should be promoted into all of them at once. In my case, things like a skills narrative that's equally relevant whether I'm leading with the engineering resume or the PM resume. Skipping the cross-cutting section means you'll independently rediscover and re-approve the same improvement four times, once per resume.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 4: Decide where the draft lives, and build a fallback
&lt;/h3&gt;

&lt;p&gt;Writing the draft straight to a shared, human-reviewable surface (a Google Doc, not a file only Claude can open) matters more than which specific tool does it. I use the Google Drive MCP tools to create a Doc in a folder I already check regularly, precisely so reviewing it doesn't require opening a terminal. But that integration can fail (auth expiry, API limits, wrong folder), so the skill has an explicit fallback: write the same draft to a local markdown file and say so, rather than silently failing or, worse, skipping the review step and applying changes anyway. Whatever your equivalent of "Drive" is, build the same two things: a reviewable destination you'll actually look at, and a local fallback that never quietly turns into "run Phase 2 without a review."&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 5: Write the grounding rule down explicitly, twice
&lt;/h3&gt;

&lt;p&gt;"Don't invent changes" shows up in this skill in two places: once for what goes &lt;em&gt;into&lt;/em&gt; the draft (only patterns actually observed across real scored listings, no embellishing) and again for what Phase 2 is allowed to &lt;em&gt;apply&lt;/em&gt; (only what's in the approved draft, using its exact wording unless you specify a change). That repetition is intentional, not redundant copy. A skill that mines your own history for what to add to your resume is one summarization pass away from quietly fabricating a metric or overstating scope because it "sounds right." Say the constraint at both the generation step and the apply step. Don't assume stating it once at the top of the skill will hold all the way through.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 6: Close the loop back to the first skill
&lt;/h3&gt;

&lt;p&gt;The last line of my Phase 2 output is a reminder that &lt;code&gt;/score-job&lt;/code&gt; reads the resume files fresh every run, so the improvements it just applied take effect automatically next time you score a listing. That's a one-sentence addition, but it's what makes the two skills actually feel like a system instead of two disconnected tools. The person running them should never have to wonder whether skill A knows about what skill B just changed.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why split it into two skills instead of one
&lt;/h2&gt;

&lt;p&gt;I could have built this as a single skill with a mode flag, but keeping them separate turned out to matter:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Different cadence.&lt;/strong&gt; I score jobs constantly (several times a week); I sharpen the resume in batches, only once there's enough new scored data to find a real pattern.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Different blast radius.&lt;/strong&gt; Scoring a job only ever &lt;em&gt;writes a new file&lt;/em&gt;. Sharpening the resume &lt;em&gt;edits files I depend on for every future application&lt;/em&gt;, so it gets a review gate that scoring doesn't need.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Composability.&lt;/strong&gt; &lt;code&gt;/resume-sharpener&lt;/code&gt; is only useful because &lt;code&gt;/score-job&lt;/code&gt; has been quietly generating structured data in the background for weeks. Neither skill needed to know that in advance. The second one just reads a directory the first one populates.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That last point is the one I'd underline for anyone building their own skills: a skill that writes structured, dated, consistently-formatted output to a predictable location is doing double duty. It's useful the day you run it, and it's raw material for a second skill you haven't built yet.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I'd do differently
&lt;/h2&gt;

&lt;p&gt;If I were starting over, I'd design the scored-listing file format with the &lt;em&gt;sharpener&lt;/em&gt; skill in mind from day one, instead of retrofitting it after 20+ files already existed with slightly inconsistent section headers. A little bit of "future skill" thinking up front saves a parsing headache later.&lt;/p&gt;




&lt;p&gt;Both skills are just markdown files, no code, no API calls beyond what Claude Code already handles for file reads and web fetches. If you're job searching and already using Claude Code, the whole pattern (score consistently, then periodically mine your own scoring history for what you're missing) is worth stealing.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>careerdevelopment</category>
      <category>productivity</category>
      <category>automation</category>
    </item>
  </channel>
</rss>
