<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Ala BEN KHALIFA</title>
    <description>The latest articles on DEV Community by Ala BEN KHALIFA (@ala_benkhalifa).</description>
    <link>https://dev.to/ala_benkhalifa</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4022805%2F70d1c59f-b479-4e10-854f-6f02614af9d7.jpg</url>
      <title>DEV Community: Ala BEN KHALIFA</title>
      <link>https://dev.to/ala_benkhalifa</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/ala_benkhalifa"/>
    <language>en</language>
    <item>
      <title>I Open-Sourced JobHunter: An AI Agent for Job Applications With Human Approval Built In</title>
      <dc:creator>Ala BEN KHALIFA</dc:creator>
      <pubDate>Sat, 11 Jul 2026 19:08:00 +0000</pubDate>
      <link>https://dev.to/ala_benkhalifa/i-open-sourced-jobhunter-an-ai-agent-for-job-applications-with-human-approval-built-in-2h6k</link>
      <guid>https://dev.to/ala_benkhalifa/i-open-sourced-jobhunter-an-ai-agent-for-job-applications-with-human-approval-built-in-2h6k</guid>
      <description>&lt;p&gt;GitHub: &lt;a href="https://github.com/alabenkhlifa/JobHunter" rel="noopener noreferrer"&gt;https://github.com/alabenkhlifa/JobHunter&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I started building &lt;strong&gt;JobHunter&lt;/strong&gt; because I had a simple problem.&lt;/p&gt;

&lt;p&gt;Searching for jobs is &lt;strong&gt;repetitive&lt;/strong&gt;, noisy, and easy to turn into a bad automation project.&lt;/p&gt;

&lt;p&gt;Most job automation ideas quickly become some version of this:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;“Scrape jobs, generate resumes, apply everywhere.”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;At first, that sounds useful. But when I looked closer, it felt wrong.&lt;/p&gt;

&lt;p&gt;A job application is not just a form submission. It includes private data, legal answers, salary expectations, visa status, truthful career history, recruiter conversations, and sometimes terms or privacy notices.&lt;/p&gt;

&lt;p&gt;If an agent guesses any of that, the automation is not helping anymore. It is &lt;strong&gt;creating risk&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;So I built JobHunter with a different rule:&lt;/p&gt;

&lt;p&gt;The agent can &lt;strong&gt;prepare the work&lt;/strong&gt;, but it must &lt;strong&gt;stop&lt;/strong&gt; at trust boundaries.&lt;/p&gt;

&lt;p&gt;JobHunter is an &lt;strong&gt;open-source&lt;/strong&gt;, &lt;strong&gt;approval-gated job-search&lt;/strong&gt; assistant for Python.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;It collects jobs&lt;/li&gt;
&lt;li&gt;Scores them&lt;/li&gt;
&lt;li&gt;Sends &lt;strong&gt;Telegram&lt;/strong&gt; review cards&lt;/li&gt;
&lt;li&gt;Learns from Interested/Skip &lt;strong&gt;feedback&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Prepares&lt;/strong&gt; truthful application packages&lt;/li&gt;
&lt;li&gt;Inspects application pages through Chromium CDP&lt;/li&gt;
&lt;li&gt;Tracks application state in SQLite and &lt;strong&gt;Google Sheets&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Watches a &lt;strong&gt;dedicated Gmail inbox&lt;/strong&gt; for recruiter or ATS replies&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;But the important part is what it refuses to do.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;It does not blindly mass-apply.&lt;/li&gt;
&lt;li&gt;It does not invent resume facts.&lt;/li&gt;
&lt;li&gt;It does not answer salary, visa, legal, or work-authorization questions without confirmation.&lt;/li&gt;
&lt;li&gt;It does not bypass CAPTCHA or anti-bot checks.&lt;/li&gt;
&lt;li&gt;It does not click final submit unless the user explicitly approves.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That constraint changed the architecture.&lt;/p&gt;

&lt;h2&gt;
  
  
  The scraper is not the product. The safety model is the product.
&lt;/h2&gt;

&lt;p&gt;JobHunter currently focuses on roles like &lt;em&gt;(it is configurable, so you can choose your focus area)&lt;/em&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Software Architect&lt;/li&gt;
&lt;li&gt;Cloud Architect&lt;/li&gt;
&lt;li&gt;Tech Lead&lt;/li&gt;
&lt;li&gt;Senior Backend Engineer&lt;/li&gt;
&lt;li&gt;Platform Architect&lt;/li&gt;
&lt;li&gt;Solutions Architect&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It collects opportunities from &lt;strong&gt;supported sources &lt;em&gt;(right now LinkedIn and FoundIt)&lt;/em&gt;&lt;/strong&gt;, stores them locally in SQLite, deduplicates them, filters noisy results, and scores jobs based on stack, seniority, location, and description signals.&lt;/p&gt;

