three layers · gated at 0.95 macro-F1 · 0.979 measured

Your inbox already holds the verdict.Applied extracts it.

Every application ends as an email — applied, interview, assessment, offer, rejection. The outcome is already written down. A three-layer classifier reads it at the source, so the tracker fills itself.

zero servers · run the classifier ↗

01 · the problem

A job search lives in your inbox.

Dozens of applications. Replies, rejections, assessments, an offer if you are lucky — all arriving unlabeled, interleaved with newsletters and receipts, across two accounts, faster than anyone keeps up with by hand.

inbox · unreadevery row hides a verdict
  • Update on your application to Northstarunclassified
  • We received your applicationunclassified
  • Take-home exercise — due in 48 hoursunclassified
  • 12 new roles match your searchunclassified
  • Next steps for your candidacyunclassified
  • Quick question about your backgroundunclassified
  • We’d like to make you an offerunclassifiedoffer

manual tracking is lossy

  • The assessment scrolls past — its 48-hour deadline passes unseen.
  • “Did I hear back from them?” has no answer but a scroll.
  • The row still says applied three weeks after they said no.
  • Two accounts, one search — half the thread lives where you aren’t looking.

A manual tracker is only ever as fresh as your discipline. Classification never gets tired.

02 · the shift

Stop tracking. Start classifying.

Tracking is bookkeeping — a symptom. The real task is classification: given an email, which job-search outcome is this, and how sure are we? Solve that at the source and the tracker maintains itself — applications link, statuses advance, and the pipeline is just a projection over labeled mail.

“If you can label the email, you never have to track the application.”

inbox · classifiedsame inbox · read at the source
Update on your application to Northstarrejection94%
We received your applicationapplied95%
Take-home exercise — due in 48 hoursassessment97%
12 new roles match your searchother · filtered98%
Next steps for your candidacyinterview96%
Quick question about your backgroundhuman review61%
We’d like to make you an offeroffer99%

The same seven emails — nothing added, the signal just made legible. The one it is not sure about, it refuses to guess on.

See it label a full sample inbox — real verdicts, no sign-in

03 · how it works

Three layers in series, cheapest first.

One email enters the top. Each layer tries to decide; clear its threshold and the cascade files and stops. Fall short and it drops to a smarter, costlier layer — and finally to a gate that would rather ask a human than guess.

inone email · unknown outcome↓ enters the cascade
1

Regex rules

201 patterns · 14 ATS domains

Instant, deterministic, fully auditable — the phrases a hiring pipeline actually uses.

accept ≥ 0.90
2

e5 similarity

pretrained e5-small-v2 · 384-d · cosine 1-NN

No rule was sure. Embed the email, match the nearest labeled example — past the exact wording.

accept ≥ 0.85
3

SetFit head

fine-tuned · MiniLM-L6 body · few-shot

The only trained model in the stack — the learned call for the genuinely ambiguous email.

accept ≥ 0.70

The 0.85 confidence gate

≥ 0.85 clears the gate → filed under its category, automatically.

< 0.85 a human decides — and the correction becomes new training data.

And the learned model runs in your browser.

The one trained model — the SetFit head — exports to int8 ONNX. 90.4 MB of float32 weights quantize to 22.8 MB; Transformers.js executes them in WebAssembly, on your own CPU. No inference server. No per-request cost. No data leaves the tab.

model
22.8 MB int8 ONNX
from
90.4 MB float32 · ≈4×
runtime
Transformers.js · WASM
privacy
allowRemoteModels = false

Every verdict, traced.

The signature view: each email’s path through the three layers and the gate. The layer that fired lights in its own hue; earlier layers passed it on, later ones were never needed. Click any row to open its adjudication.

1 rules2 e53 SetFit below 0.85 → human
  • Fired at layer 3 · SetFit few-shot head — the learned call

    0%gate 0.85100%

    Confidence clears the 0.85 gate, so Applied files this as “interview” automatically.

live logic · fixture data — no inbox is read.

04 · the receipts

0.979 macro-F1 — and a gate that blocks merges.

Macro-F1 averages the per-class F1 so no category hides behind the frequent ones. It is not a one-time screenshot: two GitHub Actions gates re-run the evaluation on every backend change and fail the build below 0.95. The number is load-bearing.

0.979

macro-F1 · hybrid classifier v3
accuracy 0.979 · two of the held-out emails misclassified

per-class F1 · held-out eval · v38 learned classes · all clear 0.95
applied
1.000
pending_application
1.000
interview
1.000
offer
1.000
other
0.960
assessment
0.960
rejection
0.957
follow_up
0.957
axis 0.90 —— 1.000.95 CI floor — merges fail below it

0.95

macro-F1 CI floor — the merge fails below it

182

tests in the backend suite

9

email classes — 8 predicted + needs_review

6 / 6

output-agreement vs the Python pipeline

05 · private by design

Your inbox stays yours.

Applied never hands your mail to an LLM. The classifier is a small, purpose-built pipeline that can run entirely in your browser — on that path, your mail never leaves your machine.

no large language model

No LLM reads your mail

Classification is three small layers — regex rules, a compact e5 embedding, and a fine-tuned SetFit head. Nothing in that path calls a third-party model or LLM API, so your email is never handed to one.

on your own cpu

It can run in your browser

The trained model compiles to a compact int8-ONNX file that Transformers.js runs on your own CPU (allowRemoteModels = false). Paste text into the in-browser Space and it is classified on-device, never leaving the tab.

least privilege

Read-only, by construction

Connecting Gmail requests exactly one Google scope — gmail.readonly. It can read messages to classify them and cannot send, delete, or modify anything; you authorize on Google's own consent screen.

See it classify on-device Connecting your own Gmail is invite-only while we're in beta.