Посібник користувача

Редагувати на GitHub

Довідка — career-ops-ui

Повний огляд кожної сторінки: від запуску застосунку до отримання запрошення на співбесіду. Кожен заголовок ## нижче відповідає пункту бічної панелі або фазі робочого процесу. При першому запуску читайте зверху донизу; пізніше переходьте до потрібного розділу через зміст у бічній панелі довідки.

Аудиторія: будь-хто, хто щойно помістив цей UI всередину career-ops та запустив bash bin/start.sh. Попередніх знань career-ops не потрібно.

Про career-ops

career-ops — це система пошуку роботи з відкритим кодом, яка працює як slash-команди всередині будь-якого AI coding CLI (Claude Code, Gemini CLI, Codex, Qwen Code, OpenCode, GitHub Copilot CLI — інші CLI, сумісні з Claude, теж працюють через той самий slash-command поверхней). Не залежить від моделі. Оцінює кожну вакансію порівняно з вашим CV за шестивимірною рубрикою 0.0–5.0, генерує адаптовані PDF-резюме та відстежує кожну заявку локально на вашому комп’ютері.

Канонічні посилання (читайте в порядку при першому встановленні):

  • What is career-ops — система, принципи та перелік концепцій.
  • Scan job portals — знаходьте вакансії; наповнюйте Pipeline.
  • Apply for a job — повний процес подачі заявки з читанням форм через Playwright.
  • Batch-evaluate offers — оцінюйте 10+ вакансій одночасно через batch-runner.sh.
  • Set up Playwright — встановіть Chromium + зареєструйте MCP для PDF та заповнення форм.

Визначальні принципиcareer-ops.org/docs/introduction/what-is-career-ops):

  • Справжній відкритий код — MIT, без платного рівня, черги очікування, телеметрії та акаунтів. Система працює без платних рівнів, акаунтів та телеметрії. Внески до коду проходять рецензування спільноти перед випуском.
  • Суверенітет данихcv.md, config/profile.yml, data/, reports/, interview-prep/ ніколи не покидають ваш ноутбук, якщо ви самі не вивантажите їх. Ви запускаєте систему локально, зберігаючи повний контроль над даними.
  • AI-агностична архітектура — career-ops НЕ постачається разом із моделлю. Вона функціонує як команди всередині наявних AI coding CLI. Змінюйте провайдерів (Anthropic ↔ Gemini ↔ OpenAI) — ваша історія оцінок залишається незмінною.
  • Подача заявки під контролем людини — career-ops готує відповіді та відкриває форму, але ви натискаєте «Надіслати». Система ніколи не подає заявки автоматично. Система забезпечує структуру та оцінку; фінальне рішення щодо подачі залишається за людиною.
  • Структурований пошук — створено для активного, свідомого пошуку роботи з багатьма заявками; не інструмент для одноразової подачі, не рекомендаційний двигун. Налаштування займає ~15 хвилин і передбачає базові знання терміналу.

Чим career-ops НЕ є (явні не-цілі):

  • Не автоматичний відправник заявок. Не подасть форми замість вас.
  • Не перебудовник резюме. Адаптує під конкретну вакансію, але не вигадує досвід.
  • Не оптимізатор LinkedIn. Ваш профіль — ваша справа.
  • Не замінник таблиць, прихований за SaaS-інтерфейсом. Дані — це звичайний Markdown на вашій файловій системі.

Ключові концепції (повний перелік — кожен артефакт, якого торкається career-ops):