&lt;p&gt;Then it sends a small number of &lt;strong&gt;Telegram cards&lt;/strong&gt; instead of flooding the user.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fv0hyilem4xb2r2543x1p.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fv0hyilem4xb2r2543x1p.jpeg" alt="_Example of a Telegram job offer message" width="720" height="1468"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Example of a Telegram job offer message.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Each card has clear actions: &lt;strong&gt;Interested&lt;/strong&gt;, &lt;strong&gt;Skip&lt;/strong&gt;, &lt;strong&gt;Details&lt;/strong&gt;, and &lt;strong&gt;skip reasons&lt;/strong&gt; like wrong stack, too junior, too senior, or low quality.&lt;/p&gt;

&lt;p&gt;That feedback is stored as &lt;strong&gt;traceable data&lt;/strong&gt; and reused to &lt;strong&gt;adjust future ranking&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;This is intentionally &lt;strong&gt;simple&lt;/strong&gt;. I did not want a black-box recommender that says “trust me bro.” I wanted a system where the user’s decisions leave a trail.&lt;/p&gt;

&lt;p&gt;If I keep skipping frontend-heavy roles, the future ranking should demote similar jobs.&lt;/p&gt;

&lt;p&gt;If I keep selecting backend architecture roles, the system should boost similar ones.&lt;/p&gt;

&lt;p&gt;The useful part is not “AI decides my career.”&lt;/p&gt;

&lt;p&gt;The useful part is “my repeated decisions make the assistant less noisy.”&lt;/p&gt;

&lt;p&gt;The resume generation flow follows the same idea.&lt;/p&gt;

&lt;p&gt;JobHunter uses a local &lt;code&gt;data/master-profile.json&lt;/code&gt; file as the source of truth. That file is ignored by Git. The open-source repository only includes an example schema.&lt;/p&gt;

&lt;p&gt;When generating a tailored resume or cover letter, the agent can &lt;strong&gt;reorder skills&lt;/strong&gt;, &lt;strong&gt;emphasize relevant experience&lt;/strong&gt;, and &lt;strong&gt;rewrite the summary&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;But it &lt;strong&gt;cannot invent companies, titles, dates, education, certifications, or skills&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;This matters because resume tailoring is a dangerous area for AI agents. It is very easy for a model to make a profile sound stronger by adding small false details.&lt;/p&gt;

&lt;p&gt;One invented certification or one fake responsibility can create a real problem.&lt;/p&gt;

&lt;p&gt;So the project treats the profile like a &lt;strong&gt;factual database&lt;/strong&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Tailoring means emphasis, &lt;strong&gt;not fabrication&lt;/strong&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The browser application flow is also approval-gated.&lt;/p&gt;

&lt;p&gt;JobHunter can connect to &lt;strong&gt;Chromium through CDP&lt;/strong&gt; and &lt;strong&gt;inspect the current LinkedIn&lt;/strong&gt; or ATS page.&lt;/p&gt;

&lt;p&gt;It extracts visible inputs, buttons, links, required fields, and page text.&lt;/p&gt;

&lt;p&gt;It &lt;strong&gt;detects blockers like CAPTCHA&lt;/strong&gt;, phone verification, identity verification, privacy notices, salary questions, visa sponsorship, work authorization, background checks, and final certification text.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;If it sees a sensitive question, it records the blocker and stops.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;If a file upload is requested, it &lt;strong&gt;requires an explicit approval flag&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;If final submit is requested, it &lt;strong&gt;requires an explicit approval flag&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  This is not just a UX preference. It is an engineering boundary.
&lt;/h2&gt;

&lt;p&gt;The agent can help with mechanical work, but the human &lt;strong&gt;stays responsible for legal consent, personal declarations, and final submission&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;I also added a &lt;strong&gt;tracker flow&lt;/strong&gt; because job search automation is useless if you lose the state.&lt;/p&gt;

&lt;p&gt;JobHunter records application stages locally, then can sync a human-readable tracker to Google Sheets.&lt;/p&gt;

