hhru-bot
CLI-бот для поиска работы на hh.ru: ищет вакансии, откликается письмом, поднимает резюме, следит за ответами и умеет редактировать само резюме. Работает через Playwright (браузер), а не через API — hh.ru закрыл его для соискателей в декабре 2025.
Чем мы отличаемся от аналогов
Идея сравнения и разбор референсов — issue #84. Легенда: ✅ есть, ❌ нет, ⚠️ частично или не проверяли (не значит «нет»).
| Фича | s3rgeym | fikstt2 | Steev193 | tgeruzov | konard | hhru-bot |
|---|---|---|---|---|---|---|
| Поиск + отклик | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
| Поднятие резюме | ✅ | ⚠️ | ⚠️ | ⚠️ | ⚠️ | ✅ |
| Троттлинг и дневные лимиты | ✅ | ⚠️ | ⚠️ | ⚠️ | ⚠️ | ✅ |
| Редактирование и создание резюме | ⚠️ клон целиком | ❌ | ❌ | ❌ | ❌ | ✅ |
| Анализ резюме конкурентов | ❌ | ❌ | ❌ | ❌ | ❌ | ✅ |
| Обучаемые ответы на анкеты | ❌ | ❌ | ❌ | ❌ | ⚠️ Q&A-файл, без обучения | ✅ |
| Честный статус «не знаю, дошло ли» | ❌ | ❌ | ❌ | ❌ | ❌ | ✅ |
| Воронка и статистика по истории | ⚠️ | ❌ | ❌ | ❌ | ❌ | ✅ |
- Редактирование и создание резюме —
create-resume,edit-experience,edit-education,edit-skills,edit-languages,resume-position,publish-resumeи другие: собрать резюме с нуля или довести до публикации. - Анализ резюме конкурентов (
competitors) — с кем ты конкурируешь за вакансию: отчёт по ролям, зарплатам и навыкам других соискателей. - Обучаемые ответы на анкеты (
questionnaire) — бот подбирает ответ по подтверждённым формулировкам, для новых вопросов подключает LLM; неуверенные случаи идут в очередь на твоё решение. - Честный статус «не знаю» (
uncertain) — если связь с hh.ru оборвалась в момент клика, бот не врёт «готово»/«не готово», а говорит «не знаю». - Воронка и статистика (
funnel,stats,responses,market) — сколько откликов ушло, сколько ответов, где «мёртвая зона».
Проекты и ссылки — «Похожие проекты» ниже. Полный список команд — «Справочник команд» ниже.
Как это работает
Запускается вручную из терминала. Каждая команда печатает, что делает,
поддерживает --dry-run (план без единого клика по hh.ru) и ограничена
дневными лимитами и случайными паузами — чтобы не выглядеть подозрительной
автоматизацией для анти-фрод системы hh.ru. Опасные действия (отклик,
публикация, удаление резюме) без --force или подтверждения не выполняются.
Для регулярного запуска (например, поднимать резюме каждые 4 часа) подключи внешний планировщик — cron/launchd или Docker (см. «Автопилот» ниже). Своего фонового демона у бота нет.
⚠️ Важное предупреждение
Селекторы hh.ru в src/hhru_bot/selectors.py не проверены вживую — код
писался без доступа к hh.ru (DDoS-Guard блокировал автоматизированный браузер).
Перед первым использованием:
- Открой hh.ru, сверь через F12 → Elements актуальные
data-qaатрибуты карточек вакансий, кнопки отклика, формы письма, кнопки поднятия резюме с тем, что вsrc/hhru_bot/selectors.py. - Поправь несоответствия прямо в этом файле.
- Прогони
search --dry-run, затемapply --dry-run, и только потом — боевой запуск с малым--limit.
Установка
pip3 install -r requirements.txt
python3 -m playwright install chromium
pip3 install -e .
Настройка
hhru account create default
./scripts/run.sh --account default login
Отредактируй созданный data/accounts/default/config.yaml:
resumes— твои резюме, у каждого свои фильтры поиска (text,area,salary_from,experience,schedule,exclude_employers,exclude_keywords) и опционально своё сопроводительное письмо.exclude_keywords— стоп-слова для заголовков вакансий (без учёта регистра), отдельно для каждого резюме. Пример — вconfig/config.example.yaml.throttle— паузы между действиями и дневные лимиты откликов/поднятий.- В письме доступны плейсхолдеры
{vacancy_title}и{company_name}.
Структура каталогов
Всё изменяемое — конфиг, база, сессия hh.ru, логи — живёт в data/, целиком
в .gitignore.
data/
accounts/
default/
config.yaml # конфиг аккаунта (создаётся account create)
history.db # история аккаунта
config.yaml # шаблон — config/config.example.yaml
history.db # SQLite: история откликов, вакансии, ответы
storage_state/
hh_session.json # сессия hh.ru — секрет, никогда не коммитить
logs/
hhru_bot.log # лог CLI (дублируется в консоль)
probe_*.html / .png # дампы probe
scheduled.log # вывод запусков по расписанию
config/
config.example.yaml # шаблон формата, лежит в репозитории
Пути — относительно текущей директории: запускай команды из корня проекта
или указывай --config/--history явно. hh_session.json даёт доступ к
hh.ru наравне с паролем — не коммить data/ и не включай в Docker-образ.
Первый запуск: вход в аккаунт
./scripts/run.sh login
Откроется окно браузера на странице входа hh.ru. Войди в аккаунт вручную
(логин, пароль, СМС-код, капча — что бы ни попросил hh.ru), затем вернись
в терминал и нажми Enter. Сессия сохранится в
data/storage_state/hh_session.json — все последующие команды будут
переиспользовать её без повторного входа.
Мультилогин: несколько аккаунтов hh.ru
Каждый аккаунт — своё имя и своя папка data/accounts/<name>/.
hhru account create marketing
./scripts/run.sh --account marketing login
# или, если куки hh.ru уже есть в профиле Chrome:
./scripts/run.sh --account marketing import-cookies --profile Default
Флаг --account <name> ставится до имени подкоманды:
./scripts/run.sh --account marketing apply --resume resume-name-1 --limit 5
Для плановых задач то же самое делает HHRU_ACCOUNT (понимает
scripts/scheduled_run.sh); явный --account в приоритете:
HHRU_ACCOUNT=marketing scripts/scheduled_run.sh --headless apply --limit 5
Список аккаунтов и их состояние: ./scripts/run.sh account list.
У каждого аккаунта своя сессия, своя история откликов/поднятий и свои
дневные лимиты — они не суммируются и не переносятся между аккаунтами.
Разные аккаунты можно гонять параллельно; два одновременных прогона
одного аккаунта запрещены (второй получит [FAIL]).
hh_session.json даёт доступ к hh.ru наравне с паролем; файлы сессии
создаются с правами 0600, каталог аккаунта — 0700 (проверка —
diagnostics doctor).
Чтобы убрать аккаунт — удали data/accounts/<name>/ вручную.
Команды
Все команды поддерживают --resume <id> (по умолчанию — все резюме из
конфига) и --dry-run (показать план действий без реальных кликов).
# Проверить, что находит поиск, без откликов
./scripts/run.sh search --resume resume-name-1 --dry-run
# Откликнуться на подходящие вакансии (максимум 5 за запуск)
./scripts/run.sh apply --resume resume-name-1 --dry-run --limit 5
# То же самое по-настоящему, без dry-run
./scripts/run.sh apply --resume resume-name-1 --limit 5
# Поднять резюме в поиске (hh.ru разрешает не чаще раза в 4 часа)
./scripts/run.sh bump --resume resume-name-1
# Полный цикл (apply + bump) для всех резюме из конфига
./scripts/run.sh run
Профиль для внешних форм
Контактные данные аккаунта сохраняются автоматически после login. Для
данных, которых нет на hh.ru (например, Telegram) — задай вручную, с тем же
--account:
./scripts/run.sh --account default profile set "Telegram" "@username"
./scripts/run.sh --account default profile show
./scripts/run.sh --account default profile unset "Telegram"
Добавь --headless, если не нужно видеть окно браузера.
Автопилот: запуск по расписанию
Регулярность задаёт внешний планировщик. Каждый вариант ниже запускает
обычную команду run (apply + bump) — те же лимиты и кулдаун, что и вручную.
Перед автоматизацией проверь ./scripts/run.sh run --dry-run.
Локаль (cron / launchd)
Скопируй scripts/crontab.example, замени __REPO_ROOT__ и __PYTHON_BIN__
на абсолютные пути, добавь через crontab -e. Обёртка пишет в
data/logs/scheduled.log сама.
responses --alert-new пишет ***** НОВОЕ ПРИГЛАШЕНИЕ ***** при новом
приглашении; HHRU_ALERT_CMD опционально запускает свою команду при
обнаружении. Пример — в scripts/crontab.example.
На macOS вместо cron — готовые шаблоны deploy/com.hhru.bot.apply.plist
(ежедневный apply) и deploy/com.hhru.bot.bump.plist (bump каждые 4 часа).
Замени __REPO_ROOT__/__PYTHON_BIN__, установи:
cp deploy/com.hhru.bot.apply.plist ~/Library/LaunchAgents/com.hhru.bot.apply.plist
launchctl load ~/Library/LaunchAgents/com.hhru.bot.apply.plist
Выгрузить: launchctl unload ~/Library/LaunchAgents/com.hhru.bot.apply.plist.
Сгенерировать шаблон: ./scripts/run.sh schedule --format plist --action apply --apply-time 10:00 --apply-limit 5.
Docker
data/ монтируется с хоста и не попадает в образ. Подготовь конфиг на хосте,
затем разовый прогон:
mkdir -p data
./scripts/run.sh account create default
docker compose run --rm --entrypoint hhru hhru --headless --account default run
Непрерывный режим — docker compose up -d: docker-compose.yml запускает
run --headless каждые 4 часа без дрейфа расписания.
docker compose up -d
docker compose logs -f hhru
Остановить: docker compose down. Не монтируй storage_state в публичные
каталоги и не добавляй data/ в образ или git.
Сценарий: пришло приглашение
-
Планировщик распознаёт новое приглашение (код выхода 10):
./scripts/run.sh --headless responses --alert-new
-
Посмотреть, что нового:
./scripts/run.sh responses. -
Что подтянуть по требованиям из собранных вакансий:
./scripts/run.sh learn --resume <id>. -
Время собеседования CLI не угадывает —
responses --calendar-hintпечатает готовую командуcalendar eventс плейсхолдерами:./scripts/run.sh responses --calendar-hint ./scripts/run.sh calendar event --summary "ООО Ромашка - 12345" \ --start 2026-09-01T14:00:00+03:00 --end 2026-09-01T15:00:00+03:00
Если работодатель молчит после отклика — напомнить о себе:
./scripts/run.sh reply-employers --follow-up --after-days 7 --dry-run
./scripts/run.sh reply-employers --follow-up --after-days 7 --force
VPS
ssh user@example.com 'cd /opt/hhru && docker compose up -d --build'
ssh user@example.com 'cd /opt/hhru && docker compose logs -f hhru'
Сессию создай локально (./scripts/run.sh --account default login) или в
контейнере с временно отключённым --headless. Обновление:
git pull && docker compose up -d --build.
Claude Code и Codex plugin
Репозиторий — маркетплейс плагина hhru-cc-plugin: подключает команды бота
как инструменты и скиллы прямо из агентской сессии Claude Code или Codex.
Установка
claude plugin marketplace add axisrow/hhru
claude plugin install hhru-cc-plugin@hhru --scope user
Codex: установка и обновление
Одна команда покрывает первую установку, апгрейд и восстановление после ошибки — она идемпотентна, повторный запуск безопасен:
hhru update
Проверить состояние без изменений: hhru diagnostics doctor (или
./scripts/run.sh diagnostics doctor из checkout). При рассинхроне между CLI,
marketplace и plugin cache печатает [DRIFT] и подсказывает hhru update.
Уже открытая задача Codex после обновления продолжает работать со старым skill — начни новую задачу, чтобы подхватить изменения.
Команда /hhru
/hhru whoami
/hhru search --resume <id> --dry-run --max-pages 3
/hhru competitors collect --text "AI" --auth-mode anonymous --detail-workers 10
/hhru apply --resume <id> --dry-run --limit 5
/hhru responses
Write-команды (apply/bump/run/...) сначала --dry-run, потом
подтверждение перед боевым запуском.
Скиллы
hhru— главный: CLI-справочник, правила безопасности, проверка готовности.hhru-apply— воркфлоу отклика (dry-run-first, safety-critical).hhru-market— анализ рынка (read-only).hhru-monitor— мониторинг/статус (read-only).
Подготовка к интервью
Бот автоматизирует цепочку «пришло приглашение → follow-up» (см. «Сценарий: пришло приглашение» выше). Само собеседование — нарратив, портфолио, поведенческие вопросы — готовишь сам:
- подготовь проекты и портфолио под требования, которые показал
learn; - подготовь нарратив («расскажите о себе») и ответы на поведенческие вопросы;
- поставь реальное время интервью в
calendar eventвместо плейсхолдера.
Справочник команд
Этот блок генерируется автоматически из argparse (см.
scripts/gen_cli_docs.py). Не редактируй его руками — правь код команд в
src/hhru_bot/commands/ и перегенерируй. CI упадёт, если блок рассинхронизирован
с кодом.
Глобальные флаги (до имени команды):
--config— Путь к config.yaml--history— Путь к файлу истории (SQLite)--account— Имя аккаунта (data/accounts//config.yaml + history.db)--headless— Запустить браузер в headless-режиме--verbose— Подробное логирование--quiet— Не печатать поток прогресса
Команды:
about
Генерирует текст раздела «Обо мне» через настроенный LLM. Сначала всегда показывает dry-run-предложение; сохранение требует --force или подтверждения. С --text LLM не нужен: готовый текст (например, перевод) сохраняется как есть (#326).
--resume— Slug из конфига или реальный resume_id HH.ru (#319)--text— Готовый текст раздела «Обо мне» без LLM (#326): ai_profile/секция ai не требуются, текст сохраняется как есть--dry-run— Показать предложение без сохранения--force— Подтвердить сохранение без prompt
account
Создание и управление локальными профилями аккаунтов hh.ru.
- (без аргументов)
account create
Создать data/accounts// и скопировать туда шаблон конфига.
- (без аргументов)
account delete
Показать, что будет удалено в data/accounts//, а с --force выполнить необратимое удаление.
--dry-run— Показать план и ничего не удалять (это поведение по умолчанию)--force— Выполнить удаление (необратимо; уносит конфиг, историю и сессию)
account list
- (без аргументов)
adaptive-report
--format— ASCII-таблица (по умолчанию: 'table')
adaptive-resume
Генерирует заголовок, «Обо мне», порядок навыков и отбор мест работы/проектов под один из четырёх кластеров вакансий (#752). Без --apply только показывает предложение (браузер не открывается). С --apply применяет title/about/skills на hh.ru; боевая запись требует --force или интерактивного подтверждения. work_experience/projects этой командой на hh.ru не пишутся (#769: вне скоупа первой версии).
--resume— Slug из конфига или реальный resume_id HH.ru (#319)--cluster— Кластер вакансий, под который адаптируется резюме--apply— Открыть браузер и применить title/about/skills на hh.ru (иначе только печать плана)--dry-run— С --apply: открыть формы и показать план по каждому шагу, ничего не сохраняя. Без --apply — no-op (команда и так не пишет на hh.ru, флаг оставлен для единообразия и совместимости)--force— С --apply: подтвердить запись без TTY prompt
apply
--resume— Slug из конфига или resume_id HH.ru (по умолчанию — все)--dry-run— Показать, что будет сделано, без реальных действий--max-pages MAX_PAGES— Явный максимум страниц поиска (по умолчанию — адаптивный)--force— Разрешить реальную отправку отклика с LLM-ответами на вопросы--learn-questionnaires— Спрашивать подтверждение сопоставления вопроса анкеты с шаблоном--limit LIMIT— Целевое число успешных откликов за запуск (0 = без ограничения кроме дневного лимита)--approved ID— Отправить ровно approved-запись review-очереди--permit— Одноразовый permit изreview approve
backup
--output OUTPUT— Путь к tar.gz
blacklist
- (без аргументов)
blacklist add
--reason--by(по умолчанию: 'cli')
blacklist list
- (без аргументов)
blacklist remove
- (без аргументов)
bump
--resume— Slug из конфига или resume_id HH.ru (по умолчанию — все)--dry-run— Показать, что будет сделано, без реальных действий--max-pages MAX_PAGES— Максимум страниц поиска (по умолчанию: 5)
calendar
Создание события только по явно подтверждённым --start/--end. Автоматического триггера из responses нет.
- (без аргументов)
calendar auth
--credentials(по умолчанию: 'data/google_calendar/client_secret.json')--token(по умолчанию: 'data/google_calendar/token.json')
calendar event
--credentials(по умолчанию: 'data/google_calendar/client_secret.json')--token(по умолчанию: 'data/google_calendar/token.json')--calendar-id(по умолчанию: 'primary')--summary--start— Начало, RFC3339, например 2026-08-20T10:00:00+07:00--end— Конец, RFC3339--timezone(по умолчанию: 'UTC')--description--location--dry-run— Показать payload без OAuth и записи
call-api
-m, --method— HTTP-метод (разрешён только GET) (по умолчанию: 'GET')
census
--url— Полный URL страницы hh.ru--json— Машиночитаемый JSON-вывод
clear-negotiations
Отозвать один отклик по уникальному topic или все отклики аккаунта. Фильтры --vacancy и --resume формируют только план; боевой отзыв требует --topic или --account-wide и --force/подтверждение.
--topic— Уникальный ID переписки для точечного отзыва--vacancy— ID вакансии (только план, не боевой отзыв)--resume— ID резюме (только план, не боевой отзыв)--account-wide— Явно отозвать все найденные отклики аккаунта--dry-run— Показать план без отзывов--force— Подтвердить боевой отзыв--max-pages MAX_PAGES— Максимум страниц переговоров (по умолчанию: 5)
clear-skipped
Удалить записи из журнала отсева (таблица skipped). Без --reason чистит все причины. Без --dry-run удаляет, с --dry-run — только показывает, сколько записей ушло бы.
--reason— Очистить только эту причину (по умолчанию — все причины)--dry-run— Показать, сколько записей будет удалено, без реального удаления
common
Заполняет через UI поля common, включая условия работы. area, metro и citizenship пока не входят в команду.
--resume— Slug из конфига или resume_id HH.ru--first-name— Имя--last-name— Фамилия--birthday— Дата в формате, который принимает форма hh.ru--gender— Пол--phone— Телефон--area— Точный leaf города из live-каталога hh.ru--metro— Точная станция метро--citizenship— Точное гражданство из live-каталога; можно повторять--work-ticket— «Наличие трудовой книжки» (true/false). Только в шейпе редактора профиля: на common-визарде черновика поле не рендерится (честный отказ), контрол work-ticket-selector визарда — это «Разрешение на работу» (#997)--relocation— Готовность к переезду--schedule— График работы; можно указать несколько раз--employment— Тип занятости; можно указать несколько раз--work-format— Формат работы; можно указать несколько раз--business-trip, --business-trips— Готовность к командировкам--show— Показать фактические значения полей common (включая предзаполненные hh.ru) и выйти--dry-run— Показать план без сохранения--force— Подтвердить запись без prompt
competitors
READ hh.ru: competitors collect --text QUERY [--search-in SCOPE] [--max-pages N]; локальный отчёт: competitors report [--text QUERY] [--search-in SCOPE] [--auth-mode MODE] [--top N].
- (без аргументов)
competitors collect
--text— Ключевое слово поиска резюме--max-pages MAX_PAGES— Необязательный safety-cap (по умолчанию — до конца видимой выдачи)--resume— Продолжить последний прерванный запуск того же запроса с checkpoint--execution-mode— Режим выполнения (по умолчанию foreground; background не поддерживается) (по умолчанию: 'foreground')--progress-verbosity PROGRESS_VERBOSITY— Поток прогресса: 1 — показывать, 0 — только финал/ошибки (по умолчанию 1) (по умолчанию: 1)--items-per-page ITEMS_PER_PAGE— Запрошенный размер страницы hh.ru (по умолчанию 100; для smoke можно 20) (по умолчанию: 100)--search-in— Область поиска --text на hh.ru: position — только желаемая должность (заголовок резюме), самая узкая и чистая (по умолчанию); keywords — по ключевым навыкам; full_text — по всему резюме (должность, навыки, описание опыта, достижения), самая широкая: запрос вроде «AI» так вытягивает дизайнеров с Adobe Illustrator (по умолчанию: 'position')--auth-mode— Сессия браузера: anonymous — чистый контекст без cookie (по умолчанию); authenticated — загрузить сохранённую сессию из конфига (по умолчанию: 'anonymous')--detail-workers DETAIL_WORKERS— Параллельные процессы деталей: 1–1000 (по умолчанию 10; для authenticated требуется 1) (по умолчанию: 10)
competitors report
--text— Ограничить отчёт одним поисковым запросом--search-in— Ограничить отчёт одной областью поиска: один и тот же --text в разных областях — это РАЗНЫЕ выборки (full_text по «AI» тянет дизайнеров с Adobe Illustrator). Без флага отчёт охватывает все области--auth-mode— Ограничить отчёт одним режимом сессии: анонимная выдача hh.ru урезана относительно авторизованной. Без флага отчёт охватывает оба режима--top TOP— Число строк в каждом топе (по умолчанию 20) (по умолчанию: 20)
config
Показать и локально изменить значения в config.yaml.
-p, --path— Показать полный путь к config.yaml-e, --edit— Открыть config.yaml в $EDITOR-k, --key— Получить значение по ключу-s, --set— Установить значение ключа-u, --unset— Удалить ключ
copy-resume
Создаёт копию резюме на hh.ru — то же, что «Дублировать» в меню резюме (в референсах — клонирование). WRITE-команда: боевой режим требует --force или интерактивного подтверждения; --dry-run ничего не отправляет.
--resume— Slug из конфига или реальный resume_id HH.ru (#319)--dry-run— Показать, что будет сделано, без реальных действий--force— Подтвердить боевой запуск без интерактивного вопроса--write-config— Добавить новое резюме в config.yaml--slug— Slug нового резюме (по умолчанию <исходный>-copy)--title— Желаемая должность для созданной копии (после клонирования)
create-resume
Открывает визард hh.ru и создаёт новый черновик резюме. Один запуск создаёт одно резюме с одной основной профессией; для нескольких профессий нужны отдельные резюме и отдельные запуски. С --allow-unresolved-area, если area отсутствует в каталоге, черновик создаётся с ролью-плейсхолдером «Другое» — профессию затем заменяют вручную через «Дополнить». WRITE-команда: по умолчанию только dry-run; боевой запуск требует --force или интерактивного подтверждения.
--area— Профессия для выбора в визарде создания резюме. Если hh.ru показывает ровно одну подсказку автодополнения с однозначной ролью, она принимается автоматически; иначе выбирается дерево каталога — точным совпадением, а при его отсутствии единственным кандидатом фильтра (#920). Несколько подсказок автоматически не выбираются — перезапустите с точным именем одной из них--title— Одна основная профессия резюме--allow-unresolved-area, --allow-unresolved— Если area не найдена в каталоге — создать черновик с ролью-плейсхолдером «Другое» (id 40), профессия заменяется вручную (синоним: --allow-unresolved)--dry-run— Показать план без создания--force— Подтвердить боевое создание--fill-common— #985: если readback после создания вернёт draft_started с nextIncompleteScreenId=common — подтвердить экран common в том же прогоне («Сохранить и продолжить»; hh.ru предзаполняет его из профиля аккаунта) и перевести резюме к ready_to_publish. Значения не выдумываются: незаполненное в профиле поле — честный отказ до клика с вердиктом draft_started
delete-education-entry
Удаляет ровно одну запись основного/дополнительного образования через UI hh.ru, адресуя её реальным id из /profile/edit/{kind}Education/{id}. --entry-id и --kind обязательны; по умолчанию выполняется только dry-run.
--entry-id— Числовой id записи из URL /profile/edit/{kind}Education/{id}--kind— Основное (primary) или дополнительное (additional) образование--dry-run— Показать план без удаления (по умолчанию; --force включает боевой режим) (по умолчанию: True)--force— Подтвердить необратимое удаление
delete-photo
По умолчанию скрывает фото из ОДНОГО резюме (пункт «Скрыть фото из резюме»; фото остаётся в библиотеке, возвращается select-photo). --from-library необратимо удаляет фото из библиотеки аккаунта — оно исчезает из ВСЕХ резюме, где установлено. WRITE-hh-ru: dry-run включён по умолчанию (read-only инвентарь библиотеки и пунктов more-меню «Действия с фото»); боевой режим (необратимый при --from-library) включает только --force и требует --photo-id.
--resume— Slug из конфига или resume_id HH.ru--photo-id— Числовой id фото из dry-run инвентаря (обязателен в боевом режиме)--from-library— Удалить фото из библиотеки аккаунта (необратимо, бьёт по ВСЕМ резюме с этим фото), а не только скрыть из одного резюме--dry-run— Показать план и пункты меню, ничего не меняя (по умолчанию; --force включает боевой режим) (по умолчанию: True)--force— Подтвердить боевое удаление/скрытие
delete-resume
Удаляет ровно одно резюме через UI hh.ru. --resume обязателен; по умолчанию выполняется только dry-run.
--resume— Slug из конфига или реальный resume_id HH.ru (#319)--dry-run— Показать план без удаления (по умолчанию; --force включает боевой режим) (по умолчанию: True)--force— Подтвердить необратимое удаление
diagnostics
- (без аргументов)
diagnostics doctor
Сравнивает версию, release/tag и commit SHA установленного CLI, marketplace snapshot и загруженного Codex plugin; проверяет права каталогов аккаунтов и файлов сессий.
--marketplace-path, --marketplace MARKETPLACE— Путь к marketplace snapshot (для диагностики нестандартной установки)--plugin-cache PLUGIN_CACHE— Путь к Codex plugin cache (для диагностики нестандартной установки)
diagnostics export
--run-id--output OUTPUT--log LOG(по умолчанию: PosixPath('data/logs/hhru_bot.log'))--dom-dir DOM_DIR(по умолчанию: PosixPath('data/logs'))
edit-education
Составляет LLM-план образования и заполняет поля через UI hh.ru. --dry-run не нажимает Save; боевой режим требует --force или TTY-подтверждение.
--resume— Slug из конфига или реальный resume_id HH.ru (#319)--section— Какой блок редактировать (по умолчанию: оба) (по умолчанию: 'both')--source— Контекст кандидата (переопределяет education.source)--mode— Режим планирования--institution— Учебное заведение (основное образование, без LLM)--faculty— Факультет (основное образование, без LLM)--specialty— Специальность (без LLM)--year— Год окончания (без LLM)--primary-entry— Готовая запись основного образования JSON без LLM (#326), можно несколько: '{"institution":..., "faculty":..., "specialty":..., "year":...}'--additional-entry— Готовая запись доп. образования JSON без LLM (#326), можно несколько: '{"institution":..., "organization":..., "specialty":..., "year":...}'--dry-run— Заполнить только локальную форму; Save не нажимать--force— Разрешить боевое сохранение
edit-experience
Предлагает записи опыта через LLM и показывает их в dry-run. WRITE-hh-ru: боевой режим требует --force или подтверждения TTY. Опыт работы общий для всех резюме аккаунта (#782): --resume задаёт не 'куда писать', а какое резюме останется отмеченным в панели привязки hh.ru.
--resume— Slug из конфига или реальный resume_id HH.ru (#319). Опыт общий для профиля (#782) — резюме определяет привязку, не место записи.--mode— Режим LLM-планирования, действует только вместе с --career: fill — до-заполнить существующие записи (по умолчанию), create — составить план с нуля. При --entry не действует: ручной путь сам читает живое состояние резюме; явный fill идентичен умолчанию, create будет отвергнут (#326). (по умолчанию: 'fill')--career— Факты карьеры для LLM (обязательно без --entry)--entry— Готовая запись опыта JSON без LLM (#326), можно несколько: '{"company":..., "position":..., "start_year":..., "start_month":..., "end_year":..., "end_month":..., "current":..., "duties":..., "achievements":[...], "company_url":...}'. start_month обязателен (число 1-12 строкой) — форма опыта hh.ru не сохраняется без месяца начала работы (#811). Записи только ДОБАВЛЯЮТСЯ к резюме (#957): существующие строки печатаются перед записью и не меняются, а дубликат (та же компания+должность+начало) отклоняется.--existing EXISTING— JSON-массив существующих записей для LLM-планирования: в режиме fill заменяет живое чтение hh.ru, в create уходит в контекст промпта и служит fallback-планом--dry-run— Показать план, не нажимая save--force— Разрешить запись без TTY prompt
edit-languages
Без --language: LLM только предлагает языки (уровень CEFR не угадывается и не пишется на hh.ru). С --language NAME=CEFR: записывает явно подтверждённые языки. Раздел 'Языки' общий для всего профиля hh.ru: запись применяется ко всем резюме аккаунта, а не только к --resume.
--resume— Slug из конфига или resume_id HH.ru — используется только для выбора аккаунт-сессии; языки общие для всего профиля--mode— (по умолчанию: 'append')--language— Добавить язык вручную; CEFR: A1, A2, B1, B2, C1 или C2 (можно повторять)--dry-run— Показать план без записи (только с --language; без него запись не идёт всегда)--force— Подтвердить WRITE без prompt (только с --language)
edit-skills
Предлагает навыки с уровнями и, после явного подтверждения, добавляет их в inline-форму hh.ru. Без --dry-run боевой запуск требует --force или TTY-подтверждение.
--resume— Slug из конфига или реальный resume_id HH.ru (#319)--mode— (по умолчанию: 'append')--skill— Добавить навык вручную; LEVEL: basic, intermediate или advanced (можно повторять)--dry-run— Показать план и отменить форму без сохранения--force— Подтвердить WRITE без интерактивного вопроса
fill-form
--url— Явный URL внешней формы--resume— ID резюме из конфига--dry-run— Обязательный режим: без submit и навигации формы
funnel
--resume— Slug из конфига или resume_id HH.ru (по умолчанию — все)--search-query— Группировать воронку по поисковому запросу вместо резюме--format— Формат вывода: table (по умолчанию) или md (по умолчанию: 'table')--period PERIOD— Срез за последние N дней (по умолчанию 30; 0 = за всё время) (по умолчанию: 30)--dead— Показать «мёртвую зону»: отклики без ответа старше --dead-days--dead-days DEAD_DAYS— Порог «мёртвой зоны» в днях (по умолчанию 14) (по умолчанию: 14)--rejections— Показать агрегат отказов по работодателю, поиску и вилке зарплаты
import-cookies
--profile PROFILE— Путь к профилю Chrome или имя профиля (Default, Profile 1) — имя резолвится от стандартного корня профилей Chrome
learn
--resume— Slug резюме для исключения уже указанных навыков--limit LIMIT— Сколько строк вывести (по умолчанию: 20)
list-resumes
--status— Дополнительно: можно ли поднять (кулдаун) и дата последнего поднятия--local— Без похода на hh.ru: только записи config.yaml (overlay настроек)
log
-n, --lines LINES— Количество строк (по умолчанию 50) (по умолчанию: 50)-f, --follow— Следить за логом (tail -f); прерывается по Ctrl-C--prune— Чистка дампов probe/apply (.html/.png) в data/logs; по умолчанию только план (dry-run), удаление — по --yes или TTY-подтверждению--older-than DAYS— Удалять дампы старше N дней (по умолчанию 14) (по умолчанию: 14)--yes— С --prune: подтвердить удаление без TTY prompt
login
- (без аргументов)
login-code
--login— Email или телефон--code-file CODE_FILE— Файл с одноразовым кодом; без него код читается из stdin
mark
--resume— Slug из конфига или resume_id HH.ru (обязательно)--vacancy— ID вакансии (число из URL https://hh.ru/vacancy/)--status— Статус для пометки (по умолчанию offer) (по умолчанию: 'offer')
market
--estimates— Достроить медиану эвристическими оценками ЗП для вакансий без указанной (помечаются ~). По умолчанию только реальные ЗП
probe
--resume— Slug из конфига или resume_id HH.ru (по умолчанию — все)--dry-run— Показать, что будет сделано, без реальных действий--max-pages MAX_PAGES— Максимум страниц поиска (по умолчанию: 5)--vacancy-id— ID целевой вакансии (число из URL https://hh.ru/vacancy/)--vacancy-url— URL целевой вакансии (альтернатива --vacancy-id)--start-page START_PAGE— Начальная страница поиска (нумерация с 0)--healthcheck— Read-only проверка ключевых селекторов hh.ru (OK/NOT_FOUND) без отклика (#88)--json— Добавить machine-readable JSON-результат healthcheck--negotiations— Read-only дамп списка переговоров или чата без отправки (#107)--topic— ID topic из SSR-дампа negotiations для открытия чата (только чтение)--questionnaires-only— Read-only на hh.ru bulk-проверка анкет; подтверждённые вопросы пишутся в локальную SQLite, без заполнения, AI и submit--limit-questionnaires LIMIT_QUESTIONNAIRES— Остановить bulk-проверку после N подтверждённых анкет (0 — без лимита)
professional-roles
Без --refresh читает только data/cache/professional_roles.json. --refresh открывает live-каталог поиска вакансий (фильтры /search/vacancy), но не выбирает профессии и не нажимает «Сохранить».
--query— Короткое название профессии для локального поиска (можно повторять)--limit LIMIT— Максимум кандидатов в выводе (по умолчанию: 20)--refresh— Явно перечитать полный live-каталог поиска вакансий и атомарно обновить локальный кэш
profile
Установить, показать или удалить ручные ответы профиля.
- (без аргументов)
profile set
- (без аргументов)
profile show
- (без аргументов)
profile unset
- (без аргументов)
publish-resume
Публикует черновик резюме кликом по кнопке hh.ru. WRITE-hh-ru: боевой режим требует --force; --dry-run ничего не нажимает.
--resume— Slug из конфига или реальный resume_id HH.ru (#319)--dry-run— Проверить состояние без клика--force— Разрешить боевой UI-клик
query
Исполнить SELECT к history.db и вывести ASCII-таблицу или CSV. Только read-only (SELECT/WITH) — история меняется только через бот.
--csv— Вывести CSV вместо ASCII-таблицы-o— Записать результат в файл вместо stdout
questionnaire
Показать очередь, аудит и шаблоны, задать ответ или обучить шаблон.
- (без аргументов)
questionnaire audit
Что бот ответил в анкетах: ответ, уверенность, шаблон.
--resume— Slug резюме или resume_id (по умолчанию — все)--last LIMIT— Сколько последних ответов показать (по умолчанию: 50)--template— Только ответы этого шаблона--low-confidence— Только вопросы, на которые бот не стал отвечать
questionnaire learn
Интерактивный разбор накопившихся вопросов анкет.
--resume— Slug резюме или resume_id--limit LIMIT— Сколько вопросов разобрать (по умолчанию: 20)
questionnaire pending
Вопросы, на которые бот не стал отвечать сам.
--resume— Slug резюме или resume_id (по умолчанию — все)--limit LIMIT— Сколько строк вывести (по умолчанию: 50)
questionnaire set
static — готовое значение; contextual — инструкция для LLM.
--mode— static (значение) или contextual (инструкция)--answer— Готовый ответ (для --mode static)--instruction— Инструкция для LLM (для --mode contextual)--example— Формулировка вопроса, относящаяся к этому шаблону (можно повторять)--cluster— Тематический кластер вопроса--resume— Задать только для этого резюме
questionnaire templates
Шаблоны уровня аккаунта и переопределения резюме.
--resume— Slug резюме или resume_id
questionnaire unset
Удаляет шаблон только из своего скоупа.
--resume— Снять только переопределение этого резюме
refresh-token
--force— Пересохранить подтверждённую сессию в storage_state
reject
--resume— ID резюме--vacancy— ID вакансии--reason— Причина ручного отклонения--generated-letter— Сгенерированное письмо до ручной правки--edited-letter— Письмо после ручной правки
rename-resume
Изменяет название одного резюме в списке hh.ru. WRITE-hh-ru: боевой режим требует --force или интерактивного подтверждения; --dry-run ничего не сохраняет. До подтверждения селектора поля названия в живом DOM боевой режим недоступен (fail-closed).
--resume— Slug из конфига или resume_id HH.ru--name— Новое название резюме--dry-run— Показать план без записи--force— Подтвердить боевую запись
reply-employers
Account-wide ответы в чатах: план из локальной истории, финальная проверка живого чата и запись аудита.
--dry-run— Показать план без отправки--limit LIMIT— Максимум чатов за запуск (0 = все)--max-pages MAX_PAGES— Максимум страниц negotiations для SSR mapping (по умолчанию 5) (по умолчанию: 5)--template TEMPLATE— Текст ответа (по умолчанию cover_letter_default)--suggest— Сгенерировать и сохранить draft по входящему сообщению (без отправки)--follow-up— Режим напоминания (#710): вместо ответа на входящее — напомнить о себе там, где последнее слово уже за нами и работодатель молчит --after-days N--after-days AFTER_DAYS— Порог молчания работодателя в днях для --follow-up (обязателен вместе с ним)--force— Подтвердить боевой запуск
report-vacancy
Открывает вакансию, кликает 'Ещё' -> 'Пожаловаться на вакансию', выбирает причину и заполняет комментарий. Останавливается ПЕРЕД финальной отправкой (issue #745): этот шаг не подтверждён живым DOM и намеренно не реализован. Всегда завершается [FAIL] — жалоба не отправляется этой командой ни при каких условиях.
--vacancy-id— ID вакансии (число из URL https://hh.ru/vacancy/)--reason— Причина жалобы (подтверждённый перечень hh.ru)--comment— Комментарий к жалобе (обязателен для всех причин на hh.ru)--dry-run— Показать план без открытия формы (по умолчанию; --force доходит до формы) (по умолчанию: True)--force— Дойти до заполненной формы жалобы (без отправки — см. описание команды)
responses
--resume— ID резюме из конфига (по умолчанию — все)--max-pages MAX_PAGES— Максимум страниц списка откликов (по умолчанию 5) (по умолчанию: 5)--since-hours SINCE_HOURS— Показать ответы, сменившие статус за последние N часов (по умолчанию 24). 0 — выполнить живой обход hh.ru и показать синхронизацию/историю. (по умолчанию: 24.0)--detect-external-tests— Прочитать последние сообщения работодателей и записать внешние тесты (#180)--remindable— Показать переписки, для которых hh.ru явно разрешает напоминание--sync-applied— Импортировать однозначные ручные/внешние отклики в dedup ledger--alert-new— Сообщить о новых приглашениях и вернуть специальный exit-код--calendar-hint— Для каждого нового приглашения напечатать готовую командуhhru calendar eventс плейсхолдерами времени (#711)
restore
--apply— Выполнить восстановление (без флага — только показать состав)
resume-pool
Копирует базовое резюме --source по разу на каждый недостающий кластер вакансий (resume_clusters.py) и помечает каждую копию своим кластером в config.yaml. WRITE-команда: боевой режим требует --force или интерактивного подтверждения; --dry-run показывает полный план без обращения к hh.ru.
--source— Slug из конфига или реальный resume_id HH.ru базового резюме (#319)--dry-run— Показать план создания пула без реальных действий--force— Подтвердить боевой запуск без интерактивного вопроса--write-config— Добавить каждую успешно созданную копию в config.yaml с её кластером--limit LIMIT— Предел числа создаваемых за прогон копий (по умолчанию — все недостающие кластеры; троттлинга у copy-resume нет вовсе, поэтому предел обязателен для контролируемого batch-запуска)
resume-position
--resume— Slug из конфига или реальный resume_id HH.ru (#319)--title— Готовая желаемая должность без LLM (#326)--specialization— Точная профессия из live-каталога поиска вакансий hh.ru; для черновика одна, для опубликованного резюме можно несколько--salary SALARY— Зарплата (целое число, без LLM)--currency— Валюта зарплаты--employment— Тип занятости (пока только одно значение — #526)--work-format— Формат работы (пока только одно значение — #526)--commute— Время в пути--business-trips— Готовность к командировкам--mode— Режим LLM-планирования (по умолчанию fill); не сочетается с ручными полями--dry-run— Показать план без изменения hh.ru--force— Подтвердить запись без prompt--allow-auto-publish— Разрешить закрытие professional_role, после которого hh.ru может автоматически опубликовать резюме--fallback-other— Если специализация не найдена в дереве резюме — выбрать роль-плейсхолдер «Другое» (id 40) вместо отказа (#950)
resume-sections
Заполняет аттестации и рекомендации по подтвержденным UI-маршрутам; умеет создать первую строку в пустом блоке. Сертификаты, портфолио и ссылки пока пропускаются, удаления не выполняются.
--resume— Slug из конфига или реальный resume_id HH.ru (#319)--attestation— Готовая аттестация JSON без LLM (#326), можно несколько: '{"name":..., "organization":..., "specialty":..., "year":...}'--recommendation— Готовая рекомендация JSON без LLM (#326), можно несколько: '{"text":..., "company":..., "name":..., "position":...}'. text не поддерживается текущей формой HH.ru и приведёт к [FAIL] для этой строки, если непустой (#367).--dry-run— Показать план без изменений на hh.ru--force— Подтвердить WRITE без prompt
resume-views
--resume— ID резюме (по умолчанию — все резюме)--limit LIMIT— Максимум snapshots на резюме (по умолчанию 100) (по умолчанию: 100)--max-pages MAX_PAGES— Максимум страниц истории (по умолчанию 5) (по умолчанию: 5)
resume-visibility
Изменяет режим видимости резюме и/или список работодателей whitelist/blacklist ('Кто видит'/'Кто не видит'). WRITE-hh.ru опасного уровня: боевой режим требует --force или подтверждения; --dry-run ничего не сохраняет. --resume all применяет одно и то же действие ко всем резюме аккаунта (основной сценарий: стоп-лист обычно общий для всех резюме).
--resume— Slug из конфига, resume_id HH.ru или 'all' — все резюме аккаунта--mode— Новый режим видимости; без флага — режим не меняется, редактируется только список--add-employer— Добавить работодателя в активный whitelist/blacklist (можно повторять)--remove-employer— Убрать работодателя из активного whitelist/blacklist (можно повторять)--dry-run— Показать план без записи--force— Подтвердить боевую запись
review
- (без аргументов)
review approve
--ttl TTL(по умолчанию: 900)
review edit
- (без аргументов)
review list
--status
review requeue
- (без аргументов)
review skip
- (без аргументов)
robot-queue
--limit LIMIT— (по умолчанию: 50)
run
--resume— Slug из конфига или resume_id HH.ru (по умолчанию — все)--dry-run— Показать, что будет сделано, без реальных действий--max-pages MAX_PAGES— Явный максимум страниц поиска (по умолчанию — адаптивный)--force— Разрешить реальную отправку отклика с LLM-ответами на вопросы--learn-questionnaires— Спрашивать подтверждение сопоставления вопроса анкеты с шаблоном--limit LIMIT— Целевое число успешных откликов за запуск (0 = без ограничения кроме дневного лимита)
schedule
--format— Формат вывода: plist (launchd, по умолчанию) или crontab (по умолчанию: 'plist')--action— Какое действие планировать: bump/run (периодически) или apply (раз в день) (по умолчанию: 'bump')--bump-interval-hours BUMP_INTERVAL_HOURS— Интервал запуска bump/run в часах (по умолчанию 4, равен кулдауну) (по умолчанию: 4)--apply-time— Время ежедневного apply в формате HH:MM (по умолчанию 10:00) (по умолчанию: '10:00')--apply-limit APPLY_LIMIT— Лимит откликов за один apply-прогон (по умолчанию 5) (по умолчанию: 5)
search
--resume— Slug из конфига или resume_id HH.ru (по умолчанию — все)--dry-run— Показать, что будет сделано, без реальных действий--max-pages MAX_PAGES— Максимум страниц поиска (по умолчанию: 5)--text— Разовый текст поиска; можно использовать без --resume
select-photo
Открывает вьюер фото на странице резюме кнопкой-карандашом, показывает библиотеку фото аккаунта и назначает выбранное фото этому резюме (в том числе замену существующего). WRITE-hh-ru: по умолчанию dry-run (read-only инвентарь библиотеки); боевой запуск требует --photo-id и --force или интерактивного подтверждения.
--resume— Slug из конфига или resume_id HH.ru--photo-id— Числовой id фото из dry-run инвентаря (обязателен в боевом режиме)--dry-run— Показать библиотеку фото, ничего не назначая--force— Подтвердить боевое назначение
settings
Показать все настройки, получить значение или установить ключ.
- (без аргументов)
skipped
Показать записи skipped с данными вакансий из локальной истории.
--reason— Показать только эту причину (по умолчанию — все причины)
stats
--resume— Slug из конфига или resume_id HH.ru (по умолчанию — все)--period— Период агрегации (по умолчанию all) (по умолчанию: 'all')--format— Формат вывода: table (по умолчанию), csv, md (по умолчанию: 'table')--list— Вместо сводки вывести список последних действий--limit LIMIT— Лимит строк в режиме --list (по умолчанию 50) (по умолчанию: 50)
uncertain
- (без аргументов)
uncertain inspect
- (без аргументов)
uncertain list
--limit LIMIT(по умолчанию: 50)
uncertain reconcile
- (без аргументов)
update
Обновляет hhru и установленный Codex plugin из одного commit, проверяет provenance обоих компонентов и явно завершается ошибкой при частичном сбое. Уже открытая задача Codex продолжит использовать старый skill — после обновления начните новую задачу.
--codex— Путь к Codex CLI (для диагностики и тестов; по умолчанию: codex) (по умолчанию: 'codex')
upload-photo
Передаёт файл фото в скрытый file-input блока аватара на странице резюме. WRITE-hh-ru: по умолчанию только dry-run (read-only осмотр блока фото); боевой запуск требует --force или интерактивного подтверждения. Замена существующего фото не поддерживается.
--resume— Slug из конфига или resume_id HH.ru--photo PHOTO— Путь к файлу jpg/jpeg/png--dry-run— Осмотреть блок фото, ничего не загружая--force— Подтвердить боевую загрузку
whoami
--resume— Slug из конфига или resume_id HH.ru (по умолчанию — все)--online— Проверить сессию на hh.ru (открывает браузер)
wizard-next
Кликает «Сохранить и продолжить» на незавершённом экране визарда черновика. WRITE-hh-ru: боевой режим требует --force; --allow-auto-publish нужен только на последнем незакрытом экране — hh.ru публикует резюме сам (#900, #1012); --dry-run ничего не нажимает.
--resume— Slug из конфига или реальный resume_id HH.ru (#319)--screen— Явный экран; по умолчанию — текущий nextIncompleteScreenId--dry-run— Проверить экран без клика--force— Разрешить боевой UI-клик--allow-auto-publish— Разрешить сабмит последнего незакрытого экрана: hh.ru опубликует резюме сам (#900, #1012). На промежуточных экранах не требуется
Как это устроено
config.py— загрузкаdata/config.yaml.history.py— локальная SQLite-история (data/history.db).throttle.py— случайные паузы и дневные лимиты.browser.py/auth.py— запуск Playwright и вход в аккаунт.search.py— поиск вакансий и фильтрация.apply.py— отклик с сопроводительным письмом.bump.py— поднятие резюме.selectors.py— все CSS/data-qa селекторы hh.ru в одном месте.
Всё — в src/hhru_bot/.
Логи
data/logs/hhru_bot.log и консоль, --verbose для подробностей. Ротация при
10 MiB (hhru_bot.log.1, .2...), архивы копятся без автоочистки.
Похожие проекты (для идей)
Источник идей, не код для копирования — смотреть, а не переиспользовать.
15 декабря 2025 hh.ru закрыл соискательский API — отклик и работа с резюме для сторонних приложений отключены, остался поиск вакансий и
GET /me. Все живые проекты 2026 года, как и наш, работают через браузер (Playwright), а не через API.
Браузерные боты (наш стек — Playwright/Selenium)
-
Steev193/hh-ru-apply — Node + Playwright, MIT. Вынесенные селекторы + codegen для их обновления.
-
tgeruzov/hh-auto-responder — Tampermonkey userscript. Роутинг трёх исходов отклика.
-
YAMAKAYAMACO/hh-autoresponder — Python + Playwright + SQLite, ближе всего к нашей архитектуре.
-
fikstt2/hh-ai-agent — Python + Playwright. Персистентная сессия: вход руками один раз, потом headless.
-
semernyakov/hh-auto-apply — Python + Playwright, MIT. Парсер cooldown поднятия резюме из текста hh.ru.
-
beatwad/XX_Auto_Jobs_Applier — Python + Playwright, MIT. Config-driven (YAML), капча через Telegram.
-
s3rgeym/hh-applicant-tool — Python, API + Playwright, 500+ звёзд. Эталон по шаблонам писем, схеме SQLite и троттлингу. README запрещает коммерческое использование — только как референс, код не брать.
-
konard/hh-job-application-automation — Bun, Playwright и Puppeteer, Unlicense. Q&A-файл с нечётким матчем (Левенштейн + keyword overlap) для тест-вопросов формы.
Поднятие резюме
- Vlad9572324/hh.ru-clicker —
bump через API
/applicant/resumes/touch(проверять актуальность после дек. 2025). - rycln/hhraiser — Go. Джиттер расписания против антифрода.
Адаптация и хранение резюме
Отдельный трек (issue #671) от ботов-автооткликов выше: у нас резюме — внешний артефакт на hh.ru, эти проекты работают с резюме как с локальными данными (JSON/PDF/веб-форма). Разобран по коду один прошедший фильтр по лицензии и активности кандидат из восьми рассмотренных — остальные отсеяны, причины ниже.
-
srbhr/Resume-Matcher — Python (FastAPI) + TypeScript, Apache-2.0, ревизия
116f9cc3b00e1ac91734a6c2679bf41ea64a0edc(2026-08-11). Единственный кандидат про адаптацию резюме под конкретную вакансию — задачу, которую наш проект пока не решает. Заимствуемая идея не код, а два механизма:apps/backend/app/services/improver.pyдвигает содержимое резюме под вакансию через diff-патчи по regex-whitelist путей (_ALLOWED_PATH_PATTERNS— толькоsummary,description-поля и списки навыков/языков/сертификатов) и явный blocklist полей (_BLOCKED_FIELD_NAMES—company,institution,title,yearsи т.п. трогать нельзя); LLM физически не может переписать факты вроде места работы или диплома, только формулировки.apps/backend/app/services/refiner.py::validate_master_alignment— постфактум-проверка, что ни один навык, сертификат или работодатель в адаптированной версии не появился «из воздуха»: сверяет их с исходным («мастер») резюме и репортитfabricated_skill/fabricated_cert/fabricated_companyкак critical-нарушения.
У нас похожий принцип уже есть с другой стороны — не пост-проверкой LLM-вывода, а входным гейтом до генерации (
STRICT_CLUSTERS+templates.is_compliance_textв пакетеquestionnaires/, см. «Ключевые архитектурные решения» вCLAUDE.md). Whitelist путей на запись и alignment-проверка Resume-Matcher — предметный пример того же принципа «уверенная ошибка здесь необратима», применённый к тексту резюме, а не к ответам на анкеты; полезно как референс, если будет отдельная задача на адаптацию резюме под вакансию.
Отсеяны без разбора по коду (см. issue #671 для метрик):
- Reactive-Resume, OpenResume — веб-конструкторы резюме с нуля. У нас резюме уже существует на hh.ru и правится по DOM; локальный конструктор — не наша задача. Дополнительно у OpenResume лицензия AGPL-3.0 (портирование кода закрыто) и последний push — октябрь 2024.
- RenderCV, sb2nov/resume, McDowell CV — генерация предсказуемого PDF/LaTeX резюме как локального файла. Наш артефакт живёт в интерфейсе hh.ru, а не в файле, который мы рендерим сами — вне скоупа.
- JSON Resume CLI (
jsonresume/resume-cli) — репозиторий архивирован; сама структура данных как формат остаётся жизнеспособной идеей, но брать нечего — код не развивается. - YAMLResume — та же задача структурированного хранения резюме, что
уже закрыта внутри проекта своими средствами (
CandidateFactsв конфиге, issue #751), без заимствования у reference-проекта.
Изучены точечно (отдельные селекторы, не полный аудит)
Разобраны по конкретным находкам (docs/research/reference-selector-diff-audit.md),
не по всему функционалу — сравнивать их с остальными в таблице фич нечестно.
- Vadtop/hh-mcp-server — Python + Playwright, MIT.
- AgentShekel/hh-bot — Python + Playwright, лицензия не подтверждена (NOASSERTION).
- RumyantsevQa/hh-ai-auto-apply-assistant — Python, MIT.
- kavotavochavo1-ctrl/hh-ai-job-bot — Python + Playwright, MIT.
- lil-zon/hh-auto-apply — Python, без LICENSE.
Обход DDoS-Guard / антидетект браузера
- Kaliiiiiiiiii-Vinyzu/patchright-python — drop-in замена Playwright, чинит Playwright-детект.
- daijro/camoufox — антидетект-форк Firefox (автор предупреждает: не для стабильного прода).
- ultrafunkamsterdam/nodriver / cdpdriver/zendriver — сильнее всех против DDoS-Guard, но не Playwright.
Гарантий обхода DDoS-Guard в headless нет; капчу приходится проходить руками
— это уже частично делает login.
Metadata
Release files for hhru-bot 0.1.1
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| hhru_bot-0.1.1.tar.gz | 1.7 MB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| hhru_bot-0.1.1-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 2.7 MB
Release files / hhru_bot-0.1.1.tar.gz
| Download URL | hhru_bot-0.1.1.tar.gz |
|---|---|
| Size | 1.7 MB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
4e47fc9ac86e35da72c28cac9678d7f7782848f4a40aebf35008fbf4bfe6594c
|
|
BLAKE2b-256 checksum How to use checksums |
493255fb2891b27b0533e083c49b6f76a9794234a36f40c08f985d9bb820b83d
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.12.10
|
Release files / hhru_bot-0.1.1-py3-none-any.whl
| Download URL | hhru_bot-0.1.1-py3-none-any.whl |
|---|---|
| Size | 951.9 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
e71771ee7a47c94f801fad8c4f3193349d74e47997c2bf648b472cdc5c497c51
|
|
BLAKE2b-256 checksum How to use checksums |
2a39134c383b09cdd79a06810112deea0f3ce29b8c291a5194143a15cbbefca2
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.12.10
|