Help us improve
Share bugs, ideas, or general feedback.
From career-navigator
Surfaces follow-up priorities across active job applications using company-specific response window data. Classifies each application as within window, approaching, overdue, or critical.
npx claudepluginhub tmargolis/career-navigator --plugin career-navigatorHow this skill is triggered — by the user, by Claude, or both
Slash command
/career-navigator:follow-upThe summary Claude sees in its skill listing — used to decide when to auto-load this skill
Surface follow-up priorities for all active applications using company-specific response window data.
Logs or updates job application records in tracker.json with full conversational tracking: stage history, contacts, interviews, offers, outcomes, and follow-ups.
Tracks interview stages, collected and missing feedback, next steps, owners, and stalls for active candidates across open roles from recruiting email threads.
View, filter by status/company, update progress, and view statistics on job applications stored in data/applications.md. Handles show tracker, updates, stats, and delete requests.
Share bugs, ideas, or general feedback.
Surface follow-up priorities for all active applications using company-specific response window data.
| File | Purpose |
|---|---|
{user_dir}/CareerNavigator/tracker.json | Active applications with stage history and dates |
{user_dir}/CareerNavigator/company-windows.json | Per-user company response window data, researched on demand |
{user_dir}/CareerNavigator/profile.md | Target companies, industries, and role context |
Read tracker.json. Collect all applications where status is not accepted, rejected, withdrew, or ghosted. These are the applications that need follow-up tracking.
For each active application, extract: company, role, date_applied, status, stage_history (most recent entry date), follow_up_date, contacts.
Read {user_dir}/CareerNavigator/company-windows.json. If it does not exist, initialize it:
{
"meta": {
"created": "{today}",
"version": "1.0",
"description": "Company-specific hiring response windows for {user's name} — researched from public sources and stored per session"
},
"companies": {},
"size_tier_fallbacks": {
"startup": {
"typical_first_response_days": { "min": 3, "max": 14 },
"follow_up_after_days": 10,
"notes": "Startups move fast; silence beyond 2 weeks usually means no."
},
"mid_market": {
"typical_first_response_days": { "min": 7, "max": 21 },
"follow_up_after_days": 14,
"notes": "Mid-market timelines vary; a single polite follow-up at 2 weeks is standard."
},
"enterprise": {
"typical_first_response_days": { "min": 14, "max": 42 },
"follow_up_after_days": 21,
"notes": "Large companies have multi-layer review queues; 3–6 weeks before initial screen is normal."
}
}
}
For each active application's company that is not already present in company-windows.json.companies, research it now.
Research method:
Use web search to find candidate-reported hiring timelines for this specific company and role level. Search for:
"{company name}" hiring process response time site:glassdoor.com"{company name}" recruiter response time PM OR director site:linkedin.com"{company name}" interview process how long Blind OR RedditFrom the results, extract:
Store the result in company-windows.json:
"Anthropic": {
"researched_at": "{today}",
"typical_first_response_days": { "min": 14, "max": 35 },
"follow_up_after_days": 21,
"size_tier": "startup",
"process_notes": "Uses Greenhouse. High application volume for PM/research roles. Recruiter screen typically 3–5 weeks. Structured multi-round process. Following up via Greenhouse portal or LinkedIn is appropriate at 3 weeks.",
"sources": ["Glassdoor reviews", "LinkedIn recruiter posts", "Blind threads"]
}
If web search returns insufficient data for a specific company, fall back to the matching size_tier_fallbacks entry and note it:
"Acme Corp": {
"researched_at": "{today}",
"typical_first_response_days": null,
"follow_up_after_days": 14,
"size_tier": "mid_market",
"process_notes": "No company-specific data found — using mid-market defaults.",
"sources": ["size_tier_fallback"]
}
Write the updated company-windows.json before proceeding.
For each active application, calculate:
days_elapsed = today − date_appliedlast_activity = date of the most recent stage_history entrydays_since_activity = today − last_activitywindow_max = company-windows.json → typical_first_response_days.max for this companyClassify:
| Status | Condition |
|---|---|
within_window | days_elapsed ≤ window_max |
approaching | days_elapsed > 75% of window_max and ≤ window_max |
overdue | days_elapsed > window_max and ≤ 1.5× window_max |
critical | days_elapsed > 1.5× window_max |
Applications at phone_screen or interview stage use days_since_activity for the overdue check rather than days_elapsed from application — these have a shorter expected cadence (typically 3–7 days between touches).
For any application with a stage_history entry where stage contains "interview" and the entry date is within the last 7 days, check whether a thank-you note has been logged (look for a notes entry with "thank-you" or "thank you" or "follow-up" after the interview date). If not:
thank_you_duethank_you_overdueFor any application where offer.deadline is set, calculate days remaining. Flag as offer_deadline_approaching if ≤ 3 days remain.
Order: critical → offer deadlines → thank-you due/overdue → overdue → approaching → within window.
**Follow-up Queue** — {today's date}
{critical count} critical · {overdue count} overdue · {approaching count} approaching
---
🔴 CRITICAL ({days_elapsed}d elapsed · window was {window_max}d)
{Company} — {Role}
Applied {date_applied}. Last activity: {last_activity_description}.
{1 sentence on what action makes sense now — follow up, move on, or both}
🟡 OVERDUE ({days_elapsed}d · window {window_min}–{window_max}d)
{Company} — {Role}
{1 sentence context}
📬 THANK-YOU DUE
{Company} — {Role} (interview {n} days ago)
🟢 APPROACHING ({days_elapsed}d · window closes in ~{n}d)
{Company} — {Role}
{follow_up_after_days} day follow-up point: {follow_up_date}
✓ WITHIN WINDOW
{Company} — {Role} (day {days_elapsed} of {window_max})
If the queue is empty (all active applications are within window and no thank-yous outstanding):
"All active applications are within their expected response windows. Nothing to follow up on yet."
For each application classified as overdue or critical (and thank_you_due / thank_you_overdue), do not draft send-ready text in this skill.
For each row that needs a message, add an object to a list:
company, rolestage_kind: post_application | thank_you_post_interview | offer_nudge | other (infer from stage_history)channel: email default; linkedin if user or notes indicaterecipient_name, recipient_title from contacts[] if present—else null and use neutral greeting instructionapplied_or_event_date, days_elapsed (or interview date for thank-yous)facts_hooks: 1–3 bullets from notes / stage_history.post_notes—no inventiontone: direct, not sycophantic; 3–5 sentences target for email bodyconnector_context: optional short inbox/calendar context when connectors are available and the user approved lookup; else nullRead {user_dir}/CareerNavigator/profile.md and voice-profile.md for sign-off name and voice.
Voice preflight (once per session before 8b): If you will invoke writer and voice-profile.md lacks substantive pasted prose under ## User writing samples or ## User writing samples (launch), ask the user for 2–5 LinkedIn posts or short writing (or skip for neutral tone). Append pastes to voice-profile.md. If samples already exist or the user skips, proceed.
writer with mode follow-up. Pass all FollowUpBrief objects in one invocation when possible. Retry once on failure.Under each application entry, show writer output (subject line if email, body, LinkedIn variant if requested).
When email/calendar connectors exist, enrich briefs with approved prior-thread context before invoking writer.
After presenting all messages, say:
"Reply 'sent [Company]' for each message you send and I'll log it to your tracker."
When the user confirms a send for a specific company:
tracker.jsoncontacts[].interactions[] for the relevant contact (or the first listed contact if ambiguous):
{ "date": "YYYY-MM-DD", "type": "email | linkedin", "notes": "Follow-up sent — {stage_kind}" }
notes[]: { "date": "YYYY-MM-DD", "text": "Follow-up sent via {channel}: {stage_kind}" }follow_up_date to today + the company's follow_up_after_days window (use size-tier fallback if not found)next_step to "Await response to follow-up"Logged: follow-up sent to {Company} — next follow-up window: {new follow_up_date}writer writes the message{user_dir}/CareerNavigator/company-windows.jsoncompany-windows.json unless the entry is more than 90 days old