Install
$ agentstack add skill-aaddrick-slushpile-onboard ✓ scanned · ✓ verified, works with Claude Code, Cursor, and more.
Security review
✓ PassedNo issues found. Passed automated security review. · v0.1.0 How review works →
- ✓ Prompt-injection patterns
- ✓ Secret / credential exfiltration
- ✓ Dangerous shell & filesystem operations
- ✓ Untrusted network calls
- ✓ Known-malicious package signatures
What it can access
- ✓ Network access No
- ✓ Filesystem access No
- ✓ Shell / process execution No
- ✓ Environment & secrets No
- ✓ Dynamic code execution No
From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.
Verified badge
Passed review? Show it. Paste this badge into your README, it links to the public security report.
Reliability & compatibility
Declared compatibility
Compatibility is declared by the source manifest. End-to-end runtime verification is coming, see below.
We're building live execution health for every listing: tool-call success rate, median latency, uptime, and last-checked timestamps, measured, not self-reported. It isn't live yet, so we don't show numbers we can't stand behind.
How agent discovery & health will work →About
Onboard
Build the workspace every other slushpile skill reads from.
Nothing in this plugin hardcodes a fact about the user. The skills and agents read three files, and this skill writes them:
| File | What it holds | Who reads it | |---|---|---| | profile.md | Every factual claim about the user's career | Every skill. Nothing may be claimed that is not here. | | preferences.yaml | Constraints: compensation, relocation, authorization, targeting, voice agent | job-board-search, application-builder, status, the pool analyst and the contrarian | | stories.md | Four to eight tellable stories with scene, stakes, arc | application-builder |
A fourth input, the voice agent, is not written here — it is generated by a separate tool. See Phase 4.
Arguments:
$1— optional. A resume PDF, a LinkedIn data export, a directory of materials, or nothing. With nothing, run the interview from scratch.
Announce at start: "Setting up a slushpile workspace here. I'll read what you have, then ask about what's missing."
Before You Start
Check whether a workspace already exists. If profile.md or preferences.yaml is present, do not overwrite. Ask what the user wants: extend the existing profile, redo one file, or start fresh in a different directory. Silently clobbering a profile someone spent an hour building is the worst outcome available in this skill.
Confirm the working directory with the user before writing anything. This should be their own job-search repository, not a checkout of the slushpile plugin. Say so if it looks like the latter — a .claude-plugin/ directory next to you is the giveaway.
Every templates/... path in this file is relative to the plugin, not to the workspace. Those two are different directories by design, and the working directory is the workspace, so a bare templates/preferences.yaml resolves to nothing. Resolve them against the directory this skill file was itself loaded from — that works on every harness, where a harness-specific plugin-root variable does not.
Phase 1: Ingest
Read whatever the user has before asking them anything. An interview that opens by asking for information already sitting in a PDF on their disk reads as not having looked.
If $1 is a path, read it. Handle:
- PDF resume — extract with
pdftotext .pdf -. Ifpdftotextis missing, read the PDF directly. .tex/.docx/.mdresume — read directly. For.docx, trypandoc -t markdownand fall back to asking for a PDF or plain text.- LinkedIn export (a zip, or a directory of CSVs) —
Positions.csv,Education.csv,Skills.csv,Certifications.csv, andProfile.csvcarry almost everything. Note that LinkedIn exports date ranges as month/year, which is exactly the granularity the resume template wants. - A directory — read every resume, cover letter, and writing sample in it.
If $1 is empty, ask for one thing before the interview: an existing resume in any format. Ten minutes of interview gets replaced by thirty seconds of reading. If they have nothing, proceed to the interview and say it will take longer.
Mention the voice agent now, in one line, because it is a separate tool the user runs on their own time and everything else here can proceed while they do. See Phase 4.
Phase 2: Build profile.md
Copy templates/profile.md from the plugin directory as the structure. Fill it from the ingested materials, then interview for the gaps.
The profile is not a resume. It is the pool a resume gets cut from. Aim for something several times longer than the source resume. A thin profile produces generic applications, and the failure is invisible until the fourth cover letter comes out sounding like the first three.
What to extract without asking
- Every role: title, employer, dates, location
- Every technology, tool, and method named
- Every number: budgets, headcount, percentages, volumes, dates
- Education, certifications, licences
- Public work: repositories, talks, writing, patents
What to interview for
Work through these. Ask in batches of two or three, not one at a time, and not all at once.
Per role, for the last three roles:
- Context. What was the company doing, how big was it, what state was it in when you arrived? A reader who has never heard of the employer cannot size anything without this.
- Scope. Budget, headcount, systems, geography, revenue touched. Numbers.
- What you personally decided, as distinct from what your team did. This is the difference that separates a senior resume from a mid-level one, and resumes almost never capture it.
- Baselines for every metric. "Reduced X by 40%" is unusable until you know 40% of what. Go back through every number found in Phase 1 and get its before-state.
- What went wrong. The most useful answer in the entire interview. Interviewers ask, and it is where the good stories are.
Across the whole career:
- Skill depth, honestly. For each significant skill: built it, ran it in production, used it once, or read about it. Push back gently on inflation here — the requirements analyst checks Skills entries against the work history and flags anything unsupported, so an inflated claim gets caught in-pipeline rather than in an interview. That is the system working, but it is cheaper to be honest now.
- Public work with real numbers. Stars, downloads, contributors, audience size, traffic. Verifiable evidence is disproportionately valuable in a stretch application because a stranger can check it in thirty seconds without calling a reference.
- Gaps. What is genuinely missing from their background for the roles they want. Ask directly. Recorded gaps never go into a cover letter — the pipeline does not volunteer weaknesses to employers — they exist so the fit scoring is honest.
Numbers table
Fill the "Numbers You Can Defend" table with every metric, its as-of date, and where it came from. The application builder cross-checks the resume and cover letter against this table. A figure that appears as 2,400 in one document and 2,707 in the other reads as carelessness, and a fatigued reader who catches one inconsistency starts looking for others.
Push on the provenance column specifically. For each number, ask where it lives: which deck, report, dashboard, repository, or commit. "Internal reporting" is not an answer and neither is "I remember it." The review pipeline will push these numbers into the most prominent positions in the resume and the letter, and a number in a prominent position is one an interviewer asks a follow-up question about.
Most of the artifacts belong to a former employer and cannot be copied into the workspace. That is fine — a path to a local file or a description precise enough to find it again does the job. This is an index, not an archive.
Where the user cannot attribute a number, mark it UNVERIFIED rather than dropping it or letting it pass unmarked. It stays usable, the builder knows it is soft, and the user has a list of what to go find before an interview. Numbers with no marking are treated as defensible.
Phase 3: Build preferences.yaml
Copy templates/preferences.yaml and fill it by interview. Every field has a comment explaining what it does — read them to the user in your own words rather than asking them to read YAML.
Handle these four carefully, because they are where a wrong default does the most damage.
Compensation method
Two real options.
nominal — one floor number. Simple, and wrong across metros: $180k in Austin and $180k in San Francisco are not the same offer.
net_qol — after-tax, after-housing surplus, compared against what they have now. Survives geography. Needs three inputs: their current after-tax-after-housing annual surplus, the minimum improvement worth moving for, and a health-insurance adjustment if they are moving between countries.
Recommend net_qol if they are looking across more than one metro or across a border. Recommend nominal otherwise. Do not make them compute the baseline in their head — ask for gross, tax, and housing, and do the arithmetic yourself.
Clearance and degree
Default both hard_blocker fields to false, and say why: postings routinely list a clearance or a degree that the hiring manager does not enforce, and treating them as blockers silently removes roles the user would have gotten. They are recorded as risk factors instead, surfaced in the role analysis, and handled in the interview if raised.
Set true only if the user has specific evidence for their field.
Relocation
Ask about the homecoming corridor explicitly, because people rarely volunteer it: is there a place they would take less money to reach? Family, partner's job, a city they left. It relaxes the compensation gate and it changes which roles surface.
Claimed differentiators
Ask what they think makes them unusual. Record it verbatim, without editorializing.
Then warn them once, plainly: the pool analyst tests each of these against the realistic applicant pool and will say so when one is median rather than rare. That is the most valuable output in the pipeline and the most uncomfortable. Better they hear it now than read it as a surprise in their first role analysis.
Leave calibration_priors empty
Do not fill it and do not ask about it. It holds observed conversion rates from the user's own resolved applications, and at onboarding there are none. /slushpile:status writes it once five applications have resolved.
Say one sentence about it, because it is the answer to a question they will have later: until it has data, every probability the pipeline produces is an estimate from company-type priors rather than from their record, and the pipeline says so each time. It gets better once they have applied to things and the outcomes come back.
Phase 4: Point the User at a Voice Agent
Cover letters are written by a voice agent — an agent that writes in one specific person's style, built from a corpus of their own writing.
slushpile ships aaddrick-voice as a working example so the pipeline runs out of the box. It is the plugin author's voice, not the user's. Letters written with it will sound like a specific stranger. Fine for testing the pipeline. Wrong for actually applying.
Do not try to build a voice profile yourself here. Generating one properly means measuring a corpus across a couple of dozen dimensions, and an ad-hoc version produced from a handful of samples in the middle of an onboarding interview lands somewhere near the model's default — which is exactly the thing a fatigued reader is trained to bin. A bad voice profile is worse than a labelled placeholder, because the user believes it.
What to tell them
Give them this, briefly:
> Your cover letters need a voice agent built from your own writing. There is a separate tool for it: https://github.com/aaddrick/written-voice-replication > > Clone it, open it in Claude Code, drop your writing samples in the project root, and tell Claude to run the pipeline orchestrator. It outputs a voice agent. Put that agent's name in preferences.yaml under voice.agent and set voice.is_mine: true. > > Until then the pipeline uses a shipped example voice that is not yours.
What makes a usable corpus
Say this now even though they will run the tool later, because gathering the corpus is the slow part and they can start while the rest of onboarding continues.
Good. Forum and Reddit posts, blog posts, long Slack or Discord messages, emails to colleagues, pull request descriptions, documentation they wrote alone, personal essays. A Reddit or Twitter data export works directly.
Bad. Anything co-written, anything edited by someone else, anything already run through an LLM, anything in an institutional voice. Marketing copy and performance reviews are the two worst — both are written in a house style rather than the person's own.
Enough of it. Several thousand words minimum. Below that the analysis converges on a generic professional voice regardless of who wrote the samples.
Record the state
Set voice.agent and voice.is_mine in preferences.yaml. Leave is_mine: false unless they have already generated their own. Every skill that drafts prose reads that flag and warns before running with a borrowed voice, which is the only thing preventing someone from submitting twelve applications in a stranger's voice without noticing.
Phase 5: Build stories.md
Copy templates/stories.md. Interview for four to eight stories.
Start from the "what went wrong" answers in Phase 2 — that is where they are. Then ask directly:
- The hardest thing you have shipped, and what nearly stopped it
- A time the plan was wrong and you had to change it in public
- Something you built that people still use
- A crisis you owned end to end
- A time you were the only person who could see the problem
- A decision you made that you would defend today against someone senior to you
For each, get the four elements: scene, complication, what they personally did, resolution with numbers. Push for the scene specifically. Most people give a summary and skip the moment, and the moment is what a reader remembers.
Then ask for the line that lands: if a tired reader remembered one sentence from this story, which is it? Cover letters get built around these.
Aim for four minimum. With fewer, every letter reuses the same story, which is fine right up until two applications go to the same company.
Phase 6: Scaffold the Workspace
Create the directory structure:
applications/ # one folder per role, created by job-board-search
job_search.md # from templates/job_search.md
companies.md # from templates/companies.md
profile.md
preferences.yaml
stories.md
Write job_search.md and companies.md from their templates, with the "Constraints" and "Current Posture" sections filled from preferences.yaml.
Do not copy resume.tex or cover_letter.tex into the workspace here. /slushpile:application-builder copies them per role, into that role's folder, because they are per-application documents and a pristine copy at the workspace root turns into a stale one the moment the first application diverges from it.
Check the document toolchain
templates/resume.tex and templates/cover_letter.tex build under XeLaTeX. Check for it now rather than at 11pm during the first application, when the user is trying to submit something and hits a missing binary instead.
command -v xelatex latexmk pdftotext
Report all three, present and absent both.
pdftotext (from poppler-utils) is the one that actually matters to the pipeline. The review agents read extracted text, because extracted text is what an ATS sees. Without it the reviews run against the source instead, which is a different document than the one the employer parses.
xelatex and latexmk are optional, and say so in those words. Every skill here works on extracted text and none of them require .tex — only the two templates do. A user who would rather write in Markdown loses the templates and nothing else.
If anything is missing, offer the install line for their platform and let them decide. Do not install it for them: this runs inside their own repository, and a skill that installs system packages unasked is doing something the user did not authorize.
sudo dnf install -y poppler-utils texlive-xetex texlive-fontspec texlive-microtype latexmk # Fedora
sudo apt install poppler-utils texlive-xetex texlive-fonts-extra latexmk # Debian, Ubuntu
brew install poppler && brew install --cask mactex-no-gui # macOS
The templates' house fonts, Public Sans and IBM Plex Mono, are a separate question and a smaller one. They ship vendored with the plugin, so installing them is one comma
…
Source & license
This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.
- Author: aaddrick
- Source: aaddrick/slushpile
- License: MIT
- Homepage: https://github.com/aaddrick/slushpile#readme
Install and usage instructions live in the source repository linked above.
Reviews
No reviews yet, be the first.
Write a review
Versions
- v0.1.0 Imported from the upstream source.