Концепція Що це
Mode Шаблон промпту в modes/<slug>.md. Вбудовані: oferta, deep, apply, pipeline, batch, contacto, followup, interview-prep, patterns, project, training, ofertas, auto-pipeline, pdf, latex, scan, tracker.
Archetype Профіль цільової ролі в config/profile.yml. Ваги рубрики зіставляють навички з активним архетипом — найважливіше поле.
Pipeline data/pipeline.md — вхідні URL вакансій, що очікують оцінки.
Tracker data/applications.md — хронологічна таблиця GFM кожної оцінки та статусу заявки.
Report reports/<NNN>-<company>-<DATE>.md — повна оцінка A–F для кожної вакансії, з балом і легітимністю в заголовку.
Scan history data/scan-history.tsv — журнал лише для додавання; запобігає дублюванню між сканами.
Proof points Блоки доказів STAR+R, вилучені з cv.md, які повторно використовуються при оцінці, підготовці відповідей і підготовці до співбесіди.
JD store jds/jd-<date>-<ts>.txt — дослівний текст вакансій, збережений під час оцінки для аудиторського сліду.
Interview-prep interview-prep/<company>-<role>.md — глибокі брифи та односторінкові підготовки до раундів.
Batch additions batch/tracker-additions/*.tsv — рядки в черзі, поставлені batch-runner.sh для злиття в трекер.

career-ops vs career-ops-ui (цей застосунок)

career-ops (CLI) career-ops-ui (цей застосунок)
Де працює всередині Claude Code / Gemini CLI / Codex / Qwen Code / OpenCode / GitHub Copilot CLI http://127.0.0.1:4317 у браузері
Поверхня slash-команди /career-ops <mode> бічна панель з окремою сторінкою для кожного кроку
Заповнення форм так, через Playwright MCP ні — генерує чеклист, ви завершуєте в CLI
PDF generate-pdf.mjs 📄 Generate PDF на #/cv, #/reports/:slug, #/evaluate, #/deep, #/interview-prep
Файли даних спільні з career-ops-ui спільні з career-ops

career-ops-ui — це чисте доповнення. Нічого всередині career-ops/ не змінюється. Обидві поверхні спільно використовують cv.md, config/profile.yml, portals.yml, data/, reports/, interview-prep/, modes/.

Порогові значення дій за балом

Після того як вакансія отримала оцінку, бал визначає наступний крок (канонічна таблиця з career-ops.org/docs/introduction/what-is-career-ops):

Бал Наступний крок
≥ 4.5 Запустіть /career-ops apply — висока відповідність, надсилайте одразу.
4.0 – 4.4 Подавайте заявку або спочатку /career-ops contacto для теплого знайомства.
3.5 – 3.9 Запустіть /career-ops deep — дослідіть компанію / роль перед рішенням.
< 3.5 Пропустіть, якщо немає особистої причини.

#/dashboard та #/tracker career-ops-ui виділяють кожен рядок з балом 4.0 і вище, щоб ви могли вибрати дію без повторного запуску.

Зовнішня документація

Повна довідка щодо рушія career-ops (сканування, рубрика оцінки, пакетна обробка, процес подачі заявки, налаштування Playwright) — на career-ops.org/docs:


1. Швидкий старт — покроковий план від «створення CV» до «подав заявку та написав»

Це канонічний покроковий посібник. Виконуйте по порядку при першому запуску. Кожен крок називає точний маршрут, точну кнопку та що ви побачите в разі успіху. Розділи 2–16 нижче детальніше розкривають кожну фазу.

Запитати довідку. Відкрийте Запитати довідку 💬 (бічна панель, під «Довідкою») і введіть запитання — відповідає лише з цього посібника вашою мовою і ніколи не читає ваше резюме. Той самий помічник доступний в один дотик з будь-якої сторінки — кнопка-робот із чатом плаває в правому нижньому куті (у лівому нижньому для мов із письмом справа наліво); натисніть, щоб запитати, не відриваючись від справ.

Запуск і ініціалізація однією командою. З терміналу можна виконати весь бутстрап, не торкаючись UI:

career-ops-ui setup      # install deps → doctor → run the server
career-ops-ui init       # pick LLM provider + paste its key (echo suppressed)
career-ops-ui doctor     # re-verify any time (exit 0 ⇔ all required green)
career-ops-ui run        # just launch the server at http://127.0.0.1:4317
career-ops-ui open       # open + RAISE the dashboard tab in your browser

Після setup/run вкладка браузера відкривається та виводиться на передній план автоматично (v1.43.0); career-ops-ui open робить те саме на вимогу, щоб ви ніколи не шукали вкладку дашборду. NO_OPEN=1 вимикає автовідкриття для headless/CI-запусків.

setup самостійно запускає весь ланцюжок. init записує ключ до батьківського career-ops/.env через той самий перевірений шлях, який використовує вкладка API-ключів #/config, та встановлює LLM_PROVIDER (auto | claude | gemini), який враховується маршрутами live evaluate / deep / mode / auto-pipeline. Форма для CI: career-ops-ui init --provider claude --anthropic-key sk-ant-… --yes. Хочете використовувати UI? Продовжуйте з наведених кроків.

A. Налаштування (виконується один раз, ~5 хвилин)

career-ops-ui має знаходитись у career-ops/web-ui/ (вкладений у батьківський проєкт career-ops). Він читає ваш cv.md, config/ та data/ з батьківської папки через ../ і не працює окремо. Якщо career-ops-ui init не знайдено після pull, виконайте cd career-ops/web-ui && npm install && npx career-ops-ui init.

Крок 1 — Відкрийте застосунок за адресою http://127.0.0.1:4317. Якщо він не запущений, у терміналі виконайте bash bin/start.sh з кореневої папки репозиторію. Завантажується Dashboard (#/dashboard).

Крок 2 — Натисніть ❤ Health у лівій бічній панелі. Кожна обов’язкова перевірка має бути зеленою:

  • cv.md, config/profile.yml, portals.yml існують
  • API-ключ встановлено (принаймні один з ANTHROPIC_API_KEY / GEMINI_API_KEY)
  • Playwright встановлено (потрібно лише якщо ви використовуватимете Generate PDF)

Якщо щось червоне, сторінка вказує точний файл або змінну середовища, яку потрібно виправити. Не переходьте далі, поки Health не стане зеленим.

Крок 3 — Натисніть ⚒ App settings у бічній панелі. Ви потрапляєте на вкладку API keys & runtime.

  • Вставте ANTHROPIC_API_KEY (рекомендовано — краще довгострокове оцінювання) та/або GEMINI_API_KEY. Отримайте ключі на https://console.anthropic.com/settings/keys або https://aistudio.google.com/apikey.
  • Натисніть 💾 Save. Потім натисніть ▶ Test Anthropic (або Gemini) — невеликий запит-відповідь підтверджує, що ключ працює.

Крок 4 — Перейдіть на вкладку Profile на тій самій сторінці. Це прямий YAML-редактор config/profile.yml. Відредагуйте щонайменше:

  • candidate.full_name — замініть будь-який плейсхолдер («Jane Smith») своїм справжнім іменем
  • candidate.email, linkedin, github — використовуються у супровідних листах
  • target.roles — посади, на які ви претендуватимете
  • target.comp_total_min_usd — мінімальна загальна компенсація; пропозиції нижче цього значення позначаються в розділі D кожної оцінки
  • target.archetypes — кар’єрні патерни, які ви приймаєте (найвпливовіше поле)

Натисніть 💾 Save. Сервер перевірить YAML і проставить канонічний заголовок # Career-Ops Profile Configuration.

B. CV (виконується один раз, ~10 хвилин)

Крок 5 — Натисніть ✎ CV у бічній панелі. Два стовпці: редактор ліворуч, попередній перегляд праворуч.

Крок 6 — Виберіть один зі способів заповнення редактора:

  • Завантажте наявне резюме — натисніть 📁 Upload CV, виберіть файл .docx / .doc / .odt / .rtf / .pdf / .html / .txt / .md. Сервер конвертує його в Markdown через pandoc або pdftotext, знешкоджує XSS і поміщає результат у редактор. Перевірте конвертацію — PDF особливо може втратити форматування.
  • Вставте Markdown безпосередньо — textarea є Markdown-редактором; права панель показує те, що побачить LLM (і ваш майбутній рекрутер).
  • Поради щодо тону: один пункт = одне досягнення з метрикою. Не перевищуйте 1500 слів. Розділи в такому порядку: Summary, Experience, Projects, Education, Skills.

Крок 7 — Натисніть 💾 Save (у верхньому правому куті сторінки CV). Сервер знешкоджує (<script> / javascript: / вбудовані обробники видаляються) та записує cv.md. Toast: «Saved».

Крок 8 (необов’язково) — Натисніть 📄 Generate PDF. Запускає generate-pdf.mjs у батьківському проєкті (потрібен Playwright); новий PDF автоматично завантажується у браузері після завершення. Список у нижній частині сторінки зберігає всі раніше згенеровані файли.

C. Пошук вакансій (~2 хвилини за скан)

Крок 9 — Натисніть 🌐 Scan у бічній панелі. Переконайтеся, що portals.yml містить потрібні вам дошки (розділ 5 цієї довідки). Натисніть кнопку 🌐 Scan now. Живий SSE-журнал транслюється, поки сканер обходить Greenhouse / Ashby / Lever / Workable / SmartRecruiters / Workday (англомовні дошки) та hh.ru / Habr Career (російськомовні дошки, якщо увімкнені).

Крок 10 — Після завершення скану перегляньте результати. Натисніть тег компанії для фільтрації; натисніть іконку ↗, щоб відкрити сторінку вакансій компанії у новій вкладці. Кожна вакансія, що пройшла фільтр за назвою, додається в Pipeline.

D. Оцінка пропозицій (~30 секунд на вакансію)

Крок 11 — Натисніть Pipeline у бічній панелі. Ви бачите кожен URL, поставлений сканером у чергу. Натисніть запис, щоб переглянути вакансію вбудовано.

Крок 12 — Натисніть ▶ Evaluate поруч із будь-якою вакансією. Це переходить до #/evaluate. Якщо API-ключ встановлено, запускається живе оцінювання; без ключа отримаєте ручний промпт для вставки у власний LLM. Живий режим повертає бал 0–5 порівняно з вашим CV за розділами A–G (Role / Company / Compensation / Risk / Stretch / Cultural fit / Verdict). Збереження записується до reports/<date>-<slug>.md.

Крок 13 — Натисніть Reports у бічній панелі та перегляньте останню оцінку. Все, що нижче comp_total_min_usd, позначено червоним у розділі D. Все з Verdict: pursue — ваш короткий список.

E. Прийняття рішення та глибоке дослідження обраної компанії (~3 хвилини)

Крок 14 — Оберіть вакансію, яка варта уваги. Натисніть Deep research у бічній панелі. Введіть назву компанії та роль. Модель створює 7-розділовий бриф компанії (місія, останні новини, технологічний стек, сигнали найму, орієнтири компенсації, ризики, рекомендований кут підходу). Збереження записується до interview-prep/<company>-<role>.md.

F. Подача заявки (~5 хвилин на заявку)

Крок 15 — Натисніть Apply checklist у бічній панелі. Вставте URL вакансії та текст. Помічник генерує покроковий чеклист подачі:

  • Чернетка адаптованого супровідного листа (використовує ваш cv.md + profile.yml)
  • Конкретні ключові слова для відзеркалення з тексту вакансії
  • Файли для додавання (PDF CV — дивіться крок 8)
  • Де подавати заявку (канонічний URL careers, не посилання-перенаправлення агрегаторів)
  • Нагадування: НІКОЛИ не подавайте автоматично — фінальний перегляд і подача завжди ручні.

Крок 16 — Відкрийте сторінку careers у новій вкладці. Використовуйте чеклист як список завдань. Подавайте через власну форму компанії. Додайте PDF, згенерований на кроці 8.

Крок 17 — Зверніться до реальної людини. Відкрийте режим Outreach (#/contacto у бічній панелі). Модель створює коротке повідомлення для LinkedIn / email, адаптоване до брифу компанії з кроку 14. Персоналізуйте вступ (одна конкретна деталь із брифу глибокого дослідження). Надішліть.

G. Відстеження та подальші дії (постійно)

Крок 18 — Натисніть Tracker у бічній панелі та додайте рядок для заявки: компанія, роль, бал, статус Applied, посилання на звіт, посилання на бриф глибокого дослідження. Дата заповнюється автоматично.

Крок 19 — Через тиждень: відкрийте режим Follow-up (#/followup). Створюється ввічливий лист із запитом щодо статусу, що посилається на первинну заявку. Надішліть. Оновіть статус трекера на Followed up.

Крок 20 — Отримали запрошення на співбесіду — запустіть режим Interview prep (#/interview-prep). Генерує цільову підготовку для конкретної компанії та етапу (системний дизайн / поведінковий / кодинг). Автоматично використовує бриф глибокого дослідження.

Крок 21 — Отримали оффер? Оновіть статус Tracker на Offer та повторно перегляньте розділ compensation у звіті оцінки — ваш мінімально прийнятний показник там є.

TL;DR — порядок у бічній панелі відповідає робочому процесу

Health → App settings → Profile → CV → Scan → Pipeline → Evaluate → Reports → Deep research → Apply checklist → Outreach → Tracker → Follow-up → Interview prep → Activity log

Все. 21 крок, покроково, від нуля до офферу.

Одним кліком: Auto-pipeline (#/auto) — скорочення 21 кроку

Якщо ви хочете швидко оцінити одну конкретну вакансію — пропустіть ручний покроковий план. Бічна панель → ✨ Auto-pipeline (або кнопка ✨ на Dashboard) відкриває окремий екран: вставте URL вакансії, натисніть Enter або ▶ Run full pipeline, і сервер виконує весь ланцюжок за один прохід:

  1. Перевірка URL — безпечна перевірка від SSRF (isValidJobUrl); відхиляє loopback / file: / приватні IP / символи скриптів.
  2. Отримання опису вакансіїsafeGet (з DNS-pinning та перевіркою перенаправлень) завантажує та знешкоджує текст вакансії.
  3. Оцінка порівняно з вашим CV — Anthropic (пріоритет) → Gemini як резервний → ручний промпт, якщо ключ відсутній.
  4. Збереження звіту — записує reports/<slug>.md з балом і легітимністю в заголовку.
  5. Додавання до трекера — додає рядок до data/applications.md.

Живий зворотний зв’язок — вертикальний степпер (кожен крок підсвічується: виконується → готово / помилка). Це впорядкований список із aria-current на активному кроці та ввічливою live-областю для зчитувачів екрану, що оголошує кожен перехід. У разі успіху картка результату веде прямо до збереженого звіту (View report · N/5) та трекера. Невдалий крок позначається червоним із повідомленням, і кнопка знову стає активною, щоб ви могли виправити URL і повторити спробу без перезавантаження.

Немає API-ключа? Pipeline запускається в ручному режимі: кроки 3–5 згортаються, і ви отримуєте готову картку промпту для копіювання (вставте в Claude Code / Anthropic / Gemini). Жодного живого виклику LLM, жодних витрат.

#/auto доступний через посилання: #/auto?url=<encoded>&go=1 відкриває екран і запускає автоматично. Кнопка ✨ на дашборді та цей пункт бічної панелі обидва ведуть сюди (єдиний зв’язний потік — тимчасове модальне вікно до версії 1.34 отримало власну сторінку).

CLI (v1.38.0). Одна команда виконує весь ланцюжок: career-ops-ui setup (bootstrap → install → start). Окремі команди: career-ops-ui doctor (перевірка env/ключів/інструментів — той самий рушій, що й сторінка Health; exit 1 при будь-якій обов’язковій помилці), career-ops-ui run, career-ops-ui init (майстер провайдера+ключа, v1.39.0). Провайдери (v1.39.0). Вкладка API-ключів додає вибір LLM_PROVIDER (auto = Anthropic→Gemini за замовчуванням · claude · gemini) та поле OPENAI_API_KEY (на стороні CLI Codex/OpenCode). career-ops-ui init — інтерактивний майстер для того самого.

Провайдери (v1.57.0). Headless live-eval тепер охоплює Anthropic → Gemini → OpenAI → Qwen → OpenRouter (порядок auto; LLM_PROVIDER фіксує один). OpenRouter — один OPENROUTER_API_KEY для 300+ моделей; випадаючий список OPENROUTER_MODEL завантажує живий каталог OpenRouter (серверний проксі, куративний офлайн-резерв). Також виправлено: ключі, вставлені з завершальним символом нового рядка / пробілами, тепер обрізаються перед перевіркою, тому /#/config більше не показує «validation failed» для жодного провайдера.


2. Налаштування застосунку та API-ключі (#/config)

Нове у v1.55 → v1.56. Без LLM-ключа червоний банер на кожному екрані пояснює, що ⚡ Run-live працює в режимі ручного промпту, та посилається сюди; щойно ключ встановлено — банер стає тихим чипом з назвою активного провайдера. Перед будь-якою кнопкою ⚡ Run-live (#/auto, #/evaluate, #/deep, режими) показується чесна орієнтовна вартість (наприклад, «Estimated cost: OpenAI gpt-5-codex · ~$0.04/eval» або примітка про відсутність витрат у ручному режимі). #/scan ховає додаткові фільтри за розкриванням Advanced filters; #/tracker додає кліковані воронкові чипи та необов’язкову серверну пагінацію; #/pipeline віртуалізується після 1000 рядків.

Інструменти CLI для ШІ. Вкладка Інструменти CLI для ШІ показує, які агентські CLI (Claude Code, Codex, Gemini, OpenCode, Copilot, Qwen, Antigravity) встановлені на сервері — сканування PATH лише для читання, без запуску. Вигляд → Показувати логотипи компаній (типово вимкнено) показує favicon кожної компанії в таблиці сканування, узятий з її власного домену (не сторонній сервіс).

Три вкладки:

  1. API keys & runtime — структурована форма полів поверх .env батьківського проєкту (той самий файл, який читають Node-скрипти career-ops при запуску). Згруповано: API keys / Runtime / Regional sources. Вкладка також надає засоби вибору моделей для кожного провайдера — OPENAI_MODEL (OpenAI/Codex) поруч із ANTHROPIC_MODEL та GEMINI_MODEL.
  2. Profileформа поле-за-полем поверх config/profile.yml (web-ui 1.32.0). Збереження зливається з файлом — ваші архетипи, докази та будь-які власні ключі залишаються незмінними.
  3. Modesструктурована форма полів для modes/_profile.md (web-ui 1.54.3), заснована на задокументованій схемі. Розділи типу «список» — Target Roles / Adaptive Framing / Comp Targets — відображаються як повторювані рядки (додавати/видаляти рядки); прозові розділи — Exit Narrative / Location Policy — відображаються як позначені textarea; будь-який невідомий або не-списковий розділ переходить до позначеної дослівної textarea. Збереження як і раніше зливається за розділами — преамбула, незмінені розділи та будь-які власні розділи зберігаються байт-у-байт. Розкривання Advanced: raw markdown залишається для редагування повного файлу — додавання/видалення розділів або редагування преамбули.

Збереження на будь-якій вкладці набирає чинності негайно — перезапуск сервера не потрібен.

Налаштування LLM-провайдера (покроково). ⚡ Live evaluation у web UI працює headless та використовує один API-ключ. Він працює за принципом «АБО» — встановіть будь-який один із них, і все запрацює; якщо встановлено кілька, auto надає перевагу в такому порядку: Anthropic → Gemini → OpenAI → Qwen. (career-ops сам по собі є CLI-агностичним — ви також запускаєте його всередині Claude Code, Codex, Gemini, OpenCode, Qwen, Copilot або Kimi; це відокремлено від цього headless-ключа.)

  1. Відкрийте #/config → вкладку API keys & runtime.
  2. Виберіть провайдера в LLM_PROVIDER: auto (використовувати будь-який встановлений ключ) або примусово вкажіть claude / gemini / openai / qwen.
  3. Заповніть ключ + модель для обраного провайдера:
    • Anthropic — встановіть ANTHROPIC_API_KEY (console.anthropic.com), за бажанням ANTHROPIC_MODEL (за замовчуванням claude-sonnet-4-6).
    • Gemini — встановіть GEMINI_API_KEY (aistudio.google.com/apikey), за бажанням GEMINI_MODEL (за замовчуванням gemini-2.0-flash).
    • OpenAI — встановіть OPENAI_API_KEY (platform.openai.com), за бажанням OPENAI_MODEL (за замовчуванням gpt-5-codex).
    • Qwen — встановіть QWEN_API_KEY (Alibaba Model Studio / DashScope, dashscope.console.aliyun.com), за бажанням QWEN_MODEL (за замовчуванням qwen-max). Для материкового CN-ендпоінту встановіть QWEN_BASE_URL у вихідному .env.
  4. Натисніть Save. Ключі записуються до .env батьківського проєкту; зміна набирає чинності негайно — перезапуск сервера не потрібен.
  5. Перевірте на #/evaluate: вставте URL/опис вакансії та натисніть ⚡ Run live. Заголовок результату показує, який провайдер спрацював (anthropic / gemini / openai / qwen). Якщо ключ відсутній — отримаєте ручний промпт для копіювання.

Секрети маскуються після збереження та ніколи не записуються в журнал. Поля model-id (*_MODEL) не є секретними.

Вкладка Profile (форма полів — v1.32.0)

До версії 1.32.0 ця вкладка була єдиною textarea з сирим YAML, де всі налаштування зберігалися в одному недиференційованому блоці. Тепер це структурована форма з полями, згрупованими в три розгортальні розділи:

  • Candidate — Повне ім’я (обов’язково), Email, Телефон, Місце розташування, LinkedIn, GitHub, URL портфоліо, X / Twitter.
  • Narrative — Headline, Exit story.
  • Compensation — Цільовий діапазон, Валюта, Мінімум для виходу, Гнучкість щодо місця роботи.
  • Structured array editors (web-ui 1.35.0) — редактори додавання/видалення рядків для полів у вигляді списків, тому навіть їх більше не потрібно редагувати в сирому YAML: Target roles + Superpowers (списки рядків); Archetypes (рядки name / level / fit); Proof points (рядки name / url / hero-metric). Порожні рядки видаляються; очищений список акуратно видаляє ключ. Та сама гарантія злиття замість заміни — будь-який масив, якого ви не торкалися, залишається незмінним.

Чому збереження безпечне:

  • Форма надсилає лише 14 змодельованих скалярних шляхів як { fields: { "candidate.full_name": … } }. Сервер читає наявний config/profile.yml, встановлює/очищає лише ці листки та повторно серіалізує весь об’єкт — тому вкладені масиви, які форма не моделює (target_roles.archetypes, narrative.proof_points, narrative.superpowers), та будь-які власні ключі, додані вручну, зберігаються після round-trip незмінними. Очищення поля акуратно видаляє ключ (без залишку phone: "").
  • Перевірка все одно вимагає повного імені; заголовок # Career-Ops Profile Configuration проставляється автоматично.
  • Один компроміс: збереження через форму полів повторно серіалізує YAML, тому вбудовані # коментарі втрачаються. Щоб зберегти коментарі або відредагувати вкладені масиви, використовуйте розкривання Advanced: edit raw YAML у нижній частині вкладки — це повний редактор файлів, що існував до 1.32.0, незмінний (замінює весь файл при збереженні).
  • Зведення лише для читання на #/profile є візуальним супутником.

Визнані ключі

Ключ Що робить Де отримати
ANTHROPIC_API_KEY Вмикає живі виклики Anthropic SDK. Рекомендовано, коли встановлено і Anthropic, і Gemini — краще довгострокове структуроване виведення для оцінки вакансій і глибокого дослідження. https://console.anthropic.com/settings/keys
ANTHROPIC_MODEL Замінює стандартний claude-sonnet-4-6. Спробуйте claude-opus-4-7 для складніших міркувань, claude-haiku-4-5-20251001 для дешевого і швидкого.
GEMINI_API_KEY Резервний, коли немає ключа Anthropic. Використовується gemini-eval.mjs для режиму oferta. Безкоштовний рівень підходить для невеликих обсягів. https://aistudio.google.com/apikey
GEMINI_MODEL Замінює стандартну модель Gemini.
(server uses default UA) Потрібен при скануванні hh.ru поза Росією (API повертає 403 зі звичайними User-Agent). Зареєструйте застосунок на https://dev.hh.ru/admin та використовуйте його UA-рядок. dev.hh.ru
PORT Порт прив’язки Express. За замовчуванням 4317.
HOST Адреса прив’язки. За замовчуванням 127.0.0.1. Встановлення 0.0.0.0 відкриває UI в локальній мережі — поки що без автентифікації, дивіться документ про Production-readiness.

Поведінка

  • Read (GET /api/config) повертає кожен визнаний ключ. Секретні ключі (ANTHROPIC_API_KEY, GEMINI_API_KEY) маскуються — ви бачите sk-ant•••••••a1b2, ніколи повне значення.
  • Save (POST /api/config) перевіряє кожне значення, записує до <parent>/.env та негайно застосовує до запущеного процесу. Перезапуск не потрібен.
  • Порожнє значення видаляє ключ. Корисно, якщо ви хочете прибрати налаштування російського IP / VPN.

Кнопки smoke-тесту

Після збереження натисніть ▶ Test Anthropic або ▶ Test Gemini — обидві надсилають мінімальний промпт (≤256 токенів виведення), тому ви витрачаєте мінімум, підтверджуючи, що ключ підключено правильно. У разі успіху повертає зразок ~200 символів.


3. Профіль (#/profile — також доступний як #/settings)

Зведення лише для читання у форматі карток для config/profile.yml. Для редагування перейдіть до App settings → вкладка Profile (#/config → Profile) — з версії web-ui 1.32.0 це форма поле-за-полем (Candidate / Narrative / Compensation), а не blob сирого YAML. Збереження зливається в той самий файл; ця сторінка повторно парсить при перезавантаженні.

Найважливіші поля:

  • candidate.full_name — використовується в кожному промпті. Замініть шаблонне Jane Smith перед будь-яким реальним скануванням, інакше ваші супровідні листи будуть відправлені з іменем-плейсхолдером.
  • candidate.email, linkedin, github — згадуються при генерації супровідних листів та в чеклисті подачі.
  • target.roles — прийнятні посади. Позитивний фільтр сканера неявно використовує це (через portals.yml::title_filter).
  • target.comp_total_min_usd — мінімальна загальна компенсація. Розділ D кожної оцінки позначає пропозиції нижче цього.
  • target.archetypesнайважливіше поле. Це кар’єрні патерни, які ви приймаєте (напр. Tech-Lead-Backend, Founding-Engineer, Data-Platform). Кожна вакансія зіставляється з ними, і найбільш відповідний архетип потрапляє в заголовок звіту.

Сторінка Health показує перевірку Profile customized, яка не проходить, поки full_name збігається з відомим іменем-плейсхолдером.


4. CV (#/cv)

Єдине джерело правди для кожної оцінки, глибокого дослідження та супровідного листа. Зберігається у cv.md у кореневій папці батьківського проєкту.

Варіанти редагування

  • Вставте безпосередньо — textarea ліворуч є Markdown-редактором. Права панель відображає те, що побачить LLM (і ваш майбутній рекрутер).
  • 📁 Upload CV — виберіть локальний файл у будь-якому з цих форматів, і сервер конвертує його в Markdown:
    • Текстові формати.md, .markdown, .txt, .html, .htm передаються без змін (HTML проходить через pandoc → GFM markdown).
    • Office-формати.docx, .doc, .odt, .rtf конвертуються через pandoc (brew install pandoc на macOS, apt install pandoc на Linux).
    • PDF.pdf витягується через pdftotext з Poppler (brew install poppler / apt install poppler-utils).
    • Конвертований Markdown потрапляє в редактор; натисніть 💾 Save для збереження. Результат знешкоджується (такий самий XSS-фільтр, як при вставці).
    • Жорстке обмеження: 10 МБ на завантаження. Більші файли → 413.
  • З LinkedIn — найпростіший шлях: відкрийте Claude Code у батьківському проєкті, запустіть /career-ops, вставте URL LinkedIn і попросіть extract my CV from this and write it to cv.md.

Що знешкоджується

На стороні сервера кожен PUT до /api/cv проходить через stripDangerousMarkdown:

  • Теги <script>, <iframe>, <object>, <embed>, <svg>, <style>, <form> — видаляються повністю.
  • Вбудовані обробники подій (onclick=, onerror= тощо) — видаляються.
  • URI-схеми javascript:, vbscript:, data:text/html — нейтралізуються.

Відповідь містить sanitized: true, коли будь-що з перерахованого було видалено, щоб ви знали, чи джерело містило щось небезпечне.

Максимальний розмір тіла: 1 МБ. Більше → 413.

Інші кнопки

  • sync-check — запускає cv-sync-check.mjs у батьківському проєкті. Позначає невідповідності: проєкт, що є у CV, але відсутній в архетипах data/applications.md тощо.
  • 📄 Generate PDF — транслює generate-pdf.mjs. Результат потрапляє до output/*.pdf. Потрібен Playwright (сторінка Health показує, чи встановлено його в батьківській папці node_modules). Коли генерація завершується, найновіший PDF автоматично завантажується до вашої стандартної папки завантажень; список на сторінці зберігає всі раніше згенеровані файли.

Поради щодо тону та формату

  • Один пункт = одне досягнення з метрикою. «Reduced p99 latency by 38%» краще для кожної рубрики оцінки, ніж «improved performance».
  • Розділи в такому порядку: Summary (3–5 рядків), Experience (зворотна хронологія), Projects (максимум 5), Education, Skills (без дублювань, без buzzword-супу).
  • Не перевищуйте 1500 слів. Рубрика оцінювання використовує щільну інформацію; розлоге CV штрафується за шум.

5. Портали та джерела (portals.yml)

Конфіг сканера знаходиться у portals.yml у батьківській кореневій папці. Важливі три розділи. Три розділи SPA (нижче) відповідають канонічній схемі career-ops.org з scan-job-portals 1:1.

Швидкий доступ: URL #/portals тепер веде прямо до App settings і (якщо налаштовано регіональне джерело) переходить до групи Regional sources — тому збережений або введений посилань #/portals більше не дає 404 (v1.42.0).

title_filter

title_filter:
  positive: [backend, engineer, senior, tech lead, golang, php]
  negative: [junior, intern, frontend, ios, android, java]
  seniority_boost: [Senior, Staff, Lead, Principal]

Відсканована вакансія проходить, коли її назва містить принаймні одне позитивне ключове слово І жодного негативного. Налаштовуйте обидва. Ключові слова — це підрядки без урахування регістру.

seniority_boost — третій ключ фільтра назв. Перераховані тут ключові слова нічого не відфільтровують — вони піднімають відповідні вакансії вище в результатах, щоб «Senior Backend Engineer» з’являлася вище за «Engineer». За замовчуванням: ["Senior", "Staff", "Lead"]. Налаштуйте відповідно до назв ваших цільових ролей.

Починайте з 3–5 позитивних ключових слів для ясності; розширюйте пізніше.

location_filter (необов’язково — web-ui 1.33.0, parent #570)

location_filter:
  allow:
    - "Remote"
    - "United States"
    - "Atlanta"
  block:
    - "India"
    - "London"
    - "Germany"

Фільтрує відскановані вакансії за рядком location (підрядок без урахування регістру), застосовується як при ATS-сканування, так і при регіональному. Семантика, ідентична канонічному scan.mjs career-ops:

  • Немає ключа location_filter → кожне місце проходить (за замовчуванням).
  • Вакансія з порожнім/відсутнім місцем → проходить (відсутність даних не штрафується).
  • Збіг ключового слова blockвідхилено (block має перевагу над allow).
  • allow порожній → проходить (block вже очищено).
  • allow непорожній → повинно збігатися принаймні з одним ключовим словом.

Ключ верхнього рівня в portals.yml (сусід title_filter, не вкладений у russian_portals). Використовуйте для відсіювання вакансій, що пройшли фільтр назв, але знаходяться в регіоні, де ви не можете працювати.

Починайте з 3–5 позитивних ключових слів для ясності; розширюйте пізніше.

content_filter (необов’язково — web-ui 1.75.0, parent #974). Ключ верхнього рівня, сусід location_filter, з тими самими списками ключових слів positive / negative, але зіставлюваний із текстом опису / фрагмента вакансії замість її місця розташування:

content_filter:
  positive: ["python", "machine learning"]
  negative: ["security clearance", "on-site only"]

Семантика ідентична location_filter: немає ключа → усе проходить; вакансія з порожнім/відсутнім описом проходить (відсутні дані не караються); збіг negative → відхилена; positive порожнє → проходить; positive непорожнє → має збігтися щонайменше з одним ключовим словом (підрядок без урахування регістру). Застосовується як ATS-, так і регіональним sweep. Стосується лише джерел, що постачають опис/фрагмент (наприклад RSS) — будь-яка інша вакансія проходить — тож його ввімкнення ніколи мовчки не видаляє рядки з джерел, що не несуть тіла. Використовуйте його, щоб відсіяти вакансію, яка пройшла фільтр назви, але тіло якої виявляє неприйнятну умову.

search_queries

search_queries:
  - name: "Greenhouse — Rails Engineer"
    query: 'site:job-boards.greenhouse.io "Rails Engineer" OR "Ruby on Rails" remote'
    enabled: true
  - name: "Ashby — Senior Backend"
    query: 'site:jobs.ashbyhq.com "Senior Backend" remote'
    enabled: false

search_queries керують AI-powered скануванням Варіанту Б (/career-ops scan всередині Claude Code / Codex). Вони НЕ виконуються в процесі npm run scan (який лише звертається до публічних API дошок). Використовуйте їх, коли хочете знаходити ролі в компаніях, яких ще немає в tracked_companies. Встановіть enabled: false, щоб зберегти запис без запуску.

tracked_companies

tracked_companies:
  - { name: Stripe,     enabled: true, careers_url: https://job-boards.greenhouse.io/stripe }
  - { name: Linear,     enabled: true, careers_url: https://jobs.ashbyhq.com/linear }
  - { name: JetBrains,  enabled: true, careers_url: https://jobs.lever.co/jetbrains }

Обов’язкові поля для кожного запису: name та careers_url. Необов’язкові: api (явний ендпоінт Greenhouse / Ashby / Lever / Workable / SmartRecruiters / Workday), enabled: true|false для включення/виключення без видалення запису. ATS-сканер визначає ATS за шаблоном URL (job-boards.greenhouse.io/<slug> → Greenhouse тощо) і безпосередньо звертається до публічного API дошок кожної компанії. Компанії без розпізнаваного ATS пропускаються (картка Active Companies на /#/scan показує їх сірим із ).

rss (RSS / Atom дошки)

tracked_companies:
  - { name: LaraJobs, enabled: true, provider: rss, rss: https://larajobs.com/feed }
  - { name: WeWorkRemotely, enabled: true, provider: rss, rss: https://weworkremotely.com/remote-jobs.rss }

Направте сканер на будь-яку дошку вакансій, що публікує RSS/Atom-стрічку (LaraJobs, WeWorkRemotely, RemoteOK, golangprojects тощо), додавши запис із provider: rss і ключем rss: (або feed_url:) — без змін у коді. RSS-адаптер парсить кожен <item> (CDATA + HTML-сутності, назви/компанії очищаються від тегів), нормалізує до вакансії та запускає той самий потік title_filter / location_filter + дедуплікація + додавання до pipeline, що й ATS-джерела. RSS потім з’являється як вибране джерело у випадаючому списку фільтрів #/scan. (web-ui v1.62.x)

russian_portals

russian_portals:
  sources: ["hh", "habr", "trudvsem", "getmatch", "geekjob"]      # or just one
  area: 113                 # 1=Moscow, 2=SPb, 113=Russia, 1001=remote
  per_page: 50
  only_remote: false
  queries:
    - "Senior PHP"
    - "Senior Go"
    - "Тимлид PHP"

queries — це підрядки без урахування регістру, що зіставляються з назвами вакансій на hh.ru та Habr Career. Будьте обережні щодо перетину з негативним списком — якщо "Senior PHP" є в queries, але "php" потрапляє до title_filter.negative, сканування поверне нуль результатів, і консоль попередить про конфлікт.

Налаштування російських порталів — детальний посібник

v1.29.0 постачається з 5 адаптерами для Russian-language. Двом не потрібно нічого, крім стандартного UA (habr-career, HTML-скрейп; trudvsem, відкрите урядове API даних — без ключа, без IP-обмеження). Два — HTML-скрейпи технічних дошок (getmatch, geekjob — також без ключа). Один — канонічне hh.ru API, яке може повернути 403 з не-російських IP, якщо не встановлено змінну середовища HH_USER_AGENT через App settings → API keys & runtime (або запустити сервер із російського IP / VPN-вузла виходу).

Інвентар джерел

Ключ джерела Мітка Тип Автентифікація Гео-обмеження
hh hh.ru JSON API необов’язковий HH_USER_AGENT не-RU IP можуть отримати 403
habr Habr Career HTML немає немає
trudvsem Trudvsem JSON API (відкриті дані) немає немає
getmatch GetMatch HTML немає немає
geekjob GeekJob HTML немає немає

Крок 1 — Відкрийте portals.yml

Файл знаходиться у корені батьківського career-ops/ (НЕ всередині web-ui/). Якщо він ще не існує, скопіюйте приклад, що постачається з батьківським проєктом:

# from the parent career-ops/ root (NOT web-ui/)
cp templates/portals.example.yml portals.yml
$EDITOR portals.yml

Крок 2 — Увімкніть усі 5 джерел

Додайте або оновіть блок russian_portals, щоб перерахувати всі джерела, які ви хочете сканувати. Порядок у масиві не важливий; сканер обходить їх у порядку реєстру.

russian_portals:
  sources: ["hh", "habr", "trudvsem", "getmatch", "geekjob"]
  area: 113                  # 1=Moscow, 2=SPb, 113=Russia, 1001=remote
  per_page: 50               # how many vacancies per query per source
  only_remote: false         # set true to keep only remote postings
  queries:
    - "Senior PHP"
    - "Senior Go"
    - "Backend Senior"
    - "Тимлид PHP"

Крок 3 — Налаштуйте запити та фільтри

queries — це рядки, які сканер використовує для пошуку в кожному джерелі. Кожен запит виконується один раз на кожному джерелі — тому 4 запити × 5 джерел = 20 звернень за скан. Тримайте список компактним (3–7 запитів), щоб час сканування був менше хвилини. area — код регіону hh.ru (інші джерела ігнорують його). per_page обмежує кількість вакансій, що повертає кожне джерело на запит. only_remote: true фільтрує всі результати до тільки-remote на рівні адаптера (таблиця результатів все одно має окремий чип Remote).

Поширені помилки

Колізія негативного списку. Якщо слово із запиту ("php", "senior") також є в title_filter.negative, всі результати відфільтровуються до того, як ви їх побачите. Сканер виводить попередження про колізію у stderr під час сканування — шукайте рядок ⚠ config: query "Senior PHP" contains "php" which is in the negative list. Виправте, видаливши слово-колізію з negative:

title_filter:
  positive: [backend, senior, lead, php, go, golang, python]
  negative: [junior, intern, frontend, ios, android]
russian_portals:
  queries:
    - "Senior PHP"     # OK — "php" no longer in negative list
    - "Senior Go"

Тимчасове вимкнення одного джерела

Щоб вимкнути джерело без видалення його даних, просто приберіть його ключ із sources:

russian_portals:
  sources: ["hh", "habr", "trudvsem"]   # only 3 of 5 sources will run

Перевірка налаштування

Після збереження portals.yml:

# 1. Save portals.yml.
# 2. In the SPA, switch to #/scan.
# 3. Click 🌐 Scan now.
# 4. Watch the SSE log for the per-source line per query:
#       "Senior PHP"
#         hh.ru    18
#         habr     21
#         trudvsem  3
#         getmatch  0
#         geekjob   2
#    A value of 0 is normal for some queries — it just means that
#    source had no matches. A "geo-blocked" or "timeout" line means
#    the adapter reached the site but couldn't read results.

Порядок бутстрепу через CLI (scan-job-portals)

Канонічне налаштування career-ops (один раз із батьківського кореня):

cp templates/portals.example.yml portals.yml
$EDITOR portals.yml

Це весь бутстреп. Відредагуйте три розділи (title_filter, tracked_companies, search_queries, необов’язково russian_portals), збережіть — і ви готові до сканування.

Поведінка SPA при бутстрепі

При першому запуску сервер додає задокументований блок russian_portals: до portals.yml, якщо він відсутній — ідемпотентно (другий запуск — no-op, оскільки рядок russian_portals: вже є). Англомовні розділи НЕ вставляються автоматично; вони беруться з templates/portals.example.yml, який ви скопіювали згідно з канонічним бутстрепом вище.


6. Health (#/health)

Кожний вентиль налаштування з бейджами OK / OPTIONAL / FAIL. Читайте це перед тим, як відкривати будь-яке питання «не працює».

Витрати та вартість ШІ. Сторінка Витрати ШІ (💳, поруч зі «Здоров’ям») показує токени живих генерацій ШІ за провайдерами за 24 г / 7 д / 30 д / весь час, з оцінкою вартості в USD за редагованою таблицею цін (до оплати не виставляється). Компактний лічильник ВИКОРИСТАННЯ також закріплено внизу лівої бічної панелі на кожній сторінці — ті самі суми токенів за 24г/7д/30д та оцінка вартості за 24 години, оновлюється наживо; меню завжди залишається видимим над ним, а клік на заголовок згортає його.

Обов’язкові перевірки (система не може функціонувати без них)

  • Node version ≥ 18 — сервер використовує нативний fetch та node:test.
  • Project root — що CAREER_OPS_ROOT (env або автовизначений) існує.
  • cv.md, config/profile.yml, portals.yml, data/applications.md, data/pipeline.md, modes/oferta.md.

Необов’язкові перевірки (лише попередження)

  • Profile customizedcandidate.full_name не є шаблонним плейсхолдером.
  • GEMINI_API_KEY / ANTHROPIC_API_KEY — встановлені в .env.
  • (server uses default UA) — має значення лише при скануванні hh.ru поза Росією.
  • Playwright (parent node_modules) — потрібен для генерації PDF та check-liveness.mjs. Встановіть за допомогою cd $CAREER_OPS_ROOT && npm install && npx playwright install chromium.
  • Parent project dependenciescd $CAREER_OPS_ROOT && npm install, якщо відсутні.
  • Директорії data/, reports/, output/, jds/ — створюються автоматично при першому записі.

Коли сервер відкрито поза loopback (HOST=0.0.0.0), абсолютні шляхи та точна версія Node замінюються на "hidden" у відповіді, щоб допитливий сусід не міг ідентифікувати вашу інсталяцію.

Кнопки запуску

  • ▶ Doctor запускає node doctor.mjs і показує вивід у модальному вікні.
  • ▶ Verify pipeline запускає node verify-pipeline.mjs.

7. Сканування (#/scan)

Сканер обходить кожну увімкнену дошку, дедублікує відносно вашої історії та записує результати до data/last-scan.json та data/pipeline.md.

Пошук + Виключити. Поле «Пошук» трактує коми як АБО («ролі для пошуку»); нове поле «Виключити» ховає рядки з будь-яким словом через кому. Обидва зберігаються з вашими пошуками.

Сканування одним кліком (SPA)

🌐 Scan запускає кожне увімкнене джерело в одному проході:

  • Greenhouse / Ashby / Lever / Workable / SmartRecruiters / Workday (ATS-прохід) для кожної компанії в tracked_companies із розпізнаваним URL ATS.
  • Агрегатори з v1.75.0 для кожного запису tracked_companies, який їх обирає: RemoteOK / Remotive / Working Nomads (загальнодошкові віддалені стрічки, provider: <slug>) та IBM / Arbeitsagentur / Glints / Jobstreet · SEEK (керовані конфігурацією, блок <provider>: на запис).
  • hh.ru API + Habr Career + Trudvsem + GetMatch + GeekJob для кожного запиту в russian_portals.

Дві фази, один клік (v1.29.2). Одна кнопка 🌐 Scan керує як ATS-проходом, так і регіональним проходом в одному SSE-потоці. У журналі ви побачите два заголовки фаз по порядку:

  1. ▶ ATS scan (Greenhouse + Ashby + Lever) — EN ATS дошки.
  2. ▶ Regional scan (hh.ru + Habr Career) — 5 RU-джерел із реєстру.

Кожна фаза закінчується зведенням ✓ done · NEW=N. Якщо ви бачите лише ATS-фазу, ви на збірці до v1.29.2 — оновіть. До v1.29.2 SSE-клієнт закривався на першій події done, і регіональна фаза мовчки відкидалась (tests/scan-stream-multi-phase.test.mjs є сіткою регресії).

Живий SSE-журнал транслюється в праву панель під час сканування. Натисніть Stop (або просто перейдіть на іншу сторінку) для переривання — сервер скасовує поточні HTTPS-запити через AbortController.

Фільтрування результатів

Під журналом таблиця результатів відображає рядки з data/last-scan.json.

v1.78.1 — живе автооновлення. Таблиця результатів тепер оновлюється автоматично, поки триває сканування, і ще раз одразу після його завершення — без ручного перезавантаження чи перемикання сторінки.

v1.80.0 — Max per source та карантин джерел. Поле Max per source поруч із кнопкою Scan обмежує, скільки вакансій надає кожна дошка (порожнє/0 = без обмежень, за замовчуванням) — зручно, коли одна величезна дошка інакше домінувала б. Окремо, будь-яке джерело, що повертає постійний 404 / 410, записується у data/scan-quarantine.json і пропускається під час подальших сканувань (самовідновлення: повторна спроба через 14 днів), тож мертві slug-и перестають засмічувати журнал. Вимкніть через scan_quarantine: false у portals.yml.

Фільтри:

  • Вільний текст — підрядковий збіг за назвою / компанією.
  • Випадаючий список Source — Arbeitsagentur / Ashby / BambooHR / Breezy HR / Comeet / GeekJob / Glints / Greenhouse / GetMatch / Habr Career / hh.ru / IBM / Jobstreet · SEEK / Lever / Personio / Recruitee / RemoteOK / Remotive / RSS / SmartRecruiters / SolidJobs / Teamtailor / Trudvsem / We Work Remotely / Workable / Workday / Working Nomads (автозаповнюється з GET /api/scan/sources).
  • Випадаючий список Remote / Hybrid / Onsite.
  • Випадаючий список Country (v1.78.0) — гео-фільтр, що заповнюється з країн, виявлених у поточних результатах, кожна показана зі своїм емодзі прапорця та лічильником (напр. 🇩🇪 Germany (12)). Виберіть одну, щоб залишити лише вакансії, прив’язані до цієї країни. Виявлення зіставляє вільний текст локації вакансії (назви країн/аліаси + ~100 великих міст ринку праці) з країною; воно консервативне й ніколи не вгадує, тож вакансія, локацію якої не вдалося визначити — або суто «Remote»-оголошення — залишається в All countries. Поєднуйте його з випадаючим списком типу роботи, щоб знаходити вакансії, прив’язані до країни, та віддалені.
  • Випадаючий список Posted within (v1.80.0) — клієнтський фільтр за віком (Last 24 hours / 7 days / 30 days). Рядки, чий pubDate старший, приховуються; рядки без зазначеної дати проходять (відсутність даних не штрафується).
  • ★ Обране (v1.80.0) — клацніть ☆ у будь-якому рядку, щоб додати вакансію в обране (зберігається в localStorage за URL); поставте позначку ★ Обране на панелі фільтрів, щоб показати лише обрані рядки. Зірочки переживають сканування та перезавантаження.
  • Збережені пошуки (v1.80.0) — панель над фільтрами: назвіть поточний набір фільтрів і натисніть 💾 Зберегти, потім застосовуйте його повторно з випадаючого списку або 🗑 Видаліть його. Зберігається в localStorage; пошкоджене/відредаговане значення чисто скидається до порожнього.
  • Стекові чипи (PHP / Go / Backend / Senior / …) — автовизначаються для кожного рядка через Skills.detectTech і Skills.detectLevel. Множинний вибір з перетином — вибір PHP + Senior показує рядки, що мають ОБИДВА.
  • Динамічні чипи під статичними стековими — топ-25 найчастіших токенів із великої літери в назвах, тому UI адаптується до ролей, які ви фактично сканували (маркетинг, дизайн, фінанси…), замість того щоб бути прив’язаним до словника backend-розробника.

Картка Active Companies

Розгортальна картка зі списком кожної компанії в portals.yml та її статусом сканування:

  • ✓ зелений тег — пряма підтримка API (Greenhouse / Ashby / Lever / Workable / SmartRecruiters / Workday).
  • ○ сірий тег — резервний режим через промпт веб-пошуку (немає збігу з API).

Натисніть назву компанії → заповнює фільтр результатів вище цією назвою. Натисніть іконку ↗ → відкриває careers_url компанії в новій вкладці.

Потік сканування через CLI (scan-job-portals)

Два способи сканування з CLI (обидва додають URL до того самого data/pipeline.md, який читає SPA):

Варіант A — прямий скрипт (~30 с, нуль AI-токенів):

npm run scan                          # all Greenhouse/Ashby/Lever boards
npm run scan -- --dry-run             # preview without persisting
npm run scan -- --company Anthropic   # narrow to one tracked company

Працює лише для Greenhouse / Ashby / Lever / Workable / SmartRecruiters / Workday (розпізнавані URL ATS). AI-токени не витрачаються — звертається безпосередньо до публічних API дошок.

Варіант B — AI-powered скан через браузер:

/career-ops scan

Всередині Claude Code / Codex / Cursor / Gemini CLI. Використовує токени моделі. Відвідує кожну сторінку tracked_companies безпосередньо та може знаходити не-API-дошки (сторінки careers, власні ATS, регіональні портали). Повільніше, але ширше охоплення. Корисно, коли ATS-прохід не повертає нічого для цілі, яка, як ви знаєте, набирає людей.

Вивід (обидва шляхи) — нові URL вакансій додаються до data/pipeline.md, кожен відвіданий URL записується до data/scan-history.tsv (дедублікація для всіх майбутніх сканувань), виводиться зведення: сканованих компаній · знайдено вакансій · відфільтровано за назвою · пропущено дублікатів · додано нових пропозицій.

Порогові значення дій за балом (застосовуються після того, як /career-ops pipeline пакетно оцінить нові URL):

Бал Рекомендований наступний крок
≥ 4.5 /career-ops apply — висока відповідність, надсилайте одразу
4.0 – 4.4 подавайте заявку або /career-ops contacto для теплого знайомства
3.5 – 3.9 /career-ops deep — спочатку дослідіть
< 3.5 пропустіть, якщо немає особистої причини

#/dashboard та #/tracker SPA виділяють кожен рядок з балом 4.0 і вище, щоб ви могли вибрати дію без повторного запуску.

Наступні команди

Після оцінювання канонічні подальші кроки:

  • /career-ops apply — заповніть заявку адаптованими відповідями
  • /career-ops contacto — підготуйте повідомлення для LinkedIn / email
  • /career-ops deep — глибоко дослідіть компанію / роль
  • /career-ops tracker — перегляньте статус pipeline

hh.ru — сканується з вебсайту (з липня 2026 потрібна російська IP)

hh.ru сканується читанням публічної пошукової видачі сайту (hh.ru/search/vacancy) — так само, як Habr Career: без ключа й налаштувань. Проте з липня 2026 hh.ru віддає HTTP 451 (регіональне юридичне блокування) для IP поза Росією, тому сканування працює лише з російської IP — запускайте сервер із Росії або через VPN з російською точкою виходу. За першого 451 (або анти-бот 403) сканер вимикає hh.ru до кінця прогону й пише про це в лог, тож інші російські джерела допрацьовують нормально. JSON API (api.hh.ru) навмисно не використовується: він повертає 403 forbidden будь-якому програмному клієнту незалежно від IP та User-Agent.

Навіть із мережі, яка виглядає правильною, hh.ru може вважати вихідний IP VPN/проксі (будь-який датацентровий/хостинговий IP підпадає під це) і відправити скан 302-редиректом на заглушку /vpncheeck («VPN мешает работе сайта»), яка відповідає HTTP 200 із нулем вакансій. Сканер розпізнає цей редирект, вимикає hh.ru до кінця прогону й повідомляє про це в лозі. Рішення — на боці мережі: переконайтеся, що трафік справді виходить через резидентний IP — системний VPN чи проксі часто лишається ввімкненим, навіть коли перемикач у браузері вимкнено (перевірте реальний вихідний IP, наприклад на api.ipify.org).

8. Pipeline (#/pipeline)

Вхідні URL, що очікують оцінки. Зберігаються в data/pipeline.md.

Смуга огляду. Компактна смуга вгорі показує пайплайн з одного погляду — скільки URL у вхідних, скільки відстежується та лічильники Applied/Responded/Interview/Offer, кожен веде до трекера.

Додавання URL

Три способи:

  • Введіть / вставте URL у поле вводу та натисніть + Add.
  • Використовуйте глобальний пошук у верхній панелі (його бейдж показує Enter): вставте будь-яке посилання http(s)://… та натисніть Enter, щоб відкрити авто-pipeline; введіть будь-який інший текст, і Enter переходить на #/scan з попередньо заповненим цим запитом (v1.78.1). Ctrl/Cmd+K, як і раніше, фокусує поле там, де це дозволяє браузер. Логотип бренда повертає на дашборд.
  • Запустіть Scan (дивіться вище) — свіжі результати додаються до pipeline автоматично.

Кожен URL проходить перевірку isValidJobUrl() на стороні сервера. Loopback (localhost, 127.0.0.1), file://, javascript:, IP-літерали та рядки з шаблонними символами (<, >, ") повертають 400.

Панель попереднього перегляду на стороні сервера

Натисніть будь-який рядок pipeline, щоб завантажити попередній перегляд праворуч. Більшість ATS-дошок не надсилають CORS-заголовки, тому браузер не може отримати їх безпосередньо; сервер проксіює запит, знімає <script> / <style> / HTML-теги та повертає до 8 КБ простого тексту.

Проксі попереднього перегляду обходить переспрямування вручну з перевіркою SSRF на кожному кроці — кожен заголовок Location повторно проходить через isValidJobUrl(), тому шкідлива дошка не зможе перенаправити вас на loopback / приватний IP / file://. Обмеження: 3 кроки, таймаут 15 секунд.

Дії рядка

  • — переходить до #/evaluate?url=… з попередньо заповненим URL.
  • — видаляє URL із data/pipeline.md.

Кнопки у верхньому правому куті

  • ⚡ Evaluate first — відкриває перший URL у черзі на сторінці Evaluate, готовий до оцінки.
  • Scan — повернення до сканера, якщо потрібно більше URL.

9. Оцінка (#/evaluate)

Оцінює одну вакансію порівняно з cv.md та config/profile.yml. Повертає структуровану оцінку A–G відповідно до modes/oferta.md та бал 0–5.

Введення

Вставте текст вакансії в textarea або потрапте сюди з #/pipeline із ?url=<href> — сторінка отримує URL через той самий SSRF-безпечний проксі, що й для попередніх переглядів pipeline, та попередньо заповнює textarea.

Натисніть 💾 Save JD, щоб зберегти текст вакансії до jds/jd-<date>-<ts>.txt для аудиторського сліду (або передайте save: true у виклику API — той самий ефект).

Ланцюжок резервних варіантів

  1. Anthropic — пріоритетний, коли встановлено ANTHROPIC_API_KEY. Сервер об’єднує cv.md, config/profile.yml, modes/_shared.md та modes/oferta.md у блок <project_context> перед промптом (кожен файл обмежений 16 КБ, м’яке обмеження всього промпту — 200 КБ). Повертає заземлений Markdown безпосередньо на сторінку.
  2. Gemini — коли встановлено лише GEMINI_API_KEY. Сервер запускає gemini-eval.mjs із текстом вакансії як тимчасовий файл. Модель безкоштовного рівня (gemini-2.0-flash) підходить для рутинного оцінювання.
  3. Ручний режим — ключ не встановлено. Сторінка повертає повністю сформований промпт, який можна вставити в Claude Code, ChatGPT або будь-який інший LLM.

Розділи виведення (канонічна схема career-ops.org A-F)

Вирівнювання v1.15.0. Літери блоків тепер відповідають канонічній схемі career-ops.org. До v1.15 звіти використовували A–G (де C=Risks, F=Verdict, G=Legitimacy); ми все ще відображаємо їх як є для зворотної сумісності, але нові звіти виводять A–F із канонічною семантикою нижче. Score і Legitimacy тепер знаходяться в заголовку звіту (score: 4.2/5, legitimacy: High|Medium|Low).

A. Role Summary — 3-пунктовий підсумок (ризики зазначаються вбудовано). B. CV Match — топ-3 навички, що збіглися + топ-3 відсутні. C. Strategy — рекомендація: подавати зараз / спочатку contacto / спочатку deep / пропустити. До v1.15 це були Risks. D. Compensation — відносно вашого target.comp_total_min_usd (legacy) або compensation.target_range (канонічний). E. Personalization — кут для акцентування, фреймінг за архетипом, гачки для згадки в супровідному листі / аутрич. До v1.15 це була Application Strategy. F. STAR stories — 1–3 готових до вставки блоки S-T-A-R, адаптовані до ролі. До v1.15 це був Verdict (сирий бал); бал тепер знаходиться в заголовку звіту поруч із legitimacy.

Збереження звіту

Натисніть 💾 Save report (або використайте перемикач save у виклику API), щоб зберегти Markdown до reports/<date>-<company>-<role>.md. Розібраний заголовок звіту (Score / Legitimacy / URL) з’являється на сторінках Reports та Dashboard.

Пакетна оцінка при 10+ вакансіях

Для однієї вакансії ця сторінка #/evaluate — правильний інструмент. Для 10+ URL у pipeline ручне клікання незручне — переходьте до підрозділу Batch evaluate розділу §14 (запуск ./batch/batch-runner.sh з батьківського проєкту), дайте йому попрацювати вночі, а потім повертайтеся до #/reports / #/tracker для результатів. Повний потік: batch-evaluate-offers.


10. Звіти (#/reports)

Перегляд усіх збережених оцінок. Картки показують назву, дату, прапор легітимності та бал (кольор-кодований: зелений ≥ 4.0, жовтий ≥ 3.0, червоний нижче).

Натисніть картку, щоб прочитати повний Markdown. Пагінація: 12 на сторінку; елементи керування внизу.

Перегляд одного звіту також має:

  • ← All reports — повернення до сітки.
  • 🔗 Open JD — відкриває оригінальну вакансію в новій вкладці.

11. Трекер (#/tracker)

CRM. Один рядок на заявку; зберігається у data/applications.md як таблиця GitHub-Flavored Markdown.

Потік статусів

EvaluatedAppliedRespondedInterviewOffer / Hired / Rejected / Discarded / SKIP.

Hired (v1.118.0) — фінальний щасливий статус: офер прийнято. Трекер позначає його святковим бейджем і вітає банером «роботу знайдено».

Білий список статусів перевіряється на стороні сервера; надсилання будь-чого іншого в POST /api/tracker за замовчуванням дає Evaluated. Канонічний перехід Evaluated → Applied відбувається автоматично, коли ви підтверджуєте Submitted. в кінці /career-ops apply (дивіться §14).

Розмітка стовпців

Стовпець Що це
# Автонумерація з нулями (001, 002, …).
Date ISO-дата (YYYY-MM-DD). За замовчуванням — сьогодні.
Company Вільний текст. Символи pipe (|) і переноси рядків екрануються автоматично.
Role Те саме.
Score Формат N/5 (наприклад, 4.2/5).
Status Перерахування з білого списку.
PDF ✅ після успішного завершення generate-pdf.mjs для цього рядка.
Report Посилання Markdown на відповідний reports/*.md.
Notes Вільний текст, обмежений 200 символами.

Фільтри

  • Випадаючий список Status.
  • Випадаючий список Score≥ 4.0 (високий), ≥ 3.0 (середній), < 3.0 (низький).
  • Search — підрядковий збіг за компанією + роллю.

Кожен фільтр скидає пагінатор до сторінки 1. 25 рядків на сторінку.

Кнопки технічного обслуговування

  • ▶ Normalize запускає normalize-statuses.mjs — повторно канонізує написання статусів (appliedApplied, interviewInterview).
  • ▶ Dedup запускає dedup-tracker.mjs — видаляє дублікати без урахування регістру за (company, role).
  • ▶ Merge запускає merge-tracker.mjs — підтягує відкладені записи з batch/tracker-additions/*.tsv (куди батьківський пакетний потік скидає заявки, надіслані через помічник Apply). Дедублікує та архівує оброблені файли до batch/tracker-additions/merged/. Дивіться batch-evaluate-offers для вхідного пакетного потоку.

Додавання рядків

POST /api/tracker — тіло { company, role, score?, status?, url?, reportSlug?, notes?, date? }. Дедублікація за (company, role) без урахування регістру. У UI сторінка Evaluate пропонує кнопку «Add to tracker» після успішного оцінювання.


12. Глибоке дослідження (#/deep)

Генеруйте структурований бриф компанії: огляд, інженерна культура, останні новини, настрої на Glassdoor, процес співбесіди, важелі для переговорів, три розумні питання рекрутеру.

Введення

Два поля — назва компанії та (необов’язково) роль. Шаблон режиму (modes/deep.md) формує структуру.

Шляхи виведення

Той самий ланцюжок резервних варіантів, що й при Evaluate:

  1. Anthropic live (пріоритет) — bundleProjectContext вбудовує cv + profile + _shared.md + deep.md. Виведення: 10–30 КБ заземленого Markdown, збереженого до interview-prep/<company>-<role>.md.
  2. Gemini live — виклик gemini-eval.mjs. Та сама ціль збереження.
  3. Ручний промпт — сторінка надає готовий промпт для Claude Code (що має WebFetch + WebSearch і може проводити реальні дослідження).

Поради

  • Anthropic на claude-sonnet-4-6 зазвичай повертає ~13 КБ корисного тексту за 1–3 хвилини на виклик.
  • Anthropic SDK не має вбудованого веб-пошуку. Для ролей, де потрібні свіжі новини + настрої Glassdoor, вставте ручний промпт у Claude Code і дайте йому використати інструмент WebFetch.
  • Живі запуски платні; один виклик глибокого дослідження Sonnet 4.6 коштує приблизно $0.30–0.50.

13. Режимні промпти (сім сторінок /#/<mode>)

Дошка каденції (v1.117.0). Сторінка фоллоу-апів тепер відкривається детермінованою дошкою каденції на даних батьківського followup-cadence.mjs: терміновість за кожною заявкою (🔴 терміново / 🟠 прострочено / 🟡 очікування / 🔵 охололо) з днями до наступного кроку, плюс кнопка «Проставити дати фоллоу-апів», що закріплює першу дату для кожного рядка Applied (followup-seed.mjs --backfill). Без батьківських скриптів дошка чесно повідомляє «недоступно».

Сім конструкторів промптів: ідеї Project, плани Training, листи Follow-up, оцінки Batch, аутрич до Outreach рекрутерів, односторінкові Interview prep, та ретроспективи Patterns. Кожен обгортає конкретний шаблон modes/<slug>.md:

Сторінка Slug Призначення
#/project project Адаптація портфоліо-проєкту під цільову роль.
#/training training Аналіз прогалин у навичках → навчальна програма.
#/followup followup Чернетка листа після співбесіди.
#/batch batch Промпт для пакетної оцінки кількох вакансій.
#/contacto contacto Повідомлення для рекрутера / рекомендатора.
#/interview-prep interview-prep Односторінкова підготовка до конкретного раунду співбесіди.
#/patterns patterns Рефлексивний аналіз «Які паттерни сприяли моєму успіху?».

Спільна форма

Кожна сторінка має невелику форму (поля специфічні для режиму), кнопку ▶ Generate prompt (ручний режим) та — при наявності ключа Anthropic або Gemini — кнопку ⚡ Run live, яка стає основною.

Натискання ▶ Generate prompt повертає зібраний промпт із вашими значеннями форми, серіалізованими в JSON у блоці User-supplied context:, а потім дослівний шаблон modes/<slug>.md. Скопіюйте та вставте у ваш LLM за вибором.

Натискання ⚡ Run live надсилає той самий промпт до Anthropic (або Gemini) із вбудованими cv.md + profile.yml + _shared.md через bundleProjectContext. Результат відображається на сторінці, доступний для копіювання та завантаження як .md.

Сім сторінок — це явний білий список — режими з окремим маршрутом (oferta → Evaluate, deep → Deep research) та режими, які батьківський проєкт підтримує лише всередині Claude Code (apply, scan, pipeline, tracker, pdf, latex, ofertas, auto-pipeline), навмисно залишені за межами цього UI.


14. Чеклист подачі заявки (#/apply)

Після прийняття рішення про подачу ця сторінка помічника генерує чеклист для кроку подачі заявки. Вона НЕ заповнює форми автоматично — цей потік залишається в /career-ops apply всередині Claude Code, що використовує Playwright у батьківському проєкті.

Режим чеклиста SPA (#/apply)

Чеклист SPA — для користувачів, які воліють заповнювати форму вручну, не викликаючи Playwright. Він охоплює:

  1. Запустіть /career-ops apply <url> у Claude Code, щоб прочитати форму через Playwright (пропустіть цей крок, якщо заповнюєте вручну).
  2. Перевірте, чи вакансія все ще активна (check-liveness.mjs).
  3. Переконайтеся, що CV актуальне (cv-sync-check.mjs, потім PDF якщо бал ≥ 4.0).
  4. Адаптуйте супровідний лист / відповідь «Чому ми?» використовуючи блоки доказів STAR+R з cv.md.
  5. Чесно відповідайте на питання EEO / спонсорства / дати початку.
  6. Збережіть заповнені відповіді до interview-prep/{company}-{role}.md перед надсиланням.
  7. НІКОЛИ не надсилайте автоматично — ви (людина) натискаєте фінальну кнопку.
  8. Після надсилання: додайте рядок до data/applications.md (або запишіть TSV до batch/tracker-additions/).

Ручне заповнення проти заповнення через Playwright

Два шляхи для фактичного надсилання:

  • Ручний — відкрийте сторінку careers у звичайній вкладці браузера, дотримуйтеся чеклиста SPA вище, копіюйте/вставляйте відповіді. Playwright не потрібен. Використовуйте, коли форма коротка або Chromium не встановлено.
  • Через Playwright — запустіть /career-ops apply <company> у Claude Code (батьківський проєкт). Playwright відкриває власний браузер, читає кожне поле форми, повертає пронумеровані чернеткові відповіді. Ви все одно натискаєте «Надіслати». Використовуйте, коли форма довга, динамічна, або ви хочете аудиторський слід того, які питання мали які відповіді.

Повний потік подачі через CLI (apply-for-a-job)

Передумови:

  1. Спочатку запустіть /career-ops pipeline, щоб у вакансії був звіт оцінки в reports/. Команда apply залежить від наявної оцінки; без неї спочатку запустіть pipeline.
  2. Мати звіт та профіль завантаженими.
  3. Рекомендовано: Playwright встановлений (npx playwright install chromium — дивіться Playwright Setup нижче). Резервно використовує WebFetch (лише текстовий попередній перегляд форми, без клік-заповнення) за відсутності.

Пронумерований потік (канонічні 8 кроків):

  1. Запустіть команду з назвою компанії:

    /career-ops apply <company>

    Приклад: /career-ops apply Anthropic. Без аргументу надайте скріншот форми, вставлений текст форми або URL заявки на наступному ході.

  2. Знайдіть звіт. Система знаходить відповідну оцінку в reports/ (ту, що створена /career-ops pipeline або #/evaluate раніше).

  3. Відкрийте форму. Playwright запускає вікно браузера автоматично — ви самі НЕ відкриваєте його.

  4. Прочитайте поля. Система читає та парсить кожне поле форми (мітка, тип, обов’язковість, варіанти для select).

  5. Генерація відповідей. career-ops створює адаптовані відповіді для кожного поля на основі вашого профілю, доказів та ролі.

  6. Повернення пронумерованого списку. Ви отримуєте відповіді в порядку форми — прості поля (ім’я, email) спочатку, поля з вільним текстом (супровідний лист, «Чому ми?») останніми. Позначені пункти вказують на речі, що потребують уваги людини — прив’язка до зарплати, відсутні деталі резюме, необов’язкові питання.

  7. Ручне заповнення. Ви копіюєте та вставляєте кожну відповідь у відповідне поле. Цей крок ручний, а не автоматичний. Ви переглядаєте кожну відповідь спочатку.

  8. Користувач надсилає. Ви натискаєте «Надіслати» самостійно. career-ops ніколи не натискає «Надіслати». Підтвердьте завершення, написавши в чаті:

    Submitted.

Автоматичні оновлення при Submitted.:

  • Статус змінюється з Evaluated на Applied в data/applications.md.
  • Заповнені відповіді зберігаються в розділі G звіту для подальшого використання.

Передача до трекера:

/career-ops tracker

Відстежуйте статус усього свого pipeline, незалежно від балу ролі.

Пакетна оцінка (batch-evaluate-offers)

Коли у вас 10+ вакансій для оцінки одночасно (сторінка #/evaluate SPA по одній незручна для такого обсягу), використовуйте batch runner із CLI.

Файл введення — batch/batch-input.tsv (розділений табуляцією):

Стовпець Призначення
id Унікальний послідовний номер
url Повне посилання на вакансію
source Платформа-джерело (LinkedIn, Greenhouse тощо)
notes Необов’язкова контекстна деталь

Приклад рядка:

1<TAB>https://jobs.example.com/senior<TAB>LinkedIn<TAB>

Прапори ./batch/batch-runner.sh:

  • --dry-run — Переглянути відкладені пропозиції без оцінки. Завжди запускайте це спочатку для перевірки TSV.
  • --parallel N — Запустити N паралельних воркерів (рекомендовано 1, 2 або 3).
  • --min-score X.X — Пропустити збереження пропозицій із балом нижче порогового. Корисно для збереження лише звітів з висококому відповідністю.
  • --retry-failed — Повторно обробити лише пропозиції, що завершилися з помилкою в попередньому запуску (мережеві збої, ліміти запитів).
  • --max-retries N — Спробувати невдалі пропозиції до N разів (за замовчуванням: 2).
  • --model NAME — Модель Claude, що передається до claude -p --model (parent career-ops 1.8.0, #504). Не встановлено = стандарт вашої підписки Claude Max. Використовуйте дешевшу модель для великих пакетів, наприклад claude-sonnet-4-6. Відображається в #/batch як поле Model (web-ui 1.31.0).
  • --start-from N — Пропустити ID пропозицій нижче N (відновити частково оброблений пакет). Відображається в #/batch як поле Start from # (web-ui 1.31.0).

Стандартна послідовність:

  1. Відредагуйте batch/batch-input.tsv — один рядок на вакансію.

  2. Dry-run (рекомендовано спочатку):

    ./batch/batch-runner.sh --dry-run
  3. Запуск — послідовний або паралельний:

    ./batch/batch-runner.sh                       # one at a time
    ./batch/batch-runner.sh --parallel 2          # two concurrent
    ./batch/batch-runner.sh --parallel 3          # three concurrent
    ./batch/batch-runner.sh --parallel 2 --min-score 4.0  # only persist high-fit
  4. Повтор невдалих (мережа / ліміт запитів):

    ./batch/batch-runner.sh --retry-failed --max-retries 3
  5. Звіти потрапляють до reports/ як {id}-{company}-{YYYY-MM-DD}.md. Підсумкові рядки додаються до batch/tracker-additions/.

  6. Злиття з трекером:

    node merge-tracker.mjs                 # apply the batch additions
    node merge-tracker.mjs --dry-run       # preview the merge

    Команда злиття дедублікує записи та архівує оброблені файли до batch/tracker-additions/merged/.

SPA відображає результуючі звіти в #/reports (з пагінацією, кольоровими балами) та рядки трекера в #/tracker — так само, як якби ви додавали кожен через #/evaluate. Поєднайте з кнопкою ▶ Merge в #/tracker, якщо ви воліть не переходити в CLI.

Налаштування Playwright (set-up-playwright)

Потрібно для двох функцій career-ops:

  • Заповнення форм у /career-ops apply (крок 3 вище — Playwright відкриває браузер, читає мітки полів, пропонує відповіді).
  • Генерація PDF через /career-ops pdf та кнопку 📄 Generate PDF у SPA на #/cv / #/reports/:slug / #/evaluate / #/deep / #/interview-prep.

Резервний варіант при відсутності Playwright: потік apply переходить до WebFetch (лише текстовий попередній перегляд форми, без клік-заповнення). Генерація PDF просто повертає помилку.

Базове налаштування (запускається з кореня батьківського career-ops):

# Install Chromium for Playwright
npm install
npx playwright install chromium

# Register the Playwright MCP so Claude Code can drive forms
claude mcp add playwright npx @playwright/mcp@latest

# Verify all three components (Chromium, Playwright lib, MCP)
npm run doctor

Альтернативна реєстрація MCP — додайте до .claude/settings.local.json:

{
  "mcpServers": {
    "playwright": {
      "command": "npx",
      "args": ["-y", "@playwright/mcp@latest"]
    }
  }
}

Примітки щодо поведінки:

  • Headless за замовчуванням. Playwright працює мовчки. Щоб спостерігати за дією браузера, скажіть Claude open up with playwright the browser and fill out the entire form.
  • Три ролі в одному пакеті — встановлення npm Playwright надає вам бібліотеку автоматизації браузера, рушій рендерингу PDF для /career-ops pdf і (через MCP) робочий процес заповнення форм усередині Claude Code.
  • Перевіряйте перед використаннямnpm run doctor підтверджує, що всі три компоненти функціонують. Перевірка Playwright (parent node_modules) на сторінці Health SPA швидко виявляє відсутність.

15. Підготовка до співбесіди

Це фаза після дослідження, перед співбесідою. Три артефакти в цьому застосунку сходяться:

  1. Збережені файли глибокого дослідження в interview-prep/, по одному на кожну пару компанія-роль, яку ви запускали. Перегляньте зі сторінки Deep research або безпосередньо через /api/interview-prep.
  2. Режим Patterns (#/patterns) — генерує промпт для саморефлексії: «в усіх моїх останніх N співбесідах / пропозиціях / відмовах, які паттерни простежуються?» Корисно, коли ви накопичили 5+ рядків трекера.
  3. Режим Interview-prep (#/interview-prep) — попередньо заповнює односторінкову підготовку до конкретного майбутнього раунду (поведінковий, технічний, системний дизайн). Результат потрапляє до тієї самої папки interview-prep/.

Рекомендований робочий процес

Для кожної співбесіди, що є у вашому розкладі:

  1. Перезапустіть Deep (або відкрийте збережений файл) напередодні.
  2. #/interview-prep — згенеруйте односторінковку для конкретного раунду. Вставте у свої нотатки.
  3. Раунди системного дизайну / кодингу — відкрийте #/training та попросіть 30-хвилинне цільове повторення конкретної підсистеми, яку акцентує вакансія.
  4. Раунди з компенсацій — відкрийте файл глибокого дослідження, перейдіть до «Negotiation leverage points». Підготуйте 2–3 конкретні точки даних (діапазон Glassdoor, нещодавнє фінансування, порівнянна пропозиція в іншій компанії).
  5. Поведінкові раунди — витягніть STAR+R-приклади зі свого cv.md, що знаходяться в розділі B оригінального звіту Evaluate.

Відразу після співбесіди:

  1. Оновіть рядок трекера: статус → Responded (потім Interview, Offer тощо).
  2. Запустіть #/followup, щоб написати лист подяки.
  3. Якщо отримали нову інформацію (діапазон компенсації, склад команди, несподівані технологічні вимоги), відредагуйте збережений interview-prep/<company>-<role>.md, додавши ## Post-round notes, щоб майбутнє «я» мало це під рукою.

16. Журнал активності + Усунення несправностей

Журнал активності (#/activity)

Аудиторський слід кожного запиту зі зміною стану, що надходить на сервер. Записує: додавання до pipeline, записи в трекер, збереження CV, збереження вакансій, запуски оцінювання, запуски глибокого дослідження, запуски сканування, зміни конфігурації, запуски режимів.

Секрети (ANTHROPIC_API_KEY, GEMINI_API_KEY) редагуються на вході; ви ніколи не побачите реальне значення ключа в data/activity.jsonl.

Фільтруйте за префіксом дії (pipeline., cv., evaluate, scan. тощо). 25 рядків на сторінку; сервер повертає до 500 найновіших подій.

Усунення несправностей

Симптом Ймовірна причина Вирішення
Сторінка Health червона на cv.md Перший запуск, файл ще не існує touch $CAREER_OPS_ROOT/cv.md і оновіть сторінку.
Health червона на Profile customized candidate.full_name досі Jane Smith Відредагуйте config/profile.yml.
hh.ru: HTTP 403 у журналі сканування Не-російський IP, немає (server uses default UA) Зареєструйтеся на dev.hh.ru/admin, використовуйте російський IP / VPN.
gemini-eval.mjs: ERR_MODULE_NOT_FOUND Залежності батьківського проєкту не встановлені cd $CAREER_OPS_ROOT && npm install.
Генерація PDF завершується з помилкою Playwright не встановлено в батьківському проєкті cd $CAREER_OPS_ROOT && npx playwright install chromium.
/career-ops apply каже «no report found» Pipeline ніколи не оцінював цю вакансію Спочатку запустіть /career-ops pipeline (або #/evaluate); дивіться §14 передумови.
batch-runner.sh: no such file Запуск із неправильної директорії cd $CAREER_OPS_ROOT перед викликом ./batch/batch-runner.sh.
Сервер повідомляє EADDRINUSE: 4317 Стара інстанція досі працює pkill -f 'node server/index.mjs' і перезапустіть.
Живий виклик LLM висить > 2 хв Промпт величезний або Anthropic повільний Перевірте прапор Anthropic на /api/health; сервер м’яко обмежує промпти на 200 КБ і повертає 413.
Попередній перегляд pipeline показує (unsafe redirect) Вакансія перенаправила на приватний IP / loopback Це функція безпеки (REVIEW-B1). Ціль переспрямування відхиляється, початковий URL залишається незмінним.
Текст рядка трекера ламає таблицю Pipe у назві компанії до v1.9.1 Оновіть до v1.9.1+ — символи pipe екрануються наскрізно (BF-1).
npm test не проходить на свіжому клоні Тести передбачають структуру батьківського проєкту Використовуйте CAREER_OPS_ROOT=$(mktemp -d) і ініціалізуйте фікстури.

Для глибшої діагностики: запустіть ▶ Doctor на сторінці Health, скопіюйте вивід та пошукайте в трекері задач на https://github.com/Fighter90/career-ops-ui/issues.


17. Як додати нове джерело вакансій

career-ops-ui розглядає кожну дошку вакансій як адаптер — один файл у server/lib/sources/<slug>.mjs, що знає, як отримати та нормалізувати результати однієї дошки. Станом на v1.118.0 реєстр server/lib/sources/ постачається з 59 адаптерами — 54 англомовних + 5 російськомовних дошок. Англомовний набір охоплює основні ATS (Greenhouse / Ashby / Lever / Workable / SmartRecruiters / Workday), загальнодошкові агрегатори, що вибираються через явний provider: (RemoteOK, Remotive, We Work Remotely, NoDesk, Get on Board, Amazon, …), та ATS на тенант, які автоматично визначаються з хоста careers_url або явного api: URL (BambooHR, Personio, Recruitee, Teamtailor, Avature, SAP SuccessFactors, …). Повний список ніколи не потрібно рахувати тут вручну — він автоматично виявляється з server/lib/sources/ і показується наживо у випадному списку Source на #/scan. Дивіться §5 щодо YAML та docs/portals-examples.md щодо готових записів для копіювання.

v1.69.0 (P-14) — підключи та використовуй з автовідкриттям. Додавання 12-го джерела тепер — це просто скинути файл. Реєстр (server/lib/sources/registry.mjs) більше не містить вручну підтримуваного списку — при завантаженні він сканує цю папку (readdirSync + динамічний import()) та збирає блок export const meta з кожного *.mjs. Напишіть адаптер, оголосіть його meta — і він одразу видимий для сканера, випадаючого фільтра #/scan та RU-диспетчера — редагування registry.mjs не потрібне. (RU-джерела все одно потребують одного рядка в portals.yml батьківського проєкту; дивіться Крок 5.)

Крок 1 — Напишіть адаптер

Створіть server/lib/sources/<slug>.mjs. Два шаблони залежно від того, чи є у джерела JSON API або лише HTML:

Джерело з API (найчистіше — використовуйте, коли є відкритий ендпоінт даних):

// server/lib/sources/example.mjs
const ENDPOINT = 'https://example.com/api/v1/vacancies';
const UA = 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) ...';

// v1.69.0 (P-14) — self-describing metadata. The registry auto-discovers
// this block at boot; THIS is what registers the source (see Step 2).
export const meta = {
  value: 'example',          // ← must equal job.source written below
  label: 'Example.com',      // ← shown in the #/scan filter dropdown
  region: 'ru',              // ← 'en' (ATS sweep) | 'ru' (regional dispatcher)
  configKey: 'example',      // ← RU only; the key used in portals.yml
};

export async function searchExample(query, opts = {}) {
  const { onlyRemote = false, fetchImpl = fetch, signal } = opts;
  const res = await fetchImpl(`${ENDPOINT}?text=${encodeURIComponent(query)}`, {
    signal,
    headers: { 'User-Agent': UA, Accept: 'application/json' },
  });
  if (!res.ok) {
    const err = new Error(`Example: HTTP ${res.status}`);
    err.status = res.status;
    throw err;
  }
  const data = await res.json();
  return (data.items || []).map(normalizeExample);
}

function normalizeExample(item) {
  return {
    id: `example-${item.id}`,
    title: item.title || '',
    company: item.company?.name || '',
    url: item.url || '',
    salary: item.salary || '',
    location: item.location || '',
    isRemote: !!item.remote,
    workplaceType: item.remote ? 'Remote' : 'Onsite',
    relocates: false,
    date: item.posted_at || '',
    snippet: (item.description || '').slice(0, 240),
    source: 'example',           // ← must match the registry `value` exactly
  };
}

Джерело з HTML-скрейпінгу (коли API немає — дивіться getmatch.mjs та geekjob.mjs для повних прикладів):

const BASE = 'https://example.com';

export async function searchExample(query, opts = {}) {
  const { fetchImpl = fetch, signal } = opts;
  const res = await fetchImpl(`${BASE}/vacancies?q=${encodeURIComponent(query)}`, {
    signal,
    headers: { 'User-Agent': UA, Accept: 'text/html' },
  });
  if (!res.ok) {
    throw Object.assign(new Error(`Example: HTTP ${res.status}`), { status: res.status });
  }
  return parseExampleCards(await res.text());
}

export function parseExampleCards(html) {
  // …regex-based card extraction. Return [] on parse failure (DON'T throw):
  // a healthy 200 with no parseable cards is "no results", not "error",
  // so the multi-source scanner can keep going.
}

Три контракти, яких повинен дотримуватися кожен адаптер:

  • Експортувати валідний блок meta (дивіться Крок 2). Без нього реєстр мовчки пропускає файл (один console.warn при завантаженні), і джерело ніколи не з’являється.
  • Приймати { onlyRemote, fetchImpl, signal } в opts. fetchImpl — те, що робить адаптери тестованими без мережі; signal необхідний для передачі відключення клієнта (REVIEW-B3).
  • Повертати записи із загальною формою{ id, title, company, url, salary, location, isRemote, workplaceType, relocates, date, snippet, source }, де source відповідає meta.value.

Крок 2 — Оголосіть meta адаптера (автореєстрація)

Це весь крок реєстрації. Ви не редагуєте registry.mjs. Просто переконайтеся, що адаптер експортує блок meta — реєстр автоматично виявить його при завантаженні:

// at the top of server/lib/sources/example.mjs
export const meta = {
  value: 'example',          // job.source value AND #/scan option.value
  label: 'Example.com',      // display label in the dropdown
  region: 'ru',              // 'en' | 'ru'
  configKey: 'example',      // RU only — key in portals.yml::russian_portals.sources
};

Як виявлення перевіряє (файл, що не проходить будь-яке правило, пропускається з одним попередженням [sources/registry], тому напівміграційна гілка залишається діагностованою):

  • value — непорожній рядок. ПОВИНЕН збігатися з job.source вашого адаптера.
  • label — непорожній рядок.
  • region — рівно 'en' або 'ru'; будь-що інше відхиляється.
  • configKeyобов’язковий для region: 'ru', ігнорується для 'en'.

region: 'en' приєднується до ATS-проходу (автовиявлення за шаблонами URL tracked_companies); region: 'ru' приєднується до регіонального диспетчера. Публічний API (SOURCES, SOURCES_BY_REGION, RU_CONFIG_KEYS, getRegionalSources) перебудовується з кожного виявленого meta, впорядкованого спочатку en, потім ru, за алфавітом за міткою всередині кожного регіону — тому порядок випадаючого списку залишається стабільним для користувачів.

Крок 3 — Підключіть до диспетчера (лише RU)

EN ATS-джерела автовиявляються за шаблонами URL tracked_companies — додаткового підключення не потрібно. Для RU-джерел відкрийте server/lib/ru-scanner.mjs, знайдіть таблицю RU_DISPATCH та додайте рядок:

import { searchExample } from './sources/example.mjs';
// …
const RU_DISPATCH = {
  // …existing…
  example: { label: 'example.com', search: searchExample },
};

Цикл диспетчера викликає entry.search(query, opts) для кожного ключа, присутнього в cfg.sources. Більше жодних змін коду не потрібно.

Крок 4 — Тестування (з моками, ніколи з живою мережею)

Додайте файл у tests/sources-<slug>.test.mjs. Реальна мережа в тестах заборонена (контракт CI-ізоляції):

import test from 'node:test';
import assert from 'node:assert/strict';
import { searchExample } from '../server/lib/sources/example.mjs';

test('searchExample normalizes one record', async () => {
  const fetchImpl = async () =>
    new Response(
      JSON.stringify({ items: [{ id: 1, title: 'Backend Engineer' }] }),
      { status: 200, headers: { 'content-type': 'application/json' } }
    );
  const out = await searchExample('q', { fetchImpl });
  assert.equal(out.length, 1);
  assert.equal(out[0].source, 'example');
});

Крок 5 — Увімкніть у своєму portals.yml

portals.yml батьківського проєкту — це конфіг, що належить користувачу. Додайте configKey нового джерела до масиву:

russian_portals:
  sources: ["hh", "habr", "trudvsem", "getmatch", "geekjob", "example"]
  area: 113
  per_page: 50
  only_remote: false
  queries:
    - "Senior PHP"
    - "Senior Go"

Перезавантажте #/scan у браузері. Випадаючий список фільтра джерел автоматично підхоплює новий запис (єдине джерело правди через GET /api/scan/sourcesregistry.mjs). Кнопка 🌐 Scan тепер включає нове джерело в кожному регіональному проході.

Референсні адаптери (копіюйте для нових джерел)

Файл адаптера Тип Примітки
hh.mjs JSON API Канонічний RU API-адаптер; UA-резерв з урахуванням гео.
trudvsem.mjs JSON API Відкриті дані уряду Росії; без IP-обмеження.
habr.mjs HTML scrape Російська технічна дошка; парсер карток на regex.
getmatch.mjs HTML scrape Захисний парсер, [] при невдалому парсингу.
geekjob.mjs HTML scrape Той самий захисний стиль, що й GetMatch.
greenhouse.mjs JSON API Канонічний EN ATS-адаптер; використовує шаблон URL tracked_companies.

Поширені помилки

  • Забули експорт meta. Починаючи з v1.69.0 блок meta — це єдине, що реєструє джерело. Відсутній meta (або некоректний) = файл мовчки пропускається при завантаженні з єдиним попередженням [sources/registry] <file> has no valid \export const meta` — skipped`, і джерело ніколи не потрапляє до випадаючого списку. Перевірте журнал сервера, якщо новий адаптер не з’являється.
  • Невідповідність поля source. Рядок, що записується вашим адаптером, ПОВИНЕН точно збігатися з meta.value. Якщо вони розходяться, випадаючий список фільтра #/scan показуватиме джерело, але вибір його відфільтрує кожен рядок (бо перевірка рівності r.source === fs).
  • Кидання виключення при невдалому парсингу. HTML-скрейпери ПОВИННІ повертати [] при здоровому 200 без парсованих карток. Кидання виключення ламає цикл багатоджерельного диспетчера — одна погана HTML-структура вбиває всі інші джерела для того самого запиту.
  • Забули fetchImpl / signal. Без них адаптер не може пройти unit-тест без звернення до живої мережі, і відключення клієнта не передається (фоновий fetch залишається активним після закриття вкладки).
  • Довіряєте tracked_companies для RU. Цей список лише для EN ATS-джерел. RU-адаптери керуються russian_portals.queries — без записів на компанію.

18. Сповіщення (🔔 у верхній панелі)

v1.58.34 — кожен toast, що з’являється в нижньому правому куті, також фіксується у внутрішньому журналі (ліміт 50, найстаріші видаляються). Натисніть дзвіночок 🔔 у верхній панелі, щоб відкрити праву бічну панель Notifications і повторно прочитати все, що ви пропустили. Журнал — на вкладку, на сесію; закриття вкладки очищає його.

Панель відкривається лише при кліку на дзвіночок (або при активації клавішами Enter / Space, коли він у фокусі). Вона ніколи не з’являється сама по собі. Червоний значок на дзвіночку підраховує записи, яких ви не бачили з моменту останнього відкриття; відкриття панелі очищає значок.

Категорії сповіщень

Категорія Коли спрацьовує Візуальна підказка
Success Saved, Copied, Refreshed, завершення сканування, імпорт CV, дії чеклиста apply («Copied unchecked», «Reset»), збереження профілю, додавання URL до pipeline зелена ліва рамка в панелі; зелений фон toast
Error Помилка валідації URL (повинен починатися з http:// / https://, без символів скрипту/шаблону), API-помилки з постфіксом (METHOD /path · HTTP NNN), мережеві збої (сервер недоступний), дублікати pipeline-400, ненульовий вихід doctor / verify-pipeline червона ліва рамка; червоний фон toast; технічний постфікс згорнуто в блок Details <details> (U-4 / v1.58.24)
Info / progress Running doctor.mjs…, Running verify-pipeline.mjs…, Refreshing…, Loading…, Generating prompt…, рядки прогресу сканування сіра ліва рамка; стандартний фон toast

Кожен запис панелі показує:

  • Часова мітка (HH:MM:SS локалізована відповідно до активної мови SPA).
  • Повідомлення (речення для людини, з технічним постфіксом, прибраним із заголовку відповідно до U-4).
  • Деталі (за наявності — постфікс виклику API (METHOD /path · HTTP NNN) або будь-яке інше технічне уточнення, моноширинний шрифт).

Що НЕ є сповіщенням

  • Результуюче модальне вікно Doctor / verify-pipeline (повний stdout / stderr) — це модальне вікно, а не toast, і не журналюється.
  • Рядки SSE-журналу на #/scan та #/auto — вони транслюються у тіло сторінки, не до конвеєра toast.
  • Стани завантаження лише зі спінером (вони використовують UI.withSpinner без toast).

Клавіатура

  • Клік або фокус + Enter / Space на дзвіночку → відкриває панель.
  • Esc, натискання кнопки × закрити або повторний клік на дзвіночку → закриває панель; фокус повертається до дзвіночка.
  • Tab при відкритій панелі → переміщується між кнопкою закриття та будь-якими фокусованими деталями всередині; панель має aria-modal="false", тому Tab не пастковує (ви все ще можете досягти решти сторінки).

19. Локалізація застосунку своєю мовою

Інтерфейс постачається 9 мовами (English, Español, Français, Português, 한국어, 日本語, Русский, 简体中文, 繁體中文). Кожен екранний ярлик береться зі словника перекладів, і ви можете додати або виправити мову, не торкаючись логіки застосунку.

Де знаходяться переклади. Починаючи з v1.60.0 кожна мова — це окремий файл у public/js/lib/locales/i18n-dict.en.js, i18n-dict.es.js, i18n-dict.ru.js тощо — простий список пар 'key': 'text'. Спільний i18n-dict.aliases.js дозволяє ключам, що повинні завжди читатися однаково (ярлик бічної панелі та заголовок сторінки), вказувати на один переклад. i18n-dict.js об’єднує їх усі при завантаженні сторінки; ви ніколи не редагуєте його.

Виправити або додати фразу. Відкрийте файл для вашої мови, знайдіть ключ (наприклад, 'nav.scan') та відредагуйте текст. Щоб додати абсолютно новий ярлик, додайте той самий ключ до всіх 8 мовних файлів із перекладеним значенням, а потім посилайтеся на нього у сторінці через t('your.key'). Запустіть npm test — він завершується з помилкою, якщо в будь-якій мові відсутній ключ, тому нічого не відвантажується напівперекладеним.

Додати цілу нову мову. Скопіюйте i18n-dict.en.js до i18n-dict.<code>.js, перекладіть кожне значення, потім зареєструйте код у i18n.js (список мов + автовизначення браузера), у збирачі i18n-dict.js та додайте рядок <script> в index.html. Повний чеклист — включаючи знімок тесту та супутні файли довідки / README — знаходиться в docs/LOCALIZATION.md.

Корисно знати. Перемикач мов знаходиться в нижньому колонтитулі бічної панелі; ваш вибір запам’ятовується для браузера. Діагностичні повідомлення сервера навмисно залишаються англійською (щоб журнали читалися однорідно) — перекладається лише екранний інтерфейс.

Дивіться docs/LOCALIZATION.md у репозиторії для повного покрокового посібника з локалізації.

20. Статистика за цільовими ролями (#/stats)

Сторінка Analytics → Статистика цільових ролей перетворює скупі дані, які вже збирають ваші сканування, на картину ринку для ролей, на які ви справді націлені: кількість вакансій і рівні зарплат за країнами, а також тренд, який можна відстежувати в часі. Нічого не вигадується: сторінка лише агрегує те, що знайшли сканери, і чесно показує, наскільки мала вибірка.

Звідки беруться цифри

  • Цільові ролі зчитуються з вашого профілю (config/profile.yml → target roles) — вони ніколи не прописані жорстко. Спершу задайте їх на #/profile; без ролей сторінка показує підказку «задайте цільові ролі» замість порожніх графіків.
  • Вакансії беруться з вашого останнього сканування (спершу запустіть його на #/scan). Локацію кожної вакансії зіставлено з країною (тим самим детектором, що й фільтр за країною у сканері), а рядок із зарплатою парситься й нормалізується до USD за приблизною таблицею курсів.
  • Усе агрегується у вашому браузері — жодні дані не залишають вашу машину, і єдине, що ця сторінка коли-небудь записує, — це знімок, який ви зберігаєте явно.

Як читати графіки

  • Вакансії за країнами — скільки відповідних вакансій припадає на кожну країну. Використовуйте фільтри Роль і Країна вгорі, щоб звузити до однієї цільової ролі або однієї країни.
  • Медіанна зарплата за країнами (USD) — серединна розпарсена зарплата для кожної країни. Враховуються лише вакансії з розбірливою зарплатою; розмір вибірки показано поруч із графіком, а суми конвертуються за приблизними курсами, тож читайте це як орієнтовне, а не точне значення. Одиночний ¥ (неоднозначний між японською єною та китайським юанем) відкидається, а не вгадується, щоб уникнути значного викривлення FX.
  • Коли в поточному скануванні немає розбірливих зарплат, графік зарплат повідомляє про це, а не вигадує числа.

Збереження знімків і відстеження тренду

  • Натисніть Зберегти знімок, щоб додати поточний агрегат до data/role-stats.jsonl. Кожен знімок отримує позначку часу на сервері; знімки — єдине, що записує ця сторінка, і вони ніколи не зачіпають ваше резюме чи профіль.
  • Графік тренду відображає кількість вакансій за вашими збереженими знімками — зберігайте по одному періодично (наприклад, після кожного щотижневого сканування), щоб спостерігати, як ринок для ваших цільових ролей змінюється в часі.

21. Ваш two-pager — відповідність кандидата ринку (#/two-pager)

Більша частина career-ops-ui відповідає на питання «чи підходить ця вакансія моєму резюме?». Two-pager відповідає на другу половину: «чи підходить ця вакансія тому, чого я насправді хочу?». Його змодельовано за зразком «Mnookin two-pager» з книги Never Search Alone — короткої заяви від першої особи про те, що вас надихає, що вам необхідно і з чим ви не готові миритися. Відкрийте його через Setup → Two-pager 🎯.

ШІ-автозаповнення + експорт (v1.100). «✨ ШІ-помічник заповнення» тепер заповнює всі поля вживу з вашого резюме (перевірте та збережіть); 👁 Перегляд і експорт відображає two-pager і експортує його в Markdown, PDF або DOCX.

Що ви заповнюєте

  • Хто я — кілька фраз від першої особи про ваш послужний список і про те, у якій ролі ви розкриваєтеся.
  • Цільове середовище — розмір компанії, стадія та культура, які вам потрібні.
  • П’ять списків-чипів — введіть текст і натисніть Enter (або кому), щоб додати кожен пункт, клацніть ×, щоб видалити:
    • Що я люблю — те, що заряджає (віддалена робота, відповідальність, greenfield, менторство…).
    • Обов’язкові умови — жорсткі вимоги (нижній поріг зарплати, країна, стек…).
    • Що я ненавиджу — те, що виснажує (чергування, нескінченні мітинги, лише legacy…).
    • Deal-breakers — абсолютні «ні» (лише офіс, без спонсорства, нижче певної суми…).
    • Непорушні межі — рамки (локація, віддалена робота, нижній поріг зарплати…).

Натисніть Save two-pager, щоб зберегти. Файл записується в користувацький шар вашого батьківського проєкту career-ops за шляхом config/two-pager.yml, тому — як ваше резюме та профіль — він ніколи не перезаписується при оновленні системи.

Помічник AI-заповнення

Не впевнені, як це сформулювати? Натисніть ✨ AI fill assistant. Він збирає готовий до запуску промпт (у форматі Mnookin, з вашим резюме та профілем усередині) і показує його в діалоговому вікні. Запустіть цей промпт у будь-якій LLM, потім вставте отримані YAML-поля назад у форму. Помічник використовує лише ваші власні резюме та профіль — він ніколи не вигадує факти про вас, і за цією кнопкою не робиться жодного живого виклику API.

Оцінка відповідності тому, чого ви хочете

Щойно ви збережете two-pager, кожна вакансія на #/scan отримує невеликий бейдж ◎ N (0–100). Він порівнює тип роботи кожної вакансії (віддалена/гібрид/офіс), країну, нижній поріг зарплати та релокацію з вашим two-pager — зелений бейдж означає сильну відповідність, червоний — що спрацював deal-breaker. Наведіть курсор, щоб побачити деталі (✓ що збіглося, ✗ що порушив deal-breaker).

Він навмисно чесний: коли вакансія не дає жодного зіставного сигналу (наприклад, усі ваші вподобання — вільний текст, який рядок сканування не може підтвердити), бейдж не показується взагалі — система ніколи не вигадує число. Порушення жорсткого deal-breaker важить більше, ніж м’яка ненависть до того самого. Окрім бейджа, ваш збережений two-pager вбудовується в кожну оцінку через LLM, тому заявлені вами вподобання формують і письмовий вердикт, а не лише збіг «резюме проти опису вакансії».

22. Пробне інтерв’ю (#/mock-interview)

Читати підготовку до інтерв’ю — це одне; проговорювати відповіді вголос — зовсім інше. Сторінка Пробне інтерв’ю (відкрийте її через Interview prep → Mock interview 🎤 у бічній панелі) проводить покрокову репетицію під конкретну роль, спираючись на ваші власні резюме, профіль, two-pager і банк історій. Це не заготовлений список питань — інтерв’юер реагує на те, що ви справді говорите.

Як почати сесію

  • Вкажіть цільову роль (і за бажанням компанію). Вставте також опис вакансії, якщо він у вас є, — питання стануть помітно точнішими.
  • Натисніть Start interview. Інтерв’юер відкриває бесіду одним сфокусованим питанням, підібраним під роль і ваш досвід.
  • Введіть відповідь і натисніть Send answer. Повторюйте стільки, скільки захочете — це розмова, а не фіксована вікторина.

Що дає кожен хід

Після кожної відповіді інтерв’юер відповідає трьома частинами:

  • Зворотний зв’язок — що спрацювало (сильні сторони) і чого забракло, у термінах STAR+R (Situation, Task, Action, Result, Reflection). Він називає конкретний вимір, який ви пропустили.
  • Оцінка — швидка N/5 з однорядковим обґрунтуванням, щоб ви відчували прогрес упродовж сесії.
  • Наступне питання — уточнювальне питання, яке навмисно промацує найслабшу частину вашої останньої відповіді.

Усе спирається на ваші реальні матеріали: cv.md, config/profile.yml, config/two-pager.yml і ваш банк історій STAR+R (interview-prep/story-bank.md) цілком вбудовуються в промпт. Інтерв’юер тиснутиме на справжні прогалини, але ніколи не вигадує досвід, якого у вас немає. Якщо ключ LLM не задано, сторінка видає вам готовий до запуску промпт, який можна вставити в будь-який асистент, — той самий чесний запасний варіант, що використовується в інших місцях застосунку.

Збереження та повернення до сесій

Натисніть Save transcript, щоб зберегти завершену репетицію. Вона записується в користувацький шар вашого батьківського проєкту за шляхом interview-prep/mock-{company}-{role}-{date}.md, тому живе поруч із рештою нотаток із підготовки до інтерв’ю і ніколи не перезаписується при оновленнях системи. Список Saved sessions унизу сторінки дозволяє знову відкрити будь-яку розшифровку або видалити її. Використайте New interview, щоб почати заново з іншою роллю.

23. Нетворкінг і глибоке дослідження компаній (#/networking)

Подати заявку через парадні двері — це лише половина гри; друга половина в тому, щоб знати когось, або принаймні знати, до кого звернутися і що сказати. Сторінка Networking (відкрийте її через Deep research → Networking 🤝 на бічній панелі) перетворює компанію на конкретний план того, як отримати співбесіду, спираючись на ваш власний CV, профіль і two-pager.

Як побудувати план

  • Вкажіть компанію (обов’язково) і, за бажанням, посаду та опис вакансії. Опис вакансії загострює зачіпки «чому я підходжу».
  • Натисніть Build plan. З ключем LLM він виконується в реальному часі й відображає план прямо на сторінці; без ключа він видає готовий промпт, який можна вставити в будь-який асистент (той самий чесний запасний варіант, що використовується по всьому застосунку — нічого не вигадується).

Що містить план

План повертається в чотирьох розділах:

  • Досьє на компанію — стислий бриф про те, чим займається компанія, свіжі сигнали, які варто згадати, і дві-три зачіпки «чому я підходжу», взяті з вашого реального досвіду.
  • До кого звертатися — від трьох до п’яти цільових персон (наймальний менеджер команди, внутрішній рекрутер, senior-інженер у команді, теплий контакт або зв’язок за alumni) з конкретним рядком пошуку в LinkedIn для знаходження кожного. Він ніколи не вигадує реальні імена — він підказує, як знайти потрібних людей.
  • Найтепліший шлях до знайомства — єдиний найреалістичніший теплий маршрут саме для вашого досвіду: спільний роботодавець, навчальний заклад чи спільнота; зв’язок другого рівня; або холодне повідомлення із сильним сигналом, коли це справді найкращий варіант.
  • Чернетки звернень — короткі, конкретні повідомлення (три-п’ять речень, без води) для ваших ключових персон, що спираються на ваші реальні докази, щоб вони не виглядали шаблонними.

Як зберігати й повертатися до планів

Натисніть Save plan, щоб зберегти план. Він записується в користувацький шар батьківського проєкту за шляхом networking/net-{company}-{role}-{date}.md — це ваш власний файл, який ніколи не перезаписується системними оновленнями. Список Saved plans унизу сторінки дозволяє знову відкрити або видалити будь-який план. Оскільки чернетки та персони спираються лише на ваші реальні матеріали, ставтеся до них як до сильної першої чернетки для доопрацювання — а не як до сценарію для розсилки наосліп.

24. CV Studio (#/cv-studio)

Додати в CV (v1.117.0). Нова картка перетворює проєкт, публікацію чи сторінку портфоліо (URL або вставлений текст) на ATS-готові пункти, засновані ЛИШЕ на цьому джерелі — метрики, роботодавці чи дати, яких немає в джерелі, опускаються, а не вигадуються. Ви переглядаєте пропозиції та самі вставляєте прийняті в редактор CV; автоматично нічого не записується, а URL проходять той самий SSRF-безпечний валідатор, що й пайплайн.

Сторінка #/cv — це місце, де ви пишете своє резюме; CV Studio (відкрийте його через Setup → CV Studio 🎨 на бічній панелі) — місце, де ви його шліфуєте. Він дає вашому cv.md три чесні інструменти, два з яких ніколи не залишають ваш браузер.

Адаптувати під вакансію (v1.101). Вставте опис вакансії — CV Studio створить адаптоване резюме та відповідний супровідний лист, прогнавши їх через рекрутерський чек-лист-гейт (помилки блокують, попередження радять), спираючись лише на ваші матеріали.

Діагностика резюме

У момент відкриття сторінки він оцінює ваше резюме за шкалою до 100 і перелічує зауваження за кожною перевіркою, кожне з коротким поясненням, щоб ви самі вирішували, що змінювати (він ніколи не переписує мовчки):

  • Довжина — чи вкладається резюме у здоровий діапазон в одну-дві сторінки?
  • Вимірюваний вплив — яка частка ваших пунктів містить реальне число або метрику? Рекрутери вихоплюють саме їх під час швидкого перегляду.
  • Сильні дієслова дії — позначає слабкі формулювання на кшталт «відповідав за» чи «допомагав».
  • Модні слівця — позначає порожні кліше («орієнтований на результат», «командний гравець»).
  • Ключові розділи — перевіряє наявність Резюме, Досвіду, Освіти та Навичок.
  • Контактні дані — переконується, що вказано email.

Усе це виконується цілком у вашому браузері без LLM — числа детерміновані, і нічого не вигадується.

Маска приватності

Перш ніж поділитися резюме як зразком письма чи скриншотом, Маска приватності приховує персональні ідентифікаційні дані: email, телефон, посилання/ніки та поштову адресу, а також ваше ім’я → ініціали, якщо ви це увімкнете та введете його. Перемикайте кожну категорію, копіюйте замасковану версію та діліться нею безпечно. Усе відбувається цілком у браузері, повідомляється точно, скільки елементів було приховано, а оригінал ніколи не зберігається й не передається.

Зробити по-людськи (підлаштування під ваш голос)

Вставте сухий рядок або абзац — той самий шаблонний текст у дусі безликого ШІ — і Зробити по-людськи перепише його вашим голосом. Переписування спирається на боці сервера на ваш voice-dna.md (як читається ваш текст) і ваші writing-samples/ (ваша реальна проза). Жорстке правило: він може переставляти, стискати й переналаштовувати голос, але ніколи не введе факт, метрику чи досягнення, яких немає у вставленому тексті. З ключем LLM він переписує наживо; без ключа він видає готовий промпт, щоб вставити його в будь-який асистент. Потім редагуйте своє резюме на сторінці #/cv як зазвичай — CV Studio пропонує, вирішуєте ви.

25. Пам’ять (#/memory)

Усі інші сторінки щоразу починають з чистого аркуша. Пам’ять (відкрийте її через Налаштування → Пам’ять 🧠 на бічній панелі) — єдине місце, де ви кажете асистенту щось один раз, і це закріплюється. Вона зберігає коротку редаговану нотатку в дусі «запам’ятай це про мене», яка підставляється в кожен запит до ШІ.

Для чого вона

Використовуйте її для сталих уподобань і стилю роботи, наприклад:

  • Типи ролей і компаній, на які ви націлені (і ті, які ви ніколи не хочете бачити).
  • Як вам подобається, щоб писалися відповіді — стисло чи докладно, старший тон, без води.
  • Жорсткі обмеження, які варто повторювати — лише віддалено, мінімальна зарплата, без чергувань.

Тримайте її в межах уподобань і спрямування. Це не місце для фактів про ваш досвід — ваші навички, роботодавці та досягнення живуть у вашому CV, профілі та двосторінковому резюме, які залишаються єдиними джерелами всього, що з’являється у ваших CV і супровідних листах. Нотатка пам’яті визначає, як асистент працює з вами, але ніколи що він стверджує про вас.

Як вона доходить до всього

Коли ви натискаєте Зберегти пам’ять, нотатка записується в користувацький шар батьківського проєкту в config/memory.md і вбудовується в спільний контекст проєкту. Це означає, що вона автоматично подорожує з кожним запитом до ШІ — оцінками, пробними співбесідами, планами нетворкінгу, переписуваннями в CV Studio — і через кожного налаштованого вами провайдера. Напишіть її один раз; не треба повторюватися на кожній сторінці. Як і інші ваші файли користувацького шару, вона ніколи не перезаписується під час оновлення системи і залишає вашу машину лише всередині тих запитів до LLM, які ви вирішуєте виконати.

Запропонувати з ваших даних

Не знаєте, що написати? ✨ Запропонувати з моїх даних читає ваш трекер відгуків і складає набір поведінкових пунктів — закономірності в тому, що ви переслідуєте, приймаєте та відхиляєте. Запустіть виданий ним запит у будь-якому LLM, перегляньте пропозиції та вставте відредаговану версію в нотатку. Він спирається лише на ваш власний трекер і ніколи не вигадує фактів; ви завжди перевіряєте, перш ніж щось збережеться.

26. Статистика (#/stats)

Вкладка «Патерни відмов» (v1.117.0). Четверта вкладка запускає батьківський analyze-patterns.mjs (лише читання) і показує розподіл результатів, практичні рекомендації та частку просування за кожним ATS-вендором (сигнал «алгоритмічної монокультури» — Bommasani et al., FAccT 2026). Вендори нижче мінімальної вибірки позначені зірочкою; без батьківського проєкту вкладка чесно про це повідомляє.

Сторінка Статистика об’єднує три види в одному розділі: згенерований ШІ звіт про ринок, аналітику вашого власного пайплайну та тренд вакансій для ваших цільових ролей із ваших сканувань. Перемикайтеся між ними за допомогою вкладок угорі.

Звіт про ринок

Вкладка Звіт про ринок просить модель зробити аналіз зарплат і ринку праці для ваших цільових ролей — вона читає ваше CV і профіль, щоб знати, які ролі та рівень seniority охопити. Введіть Регіон / ринок (наприклад, Russia, EU-remote, US або Germany), оберіть Валюту та натисніть Згенерувати звіт про ринок. Ви отримаєте структурований звіт із виконавчим резюме, зарплатами за грейдами (медіана плюс P10/P25/P75/P90), провідними роботодавцями, таблицею затребуваних навичок, частотою пільг, розподілом офіс/гібрид/віддалено, трендами на 12–24 місяці, включно з впливом ШІ, та рекомендаціями щодо перемовин. Кожна цифра — це орієнтовна оцінка зі знань, отриманих під час навчання моделі — не зібрані й не живі дані — і звіт про це повідомляє; сприймайте числа як діапазони, а не як точні пропозиції. Без встановленого API key ви отримаєте натомість запит для копіювання-вставлення, а не вигаданий звіт. Скористайтеся Завантажити .md, Зберегти як PDF або Копіювати, щоб вивести звіт із застосунку.

Мій пайплайн

Вкладка Мій пайплайн будує графіки за вашим власним трекером заявок — нічого зовнішнього. Вона показує, скільки ролей ви відстежували, розподіл ваших оцінок, воронку статусів, ваші провідні компанії та ролі, заявки в часі й коефіцієнти конверсії (яка частка заявок досягає Applied, Responded, Interview та Offer). Це чесне дзеркало ваших пошуків: воно завжди відображає лише те, що вже є в data/applications.md.

Тренд цільових ролей

Вкладка Тренд цільових ролей — це початковий вид: кількість вакансій і медіанна зарплата за країнами для ваших цільових ролей, агреговані з вашого останнього сканування, із селектором валюти та оглядом Вакансії за цільовою роллю. Зберегти знімок записує поточну агрегацію, щоб ви могли спостерігати, як кількість вакансій змінюється в часі, а лінія тренду зчитує ці знімки назад. Розріджені дані очікувані й позначаються як орієнтовні — вони ніколи не доповнюються вигаданими числами.

За весь час і компенсація

Вкладка «За весь час» (v1.118.0) ретранслює в режимі лише для читання два батьківські скрипти з нульовою вартістю токенів: stats.mjs — зведення трекера за весь час, накопичені частки воронки (відповіді / співбесіди / офери), підсумки сканера та покриття порталів — і salary-gap.mjs — бажану vs заявлену vs фактичну компенсацію за кожною заявкою, зібрану з Machine Summary звітів і data/salary-observations.tsv. Малі вибірки позначаються як орієнтовні; без батьківського проєкту вкладка показує чесну примітку.

27. Кар’єрний план (#/career-plan)

Сторінка Кар’єрний план перетворює ваше резюме та профіль на конкретний, персоналізований план розвитку — такий, який ви склали б із кар’єрним коучем, але згенерований із ваших власних матеріалів і доступний вам для редагування.

Генерування плану

Виберіть Горизонт (6, 12 або 24 місяці), за бажанням введіть Фокус (наприклад, «перейти в менеджмент», «перейти на віддалену роботу» або «переключитися на Go») і натисніть Згенерувати план. Модель читає ваше резюме, профіль, two-pager та нотатку пам’яті (через спільний контекст проєкту) і пише структурований план: чесний знімок відправної точки, SWOT сильних сторін і зон зростання, цілі, виражені як SMART / OKR / WOOP, альтернативні кар’єрні траєкторії з їхніми компромісами, план твердих і м’яких навичок, помісячну дорожню карту для обраного горизонту, як відстежувати прогрес, ймовірні підводні камені та підтримувальні кроки. Кожна рекомендація ґрунтується на тому, що ваші матеріали справді показують — план дивиться вперед, але ніколи не вигадує фактів про вашу історію. Якщо ключ API не задано, ви натомість отримуєте промпт для копіювання та вставлення.

Редагування та збереження

План з’являється в редагованому текстовому полі — правте будь-що, а потім натисніть Зберегти план. Він записується в користувацький шар вашого батьківського проєкту, у config/career-plan.md, тож переживає оновлення системи й надсилається лише всередині тих промптів LLM, які ви вирішите запустити. Попередній перегляд відрендерює ваш Markdown, щоб ви могли прочитати його у відформатованому вигляді перед збереженням.

Експортування

Використовуйте Завантажити .md, Зберегти як PDF або Копіювати, щоб винести план за межі застосунку — ті самі елементи експорту, що використовуються в усіх ШІ-звітах застосунку. PDF проходить через наявний вбудований генератор PDF; Markdown — це пряме завантаження.

28. Кар’єрна орієнтація (#/orientation)

Сторінка Кар’єрна орієнтація відповідає на питання «які напрями мені насправді підходять?» — така собі оцінка, яку дав би профорієнтаційний тест, але виведена з вашого власного резюме та профілю, а не з опитувальника.

Що вона створює

Натисніть Згенерувати профіль, і модель прочитає ваше резюме, профіль, two-pager та нотатку пам’яті й напише профіль кар’єрної орієнтації: ваші найкращі кар’єрні вектори (які з восьми архетипів — Функціоналіст, Адміністратор, Комунікатор, Спеціаліст, Аналітик, Новатор, Менеджер, Підприємець — підходять найкраще, з доказами з вашого резюме), схильність до кар’єрного типу, набір рекомендованих ролей, ваші професійні сильні сторони, прив’язані до того, що показує резюме, тенденції робочого стилю («як читається ваше резюме» за кількома осями) та рекомендації щодо розвитку, щоб розширити вашу відповідність.

Як вона генерується

Це ШІ-рефлексія того, як читається ваше резюме, — а не психометричний тест. Промпт повністю ґрунтується на ваших власних матеріалах: він не вигадує досягнень і ніколи не подає числових результатів тестів так, ніби їх виміряли. Без заданого API key ви натомість отримаєте промпт для копіювання-вставлення, який можна запустити в будь-якому LLM, замість живого профілю. Нічого не записується на диск — профіль щоразу генерується заново.

Експортування

Скористайтеся Завантажити .md, Зберегти як PDF або Копіювати, щоб зберегти профіль — ті самі елементи експорту, що використовуються в усіх ШІ-звітах застосунку. PDF проходить через наявний вбудований генератор PDF; Markdown — це пряме завантаження.