job-form-filler
v1.3.0
Published
Chrome Extension and Bridge/MCP Server for 0-token and AI-assisted job application form filling
Maintainers
Readme
⚡ Job Form Filler (0-Token & AI Hybrid)
Розширення для Google Chrome + опційний локальний міст (Local Bridge & MCP Server) для заповнення форм вакансій (Ashby, Greenhouse, Lever, Workable, LinkedIn Easy Apply, Djinni та будь-які інші).
Замість того щоб віддавати ШІ весь DOM або скріншоти, розширення ділить поля на рівні:
- Tier 1 (0 токенів): стандартні поля (ім'я, контакти, адреса, лінки, дозвіл на роботу, віза, релокація, notice period, зарплата, EEO, файл резюме) заповнюються локально з вашого профілю.
- Tier 2 (мінімум токенів): ШІ отримує лише незаповнені питання (зі стабільними
fieldIdта варіантами відповідей) і стислий текст вакансії. - Tier 3 (людина): мотиваційні/поведінкові питання ШІ ніколи не пише — вони повертаються вам.
🚀 Швидкий старт (без мосту, без ШІ)
chrome://extensions/→ увімкніть Developer mode → Load unpacked → оберіть папкуextension/.Відкрийте попап → вкладка 👤 Профіль → заповніть дані → 💾 Зберегти. Там же завантажте файл резюме (PDF/DOCX до 5 МБ).
- Або ⬆️ Імпорт готового
profile.json(формат — як у ⬇️ Експорт; поля описані вextension/shared/default-profile.js). - Або заповніть одну форму вручну й натисніть 🧠 Запам'ятати з цієї форми: розпізнані стандартні поля потраплять у профіль.
- Або попросіть агента через MCP: «заповни мій профіль у job-form-filler з мого резюме» (тул
update_candidate_profile).
Обидва автоматичні шляхи заповнюють лише порожні поля профілю. Розбіжності з уже збереженими значеннями показуються, але не застосовуються.
- Або ⬆️ Імпорт готового
Відкрийте форму вакансії → ⚡ Заповнити стандартні поля. Попап покаже, яких даних бракує в профілі та які поля не вдалося заповнити.
Профіль і резюме зберігаються лише локально в chrome.storage.local. Розширення ніколи не перезаписує поля, які ви вже заповнили.
Формат профілю
{
"personal": { "firstName": "", "lastName": "", "email": "", "phoneCountryCode": "+380", "phone": "", "city": "", "country": "" },
"links": { "linkedin": "", "github": "", "website": "" },
"work": { "currentCompany": "", "currentTitle": "", "yearsOfExperience": "", "noticePeriod": "", "salaryExpectation": "" },
"legal": { "authorizedToWork": "Yes", "requiresSponsorship": "No", "willingToRelocate": "" },
"eeo": {},
"profiles": { "frontend-developer": { "title": "Senior Frontend Developer", "summary": "..." } },
"localized": { "uk": { "personal": { "firstName": "Дмитро", "city": "Вінниця" }, "work": { "noticePeriod": "2 тижні" } } }
}Порожні EEO-поля (gender, ethnicity, veteran, disability) заповнюються варіантом «Decline to self-identify» мовою форми. profiles — необов'язкові варіанти ролі (обираються в попапі).
Щоб додати нове стандартне поле: рядок у PROFILE_FIELDS (extension/shared/default-profile.js), правило в FIELD_RULES та значення в profileValue (extension/content/content.js).
🌍 Мови
Підтримувані мови: English, Українська, Polski, Deutsch, Français, Español, Italiano, Português, Nederlands. Російська свідомо не підтримується.
- Форми розпізнаються всіма цими мовами. Мова форми визначається за підписами полів (кирилиця →
uk, польські літери →pl), а<html lang>використовується як запасний варіант. ATS часто лишають тамen. - Значення: основний профіль заповнюється однією мовою, а для інших мов можна задати переклади (вкладка «Профіль» → «Переклади для форм іншими мовами», у JSON це
localized.<lang>). На формі цією мовою спершу береться переклад. Назви країн («Ukraine» ⇄ «Україна» ⇄ «Ucraina») і «Так/Ні» перекладаються автоматично. - «Запам'ятати з цієї форми» на неанглійській формі записує значення, що відрізняються від профілю, як переклади цієї мови.
- ШІ відповідає мовою форми (
get_active_job_form.language). Tier 3 (особисті питання) розпізнається всіма цими мовами. - Інтерфейс перекладено тими самими мовами (португальська —
pt_BRіpt_PT). Мова обирається за мовою браузера, за замовчуванням англійська (extension/_locales/). Щоб додати мову інтерфейсу, створіть_locales/<lang>/messages.jsonз тими самими ключами, що й вuk. - Щоб додати мову форм: по рядку в кожному правилі
FIELD_RULES(content.js), мову вFORM_LANGUAGES(default-profile.js) і шаблони вHUMAN_PATTERNS(server/human-questions.js).
🔌 Міст і MCP (для Claude Code / AGY)
npm install
npm run bridge # http://127.0.0.1:8765, ws://127.0.0.1:8765/wsПідключіть MCP-сервер (~/.claude/mcp.json або claude mcp add):
{
"mcpServers": {
"job-form-filler": {
"command": "node",
"args": ["/path/to/job-form-filler/bin/mcp.js"],
"env": { "RESUME_REPO_PATH": "/path/to/your/resume-repo" }
}
}
}Агент отримує інструкції робочого циклу від самого MCP-сервера: autofill_static_fields → get_active_job_form → get_candidate_profile → fill_job_form → ви перевіряєте й натискаєте Submit → get_submission_status.
Змінні оточення (усі опційні)
| Змінна | Що робить |
|---|---|
| RESUME_REPO_PATH | Папка з варіантами резюме: <repo>/resume/<role>/*.md, *.pdf або <repo>/<role>/.... За замовчуванням не задано (функція вимкнена). Дає варіанти ролей у попапі, PDF для завантаження і markdown-факти для ШІ. Назви файлів довільні (перевага resume*/cv*). |
| BRIDGE_PORT | Порт мосту (за замовчуванням 8765). |
| JFF_DATA_DIR | Куди зберігати learned answers і заявки без репо (за замовчуванням ~/.job-form-filler). |
🎯 Як це працює
Крок 0: навігація — ваша відповідальність
Відкрийте вкладку з формою самі (або іншим інструментом). Цей інструмент ніколи не переходить за URL.
Попап
- ⚡ Заповнити стандартні поля — 0 токенів.
- 📋 Скопіювати промпт для CLI — компактний промпт з
fieldIdі варіантами відповідей для будь-якого агента. - 💾 Зберегти в репо —
job-posting.mdу<role>/applications/<company>/(або~/.job-form-filler/applications/). - 🧠 Запам'ятати з цієї форми — стандартні поля, заповнені вручну, додаються в профіль (лише порожні слоти); відповіді на нестандартні питання зберігаються для наступних форм.
🔒 Безпека та контроль
❌ Submit — НІКОЛИ не натискається автоматично
Це навмисне архітектурне рішення безпеки, а не відсутня фіча.
- Жоден MCP-тул, команда bridge або дія попапу не може натиснути кнопку Submit / Apply.
- Якщо майбутній контриб'ютор захоче додати
submit_form— не треба: ризик випадкової подачі резюме на небажану вакансію є неприйнятним. get_submission_statusлише читає заголовок сторінки після того, як ви натиснули Submit.
🧑 Tier 3 — Питання, що потребують людини
Поведінкові («Розкажіть про випадок, коли…»), мотиваційні («Чому саме зараз?») та особистісні питання ніколи не заповнюються ШІ. get_active_job_form позначає їх humanRequired: true.
Міст
- Слухає лише
127.0.0.1; приймає запити тільки від розширення (chrome-extension://) та локальних процесів безOrigin. Веб-сторінки отримують 403 (захист від читання профілю й DNS-rebinding). - Персональні дані (learned answers, заявки) зберігаються поза папкою проєкту.
🛠 MCP-інструменти
| Інструмент | Опис |
|---|---|
| autofill_static_fields | Заповнює Tier 1 поля; повертає filled, missingProfile, failed |
| get_active_job_form | Незаповнені питання (fieldId, label, options, humanRequired) + метадані вакансії |
| get_form_state | Поточні значення всіх полів форми (заповнених і порожніх): перевірка після автозаповнення; паролі приховані, файли — імена, групи чекбоксів — позначені опції |
| click_button | Просуває багатокрокову форму кнопкою навігації (Continue/Next/Apply Now/Продовжити/Далі): точний збіг мітки; Submit/Send/Apply/Delete/Pay та кнопки з такою aria-label відхиляються; фінальний Submit завжди натискає користувач |
| fill_job_form | Вписує відповіді за fieldId; повертає failed, notFound |
| get_candidate_profile | Профіль з розширення + markdown резюме обраного варіанту ролі |
| update_candidate_profile | Записує дані в профіль розширення (лише відомі поля; наявні значення — тільки з overwrite) |
| save_job_application | Зберігає job-posting.md (+ cover letter); використовуйте log_application для запису результату |
| get_job_posting | Отримує повний текст, вимоги та питання вакансії серверно без браузера |
| log_application | Логує результат заявки (submitted/skipped) до info/applications-log.md, профілю резюме та job-posting.md. Ідемпотентна за URL чи company+date. Підтримує dryRun |
| get_submission_status | Перевіряє URL (/confirm, /applied, /thank-you, /connect/dashboard) і текст/заголовок після Submit; повертає matchedBy |
🧪 Тести
npm test