AS Amy Sullivan

Case File 01 · Internal System · Declassified

Multi-Model Agent Pipeline with Human-in-the-Loop Review

100% Human-Approved

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

Three constraints that fight each other

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:

CONSTRAINT 01

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.

CONSTRAINT 02

Quality

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.

CONSTRAINT 03

Cost

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

Two lanes, one router,
hard gates, human finish

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.

Lane A · LinkedIn Easy Apply

Human-paced · daily cap · dedup via applied_jobs.json

Lane B · External ATS Forms

Company career pages, driven by the agent browser

Model Router · OpenRouter — routed by task value

DeepSeek V4 Flash / Pro → page extraction · navigation   |   Claude Sonnet (high effort) → cover letters — the quality bottleneck

Guardrail Gates · hard blocks — no agent discretion

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.

Review Queue · review_queue.md

Staged for review — none sent. Human — final authority. Manual review + click; nothing auto-submits.

Telegram Reporting

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

Route by task value, not by habit

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.

COVER-LETTER WRITING

Claude Sonnet
(high effort)

Quality is the bottleneck. This is the one output a human at the company actually reads, so it gets the strongest model, run deliberately.

PAGE EXTRACTION & NAVIGATION

DeepSeek V4
Flash / Pro

Volume is the bottleneck. Reading postings and driving forms happens on every job, so it runs on models cheap enough to call constantly.

APPLICATION LOGGING

DeepSeek
Flash

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

What failed → what gate we added

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.

INCIDENT 01

Soft heuristics fail in practice

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.

INCIDENT 02

Location labels can't be trusted

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.

INCIDENT 03

Hard requirements hide in wish lists

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.

INCIDENT 04

A plausible role at the wrong employer is still wrong

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.

INCIDENT 05

Individual gates consolidate into one checklist

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

Nothing auto-submits.
That's the design, not a limitation.

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.

Stage, don't send

The agent's terminal action is writing to a review queue. Only a human action crosses the boundary into the outside world.

Contain the agent

Dedicated browser instance for agent runs, separated from my personal browser. Human-paced activity with capped daily volume on Lane A.

Cap the spend

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

  • — applications processed to date
  • — rejection-gate catches logged
  • One documented catch on record: the location gate stopped a Slovenia-based role mislabeled as US before it reached the queue.

Outcomes · Structural

  • Zero duplicate applications by construction — the applied_jobs.json ledger dedupes every run.
  • A complete audit trail — every application logged by the Telegram bot with source tag and date.
  • 100% of submissions human-approved — nothing has ever gone out without a person deciding it should.

Why This Matters Beyond Job Applications

The pattern generalizes

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.

Get in Touch → More Case Files