---
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:00–22:00 GMT+7**. Comfortable day: 11:00–20:00.

| Required overlap | Pass condition |
|---|---|
| Fits within 9:00–22: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:00–22:00 GMT+7.

### Gate 3 — Compensation

| Tier | Range | Treatment |
|---|---|---|
| Target | $8–12k/month | Main funnel |
| Floor | $6–8k/month | Normal lower bound |
| Fallback | $4.5–6k/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 A–B 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 2–3 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): ✅ $X–Yk (target) / ⚠️ floor / ❌
- Gate 4 (Level): ✅ Senior / ❌ Junior

**Track:** A / B / Backend-first / Hybrid — CV: [filename]

**Strong matches:** [2–4 bullets: specific tech/scope from JD that map directly to Oleg's background]

**Open questions:** [missing skills to ask Oleg about; 1–2 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:** [2–3 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`:

1. Read the file. Group entries by channel `priority` field (`p1` / `p2` / `p3`).
2. **p1 entries**: triage in the main session (full Step 1–8 per entry).
3. **p2 and p3 entries**: delegate to a Haiku subagent to protect main context.
   - Pass the raw entries and the playbook summary to the subagent.
   - Subagent returns a structured verdict list.
   - Review, escalate any surprising p2/p3 passes to main session for full triage.
4. After all verdicts: promote APPLY entries to `tracking/applications.md`.
5. For QUICK-APPLY entries: note explicitly, ask Oleg if he wants to proceed.

### Haiku subagent prompt template

```
You are triaging job vacancies for Oleg Proskurin (Tech Lead / AI Engineer, based in Thailand, 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:00–22: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 $6–8k, target $8–12k.
Gate 4 (Level): Skip if explicitly Junior or mid with no growth ceiling.

Posture: trying-friendly. On ambiguous cases, lean toward APPLY.

For each vacancy below, output:
- APPLY, SKIP, or QUICK-APPLY (≥50% match + easy application)
- Gate that failed (for SKIP)
- Probable track: A (AI must-have), B (full-stack/frontend), Backend-first, Hybrid
- 1-line reason

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.
