169 lines
7.1 KiB
Markdown
169 lines
7.1 KiB
Markdown
---
|
|
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 `<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, 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.
|