build-profile
Build or update the JobClaw master profile — the single file every other job-hunt skill reads. Ingests a resume (extracting every embedded URL), LinkedIn PDF, exported AI-memory, and links, then asks only for what's missing in one batched, optional gap prompt. Captures career-goal context for downstream skills.
- License 许可
- MIT
- 最近更新
- 2026-06-09
- Stars
- ★ 7
- Forks
- 1
01 前言 Front Matter
- name
- build-profile
- description
- Build or update the JobClaw master profile — the single file every other job-hunt skill reads. Ingests a resume (extracting every embedded URL), LinkedIn PDF, exported AI-memory, and links, then asks only for what's missing in one batched, optional gap prompt. Captures career-goal context for downstream skills.
- when_to_use
- Use at the start of a job hunt, when onboarding a new user, when the user shares a resume/CV/LinkedIn export, or whenever profile/master-profile.md is missing or stale.
- allowed-tools
- Read, WebFetch, WebSearch, Write, Edit, Bash, mcp__playwright__browser_navigate, mcp__playwright__browser_snapshot
- user-invocable
- true
02 资源文件 3
- 参考文档reference/profile-schema.md5.5 KB
- 参考文档reference/track-presets.md7.8 KB
- 脚本scripts/extract_links.py9.1 KB
03 SKILL.md 正文
build-profile
Produce profile/master-profile.md from whatever the user already has, then fill gaps with a short, track-aware interview. Ingest first, ask last.
1. Gather what exists (don't ask the user to retype anything)
Collect any of these the user provides; actively offer the options:
- Resume / CV — see step 1a for PDFs (mandatory link-extractor first), then read the body with your runtime's file-read tool.
- LinkedIn PDF — read it. (Point them to LinkedIn → profile → Resources → Save to PDF if they don't have it.)
- AI-memory (proactively offer it). Ask once: "Have you used ChatGPT, Claude, or Gemini for your job search or career? Paste this prompt into the one you use most and bring back the result — I'll fold in recent interviews, feedback, and career details you'd otherwise have to retype." Then surface the prompt from
../../profile/IMPORT_MEMORIES_PROMPT.md(it pulls only job-search-relevant memories, not everything). On ingest, merge only new facts — never duplicate what the resume/profile already has; mark uncertain items[VERIFY]. - Links — record every link, then enrich the user's own ones (see §1b). LinkedIn stays record-only (ToS).
Read everything before asking anything.
1a. For every PDF input — run the link extractor FIRST
A typical agent file-read tool surfaces visible anchor text only (it shows the word "LinkedIn" but not the URL it's hyperlinked to). LaTeX/Word/Docs resumes routinely embed \href{url}{anchor} annotations whose URLs are invisible to a plain read. You will silently lose the user's LinkedIn / GitHub / portfolio URLs if you skip this step — which is why extract_links.py exists.
python3 skills/build-profile/scripts/extract_links.py <path-to-resume.pdf>
The script decompresses every FlateDecode stream and pulls every /URI annotation it can find. Stdout is JSON:
{
"urls": ["https://...", ...], // every URL found, in order
"classified": {
"linkedin": "https://linkedin.com/in/...",
"github": "https://github.com/...",
"other": { "<host-or-label>": "<url>", ... }
}
}
The script also returns a status field — branch on it:
ok→ use theclassifiedmap directly to populatelinks:(canonical keys land in their named fields; unknowns land inlinks.other). Surface anylinks.otherentries with one short question — "I found these other URLs in your resume: <list>. Keep any as portfolio links?" — so project pages (e.g. lambdatest.com/visual-ai-testing) can be promoted toportfolioif relevant.encrypted/scanned_image/unreadable→ the script never crashes (exit 0). When status is one of these and the file-read tool also returns little/no body text, the PDF is unusable: tell the user what's wrong (use the script'snote) and offer the fallback ladder — (a) paste the resume text, (b) supply a.txt/.md/.docxversion, or (c) re-export from LinkedIn (profile → Resources → Save to PDF). Explicitly warn that embedded links are lost on scanned/encrypted PDFs and ask them to paste their LinkedIn / GitHub / portfolio URLs manually.
After the extractor, use your runtime's file-read tool for body text. For non-PDF inputs (markdown, pasted text,
LinkedIn URLs), scan the text directly with regex for any https?://… matches.
1b. Enrich the user's own links (don't just record URLs)
A portfolio or personal site usually holds proof points the resume omits (projects, metrics, roles, skills). Mine the user's own links — portfolio, personal site, project pages, and GitHub beyond the API — with a graceful fallback ladder. Skip LinkedIn (record-only, ToS). Cap at the few most relevant links so onboarding stays fast.
For each link, stop at the first tier that yields usable content:
- GitHub →
WebFetch https://api.github.com/users/<user>+/repos?sort=stars(top repos, languages, bio). No key. WebFetchthe page → extract real proof points from the readable HTML.WebSearch(when WebFetch returns an SPA shell / thin content) → search the person + domain/handle for indexed content (project write-ups, talks, press).- Playwright MCP (only if the session exposes it — optional, not required) →
mcp__playwright__browser_navigatethenmcp__playwright__browser_snapshotto render a JS-only page and read it. If Playwright isn't available, skip it and ask the user to paste a few highlights instead.
Rules: ingest only new facts not already in the resume/profile (no duplication); mark anything
inferred (not explicitly stated by the user) as [VERIFY]; never fabricate. Summarize what you
learned back to the user in one line per link ("Your portfolio shows X, Y — added as projects").
2. Know the track and region
- Track (ask if unclear):
product · software · finance · quant · marketing · founders-office · hr · design · data · sales · operations · customer-success · content. Decides which fields matter and which links to push for — see reference/track-presets.md. - Region: infer the applicant's
regionusing this ladder, stopping at the first that resolves:- Location string → region code (
New York→US,Bengaluru→IN). - Contact clues if location is missing/ambiguous (e.g. "Remote") → a
+91phone or₹/CTC/LPA mentions →IN; a+1phone or$/state abbreviations →US. target.regionsif already known from the conversation.- Otherwise ask one short question: "Which country are you based in, and where are you hunting?"
Codes must match a pack in
../../knowledge/regions/. Never silently default to US. When region was inferred from weak signals (clues, not an explicit location), write it as[VERIFY]so downstream skills treat it as soft. Then confirm where they're hunting (target.regions). The chosen pack dictates which region-specific fields to collect (IN → current/expected CTC + notice period; US → work authorization per../../knowledge/work-authorization.md) and what to omit (e.g., don't collect photo/DOB).
- Location string → region code (
3. Ask only for gaps
Compare what you extracted against reference/profile-schema.md. Then ask a short, batched set of questions for only the missing or [VERIFY] fields, prioritizing the track's must-haves, the region's required fields (per the region pack), and anything find-jobs/score-fit need (target roles, locations, remote preference, salary floor; work authorization for US; current/expected CTC + notice period for IN). Don't interrogate — 5–8 crisp questions max, grouped, with sensible defaults offered.
3a. The single optional links-gap prompt
After populating links: from extraction, run one track-aware optional prompt to surface what the resume didn't include. Use the link gap matrix in reference/track-presets.md to decide what to suggest.
Shape:
"I found these links: <list of canonical keys filled>. For <track> roles, candidates also commonly include: <strongly + optional gaps from the matrix>. Want to add any? (Paste or skip.)"
One prompt. Dismissible. No follow-ups. The user can paste any handle/URL or skip entirely.
3b. Two closing context prompts
The context: block is read by find-jobs, score-fit, and tailor-resume to bias direction — never rendered into a PDF or external message. Ask once:
- "In 2–3 sentences, what are you actually optimizing for over the next 12–24 months?" →
context.career_goal(≤ 600 chars). - "Anything else I should know that won't go on the resume — geo constraints, life situation, things to avoid?" →
context.additional_info(≤ 400 chars). Skip if the conversation already covered it; record what surfaced.
Both fields are optional but high-value.
3c. The single optional proof-point gap prompt
Gaps aren't just blank fields — the highest-value gap is evidence a strong candidate for this target would show but the resume doesn't. Compute the expected proof points for the user's target.tracks (+ AI archetype if applicable) from the "Proof-point coverage" section of reference/track-presets.md (which points at the archetype proof points in ../../knowledge/ai-roles.md for AI tracks). Check coverage against the extracted Experience/Projects/Achievements, then ask one target-framed prompt:
"Strong <target track/archetype> candidates usually show <X / Y / Z>. From your resume I can see <X>; I don't see <Y, Z> — anything to add there? (Paste or skip.)"
This is the fix for the case where a missing portfolio/case-study (marketing) or eval/LLMOps evidence (AI Platform) is the candidate's #1 gap for their target, not a generic blank. Frame it by the target, never invent the evidence. One prompt. Dismissible. No follow-ups. Shares the relevance vocabulary in ../../knowledge/relevance.md.
4. Write the profile
Write profile/master-profile.md following reference/profile-schema.md exactly (YAML frontmatter + markdown sections). Rules:
- Never fabricate. If a fact is unknown, leave the field empty / omit it; mark anything uncertain inline as
[VERIFY]. - Quantify achievements where the source gives numbers; don't invent metrics.
- Capture the user's voice/constraints in the Notes section (tone, hard limits like no-relocation, sponsorship needs) — downstream skills rely on it.
- Populate every link the extractor found (canonical keys to their named fields; everything else under
links.other). Keep unfamiliar URLs even if you can't classify them. - If the file already exists, update in place (preserve user edits; only fill/correct).
5. Confirm
Show a tight summary (identity, target, # roles captured, # links captured, gaps still [VERIFY]) and tell the user they can now run /find-jobs. Keep tone encouraging and concise — no emoji.
Heads-up on setup (mention once, now). Run python3 scripts/doctor.py to check dependencies. Everything works with no install except producing resume PDFs, which needs rendercv (a one-time install: python3 -m venv skills/render-resume/.venv && skills/render-resume/.venv/bin/pip install "rendercv[full]"). Flag this here so it's installed before the user reaches /tailor-resume, not mid-render. (API keys are all optional; doctor lists which strengthen find-jobs/research.)
Next steps
Profile saved. Next: /find-jobs to pull matching roles — or /apply-to-job <url> to evaluate one specific job end-to-end.
04 同仓库更多 Skills
write-outreach
Write a short, profile-grounded cold outreach message to a recruiter, hiring manager, or potential referrer — LinkedIn DM or email — with one clear CTA and no flattery.
write-cover-letter
Produce a job-specific, profile-grounded cover letter in markdown — ≤ 350 words, ≤ 1 page, three paragraphs (hook → two quantified proofs → fit close). Reuses keywords from a prior tailor-resume sidecar when present. Writes a JSON sidecar reserved for a future /render-resume --kind cover-letter (rendercv).
triage-inbox
Classify a recruiting email (or a batch) into one of the 10 canonical email classes, extract structured fields (company / role / dates / links / asks / deadline / sentiment), and suggest the next action. Writes inbox/triage-<YYYY-MM-DD>.json — consumed by infer-status and draft-reply.
tailor-resume
Produce a job-specific, ATS-optimized resume from the user's master profile and a target job — reordering, reframing, and surfacing the most relevant real experience and keywords. Enforces a content rubric (bullet shape, length, parallel grammar, metric coverage), then renders a polished PDF by default (via render-resume) and visually QAs it. Never fabricates.
score-fit
Score how well the user's master profile fits a specific job — an ATS-style match percentage with matched/missing keywords, strengths, gaps, and a clear apply-or-skip recommendation. Optionally writes a structured sidecar that tailor-resume consumes.
review-render
Visually QA a rendered resume PDF and auto-fix layout/content defects in a bounded loop: render → screenshot → deterministic gate → vision rubric → apply one fix → re-render, until it passes or hits a pass cap. Catches widows, under-fill, overflow, orphaned headers, and imbalance that text-only logic can't see.