<?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: Sriram Hariharan Neelakantan</title>
    <description>The latest articles on DEV Community by Sriram Hariharan Neelakantan (@sriram_hariharan_2def71eb).</description>
    <link>https://dev.to/sriram_hariharan_2def71eb</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%2F4170447%2F8a322b93-dffc-4202-9fcd-2c4e5dde03b8.png</url>
      <title>DEV Community: Sriram Hariharan Neelakantan</title>
      <link>https://dev.to/sriram_hariharan_2def71eb</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/sriram_hariharan_2def71eb"/>
    <language>en</language>
    <item>
      <title>[Boost]</title>
      <dc:creator>Sriram Hariharan Neelakantan</dc:creator>
      <pubDate>Thu, 08 Oct 2026 08:17:22 +0000</pubDate>
      <link>https://dev.to/sriram_hariharan_2def71eb/-27n2</link>
      <guid>https://dev.to/sriram_hariharan_2def71eb/-27n2</guid>
      <description>&lt;div class="ltag__link--embedded"&gt;
  &lt;div class="crayons-story "&gt;
  &lt;a href="https://dev.to/sriram_hariharan_2def71eb/from-job-scraper-to-production-ai-system-building-applylens-ai-4fdj" class="crayons-story__hidden-navigation-link"&gt;From Job Scraper to Production AI System: Building ApplyLens AI&lt;/a&gt;


  &lt;div class="crayons-story__body crayons-story__body-full_post"&gt;
    &lt;div class="crayons-story__top"&gt;
      &lt;div class="crayons-story__meta"&gt;
        &lt;div class="crayons-story__author-pic"&gt;

          &lt;a href="/sriram_hariharan_2def71eb" class="crayons-avatar  crayons-avatar--l  "&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%2Fuser%2Fprofile_image%2F4170447%2F8a322b93-dffc-4202-9fcd-2c4e5dde03b8.png" alt="sriram_hariharan_2def71eb profile" class="crayons-avatar__image"&gt;
          &lt;/a&gt;
        &lt;/div&gt;
        &lt;div&gt;
          &lt;div&gt;
            &lt;a href="/sriram_hariharan_2def71eb" class="crayons-story__secondary fw-medium m:hidden"&gt;
              Sriram Hariharan Neelakantan
            &lt;/a&gt;
            &lt;div class="profile-preview-card relative mb-4 s:mb-0 fw-medium hidden m:inline-block"&gt;
              
                Sriram Hariharan Neelakantan
                
                
              
              &lt;div id="story-author-preview-content-4816235" class="profile-preview-card__content crayons-dropdown branded-7 p-4 pt-0"&gt;
                &lt;div class="gap-4 grid"&gt;
                  &lt;div class="-mt-4"&gt;
                    &lt;a href="/sriram_hariharan_2def71eb" class="flex"&gt;
                      &lt;span class="crayons-avatar crayons-avatar--xl mr-2 shrink-0"&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%2Fuser%2Fprofile_image%2F4170447%2F8a322b93-dffc-4202-9fcd-2c4e5dde03b8.png" class="crayons-avatar__image" alt=""&gt;
                      &lt;/span&gt;
                      &lt;span class="crayons-link crayons-subtitle-2 mt-5"&gt;Sriram Hariharan Neelakantan&lt;/span&gt;
                    &lt;/a&gt;
                  &lt;/div&gt;
                  &lt;div class="print-hidden"&gt;
                    
                      Follow
                    
                  &lt;/div&gt;
                  &lt;div class="author-preview-metadata-container"&gt;&lt;/div&gt;
                &lt;/div&gt;
              &lt;/div&gt;
            &lt;/div&gt;

          &lt;/div&gt;
          &lt;a href="https://dev.to/sriram_hariharan_2def71eb/from-job-scraper-to-production-ai-system-building-applylens-ai-4fdj" class="crayons-story__tertiary fs-xs"&gt;&lt;time&gt;Oct 8&lt;/time&gt;&lt;span class="time-ago-indicator-initial-placeholder"&gt;&lt;/span&gt;&lt;/a&gt;
        &lt;/div&gt;
      &lt;/div&gt;

    &lt;/div&gt;

    &lt;div class="crayons-story__indention"&gt;
      &lt;h2 class="crayons-story__title crayons-story__title-full_post"&gt;
        &lt;a href="https://dev.to/sriram_hariharan_2def71eb/from-job-scraper-to-production-ai-system-building-applylens-ai-4fdj" id="article-link-4816235"&gt;
          From Job Scraper to Production AI System: Building ApplyLens AI
        &lt;/a&gt;
      &lt;/h2&gt;
        &lt;div class="crayons-story__tags"&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/ai"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;ai&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/machinelearning"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;machinelearning&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/python"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;python&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/architecture"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;architecture&lt;/a&gt;
        &lt;/div&gt;
      &lt;div class="crayons-story__bottom"&gt;
        &lt;div class="crayons-story__details"&gt;
          &lt;a href="https://dev.to/sriram_hariharan_2def71eb/from-job-scraper-to-production-ai-system-building-applylens-ai-4fdj" class="crayons-btn crayons-btn--s crayons-btn--ghost crayons-btn--icon-left"&gt;
            &lt;div class="multiple_reactions_aggregate"&gt;
              &lt;span class="multiple_reactions_icons_container"&gt;
                  &lt;span class="crayons_icon_container"&gt;
                    &lt;img src="https://assets.dev.to/assets/sparkle-heart-5f9bee3767e18deb1bb725290cb151c25234768a0e9a2bd39370c382d02920cf.svg" width="18" height="18"&gt;
                  &lt;/span&gt;
              &lt;/span&gt;
              &lt;span class="aggregate_reactions_counter"&gt;1&lt;span class="hidden s:inline"&gt;&amp;nbsp;reaction&lt;/span&gt;&lt;/span&gt;
            &lt;/div&gt;
          &lt;/a&gt;
            &lt;a href="https://dev.to/sriram_hariharan_2def71eb/from-job-scraper-to-production-ai-system-building-applylens-ai-4fdj#comments" class="crayons-btn crayons-btn--s crayons-btn--ghost crayons-btn--icon-left flex items-center"&gt;
              

              1&lt;span class="hidden s:inline"&gt;&amp;nbsp;comment&lt;/span&gt;
            &lt;/a&gt;
        &lt;/div&gt;
        &lt;div class="crayons-story__save"&gt;
          &lt;small class="crayons-story__tertiary fs-xs mr-2"&gt;
            11 min read
          &lt;/small&gt;
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;/div&gt;


