Volume
The workflow is high-volume and repetitive: discover postings, extract requirements, check fit, fill forms. Done by hand, it consumes hours that produce nothing durable.
Case File 01 · Internal System · Declassified
A two-lane automated job-application pipeline: cheap models handle the volume work, Claude Sonnet handles the writing that a human will actually read, hard guardrail gates filter what gets through — and nothing is submitted without my review and my click.
INTERNAL SYSTEM — BUILT AND OPERATED BY ME · SHOWN AS A DEMONSTRATION OF CAPABILITY, NOT CLIENT WORK
Before
Job applications as a fully manual workflow: find roles, read postings, judge fit, write a tailored cover letter, fill out forms — high-volume and repetitive, with quality mattering most exactly where the volume made it hardest to sustain.
After
A two-lane agent pipeline finds, extracts, filters, and drafts — then stages every passing job to a review queue. I make the final call and click submit. Every application is logged automatically by source tag and date.
The Problem
Applying for jobs at volume is the kind of workflow AI is constantly pitched for — and the kind where naive automation does real damage. The design problem is holding three constraints at once:
The workflow is high-volume and repetitive: discover postings, extract requirements, check fit, fill forms. Done by hand, it consumes hours that produce nothing durable.
The output is quality-sensitive. A cover letter is read by a real person at a real company. A sloppy or wrong application isn't a neutral miss — it costs reputation.
Running a frontier model on every page load and form field would make per-application cost balloon. Spend has to stay predictable — API budget caps are enforced on all keys.
Architecture
The pipeline runs on the Hermes agent framework (Nous Research) on a Vultr VPS, with OpenRouter providing multi-model API access. Two intake lanes feed a shared filtering-and-drafting core; everything that passes the gates lands in a review queue for a human decision.
Human-paced · daily cap · dedup via applied_jobs.json
Company career pages, driven by the agent browser
DeepSeek V4 Flash / Pro → page extraction · navigation | Claude Sonnet (high effort) → cover letters — the quality bottleneck
1 Location verification · 2 Requirements-tier filter · 3 Audience-fit employer check · 4 Exclusion list → a 9-point pre-apply checklist runs before any job can stage. Fail = blocked before staging.
Staged for review — none sent. Human — final authority. Manual review + click; nothing auto-submits.
Bot on DeepSeek Flash logs every application by source tag, with dates.
The data layer is a plain-text vault
My Obsidian vault syncs to the VPS through a GitHub repo over SSH, and the agent reads vault files directly — job notes, the exclusion list, the review queue. No custom database, no admin UI: the system's state is human-readable markdown I already work in daily.
The agent is contained by design
Agent runs happen in a dedicated browser instance, fully separated from my personal browser and its sessions. Combined with capped daily volume, the applied_jobs.json deduplication ledger, and API budget caps, the blast radius of any bad run is bounded.
Model Routing
The routing principle across the whole system: the cheapest model that clears the quality bar for each task class — expensive models only where quality is the bottleneck.
Quality is the bottleneck. This is the one output a human at the company actually reads, so it gets the strongest model, run deliberately.
Volume is the bottleneck. Reading postings and driving forms happens on every job, so it runs on models cheap enough to call constantly.
Reporting is high-frequency and low-stakes: every application logged by source tag with dates. No reason to pay frontier prices for status messages.
The evaluation method behind these routing choices — discriminator tasks instead of vibe comparisons — is documented in its own case study.
Guardrails · Incident Reports
Every gate in this system exists because of a real observed failure. The through-line: soft heuristics — asking the agent to use judgment — failed. Hard blocking gates work.
FAILED: the first filters were prompt-level guidance — instructions asking the agent to judge whether a job was a fit. Judgment expressed as a suggestion gets applied inconsistently.
ADDED: a design rule, not just a fix — every filter that matters became a hard blocking gate. A gate either passes a job or stops it; the agent gets no discretion to talk its way past one.
FAILED: postings carry location labels that don't always match the actual role.
ADDED: a location-verification gate that checks the role's real location before a job can proceed. It has receipts: it caught a Slovenia-based role that was mislabeled as US.
FAILED: roles with hard coding requirements — genuine must-haves, not nice-to-haves — were getting past the soft fit check.
ADDED: a requirements-tier filter that catches hard coding requirements and blocks on them, instead of letting them blend into the posting's wish-list language.
FAILED: role-level checks alone don't ask whether the employer matches the work I actually do.
ADDED: an audience-fit employer check, plus a maintained exclusion list (Excluded_Companies.md) so a ruled-out employer stays ruled out across every future run.
FAILED: gates added one at a time risk becoming scattered special cases — easy to skip, hard to audit.
ADDED: a consolidated nine-point pre-apply checklist that every job must clear before it stages to the review queue. One list, run every time, in one place.
Human-in-the-Loop
Submitting an application is an irreversible, reputation-carrying action aimed at a real company. So the pipeline's job ends one step before the finish line: every job that clears the gates stages to review_queue.md, and the final review and the actual click are mine, every time. This split puts each side of the system where it's strongest. The agent does the repetitive middle — discovery, extraction, filtering, drafting — at a volume I couldn't sustain manually. I hold the boundary where judgment and consequences live.
It also makes the guardrails honest. Because the queue is the only exit, a gate failure means a bad job appears in a markdown file in front of me — not a bad application arriving at an employer. The system is allowed to be wrong cheaply.
The agent's terminal action is writing to a review queue. Only a human action crosses the boundary into the outside world.
Dedicated browser instance for agent runs, separated from my personal browser. Human-paced activity with capped daily volume on Lane A.
API budget caps enforced on all keys, and model routing that keeps frontier-model calls reserved for the one task where they pay off.
Outcomes · Measured
Outcomes · Structural
Why This Matters Beyond Job Applications
Strip out the job-hunting nouns and this is a general architecture for any high-volume, quality-sensitive workflow: cheap models for extraction and triage, a strong model reserved for the output a human will actually read, hard gates built from observed failures instead of imagined ones, and a staging queue that keeps a person on the trigger. The same shape fits document triage, application and intake processing, and content review queues — anywhere the work is repetitive but the cost of a wrong send is real.
Have a Workflow With the Same Shape?High volume, quality-sensitive, and too risky to fully automate —
that's exactly the kind of system I build.