&lt;p&gt;The tracker can include status, company, title, application URL, resume link, cover letter link, evidence screenshot link, notes, and next action.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fiu7bn6hf48p5qbja3jdj.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fiu7bn6hf48p5qbja3jdj.png" alt="Google Sheet to keep track of the job applications" width="800" height="190"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Google Sheet to keep track of the job applications&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;There is also a &lt;strong&gt;Gmail watcher&lt;/strong&gt; for a dedicated jobs mailbox.&lt;/p&gt;

&lt;p&gt;It checks recruiter and ATS replies, filters noise like newsletters and Google Sheet share emails, marks inspected messages as read, and reports relevant replies.&lt;/p&gt;

&lt;p&gt;This creates a loop:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Collect jobs.&lt;/li&gt;
&lt;li&gt;Review only the best candidates.&lt;/li&gt;
&lt;li&gt;Mark Interested or Skip.&lt;/li&gt;
&lt;li&gt;Generate truthful documents.&lt;/li&gt;
&lt;li&gt;Inspect the application page.&lt;/li&gt;
&lt;li&gt;Stop at sensitive gates.&lt;/li&gt;
&lt;li&gt;Track status.&lt;/li&gt;
&lt;li&gt;Watch for replies.&lt;/li&gt;
&lt;li&gt;Improve future recommendations from feedback.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;That loop is the real project.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I learned while building this is that “agentic automation” needs more stopping rules than action rules.
&lt;/h2&gt;

&lt;p&gt;Most demos focus on what the agent can do.&lt;/p&gt;

&lt;p&gt;I think production-useful agents also need clear answers to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Where should the agent stop?&lt;/li&gt;
&lt;li&gt;Which facts are allowed to be reused?&lt;/li&gt;
&lt;li&gt;Which answers must be confirmed again?&lt;/li&gt;
&lt;li&gt;Which files must never be committed?&lt;/li&gt;
&lt;li&gt;Which actions require approval?&lt;/li&gt;
&lt;li&gt;Which states should be recorded for audit?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Without those boundaries, the assistant becomes fast but &lt;strong&gt;unsafe&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;With those boundaries, it becomes slower in the right places.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;That is the tradeoff I wanted.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;JobHunter is &lt;strong&gt;not trying to replace the person applying&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;It is trying to &lt;strong&gt;remove the repeated work around the person&lt;/strong&gt;: scraping, deduplication, ranking, packaging, tracking, and reply monitoring.&lt;/p&gt;

&lt;h2&gt;
  
  
  The human still owns the truth.
&lt;/h2&gt;

&lt;p&gt;The human still &lt;strong&gt;approves the submission&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;The human still &lt;strong&gt;decides whether the job is worth it&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  I open-sourced it because I think this pattern is useful beyond job search.
&lt;/h2&gt;

&lt;p&gt;Many agent workflows have the same shape:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Do the boring work automatically.&lt;/li&gt;
&lt;li&gt;Record state.&lt;/li&gt;
&lt;li&gt;Reuse confirmed facts.&lt;/li&gt;
&lt;li&gt;Stop at sensitive decisions.&lt;/li&gt;
&lt;li&gt;Ask for approval before irreversible actions.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That is a better agent pattern than “just automate everything.”&lt;/p&gt;




&lt;p&gt;Also one important thing to know, this project should be setup with Hermes Agent, for best results use Raspberry Pi to host it and a decent LLM.&lt;/p&gt;

&lt;p&gt;Personally I use&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Raspberry Pi 5 with 8 Gb of RAM&lt;/li&gt;
&lt;li&gt;Hermes with GPT-5.5 as LLM brain&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The project also supports multiple profiles if you want to bless your friend that is looking for a new job with you, you can setup their profile and add a Hermes Gateway so they can receive job offers and apply automatically.&lt;br&gt;
Another alternative would be to setup 2 NTFY channels, one for receiving the offers and the other for replying with the offer ID so Hermes can generate the resume, cover letter and apply for them.&lt;br&gt;
Please Star this repo if you like the article, it took me huge effort to implement it and refine, it is still being refined everyday with every job offer I receive.&lt;/p&gt;




&lt;p&gt;Please Star this repo if you like the article, it took me huge effort to implement it and refine, it is still being refined everyday with every job offer I receive.&lt;/p&gt;

&lt;p&gt;GitHub: &lt;a href="https://github.com/alabenkhlifa/JobHunter" rel="noopener noreferrer"&gt;https://github.com/alabenkhlifa/JobHunter&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you have any questions like how to setup LinkedIn on the Raspberry Pi for automatically applying for jobs or adding a secondary profile, feel free to reply to this post. I will do my best to assist you.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>agents</category>
      <category>raspberrypi</category>
      <category>career</category>
    </item>
  </channel>
</rss>