</description>
      <category>ai</category>
      <category>automation</category>
      <category>saas</category>
      <category>softwaredevelopment</category>
    </item>
    <item>
      <title>From Job Scraper to Production AI System: Building ApplyLens AI</title>
      <dc:creator>Sriram Hariharan Neelakantan</dc:creator>
      <pubDate>Thu, 08 Oct 2026 07:17:53 +0000</pubDate>
      <link>https://dev.to/sriram_hariharan_2def71eb/from-job-scraper-to-production-ai-system-building-applylens-ai-4fdj</link>
      <guid>https://dev.to/sriram_hariharan_2def71eb/from-job-scraper-to-production-ai-system-building-applylens-ai-4fdj</guid>
      <description>&lt;p&gt;Job searching started feeling like a second job.&lt;/p&gt;

&lt;p&gt;I was jumping between different job sites and ATS platforms, seeing duplicate or stale postings, comparing multiple resume versions, and still manually trying to answer the questions that actually mattered:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Is this role really worth applying to? Which resume should I use? What am I missing? Should I tailor first — or move on?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;There are already strong products that solve valuable parts of this workflow: resume analysis, job tracking, autofill, matching, and application organization.&lt;/p&gt;

&lt;p&gt;I wasn't trying to claim that those problems had never been solved.&lt;/p&gt;

&lt;p&gt;The engineering question that interested me was different:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;What would happen if I treated the entire workflow as one AI systems problem instead of a collection of separate tools?&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;So I started with something much simpler: a job scraper.&lt;/p&gt;

&lt;p&gt;Somewhere between ATS integrations, deduplication, ranking, LLM evaluation, resume matching, provider routing, retries, observability, agentic workflows, persistence, and production deployment... things got slightly out of hand. 😅&lt;/p&gt;

&lt;p&gt;That project became &lt;strong&gt;ApplyLens AI&lt;/strong&gt; — a production-deployed AI job intelligence and application planning platform.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Live deployment:&lt;/strong&gt; &lt;a href="https://applylensjobs.com" rel="noopener noreferrer"&gt;applylensjobs.com&lt;/a&gt; &lt;em&gt;(access-controlled)&lt;/em&gt;&lt;br&gt;&lt;br&gt;
&lt;strong&gt;Source code:&lt;/strong&gt; &lt;a href="https://github.com/sriram-hariharan/job-scraper" rel="noopener noreferrer"&gt;GitHub — ApplyLens AI&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  What ApplyLens does
&lt;/h2&gt;

&lt;p&gt;At a high level, ApplyLens combines job acquisition, deterministic filtering, AI evaluation, resume intelligence, application prioritization, evidence-grounded tailoring, retrieval, and human review within one production system.&lt;/p&gt;

&lt;p&gt;Three numbers give a useful sense of the current scope:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;11 acquisition adapters&lt;/strong&gt; across ATS platforms and job sources&lt;/li&gt;
&lt;li&gt;a &lt;strong&gt;16-stage observable processing pipeline&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;shared production job acquisition running automatically &lt;strong&gt;every 6 hours&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The acquisition layer currently includes:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Workday, Greenhouse, Lever, Ashby, Workable, Jobvite, Recruitee, SmartRecruiters, Built In, USAJobs, and Himalayas.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;But the number of sources is not the part of the architecture I find most interesting.&lt;/p&gt;

&lt;p&gt;The important part is what happens after the jobs arrive.&lt;/p&gt;




&lt;h2&gt;
  
  
  The architecture in one view
&lt;/h2&gt;

&lt;p&gt;The system is built around a simple separation: &lt;strong&gt;shared acquisition, personalized intelligence, bounded AI reasoning, and human-controlled action&lt;/strong&gt;.&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%2Fjbc5imli60i0bujaz2jn.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%2Fjbc5imli60i0bujaz2jn.png" alt="ApplyLens AI system architecture" width="800" height="600"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;ApplyLens AI architecture: jobs are acquired into a shared corpus, then processed through user-specific intelligence, bounded AI evaluation, scoring, planning, and human review.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;There are several design decisions behind this that became much more important than the original scraping problem.&lt;/p&gt;




