| name | onboarding |
| description | Set up your personalized career-manager pipeline. Reads your resume, asks 1 question, then generates all config files so the pipeline is ready to run. Use when first setting up the pipeline or when your career goals change. |
Onboarding
Personalize the career-manager pipeline for a new user through a focused setup.
When to Use
- First time setting up the pipeline after cloning
- Career goals, target roles, or compensation targets have changed
- Want to regenerate search queries or scoring criteria
Flow
Step 0: Ensure Local Python Environment
Before reading the resume or generating files, create a repo-local virtual environment if one doesn't already exist:
uv venv
uv pip install -r requirements.txt
Run all subsequent Python commands through uv run (e.g., uv run python3 scripts/smoke_test.py) so dependencies resolve against the repo-local .venv and never install into a global Python, Conda, or system environment.
Step 1: Get the Resume
Ask: "Where's your resume? Give me the file path (e.g., ~/Desktop/resume.docx)"
When the user provides a path:
- Verify the file exists and is
.docx or .pdf
- Copy it to
cv-tailor/data/CV/Master CV/ (create directory if needed)
- Read the resume and extract: work history, skills, industries, seniority, education, accomplishments
If the file doesn't exist or isn't a supported format, ask again with guidance.
Do NOT ask the user to copy files manually. You handle the copy.
Step 2: One Question
Ask this single combined question:
"Based on your resume, I can see your background. I need four things your resume doesn't tell me:
- Target roles - What roles are you going after? Be specific about seniority (Senior PM, Director of Engineering, Solutions Architect) and domain.
- Salary floor - What's the minimum base salary you'd accept?
- Location - Remote, hybrid, or onsite? Open to relocation?
- Job markets - Which countries should I search for jobs in? (Default: United States)"
Step 3: Confirm Profile
Present the full profile combining resume inference + user answers:
"Here's your profile:
Background: [inferred from resume - key roles, industries, years of experience, strongest skills]
Target roles: [from answer]
Salary floor: [from answer]
Location: [from answer]
Career paths I'd search:
Derive paths in two phases:
- From resume: For each sector or employer type the user spent 2+ years in, derive a career path. Group similar employers (e.g., multiple Big 4 firms = one "Professional Services / Advisory" path, not four). If no employer meets the 2-year threshold, use the user's longest-tenured roles regardless.
- From targets: Add paths from the user's stated target roles that aren't already covered by Phase 1.
Merge only paths that are truly redundant (same companies, same roles). Prefer granular paths over merged ones. When in doubt, keep them separate. List Phase 1 paths first (longest tenure first), then Phase 2 paths. Final count: 5-8 paths.
Anything you'd change?"
Wait for confirmation. If the user tweaks anything, update and re-confirm.
Step 4: Generate Files
After confirmation, generate all files silently. No overwrite warnings. No "about to write..." messages. Just write them.
IMPORTANT: Before writing each file, read the existing file first (Write tool requirement). Do this silently. Do NOT tell the user you're reading before writing. Do NOT warn about overwriting.
Never touch pipeline data files (target-companies.csv, applications.csv, etc.).
File 1: config.yaml
Generate from config.yaml.example template with:
paths.cv_base set to the directory where the user's resume was found (parent of the file they provided)
- All integrations set to
false
- Email fields left as placeholders
File 2: job-search/references/criteria.md
Generate with this structure. The rubric must be CALIBRATED (tight, evidence-based) rather than loose; a well-calibrated rubric produces a spread of scores, not a cluster at the top. The average company the user's agents encounter should score around 50, not 70.
## Unique Value Proposition
[2-3 paragraphs: what makes this person uniquely valuable]
## Target Roles
[Role categories with descriptions]
## Target Company Types
[5-8 career paths. Each path has:]
### Path N: [Path Name]
- **Description:** [What kind of companies]
- **Example Companies:** [2-3 well-known examples for context, not monitored]
- **Role Types:** [Specific roles that fit]
- **Why You Fit:** [Connection to background]
- **Compensation Notes:** [Range based on salary floor]
## Evaluation Framework
10 scoring dimensions, each scored 0-10. Total score = sum (0-100).
### Group 1: Core Fit (4 dimensions)
### Group 2: Compensation & Career (3 dimensions)
### Group 3: Culture & Growth (3 dimensions)
For EACH dimension you generate, produce:
- **Name** and 1-line purpose.
- **Score anchors** for 0, 3, 5, 7, 9 — each anchor is a concrete observable example, not an adjective. "Score 9 = public Levels.fyi data showing $200K+ TC at this level" is good. "Score 9 = very high comp" is bad.
- **Evidence required for 7+.** Named source (job posting, employee review, funding announcement, public statement, etc.). If evidence is unavailable, score 5 or below — not 7+ by default.
- **Default when unknown:** 5 (middle-of-band neutral), not 7.
Emphasize in the rubric itself: "If you cannot find specific evidence, default to 5 rather than assuming the best case. A company without disclosed comp is a 5, not a 9."
## Scoring Guide
Thresholds align with `pipeline.action_list.*_min_score` in `config.yaml`:
- **85-100 (HIGH):** Pursue aggressively. Cold outreach or immediate apply.
- **70-84 (MED):** Strong fit with current evidence — apply if role is open.
- **60-69 (LOW):** Moderate fit. Watch list or skip unless specific role matches.
- **<60:** Skip.
**Handling unknowns:** If fewer than 5 of 10 dimensions are assessable, set `llm_flags: "needs_research"` and omit the score. Otherwise, unknown dimensions default to 5, not the top of the scale.
**Distributional check:** When this rubric is applied to the user's existing target list, expect roughly:
- ~20% score ≥85 (genuine A-tier)
- ~30% score 70-84 (B-tier, apply-worthy)
- ~35% score 60-69 (C-tier, watch)
- ~15% score <60 (skip)
If the distribution is heavily skewed high, the rubric is too loose — tighten anchors.
File 3: job-search/references/background-context.md
Generate with this structure:
## Personal Information
## Technical Capabilities
## Project Portfolio
## Professional Experience
## Education & Certifications
## Positioning Angles
## Travel & Location Preferences
File 4: job-search/data/search-config.json
Generate valid JSON matching this exact structure. Pay close attention to types. query_packs and path_check_instructions are dicts, not lists.
{
"search_locations": ["United States"],
"query_packs": {
"<snake_case_path_key>": {
"label": "Human-Readable Path Name",
"queries": ["search query 1", "search query 2", "..."],
"locations": ["Remote", "United States"],
"job_type": "fulltime"
}
},
"role_include_patterns": ["regex_pattern", "..."],
"role_exclude_patterns": ["regex_pattern", "..."],
"employer_exclude_patterns": ["regex_pattern", "..."],
"location_exclude_patterns": ["regex_pattern", "..."],
"keywords": {
"domain": ["keyword", "..."],
"ai": ["keyword", "..."],
"tech": ["keyword", "..."]
},
"path_check_instructions": {
"1": "Multi-sentence discovery strategy for path 1...",
"2": "Multi-sentence discovery strategy for path 2..."
},
"role_patterns": ["human-readable role title", "..."],
"scoring": {
"domain_keywords": {"keyword": 8},
"ai_keywords": {"keyword": 6},
"role_keywords": {"keyword": 7},
"comp_indicators": {"keyword": 5},
"growth_indicators": {"keyword": 4}
},
"path_aliases": {
"fuzzy variant": "Exact Query Pack Label",
"another variant": "Exact Query Pack Label"
},
"display_groups": {
"Group Name": ["Query Pack Label 1", "Query Pack Label 2"],
"Another Group": ["Query Pack Label 3"]
}
}
Critical rules:
query_packs is a dict keyed by snake_case name, NOT a list. Each value has label, queries, locations, job_type
path_check_instructions is a dict keyed by path number as string ("1", "2", etc.), NOT a single string
- One query pack per career path (for JobSpy)
- All regex patterns must be valid Python regex, no inline flags like
(?i)
- Minimum: 5 paths, 3+ queries per pack
display_groups groups related query pack labels into 3-4 dashboard display categories. Each label must match a query pack's label field exactly. Paths not mapped go to "Other"
Search locations:
search_locations is the user's answer to "Which countries should I search for jobs in?"
- Default:
["United States"] if the user doesn't specify
- If user says "Europe", expand to specific countries: Ireland, United Kingdom, Germany, Netherlands, France
- Populate each query pack's
locations field from search_locations (plus "Remote")
- Auto-generate
location_exclude_patterns to exclude countries NOT in search_locations. Do not add exclude patterns for countries the user wants to search in.
Scoring keywords: Each scoring dict maps keyword strings to integer weights. Higher weights = stronger signal for that category. Generate weights based on how central each term is to the user's target roles.
Path aliases: Map fuzzy LLM path variants to canonical query_pack labels. The LLM sometimes returns shortened or rephrased path names during evaluation. This map catches common variants so they normalize correctly. Generate 3-5 aliases per career path based on likely LLM rephrasings. Keys are lowercase variants, values are exact query_pack labels.
Path check instructions: Generate 3-4 sentence discovery strategies per path. Each instruction must include:
- What signals indicate a good fit for this path
- What to look for on careers pages
- What disqualifies a company
- Location requirements (reference
search_locations)
See onboarding/references/example-output.md for a complete working example.
Step 5: Verify Setup
Run smoke test checks inline (do not ask the user to run a separate command):
- Verify all 4 generated files exist and are non-empty
- Run
uv run python3 scripts/smoke_test.py and verify all checks pass (this validates search-config schema, query_packs is a dict, path_check_instructions is a dict, dependencies, and config.yaml)
If all checks pass: "Setup complete."
If any check fails: report the specific issue and fix it.
Step 6: Start First Search
Automatically hand off to the job-search skill and run the full pipeline. Do not ask the user for confirmation — they just completed setup, so the next step is always discovery.
Re-run Behavior
If the user has already run onboarding (files exist):
- Ask: "You already have a profile set up. What's changed?"
- Only regenerate files that need updating
- Never touch pipeline data (target-companies.csv, applications.csv)
Boundaries
- This skill generates config files only. It does not run the pipeline.
- It does not modify pipeline scripts.
- It does not create or modify the Master CV content. It only copies the user's file.