--- name: get-tg-jobs description: Full autonomous end-to-end job pipeline. Fetches fresh vacancies from Oleg's Telegram "Jobs" folder, handles new/pending channels, runs the full triage cycle (triage-jobs), pushes APPLY verdicts to Trello, then reports results in the chat session AND sends a Telegram notification to Oleg via telegram-helper. Trigger on "забери из Jobs", "что нового в каналах", "запусти pipeline", or similar. --- # get-tg-jobs Autonomous end-to-end pipeline: fetch → curate new channels → triage → Trello → report. Does everything without stopping for confirmation. Only halts if a hard error occurs (auth failure, script crash, etc.). **Trigger only when Oleg explicitly asks** — e.g. "забери свежее из Jobs", "что нового в каналах", "запусти pipeline". No background polling. --- ## Notification targets All pipeline reports go to the **"New cool job"** Telegram group. The `telegram-helper` account (samuishechka) is a member of that group and sends messages there. | Target | chat_id | When | |---|---|---| | "New cool job" group | `-4783500394` | All reports — success and errors | Tool to use: `mcp__telegram-helper__send_message(chat_id=-4783500394, message="...", parse_mode="html")` This section is the canonical reference for notification targets. Update here if the group changes. --- ## Step 1 — Run the pipeline ```bash ~/.local/bin/uv run scripts/list_telegram_channels.py \ | ~/.local/bin/uv run scripts/fetch_telegram_jobs.py - ``` Run from the project root. The script prints a per-channel summary to stdout — echo it to the session so Oleg can see raw progress. **If the script fails:** - `TELEGRAM_SESSION_STRING not set` or auth error → `.env` is missing or the session is expired. Regenerate with `scripts/regen_telegram_session.sh` and tell Oleg. - `TELEGRAM_API_ID / TELEGRAM_API_HASH not set` → same `.env` issue. - `Could not find folder "Jobs"` → the folder was renamed or the wrong session is in `.env`. Must be the **usulsu** session, not samuishechka. - Any other exception → paste the error and stop. Don't retry blindly. --- ## Step 2 — Check for pending (new) channels ```bash test -f tracking/telegram_pending_channels.json && echo PENDING || echo OK ``` **If OK**: skip to Step 3. **If PENDING**: curate each new channel using the procedure below, then rerun Step 1. --- ### New-channel curation procedure For each channel in `telegram_pending_channels.json`: #### 2a — Read keyword frequency scan ```bash jq -r 'to_entries[] | "\n=== \(.key) ===\nmessages_scanned: \(.value.messages_scanned)\ntruncated: \(.value.truncated)\ntop keywords:\n\(.value.keyword_counts_from_other_channels | to_entries | sort_by(-.value) | .[:20] | .[] | " \(.key): \(.value)")"' \ tracking/telegram_pending_channels.json ``` #### 2b — Sample messages ```bash jq -r '.channels[""].messages[:6] | .[] | "── \(.date[0:16])\n\(.text[0:400])\n"' \ tracking/telegram_inbox.json ``` Look for: hashtag patterns, language, post structure (single role / digest / chat), recurring noise. #### 2c — Decide lang, priority, filter shape **Priority:** - `p1` — strong stack hits (JS/TS/React/Node/AI/LLM) AND global-remote culture - `p2` — stack OK but CIS/RUB market, or occasional gems; recruiter/market-intel content - `p3` — wrong stack, off-market, noise, dead channels Base priority on the **best** vacancy in the sample, not the average. **Filter shape:** | Channel pattern | Filter | |---|---| | Consistent `#vacancy` + `#remote` hashtags | AND-of-OR hashtag filter | | Vacancy text without consistent hashtags | Positive stack include + Oleg-stack excludes | | Low-volume personal/curated digest | Trust-all (no `include`/`exclude`) | | Mixes resumes and vacancies | Trust-all | | Mostly noise but worth keeping | Strict positive filter | Standard Oleg-stack excludes: `["kafka", "golang", "kotlin", "android", "swift"]` For `*_jobs` channels add resume excludes: `["#резюме", "#resume", "#cv", "#ищуработу"]` Positive stack include: `["javascript", "typescript", " react", "node.js", "nodejs", "fullstack", "full-stack", "tech lead", "techlead", "ai engineer", " llm"]` #### 2d — Add entry to telegram_channels.json Insert in correct priority block (p1 → p2 → p3, alphabetically within each group): ```jsonc "": { "lang": "ru" | "en" | "mixed", "priority": "p1" | "p2" | "p3", "include": [["kw1","kw2"], ["kw3"]], // optional "exclude": ["kw4", "kw5"] // optional } ``` #### 2e — Rerun and confirm clean ```bash ~/.local/bin/uv run scripts/list_telegram_channels.py \ | ~/.local/bin/uv run scripts/fetch_telegram_jobs.py - test -f tracking/telegram_pending_channels.json && echo "STILL PENDING" || echo "Clean" ``` #### 2f — Validate the filter ```bash jq -r '.channels[""] | "kept \(.kept)/\(.seen)" + (.messages | map("\n── \(.date[0:16])\n\(.text[0:300])") | join(""))' \ tracking/telegram_inbox.json ``` If `kept == 0` and a filter is set — verify the filter isn't too strict before accepting zero as correct. --- ## Step 3 — Run full triage Follow the complete `triage-jobs` skill procedure on `tracking/telegram_inbox.json`. Key points from that skill: 1. **Pre-step**: build the `known_applied` list from **Trello** (the source of truth) before spawning Haiku. Fetch the vacancy-bearing lists and keep **only card titles**: ``` mcp__trello__set_active_board(boardId="6a1a9a5af082cb0526b22704") mcp__trello__get_cards_by_list_id(listId="6a1aa59555aab72a261c42aa") # TODO mcp__trello__get_cards_by_list_id(listId="6a1aa59a5e7e651b1352895b") # In Progress mcp__trello__get_cards_by_list_id(listId="6a267e2e9ed02737346dc047") # In touch mcp__trello__get_cards_by_list_id(listId="6a1aa5a1d8bcb0ed7234987b") # Applyed mcp__trello__get_cards_by_list_id(listId="6a245a328452976c0d1fcca1") # Rejected ``` Distill to titles only, then pass that list into every Haiku subagent prompt. See the triage-jobs batch pre-step for the context-safety rules and the REST fallback when the board grows. `tracking/applications.md` is frozen/legacy — don't grep it. 2. **Stratify by priority**: all p1, p2, p3 go through Haiku first pass. Main session reviews only APPLY and VERIFY verdicts from Haiku. SKIP verdicts from Haiku accepted without re-review. 3. **VERIFY verdicts**: run a fast `WebSearch "{company} remote hiring countries"` to resolve geo, then apply Gate 1. 4. **APPLY verdicts**: for every confirmed APPLY — create a Trello card in the TODO column (`6a1aa59555aab72a261c42aa`) on board `6a1a9a5af082cb0526b22704`. The card **is** the application record (replaces the old applications.md row): title `Company — Role (Track X)`, description = verdict summary + a `Tracking` footer (date added, channel, CV used, JD link, status). See the triage-jobs skill ("After triage — update tracking") for the exact card schema. Do not write to `tracking/applications.md` (frozen/legacy). 5. **QUICK-APPLY verdicts**: note them explicitly in the session report; do not auto-add to Trello. Ask Oleg if he wants to proceed. Full triage playbook: `base/reference/vacancy-filter-and-triage-2026.md`. Full batch instructions: `.claude/skills/triage-jobs/SKILL.md`. --- ## Step 4 — Report in session After triage is complete, output a consolidated summary to the chat: ``` Pipeline done — Fetch: N messages from X channels (Y with results) [⚠️ Truncated: channel_name (kept K/500, p2/ru)] Triage results: ✅ APPLY: N roles → added to Trello 🔍 VERIFY: N roles → resolved / still open ⚡ QUICK-APPLY: N roles (ask Oleg before adding) ❌ SKIP: N roles APPLY roles: - Company A — Role Title (Track A) → [Trello card] - Company B — Role Title (Track B) → [Trello card] New channels curated: N [or: none] ``` --- ## Step 5 — Send Telegram notification After the session report, send a summary to the **"New cool job"** group via telegram-helper. ### Success message format ``` mcp__telegram-helper__send_message( chat_id=-4783500394, parse_mode="html", message="""Jobs pipeline done · 2026-06-07 ✅ APPLY: N роли → Trello 🔍 VERIFY: N (нужен ресёрч) ⚡ Quick-apply: N (нужно ок) ❌ SKIP: N 📥 Всего: N сообщений из X каналов APPLY:Company A — Role (Track A)Company B — Role (Track B)""" ) ``` Rules: - Always include Trello links for APPLY roles — это главная ценность уведомления. - If QUICK-APPLY roles exist, list them with direct JD links (not Trello — для быстрого решения): ``` ⚡ Quick-apply (нужно ок): – Company X — Role → wantapply.com/... – Company Y — Role → linkedin.com/jobs/... ``` - Keep VERIFY as a count only (no list) — they need more research, not immediate action. - If zero APPLY and zero QUICK-APPLY: still send the message — "всё просмотрено, ничего релевантного в этот раз". ### Error message format If the pipeline failed at any step and cannot complete — send a short error notification to the **same group**: ``` mcp__telegram-helper__send_message( chat_id=-4783500394, parse_mode="html", message="""⚠️ Pipeline error · 2026-06-07 Упало на шаге: Причина: Что сделано до ошибки: Что нужно: """ ) ``` Send the error notification **even if only partial work was done**. Better to have an incomplete notification than silence when something breaks. --- ## Sanity notes - `telegram_state.json` is not in git — per-machine cursor. If lost, next run fetches 30 days back per channel (slow but correct). - To reset a single channel's cursor for filter re-validation: ```bash jq 'del(.[""])' tracking/telegram_state.json > /tmp/s.json && mv /tmp/s.json tracking/telegram_state.json ``` - `telegram_inbox.json` is overwritten every run — it's the current snapshot only. - The pipeline reads the live "Jobs" folder — new channels Oleg added in Telegram are automatically included in the next run.