&lt;h2&gt;
  
  
  1. Collect once. Personalize independently.
&lt;/h2&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%2Fhwlwnqhl28hxgmqbxfmb.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%2Fhwlwnqhl28hxgmqbxfmb.png" alt="Shared acquisition with isolated personalization in ApplyLens AI" width="800" height="600"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Jobs are acquired once into a shared corpus, while preferences, resumes, seen-state, ranking, AI settings, and application planning remain isolated per user.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;One of the first architectural decisions was separating &lt;strong&gt;global acquisition&lt;/strong&gt; from &lt;strong&gt;user-specific intelligence&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;A naive multi-user design could effectively repeat acquisition work for every user.&lt;/p&gt;

&lt;p&gt;I didn't want that.&lt;/p&gt;

&lt;p&gt;Instead, ApplyLens maintains a shared job corpus and then projects that data through an authenticated user's own workflow.&lt;/p&gt;

&lt;p&gt;The shared layer handles job acquisition.&lt;/p&gt;

&lt;p&gt;The personalized layer owns things such as:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;role and seniority preferences&lt;/li&gt;
&lt;li&gt;location preferences&lt;/li&gt;
&lt;li&gt;excluded terms&lt;/li&gt;
&lt;li&gt;preferred skills&lt;/li&gt;
&lt;li&gt;seen-job state&lt;/li&gt;
&lt;li&gt;resume variants&lt;/li&gt;
&lt;li&gt;ranking context&lt;/li&gt;
&lt;li&gt;AI credentials&lt;/li&gt;
&lt;li&gt;provider/model routing&lt;/li&gt;
&lt;li&gt;application planning state&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In other words:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Collect once. Personalize independently.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This also creates a useful operational boundary.&lt;/p&gt;

&lt;p&gt;The production job acquisition schedule runs every six hours in &lt;strong&gt;global-acquisition-only mode&lt;/strong&gt;. It refreshes the shared job corpus without silently launching user-specific planning, tailoring, or application decisions.&lt;/p&gt;

&lt;p&gt;Personalization happens separately.&lt;/p&gt;

&lt;p&gt;That separation became one of the most important pieces of the system.&lt;/p&gt;




&lt;h2&gt;
  
  
  2. I deliberately did not let one LLM make the whole decision
&lt;/h2&gt;

&lt;p&gt;It is very easy to design an AI application like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Resume + Job Description
          ↓
         LLM
          ↓
       Fit Score
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;It is simple.&lt;/p&gt;

&lt;p&gt;It is also not the architecture I wanted.&lt;/p&gt;

&lt;p&gt;Those are deliberately different stages with different authority.&lt;/p&gt;
&lt;h3&gt;
  
  
  Where AI gets authority — and where it doesn't
&lt;/h3&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%2Faa5wft4tio8sqbj9bb1r.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%2Faa5wft4tio8sqbj9bb1r.png" alt="ApplyLens AI deterministic, LLM, and human decision boundaries" width="800" height="600"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Cheap, reproducible decisions remain deterministic. LLM reasoning is introduced where interpretation adds value, while consequential actions remain human-controlled.&lt;/em&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  Deterministic prefiltering
&lt;/h3&gt;

&lt;p&gt;Before an expensive model needs to interpret anything, deterministic logic can evaluate things such as:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;role/title relevance&lt;/li&gt;
&lt;li&gt;seniority&lt;/li&gt;
&lt;li&gt;location policy&lt;/li&gt;
&lt;li&gt;freshness&lt;/li&gt;
&lt;li&gt;exclusions&lt;/li&gt;
&lt;li&gt;duplicate identity&lt;/li&gt;
&lt;li&gt;previously seen jobs&lt;/li&gt;
&lt;li&gt;early evidence rules&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;There is no reason to ask an LLM whether a posting is three weeks old or whether a title violates an explicit exclusion rule.&lt;/p&gt;

&lt;p&gt;Those are deterministic questions.&lt;/p&gt;
&lt;h3&gt;
  
  
  LLM evaluation
&lt;/h3&gt;

&lt;p&gt;The LLM becomes useful later, where interpretation matters.&lt;/p&gt;

&lt;p&gt;For example:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;interpreting job-description requirements&lt;/li&gt;
&lt;li&gt;reasoning over less explicit fit signals&lt;/li&gt;
&lt;li&gt;enriching structured intelligence&lt;/li&gt;
&lt;li&gt;producing grounded tailoring assistance&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;But the model operates on a &lt;strong&gt;bounded candidate set&lt;/strong&gt; rather than becoming the first and only filter.&lt;/p&gt;
&lt;h3&gt;
  
  
  Final application scoring
&lt;/h3&gt;

&lt;p&gt;Final application-priority scoring remains a separate responsibility.&lt;/p&gt;

&lt;p&gt;This matters because an LLM evaluation is not automatically equivalent to the final decision the application should make.&lt;/p&gt;

&lt;p&gt;A relevance score, model interpretation, resume-match score, optimization score, and final application-priority score represent different things.&lt;/p&gt;

&lt;p&gt;I wanted the architecture to preserve those distinctions instead of collapsing them into one mysterious number.&lt;/p&gt;


