--- name: triage-jobs description: Triage the latest Telegram vacancy inbox (`tracking/telegram_inbox.json`) — stratifies by priority (p1 in this session, p2/p3 via a Haiku subagent) and returns a deduped shortlist of vacancies worth applying to. Use when the user says "разбери inbox", "что нового по работе", "разбери вакансии", "пройдись по telegram-вакансиям", "triage the inbox", "find relevant jobs from telegram", or similar. --- # triage-jobs Read the latest Telegram vacancy fetch and present a shortlist that fits Oleg's targeting. The inbox file is large (~200K tokens). To keep the main session lean, p2/p3 channels go to a **Haiku subagent** that returns only finalists. p1 (small, high-signal) is processed here. ## Args Optional priority filter as positional arg(s): `p1`, `p2`, `p3`, or `all` (default). - `/triage-jobs` → all three tiers - `/triage-jobs p1` → only p1 in this session, skip subagent - `/triage-jobs p2 p3` → only subagent run ## Step 1 — Pre-checks Verify the inbox exists and is recent: ```bash ls -lh tracking/telegram_inbox.json jq '{generated_at, total_in_inbox, channels_count: (.channels | length)}' tracking/telegram_inbox.json ``` If the file is missing or its `generated_at` is older than ~6 hours, **don't run triage on stale data** — offer to refetch first: ```bash ~/.local/bin/uv run scripts/list_telegram_channels.py \ | ~/.local/bin/uv run scripts/fetch_telegram_jobs.py - ``` ## Step 2 — Oleg's targeting (apply strictly during triage) This is the rubric — use it verbatim when deciding "keep or drop" and when briefing the subagent. **Roles he targets:** - Senior / Staff / Principal Full-Stack Engineer - Tech Lead, Engineering Lead, Engineering Manager (with hands-on) - AI Engineer / Applied AI / LLM Engineer (TS or Python OK for AI roles) **Stack match (strong signal):** TypeScript, JavaScript, Node.js, React, Next.js, TanStack, Tailwind, PostgreSQL, Drizzle, Vercel, Cloudflare, Sanity/Storyblok/Contentful/Payload (Headless CMS), Shopify/Hydrogen, GraphQL, WebSockets. For AI roles also: LLM orchestration, MCP, RAG, embeddings, Mastra, Vercel AI SDK, Claude/GPT/Gemini APIs. **Culture must-haves:** - **Global remote** (he's in GMT+7, full EMEA overlap + US East AM). EMEA / global / US-East-friendly TZ all fine. "Remote within Russia only" or "US only — must be in EST 9-5" → reject. - **Compensation in USD/EUR** preferred. Target ~$100k+ FT or $70+/hr contractor. Russian-RUB roles at ₽70-100k/mo (≈ $750-1100) are below floor. - Deel/W-8BEN contractor format is a plus. **Deal-breakers (auto-reject):** - Mobile-native (Kotlin, Swift, Android, iOS, Flutter) - Non-stack backend (Go/Golang, Java, .NET, C#, Ruby, PHP, Rust, Scala) **as primary** — if the role is fullstack with React/Node + Go on side, that's fine - DevOps / SRE as primary role - QA / Manual testing - Sales, Marketing, Designer, Recruiter, PM (non-engineering) - Junior / Trainee / Intern - On-site outside major remote-friendly hubs (e.g. Lagos, low-cost-region on-site) - Sub-$50k FT compensation when the salary is stated **Stretch interests (consider even if not perfect match):** - AI/ML engineering roles using Python (his AI CV covers this) - Vetted-contractor platforms (Toptal, Lemon.io, Turing) — separate financial track - Headless CMS, Shopify Hydrogen, eCommerce platforms - Roles at companies building dev tooling, AI agents, MCP ecosystem (his open-source overlaps) For canonical source-of-truth, the CVs are at: - `base/oleg_proskurin_ai_engineer_fullstack_cv.md` - `base/oleg_proskurin_fullstack_techlead_cv.md` ## Step 3 — p1 (process here) Pull p1 channels from inbox and walk through every kept message: ```bash jq '.channels | to_entries | map(select(.value.priority == "p1")) | from_entries' tracking/telegram_inbox.json ``` For each kept message, classify: - **Apply** — fits role + culture + comp. Note: company, role, link, why-fit (1 line). - **Maybe** — fits role/stack but unclear comp or stretch culture. Note same fields + the uncertainty. - **Drop** — fails targeting. Don't list, don't explain. p1 should be small enough (~12K tokens currently) to do in main session without context strain. ## Step 4 — p2 and p3 (delegate to Haiku subagent) Spawn a subagent via the Agent tool. Use `general-purpose` agent type with **Haiku model** for cost/speed. **Critical:** the subagent does not see this conversation. The prompt must be self-contained. Template (fill `` with `p2`, or pass both p2 and p3 in one call): ``` Agent({ description: "Triage Telegram inbox ", subagent_type: "general-purpose", model: "haiku", prompt: ` Triage job postings from Oleg's Telegram inbox. Read tracking/telegram_inbox.json and filter to channels with priority "": jq '.channels | to_entries | map(select(.value.priority == "")) | from_entries' tracking/telegram_inbox.json Oleg's targeting (apply strictly): [paste the "Step 2 — Oleg's targeting" section verbatim] For each kept message that is a REAL vacancy (not a resume/CV digest entry, not a chat-room message, not a market-intel essay), decide if it fits the targeting. Return ONLY the shortlist as JSON. Reject everything else silently — no commentary on rejected items. Shortlist schema: [ { "channel": "", "id": , "link": "", "title": "", "company": "", "stack": [""], "comp": "", "remote": true | false | "unclear", "fit": "apply" | "maybe", "why": "" } ] If there are zero matches, return []. Do not paraphrase or summarize messages — quote the original title verbatim and just extract structured fields. Do not include personal opinions or formatting commentary. ` }) ``` Run subagents in parallel where possible (one for p2, one for p3 in the same message). ## Step 5 — Aggregate and present Combine p1 finalists (from Step 3) with subagent shortlists (Step 4). Dedupe by `(company, title)` pair when possible. Present grouped output to Oleg, e.g.: ``` 🎯 APPLY (N) - jaabz_com #10233 — AI-Native Full Stack Developer @ Geeky Tech — TS/React/Python, Fully Remote, B2B SaaS - dev_connectablejobs #2039 — Full-Stack Engineer @ VOYGR — AI-native, $4-7k, Remote, founders ex-Google - ... 🤔 MAYBE (N) - jsspeak #58062 — AI Engineer (Python & Node.js) Senior @ Eshe App — 300-400k₽, RU+BY citizenship only — fit but comp lower - ... ``` ## Step 6 — Suggest next step After the shortlist, offer to: - Append apply-list to `tracking/applications.md` (one row each, status `to-apply`). - For 1-2 top picks, switch to the tailoring workflow (see main CLAUDE.md "Workflow 2 — Tailor CV"). ## Notes - **Don't auto-add to `applications.md`** without explicit confirmation — Oleg curates that file. - **Don't auto-refetch.** If the inbox is stale, ask first. - **State cursor advances on every fetch.** A skill run only reads the existing inbox — it doesn't trigger a new fetch unless explicitly requested. - **Skip P3 by default if user says "quick triage"** — p3 is mostly market-intel and dead channels, low ROI.