← BACK TO LEVEL SELECT

🤖 Agentic AI · ★★★ FEATURED

Sortie — Job-Application Autopilot

A self-hosted agent that applies to jobs for you inside your own logged-in browser, tailors the résumé per role without inventing facts, and keeps the ledger so you always know where you stand.

Overview

So here’s the thing. Job hunting is a numbers game with terrible bookkeeping. You apply to hundreds of postings across Naukri, Wellfound, and Indeed, re-typing the same details and answering “what’s your notice period?” for the tenth time, and two weeks later you genuinely can’t remember which companies you already hit.

Sortie fixes both halves. It does the repetitive applying for you, inside a real browser you’re already logged into, and it keeps the ledger. Every application lands in one of five states: applied, pending your review, submit failed, duplicate, skipped. The “wait, did I already apply here?” problem just goes away.

That’s the whole pitch. Apply to a lot of positions without the grind, and never lose track of where you’ve been.

The trick that makes it work

Every headless job-application bot dies the same death: the bot wall. Cloudflare checks, fingerprinting, login CAPTCHAs. Sortie sidesteps the entire fight by refusing to be a bot in the way that matters.

It opens a real, headed Chromium. You log into Naukri or Wellfound or Indeed yourself, like a person, because you are one. Sortie never sees your password and never stores a credential. It just drives the session you started, at a human pace, inside daily caps you set. The platforms see a logged-in user doing logged-in user things, because that is literally what’s happening. Your cookies and browser profiles never leave your disk. That part is not negotiable, it’s what makes the whole thing work.

STAGE MAP — the system

flowchart TB
    YOU["You<br/>log in once, real browser"]
    subgraph FRONT["Next.js 16 Dashboard"]
        STUDIO["Résumé Studio"]
        RUNS["Run Control<br/>platform · caps"]
        LEDGER["The Ledger<br/>applied · pending · failed · dup · skipped"]
    end
    subgraph BACK["FastAPI Backend + Typer CLI"]
        ENGINE["Apply Engine<br/>search · filter · submit"]
        RESUME["Résumé Engine<br/>ATS DOCX/PDF, grounded tailoring"]
        MEMORY["Answer Memory<br/>per-candidate Q&A cache"]
    end
    CHROME["Headed Chromium (Playwright)<br/>your live session, cookies stay local"]
    DB[("SQLite / Postgres<br/>candidates · apps · answers")]
    LLM["LLM (optional)<br/>tailoring + answer drafts"]
    YOU --> CHROME
    FRONT <-->|HTTP| BACK
    ENGINE --> CHROME
    ENGINE --> DB
    RESUME --> LLM
    MEMORY -->|novel question| LLM
    MEMORY -->|hold for human| LEDGER

Anatomy of one sortie

Every run processes jobs through the same pipeline, and every job exits into the ledger no matter what happened to it. Nothing silently disappears.

flowchart LR
    SEARCH["Search roles<br/>keywords · location · experience"]
    FILTER["Filter by fit<br/>skip dups · ineligible · already-applied"]
    OPEN["Open posting<br/>one-click apply only"]
    TAILOR["Tailor résumé<br/>grounded to the JD"]
    ANSWER["Screening questions<br/>memory first, LLM draft held for you"]
    SUBMIT["Submit"]
    LEDGER[("The Ledger<br/>applied / pending / failed / dup / skipped")]
    SEARCH --> FILTER --> OPEN --> TAILOR --> ANSWER --> SUBMIT --> LEDGER
    FILTER -.->|"dup / ineligible"| LEDGER
    ANSWER -.->|"novel question"| LEDGER

The pending state is the interesting one. When a recruiter asks something Sortie has never seen (“are you open to night shifts?”), it drafts an answer with the LLM and parks the application as pending your review. You confirm or fix the answer once. It’s cached in that candidate’s memory forever, and the next posting that asks gets an instant answer. The agent gets smarter about you specifically, one confirmed answer at a time.

The résumé engine

Spraying one PDF at 300 postings is how you lose the ATS game. Sortie rebuilds a clean, ATS-friendly DOCX and PDF per role (reportlab and python-docx, no fragile templates), optionally LLM-tailored to the job description.

The tailoring is grounded, and I mean that as a hard constraint, not a vibe. It can rephrase, reorder, and emphasize from your actual profile. It cannot add a skill, a year, or a project you don’t have. I was not going to ship a thing that lies to recruiters on your behalf.

Multi-candidate by design

One login (you), as many candidate profiles as you want. Each candidate gets its own data scope in the database and its own browser profile directory on disk. That isolation is what lets you run a household or a friend group off one box without sessions and answer memories bleeding into each other.

The honest part

I’d rather say the limits up front than have you find them.

  • It applies to one-click jobs, not everything. Postings that bounce to an external company portal with a 12-field form are not the target. Sortie is honest about what it can actually submit end to end.
  • It operates your accounts, with you in the loop. No credential storage, no login bypass, human-pace throttling, a daily cap (default 45) to stay inside each platform’s fair-use limits.
  • AI is optional, not the whole product. No API key means no tailoring and no draft answers, and everything else still works. The engine, the tracking, and the applying don’t need a model at all.

Engineering decisions

  • SQLite by default, Postgres when you’re ready. Clone and run with zero setup on a local file. Point JOBPILOT_DB_URL at a free Neon database and the same code runs on a server. The browser sessions stay local either way.
  • One engine, three platforms. Naukri, Wellfound, and Indeed are adapters over the same apply pipeline, so a new board is a new adapter, not a new product.
  • CLI and dashboard share the backend. sortie apply -c <candidate> --platform naukri --cap 20 and the Run Control page hit the same FastAPI surface. Power users script it, everyone else clicks.
  • A demo candidate ships in the box. sortie seed-sample inserts a fictional profile so you can poke every feature before trusting it with your real one.
  • PolyForm Noncommercial license. Free for personal use, research, and learning. Commercial use needs a conversation.

Stack

Python 3.11, FastAPI, SQLAlchemy 2.0, Typer, Playwright (headed Chromium), reportlab + python-docx on the backend. Next.js 16, React 19, Tailwind v4, SWR on the dashboard. SQLite or any Postgres. OpenAI, strictly optional.

Highlights

  • 3 job boards, one engine, human-pace throttling, per-platform daily caps
  • 5-state ledger per candidate, live on the dashboard, nothing silently dropped
  • Grounded LLM tailoring that rewrites phrasing without inventing facts
  • Answer memory that turns every confirmed screening answer into a permanent one
  • Headed-browser architecture that beats bot walls by not being a bot where it counts