&lt;h2&gt;
  
  
  3. Different AI workloads should not automatically use the same model
&lt;/h2&gt;

&lt;p&gt;Another thing I wanted to avoid was this:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;MODEL&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;whatever-model-is-currently-best&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;followed by sending every AI task through it.&lt;/p&gt;

&lt;p&gt;ApplyLens treats AI work as &lt;strong&gt;workload-specific&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Different workloads include areas such as:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;skill extraction&lt;/li&gt;
&lt;li&gt;job-fit evaluation&lt;/li&gt;
&lt;li&gt;JD intelligence&lt;/li&gt;
&lt;li&gt;grounded RAG answers&lt;/li&gt;
&lt;li&gt;resume fallback ranking&lt;/li&gt;
&lt;li&gt;ambiguous resume adjudication&lt;/li&gt;
&lt;li&gt;critic evaluation&lt;/li&gt;
&lt;li&gt;tailoring generation&lt;/li&gt;
&lt;li&gt;tailoring refinement&lt;/li&gt;
&lt;li&gt;tailoring judging&lt;/li&gt;
&lt;li&gt;manual Scan phrase generation&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The application maintains explicit provider/model qualification and routing rather than assuming that one preferred provider should own every task.&lt;/p&gt;

&lt;p&gt;For authenticated workflows, the effective route is resolved for the specific workload.&lt;/p&gt;

&lt;p&gt;A user's generic provider preference does not silently override a workload-specific qualified route.&lt;/p&gt;

&lt;p&gt;And if required routing, qualification, or credentials are unavailable, sensitive AI paths can &lt;strong&gt;fail closed rather than silently switching behavior&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;That was an important lesson for me:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Multi-model support is not the same thing as model routing.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Supporting several APIs is easy.&lt;/p&gt;

&lt;p&gt;Defining which workload is allowed to use which model, how that decision is resolved, and what happens when that route is unavailable is the actual systems problem.&lt;/p&gt;


&lt;h2&gt;
  
  
  4. Resume tailoring has an evidence boundary
&lt;/h2&gt;

&lt;p&gt;Resume optimization creates another tempting failure mode for generative AI.&lt;/p&gt;

&lt;p&gt;If the system's only goal is "make this resume look more relevant," a model can produce wording that sounds excellent while quietly introducing experience that never existed.&lt;/p&gt;

&lt;p&gt;I didn't want that behavior.&lt;/p&gt;

&lt;p&gt;The tailoring path is built around resume and job evidence.&lt;/p&gt;

&lt;p&gt;Conceptually:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Resume evidence + JD evidence
            ↓
     Rewrite direction
            ↓
     Candidate generation
            ↓
        Validation
            ↓
    Replacement selection
            ↓
      Human review/export
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Generated changes are expected to remain grounded in supplied evidence.&lt;/p&gt;

&lt;p&gt;Unsupported tools, skills, metrics, methods, domains, or responsibilities are rejected or kept as directional guidance instead of being silently inserted into the resume.&lt;/p&gt;

&lt;p&gt;And the source resume itself is not overwritten by generation.&lt;/p&gt;

&lt;p&gt;That distinction is important to me because a resume assistant should help express real evidence better — not manufacture new evidence.&lt;/p&gt;


&lt;h2&gt;
  
  
  5. The human remains the authority for consequential actions
&lt;/h2&gt;

&lt;p&gt;This eventually became one of the core design principles behind ApplyLens.&lt;/p&gt;

&lt;p&gt;AI can:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;analyze&lt;/li&gt;
&lt;li&gt;interpret&lt;/li&gt;
&lt;li&gt;recommend&lt;/li&gt;
&lt;li&gt;prioritize&lt;/li&gt;
&lt;li&gt;explain&lt;/li&gt;
&lt;li&gt;draft&lt;/li&gt;
&lt;li&gt;critique&lt;/li&gt;
&lt;li&gt;assist with tailoring&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;But ApplyLens does &lt;strong&gt;not&lt;/strong&gt; give the AI unrestricted authority over consequential actions.&lt;/p&gt;

&lt;p&gt;It does not silently:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;submit applications to an ATS&lt;/li&gt;
&lt;li&gt;mark jobs as applied&lt;/li&gt;
&lt;li&gt;message recruiters&lt;/li&gt;
&lt;li&gt;overwrite source resumes&lt;/li&gt;
&lt;li&gt;turn an AI recommendation into application approval&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Human review and application execution remain separate.&lt;/p&gt;

&lt;p&gt;Even optional adjudication is intentionally constrained: commentary can be added without silently overriding the authoritative resume winner, final score, ranking, queue, or action.&lt;/p&gt;

&lt;p&gt;I think this boundary becomes more important as AI systems become more agentic.&lt;/p&gt;

&lt;p&gt;The interesting question is no longer only:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"Can the model do this?"&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;It is also:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;"Should the model have authority to do this?"&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Those are very different questions.&lt;/p&gt;


&lt;h2&gt;
  
  
  6. Agentic does not have to mean autonomous
&lt;/h2&gt;

&lt;p&gt;I also experimented with agentic orchestration and LangGraph.&lt;/p&gt;

&lt;p&gt;But I did not want to rebuild the entire application around an "agent owns everything" architecture just because agent frameworks became available.&lt;/p&gt;

