cv-2026/.claude/skills/triage-jobs/SKILL.md

301 lines
14 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

---
name: triage-jobs
description: Triage one or more job vacancies using Oleg's canonical apply/skip playbook (vacancy-filter-and-triage-2026.md). Applies 4 hard gates, classifies the CV track, runs the research protocol, checks for prior applications, and outputs a consolidated verdict. For batch runs from telegram_inbox.json, stratifies by priority and delegates p2/p3 bulk to a Haiku subagent to protect the main session.
---
# triage-jobs
Operational implementation of `base/reference/vacancy-filter-and-triage-2026.md`. That file is the authoritative playbook — read it before running this skill if you don't have it in context.
Posture: **trying-friendly, not filtering-friendly.** Hard skip is rare and requires a concrete objective blocker. On every ambiguous case, default to "подаём".
---
## When to use
- Oleg provides a job posting URL, raw JD text, or says "разбери вакансию".
- After running `scripts/fetch_telegram_jobs.py` — triage `tracking/telegram_inbox.json`.
- Any "should we apply?" question about a specific role.
---
## Input modes
| Mode | What Oleg provides |
|---|---|
| **Single URL** | One job posting link — fetch, triage, output verdict |
| **Raw JD** | Pasted text — triage directly |
| **Batch (inbox)** | No specific job — triage all entries in `tracking/telegram_inbox.json` |
---
## Step 0 — Read the playbook (if needed)
If `vacancy-filter-and-triage-2026.md` is not already in context:
```
Read: base/reference/vacancy-filter-and-triage-2026.md
```
---
## Step 1 — Fetch the JD
For URL input:
1. Try `WebFetch` first.
2. If blocked (403, bot wall, login wall, JS-only, empty body) → switch to `chrome-session` skill immediately, no confirmation needed.
3. If neither works → halt and report. **Never reconstruct a JD from memory.**
For Greenhouse / Lever / Ashby / Freshteam ATS: SSR usually works; confirm the "Apply" button is active (not a JS overlay saying "not accepting applications").
---
## Step 2 — Extract fast facts (< 1 min)
Pull from the JD:
- Role title and seniority signals
- Must-have stack (vs. nice-to-have)
- AI involvement: **must-have** / nice-to-have / not mentioned
- Location & remote policy
- Timezone / overlap requirements (explicit or inferable from location)
- Compensation signals (range, equity framing, "scrappy" language, funding stage)
---
## Step 3 — Run 4 hard gates
Evaluate gates in order. First failure → `SKIP` with one objective reason. All four pass → continue.
### Gate 1 — Geography / hiring
Passes if the role can hire Oleg via **any** of:
- Global remote (non-US/UK/EU-restricted)
- Contractor via Deel or equivalent EOR covering Thailand
- B2B contract for remote work
- Russian-speaking team / Russian-speaking founders, hiring remotely (excluding RU/BY companies explicitly requiring presence)
- Russian companies hiring remotely (presence in RU not required)
- Relocation offered **AND** comp ≥ $10k/month
- Temporary contract fully geography-agnostic (Mira, Algery, similar aggregators)
Skip if: location-locked / US-only / UK-only / EOR doesn't cover Thailand and no contractor option.
### Gate 2 — Timezone (comp-scaled, not binary)
Oleg's flexible window: **9:0022:00 GMT+7**. Comfortable day: 11:0020:00.
| Required overlap | Pass condition |
|---|---|
| Fits within 9:0022:00 GMT+7 | Passes at any comp ≥ floor |
| Partially outside the window | Passes if comp > $9k |
| Full US-day / PST core hours / night work | Passes if comp > $10k |
Skip only if: comp ≤ $9k **AND** required overlap falls outside 9:0022:00 GMT+7.
### Gate 3 — Compensation
| Tier | Range | Treatment |
|---|---|---|
| Target | $812k/month | Main funnel |
| Floor | $68k/month | Normal lower bound |
| Fallback | $4.56k/month | Temporary bridge only — штучно и осознанно |
| Skip | < $4.5k/month | Hard skip |
No explicit comp? Read signals: pre-seed + equity-heavy framing + "scrappy team" → likely below floor. Founding-engineer at Series AB AI startup can stretch to $15k+ if profile matches.
### Gate 4 — Seniority
Passes for: Senior / Staff / Tech Lead / experienced middle+.
- **Skip** if: explicitly Junior or mid with no growth ceiling.
- **Do NOT skip** if: role title is Lead / Principal / Head of — treat as "they don't have that person internally, try it."
- **Do NOT skip** if: role looks like middle but comp fits floor/target AND the role offers interesting new experience (AI, client-facing, English immersion).
---
## Step 4 — Anti-pattern self-check
Before marking skip, run through the false-blocker list. If you're about to skip on any of these, escalate to the next tier instead:
1. Role looks senior-heavy (Lead/Principal/Head) → that's a try signal.
2. One missing skill → ask Oleg first (see Step 6), not skip.
3. "Not an AI-first company" → Track B or Hybrid, not skip.
4. Superficial domain mismatch → look at actual technical tasks (orchestration, LLM workflows, structured extraction).
5. "Not a Russian-speaking scale-up" → neutral, not negative.
6. Timeline outside 8-week window → affects sequencing, not eligibility.
7. Comp below $8k but in floor/fallback → consider, especially strategic or interesting roles.
8. Tech stack mismatch with fast ramp → lean toward apply, mention ramp honestly.
9. Doesn't fully pass triage but ≥50% match + low application effort (LinkedIn Easy Apply, simple form, DM) → **quick-apply** mode: note it explicitly as "fast/training apply."
---
## Step 5 — Research protocol
Run for all roles that cleared the gates (and for borderline cases to resolve ambiguity).
### 5.0 — Check for prior application
Before deep research, check whether Oleg already applied to this role or company:
- **Trello** (`mcp__trello__set_active_board` → board `6a1a9a5af082cb0526b22704`, then search cards or scan the "Applyed" list).
- **`tracking/applications.md`** — grep for company name.
- **Telegram** — search in job-tracking chats if applicable.
- **Gmail** — search for company name if accessible.
If already applied → note it in the output, don't re-triage as new.
### 5.1 — Research the company
What the company does, product, stage, funding, team size, recent news, reputation (Glassdoor / Blind if available). Goal: context + ghost/red-flag filter.
### 5.2 — Cross-platform posting check
Find the same vacancy on: company careers page, LinkedIn, ATS link (Greenhouse/Lever/Ashby/etc.), job boards, aggregators. Consolidate:
- **Posting date** — earliest appearance. 90+ days without update = ghost signal.
- **Comp range** — different platforms often show different bands. Collect all.
- **Geo restrictions** — any platform saying US Only / UK Only / location-locked / eligible countries list?
### 5.3 — Restriction priority rule
**Restrictions are authoritative.** If one source says "remote" and another says "US only" → US only wins → Gate 1 skip. Less restrictive wording wins **only** if it explicitly and clearly overrides/removes the restriction.
---
## Step 6 — Missing skills
One missing skill is **not** a skip if it isn't flagged as explicit MUST HAVE.
Action: **ask Oleg before applying** — "JD asks for X, I don't see it in your materials — did you have any experience with it?" Many skills exist but were trimmed from CV (examples: Redux Toolkit/RTK Query, Vitest, Playwright, Jest, eCommerce/CMS work).
Real gaps — can name without checking: Go, Rust, Java, C++, Ruby, PHP, heavy DevOps (K8s orchestration at scale, SRE), native mobile (Swift, Kotlin). React Native and Python are bridgeable, not gaps.
**Never flag a gap explicitly in a cover letter** — don't write "one thing to flag" or "I notice a gap here."
---
## Step 7 — Classify track (for roles that cleared gates)
| JD condition | Track | CV file |
|---|---|---|
| AI in **must-have**: LLM / agents / MCP / RAG / orchestration / embeddings in core requirements | **Track A** | `base/cv-2026-05-base.md` |
| Pure Node.js / backend, AI as nice-to-have or "significant plus" | **Backend-first** | `base/cv-backend-variant-hostinger-2026-05.md` |
| Senior / full-stack / frontend, no AI in must-have | **Track B** | `base/oleg_proskurin_fullstack_techlead_cv.md` |
| Senior + AI-tooling fluency as requirement (build with AI assistance, not AI product) | **Hybrid** | CV-B with AI moved up 23 positions in Skills |
Russian-speaking scale-ups (Manychat, inDrive, Wheely, Joom, Adapty, similar) → **Track B by default**, even if AI not mentioned.
Tiebreakers:
- Track B vs. skip → Track B wins.
- Track A vs. Track B for hybrid JD → AI in must-have → A; otherwise → B.
---
## Step 8 — Output format
One consolidated block per vacancy. No separate research section — merge everything.
```
## [Company] — [Role Title]
**Verdict:** APPLY (Track A) | SKIP | QUICK-APPLY
**Gate check:**
- Gate 1 (Geo): ✅ global remote / ❌ US-only
- Gate 2 (TZ): ✅ EMEA overlap fits / ⚠️ partial, comp > $9k ok / ❌
- Gate 3 (Comp): ✅ $XYk (target) / ⚠️ floor / ❌
- Gate 4 (Level): ✅ Senior / ❌ Junior
**Track:** A / B / Backend-first / Hybrid — CV: [filename]
**Strong matches:** [24 bullets: specific tech/scope from JD that map directly to Oleg's background]
**Open questions:** [missing skills to ask Oleg about; 12 items max]
**Research notes:**
- Company: [stage, product, funding, red flags if any]
- Posting date: [earliest found] — [fresh / stale signal]
- Comp across platforms: [consolidate bands found]
- Geo/restrictions: [what each platform says; which is authoritative]
**Prior application:** none found / ⚠️ already applied on [date], see Trello card [name]
**Proof-points for letter:** [23 concrete bullets that directly answer the JD's key asks]
```
For SKIP: one-liner after gate check explaining the objective blocker. No research section needed unless it was needed to determine the gate outcome.
---
## Batch mode — stratified triage from telegram_inbox.json
When triaging `tracking/telegram_inbox.json`:
### Pre-step: build prior-applications list (do this once before spawning any subagent)
```bash
grep -E '^\|' tracking/applications.md | tail -n +2 | awk -F'|' '{print $3}' | sort -u
```
Also call `mcp__trello__get_cards_by_list_id` for all BestJob board lists to extract card titles. Merge both into a `known_applied` list (company name → date/status where available). Pass this list to every Haiku subagent prompt (see template below).
### Stratification rules
1. Read the file. Group entries by channel `priority` field (`p1` / `p2` / `p3`).
2. **All p1, p2, and p3 entries**: delegate to a Haiku subagent first pass.
- Pass the raw entries, the playbook summary, and the `known_applied` list to the subagent.
- Subagent returns a structured verdict list (APPLY / SKIP / QUICK-APPLY / VERIFY).
- SKIP verdicts from Haiku are accepted without re-review.
3. **Main session reviews only** APPLY and VERIFY verdicts from Haiku — runs full Step 18 per entry.
4. After all verdicts: promote confirmed APPLY entries to `tracking/applications.md`.
5. For QUICK-APPLY entries: note explicitly, ask Oleg if he wants to proceed.
6. For VERIFY entries: run a fast WebSearch `"{company} remote hiring countries"` to resolve geo; then apply the gate.
**Why Haiku-first for everything:** p1 channels can have 50100+ messages per run. Sending them straight to the main session risks context overflow and losing genuine APPLY roles in the flood. Haiku filters down to a manageable APPLY+VERIFY set; main session then does quality deep-dive on only those. A few extra false VERIFYs from Haiku are fine — main session catches them. Missing a real APPLY because main session ran out of context is not fine.
### Haiku subagent prompt template
```
You are triaging job vacancies for Oleg Proskurin (Tech Lead / AI Engineer, based in Thailand GMT+7, available for remote work).
Apply these 4 hard gates — SKIP on first failure:
Gate 1 (Geo): Must allow: global remote non-US/UK/EU, contractor via Deel/EOR from Thailand, B2B remote, Russian-speaking teams hiring remotely (not RU/BY presence-required), relocation with comp ≥$10k, geography-agnostic temp contracts.
Gate 2 (TZ): Oleg's window 9:0022:00 GMT+7. Outside window: ok if comp > $9k. Night/PST core: ok if comp > $10k. Skip only if comp ≤ $9k AND overlap is outside window.
Gate 3 (Comp): Skip if < $4.5k/month. Floor $68k, target $812k.
Gate 4 (Level): Skip if explicitly Junior or mid with no growth ceiling.
Posture: trying-friendly when data IS PRESENT and borderline. When key gate data is ABSENT from the message text, return VERIFY — not APPLY. Lean toward APPLY only when geo and comp are explicitly stated and borderline (e.g. "global remote", "$7k/month").
Geo rules (Gate 1):
- Message explicitly says "global remote" / "worldwide" / "anywhere" / "любой город" / contractor-friendly → Gate 1 passes, proceed.
- Message says "United States" / "US only" / "United Kingdom only" / specific country list excluding Thailand → SKIP Gate 1.
- Message says "Remote" with no geo qualifier → VERIFY geo (cannot confirm Thailand eligibility without JD).
- Message has no location info at all → VERIFY geo.
Comp rules (Gate 3):
- Explicit salary ≥ $4.5k/month or ≥ $54k/year → Gate 3 passes, proceed.
- Explicit salary < $4.5k/month → SKIP Gate 3.
- No salary mentioned → VERIFY comp.
- Timezone offset explicitly stated (e.g. GMT-GMT+6) → treat as geo restriction, apply Gate 1.
Known applied companies — flag these as SKIP (already applied):
[INSERT known_applied LIST HERE — one line per company]
For each vacancy below, output one line:
APPLY | SKIP | QUICK-APPLY | VERIFY — [company/role] — [gate failed or what's missing] — [track: A/B/Backend-first/Hybrid]
Vacancies:
[paste entries from telegram_inbox.json]
```
---
## After triage — update tracking
For every APPLY verdict:
- Add a row to `tracking/applications.md` with status `todo` (not yet applied) or `applied` if Oleg confirms.
- Create a Trello card in the TODO column (`6a1aa59555aab72a261c42aa`) on board `6a1a9a5af082cb0526b22704` with: company, role, track, verdict summary, link to JD.
For SKIP: no tracking entry needed unless Oleg says to keep it for reference.