7.1 KiB
| name | description |
|---|---|
| triage-jobs | 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:
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:
~/.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.mdbase/oleg_proskurin_fullstack_techlead_cv.md
Step 3 — p1 (process here)
Pull p1 channels from inbox and walk through every kept message:
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 <PRIORITY> with p2, or pass both p2 and p3 in one call):
Agent({
description: "Triage Telegram inbox <PRIORITY>",
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 "<PRIORITY>":
jq '.channels | to_entries | map(select(.value.priority == "<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": "<channel_key>",
"id": <message_id>,
"link": "<t.me url>",
"title": "<role title>",
"company": "<company or null>",
"stack": ["<key tech tokens>"],
"comp": "<salary string or null>",
"remote": true | false | "unclear",
"fit": "apply" | "maybe",
"why": "<one short sentence>"
}
]
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, statusto-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.mdwithout 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.