&lt;p&gt;ApplyLens keeps its existing deterministic and AI owners, while selected stages can be routed through &lt;strong&gt;bounded, explicitly gated LangGraph paths&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Those guarded paths cover areas such as:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;deterministic prefilter/deduplication&lt;/li&gt;
&lt;li&gt;JD intelligence&lt;/li&gt;
&lt;li&gt;semantic evaluation&lt;/li&gt;
&lt;li&gt;final scoring&lt;/li&gt;
&lt;li&gt;prioritization&lt;/li&gt;
&lt;li&gt;tailoring decisions&lt;/li&gt;
&lt;li&gt;tailoring generation&lt;/li&gt;
&lt;li&gt;conditional operator review&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The important word there is &lt;strong&gt;bounded&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;These paths are not permission for an agent to invent a new application state or bypass an existing authority.&lt;/p&gt;

&lt;p&gt;Agent recommendations, trace persistence, human checkpoints, and authoritative application actions remain separate concerns.&lt;/p&gt;
&lt;h3&gt;
  
  
  Agentic workflows are inspectable, not opaque
&lt;/h3&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%2Fxa1j84y4jzbhhg0q82ai.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%2Fxa1j84y4jzbhhg0q82ai.png" alt="ApplyLens AI Agentic Review showing workflow inspection and diagnostics" width="800" height="370"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Run-scoped Agentic Review keeps workflow summaries, artifacts, traces, diagnostics, and advisory evidence inspectable without giving the agent unrestricted production authority.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Many of these capabilities are also deliberately &lt;strong&gt;default-off unless explicitly enabled&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;That may sound less exciting than saying "fully autonomous AI agent."&lt;/p&gt;

&lt;p&gt;I think it is better engineering.&lt;/p&gt;


&lt;h2&gt;
  
  
  7. Observability became part of the product
&lt;/h2&gt;

&lt;p&gt;Once a pipeline has enough moving pieces, "it failed" is no longer useful information.&lt;/p&gt;

&lt;p&gt;I wanted to be able to answer:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Which stage is currently running?&lt;/li&gt;
&lt;li&gt;Which stages completed?&lt;/li&gt;
&lt;li&gt;How many jobs survived each stage?&lt;/li&gt;
&lt;li&gt;Which source degraded?&lt;/li&gt;
&lt;li&gt;Was a failure transport-related, parsing-related, or pagination-related?&lt;/li&gt;
&lt;li&gt;Did an AI workload hit cache?&lt;/li&gt;
&lt;li&gt;Which provider/model route was resolved?&lt;/li&gt;
&lt;li&gt;Did parsing fail?&lt;/li&gt;
&lt;li&gt;Was there a retry?&lt;/li&gt;
&lt;li&gt;What artifacts were produced?&lt;/li&gt;
&lt;li&gt;What happened in an agentic workflow?&lt;/li&gt;
&lt;li&gt;What is the scheduler doing?&lt;/li&gt;
&lt;li&gt;Did a persisted operation actually succeed?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That led to several operational surfaces inside the application:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Pipeline Dashboard&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Advanced Diagnostics&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Agentic Operations&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Run-scoped Agentic Review&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Scheduler Health&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;run/artifact inspection&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;notification and operational state&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;admin and Super User controls&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;
  
  
  The operational layer is visible in the product
&lt;/h3&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%2Fxr5slu5979j3l22piffe.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%2Fxr5slu5979j3l22piffe.png" alt="ApplyLens AI Executive Queue showing personalized job intelligence and acquisition state" width="800" height="370"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;ApplyLens AI Executive Queue — shared acquisition, personalized recommendations, source intelligence, and pipeline freshness exposed directly through the product.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;The runtime itself tracks a 16-stage status model:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;startup
→ scraping
→ filtering
→ dedupe
→ ranking
→ cache_filter
→ details
→ intelligence
→ ai_evaluation_filter
→ embedding_prefilter
→ ai_evaluation
→ resume_matching
→ application_priority
→ rag_export
→ planning
→ finalization
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Different runtime modes can substitute or bypass work where appropriate — for example, an authenticated shared-corpus projection uses shared input rather than scraping — but the stage model provides a common observability contract.&lt;/p&gt;

&lt;p&gt;The lesson here was simple:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;For production AI, observability is not an admin afterthought. It is part of the architecture.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;


&lt;h2&gt;
  
  
  8. Acquisition needed its own reliability model
&lt;/h2&gt;

&lt;p&gt;Scraping multiple ATS platforms is not simply "send HTTP requests in a loop."&lt;/p&gt;

&lt;p&gt;Different sources have different:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;APIs&lt;/li&gt;
&lt;li&gt;pagination rules&lt;/li&gt;
&lt;li&gt;rate limits&lt;/li&gt;
&lt;li&gt;HTML/data structures&lt;/li&gt;
&lt;li&gt;detail endpoints&lt;/li&gt;
&lt;li&gt;completeness characteristics&lt;/li&gt;
&lt;li&gt;failure modes&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So acquisition has bounded retry, timeout, pagination, and concurrency behavior.&lt;/p&gt;

&lt;p&gt;Source health distinguishes states such as:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;SUCCESS&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;EMPTY&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;PARTIAL&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;FAILED&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Failures are classified rather than flattened into one generic exception.&lt;/p&gt;

&lt;p&gt;The system also tracks data-quality signals such as URL, timestamp, and description completeness.&lt;/p&gt;

&lt;p&gt;Why does that matter?&lt;/p&gt;

&lt;p&gt;Because "this source returned zero relevant jobs" and "this source silently failed halfway through pagination" are &lt;strong&gt;not the same operational event&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;If downstream AI consumes bad or incomplete acquisition data, the problem may look like a model-quality problem even though the failure happened much earlier.&lt;/p&gt;


&lt;h2&gt;
  
  
  9. PostgreSQL is authoritative; Redis is not
&lt;/h2&gt;

&lt;p&gt;Another production decision was making state ownership explicit.&lt;/p&gt;

&lt;p&gt;In the deployed architecture:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;PostgreSQL 18&lt;/strong&gt; is authoritative for persistent application state.&lt;/p&gt;

&lt;p&gt;It stores areas such as:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;authentication/session state&lt;/li&gt;
&lt;li&gt;profile resumes&lt;/li&gt;
&lt;li&gt;onboarding preferences&lt;/li&gt;
&lt;li&gt;AI settings&lt;/li&gt;
&lt;li&gt;pipeline runs&lt;/li&gt;
&lt;li&gt;seen-job state&lt;/li&gt;
&lt;li&gt;saved scans&lt;/li&gt;
&lt;li&gt;application actions&lt;/li&gt;
&lt;li&gt;operator decisions&lt;/li&gt;
&lt;li&gt;scheduler history&lt;/li&gt;
&lt;li&gt;job/RAG documents&lt;/li&gt;
&lt;li&gt;discovery state&lt;/li&gt;
&lt;li&gt;metrics&lt;/li&gt;
&lt;li&gt;agent traces and related operational state&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Redis 7&lt;/strong&gt; is used for acceleration and coordination where appropriate — caching, invalidation, and locking — but it is not treated as authoritative application storage.&lt;/p&gt;

&lt;p&gt;I wanted the system to remain understandable when caches disappear.&lt;/p&gt;

&lt;p&gt;That sounds basic, but clear state ownership prevents a surprising number of production problems.&lt;/p&gt;


&lt;h2&gt;
  
  
  10. RAG is useful, but it still needs boundaries
&lt;/h2&gt;

&lt;p&gt;ApplyLens also includes retrieval over the job corpus for search and grounded question answering.&lt;/p&gt;

&lt;p&gt;The retrieval layer supports things such as:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;job corpus search&lt;/li&gt;
&lt;li&gt;query filtering&lt;/li&gt;
&lt;li&gt;lexical retrieval&lt;/li&gt;
&lt;li&gt;semantic retrieval where configured&lt;/li&gt;
&lt;li&gt;result deduplication/ranking&lt;/li&gt;
&lt;li&gt;grounded answer generation&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Owner-facing retrieval is constrained to allowed job identities before evidence reaches the answerer.&lt;/p&gt;

&lt;p&gt;An empty allowed set fails closed instead of silently widening into the entire shared corpus.&lt;/p&gt;

&lt;p&gt;That is another example of a pattern that appears throughout the project:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Retrieval convenience should not override identity boundaries.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;


&lt;h2&gt;
  
  
  11. Production engineering was most of the work nobody sees
&lt;/h2&gt;

&lt;p&gt;The visible AI features are only one part of the application.&lt;/p&gt;

&lt;p&gt;A large amount of development time went into things that are much less impressive in a screenshot:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;retry behavior&lt;/li&gt;
&lt;li&gt;rate limiting&lt;/li&gt;
&lt;li&gt;timeout bounds&lt;/li&gt;
&lt;li&gt;pagination limits&lt;/li&gt;
&lt;li&gt;source-health monitoring&lt;/li&gt;
&lt;li&gt;cache behavior&lt;/li&gt;
&lt;li&gt;deduplication&lt;/li&gt;
&lt;li&gt;owner isolation&lt;/li&gt;
&lt;li&gt;authentication&lt;/li&gt;
&lt;li&gt;role-based access&lt;/li&gt;
&lt;li&gt;registration approval&lt;/li&gt;
&lt;li&gt;persisted run identity&lt;/li&gt;
&lt;li&gt;concurrency controls&lt;/li&gt;
&lt;li&gt;scheduler safety&lt;/li&gt;
&lt;li&gt;process liveness&lt;/li&gt;
&lt;li&gt;artifact tracking&lt;/li&gt;
&lt;li&gt;backups&lt;/li&gt;
&lt;li&gt;rollback procedures&lt;/li&gt;
&lt;li&gt;deployment health checks&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The production topology currently looks roughly like this:&lt;/p&gt;
&lt;h3&gt;
  
  
  Production topology
&lt;/h3&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%2F4l4dki4x3mf0zkftowzy.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%2F4l4dki4x3mf0zkftowzy.png" alt="ApplyLens AI production deployment architecture" width="800" height="600"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Production topology: Caddy fronts the FastAPI application, PostgreSQL remains authoritative, Redis provides cache and coordination, and systemd manages scheduled operational workloads.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;The application is containerized with Docker Compose.&lt;/p&gt;

&lt;p&gt;Production scheduling is handled through systemd, including the six-hour shared acquisition schedule.&lt;/p&gt;

&lt;p&gt;Deployment has an explicit backup and rollback path rather than treating &lt;code&gt;git pull &amp;amp;&amp;amp; restart&lt;/code&gt; as a deployment strategy.&lt;/p&gt;

&lt;p&gt;This project started as a scraper.&lt;/p&gt;

&lt;p&gt;It ended up teaching me much more about operating an AI system than about scraping itself.&lt;/p&gt;


&lt;h2&gt;
  
  
  12. The frontend also had to grow with the architecture
&lt;/h2&gt;

&lt;p&gt;ApplyLens is not only a pipeline with a thin HTML wrapper.&lt;/p&gt;

&lt;p&gt;The application has a hybrid frontend architecture:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;FastAPI server-rendered surfaces&lt;/li&gt;
&lt;li&gt;classic JavaScript for several workflow-heavy pages&lt;/li&gt;
&lt;li&gt;React 18 + TypeScript + Vite for dashboard/operational surfaces&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The product now includes areas for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;executive overview&lt;/li&gt;
&lt;li&gt;planning&lt;/li&gt;
&lt;li&gt;decisions&lt;/li&gt;
&lt;li&gt;application tracking&lt;/li&gt;
&lt;li&gt;pipeline execution&lt;/li&gt;
&lt;li&gt;optimization review&lt;/li&gt;
&lt;li&gt;tailoring&lt;/li&gt;
&lt;li&gt;scheduler health&lt;/li&gt;
&lt;li&gt;agentic operations&lt;/li&gt;
&lt;li&gt;advanced diagnostics&lt;/li&gt;
&lt;li&gt;profile/resume management&lt;/li&gt;
&lt;li&gt;AI provider/model settings&lt;/li&gt;
&lt;li&gt;saved scans&lt;/li&gt;
&lt;li&gt;admin workflows&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Building the UI changed the backend design too.&lt;/p&gt;

&lt;p&gt;Once users can inspect a score, save a decision, rerun a pipeline, or review an AI suggestion, concepts like identity, persistence, dirty state, idempotency, and write verification stop being backend implementation details.&lt;/p&gt;

&lt;p&gt;They become product behavior.&lt;/p&gt;


&lt;h2&gt;
  
  
  What makes ApplyLens different for me
&lt;/h2&gt;

&lt;p&gt;I don't think the interesting claim is:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"I built a job app with AI."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;There are already many good products in that category.&lt;/p&gt;

&lt;p&gt;The part I wanted to explore was the architecture underneath the experience:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Can shared acquisition, deterministic processing, bounded model reasoning, workload-specific routing, evidence-grounded generation, retrieval, agentic orchestration, observability, and human authority coexist in one system without collapsing everything into an LLM call?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;ApplyLens became my attempt to answer that question.&lt;/p&gt;

&lt;p&gt;And the answer I arrived at is:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Yes — but only if the boundaries are designed deliberately.&lt;/strong&gt;&lt;/p&gt;


&lt;h2&gt;
  
  
  What I learned
&lt;/h2&gt;

&lt;p&gt;A few lessons became much clearer while building this.&lt;/p&gt;
&lt;h3&gt;
  
  
  1. The biggest AI decision is often where &lt;em&gt;not&lt;/em&gt; to use AI
&lt;/h3&gt;

&lt;p&gt;Freshness, explicit exclusions, identity, access control, deterministic scoring boundaries, and state transitions do not become better merely because a language model can participate in them.&lt;/p&gt;
&lt;h3&gt;
  
  
  2. Expensive intelligence should come after cheap certainty
&lt;/h3&gt;

&lt;p&gt;Filter and deduplicate first.&lt;/p&gt;

&lt;p&gt;Use model reasoning when the remaining ambiguity actually benefits from it.&lt;/p&gt;
&lt;h3&gt;
  
  
  3. Model routing is an application architecture problem
&lt;/h3&gt;

&lt;p&gt;Provider/model selection, qualification, credentials, failure behavior, caching, and fallback rules need explicit ownership.&lt;/p&gt;
&lt;h3&gt;
  
  
  4. Agentic systems need authority boundaries
&lt;/h3&gt;

&lt;p&gt;A traceable recommendation is not the same thing as permission to mutate production state.&lt;/p&gt;
&lt;h3&gt;
  
  
  5. Observability is part of AI quality
&lt;/h3&gt;

&lt;p&gt;If you cannot tell whether the source failed, the cache was stale, parsing broke, the provider route changed, or the model produced poor output, every failure starts looking like "the AI is bad."&lt;/p&gt;
&lt;h3&gt;
  
  
  6. Human-in-the-loop should be an architectural property
&lt;/h3&gt;

&lt;p&gt;It should not be a disclaimer added after autonomous behavior is already designed.&lt;/p&gt;


&lt;h2&gt;
  
  
  The stack
&lt;/h2&gt;

&lt;p&gt;The main technology stack currently includes:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Python · FastAPI · PostgreSQL · Redis · React · TypeScript · Vite · Docker · LangGraph · LLM/GenAI workflows · RAG · systemd · Caddy&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;But the most valuable part of this project for me has not been learning another framework.&lt;/p&gt;

&lt;p&gt;It has been learning how to decide &lt;strong&gt;which component should own which decision&lt;/strong&gt;.&lt;/p&gt;


&lt;h2&gt;
  
  
  Explore the project
&lt;/h2&gt;

&lt;p&gt;If you'd like to look deeper:&lt;/p&gt;

&lt;p&gt;🌐 &lt;strong&gt;Access-controlled live deployment:&lt;/strong&gt; &lt;a href="https://applylensjobs.com" rel="noopener noreferrer"&gt;https://applylensjobs.com&lt;/a&gt;&lt;/p&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://assets.dev.to/assets/github-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/sriram-hariharan" rel="noopener noreferrer"&gt;
        sriram-hariharan
      &lt;/a&gt; / &lt;a href="https://github.com/sriram-hariharan/job-scraper" rel="noopener noreferrer"&gt;
        job-scraper
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      Production AI job intelligence &amp;amp; application planning platform with multi-source acquisition, LLM evaluation, resume intelligence, RAG, and observability.
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;ApplyLens AI&lt;/h1&gt;
&lt;/div&gt;

&lt;p&gt;
  &lt;strong&gt;AI-powered job discovery, application planning, resume scanning, and tailoring workspace.&lt;/strong&gt;
&lt;/p&gt;

&lt;p&gt;
  Scrape jobs from modern ATS platforms, rank opportunities against saved resumes, review AI optimization guidance, generate tailored drafts, and track the full application workflow from one local operator app
&lt;/p&gt;




&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Table of Contents&lt;/h2&gt;
&lt;/div&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/sriram-hariharan/job-scraper#what-this-app-does" rel="noopener noreferrer"&gt;What This App Does&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/sriram-hariharan/job-scraper#core-workflows" rel="noopener noreferrer"&gt;Core Workflows&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/sriram-hariharan/job-scraper#dashboard-pages" rel="noopener noreferrer"&gt;Dashboard Pages&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/sriram-hariharan/job-scraper#pipeline-capabilities" rel="noopener noreferrer"&gt;Pipeline Capabilities&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/sriram-hariharan/job-scraper#ai-optimize-scan" rel="noopener noreferrer"&gt;AI Optimize Scan&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/sriram-hariharan/job-scraper#resume-tailoring-workspace" rel="noopener noreferrer"&gt;Resume Tailoring Workspace&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/sriram-hariharan/job-scraper#scheduler-operations" rel="noopener noreferrer"&gt;Scheduler Operations&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/sriram-hariharan/job-scraper#storage-and-persistence" rel="noopener noreferrer"&gt;Storage and Persistence&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/sriram-hariharan/job-scraper#supported-ats-sources" rel="noopener noreferrer"&gt;Supported ATS Sources&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/sriram-hariharan/job-scraper#project-structure" rel="noopener noreferrer"&gt;Project Structure&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/sriram-hariharan/job-scraper#local-setup" rel="noopener noreferrer"&gt;Local Setup&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/sriram-hariharan/job-scraper#running-the-app" rel="noopener noreferrer"&gt;Running the App&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/sriram-hariharan/job-scraper#running-pipelines-from-the-cli" rel="noopener noreferrer"&gt;Running Pipelines from the CLI&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/sriram-hariharan/job-scraper#environment-variables" rel="noopener noreferrer"&gt;Environment Variables&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/sriram-hariharan/job-scraper#testing-and-validation" rel="noopener noreferrer"&gt;Testing and Validation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/sriram-hariharan/job-scraper#portfolio-and-demo-docs" rel="noopener noreferrer"&gt;Portfolio and Demo Docs&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/sriram-hariharan/job-scraper#deployment-notes" rel="noopener noreferrer"&gt;Deployment Notes&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/sriram-hariharan/job-scraper#roadmap-ideas" rel="noopener noreferrer"&gt;Roadmap Ideas&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;




&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;What This App Does&lt;/h2&gt;

&lt;/div&gt;

&lt;p&gt;ApplyLens AI is a job-search operating system for serious application workflows. It combines job scraping, resume intelligence, AI-assisted review, and decision tracking into a single FastAPI web application.&lt;/p&gt;

&lt;p&gt;The app is designed around a practical application loop:&lt;/p&gt;


&lt;ol&gt;

&lt;li&gt;Discover and scrape jobs from multiple ATS platforms.&lt;/li&gt;

&lt;li&gt;Filter, deduplicate, and rank jobs against your saved…&lt;/li&gt;

&lt;/ol&gt;&lt;/div&gt;
&lt;br&gt;
  &lt;/div&gt;
&lt;br&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/sriram-hariharan/job-scraper" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;br&gt;
&lt;/div&gt;
&lt;br&gt;


&lt;p&gt;I'm especially interested in conversations around &lt;strong&gt;AI engineering, ML engineering, production LLM systems, model routing, evaluation, RAG, agentic workflows, and human-in-the-loop system design&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;If you've built something similar — or disagree with any of these architectural choices — I'd genuinely like to hear how you approached it.&lt;/p&gt;




&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;AI disclosure:&lt;/strong&gt; I used ChatGPT to help research, structure, and edit this article. The ApplyLens project, implementation, architecture decisions, and technical claims are my own, and I reviewed the final content against the project repository before publishing.&lt;/p&gt;
&lt;/blockquote&gt;

</description>
      <category>ai</category>
      <category>machinelearning</category>
      <category>python</category>
      <category>architecture</category>
    </item>
  </channel>
</rss>
