← Back to Projects

Project

Job Application Pipeline

n8n workflow that scores a job URL, drafts a package for strong fits, and stops for a human

Role
Solo
Focus
Structured LLM output, Human review, No auto-apply
Testing
Eval fixtures, Fit-score threshold, Digest does not apply
Key patterns
n8n, OpenAI, Structured JSON, Google Sheets
  • n8n
  • Docker
  • OpenAI
  • Google Sheets
  • Gmail
  • TypeScript

What it does

  • Takes a job URL, fetches the posting, and scores it against a fixed résumé profile
  • Returns structured JSON: fit score, stack match and gaps, live-coding risk, and apply priority
  • Drafts a cover letter, bullets, and a short recruiter note only when the score clears 7
  • Appends the result to a Google Sheet and emails a digest for human review
  • A second workflow lists still-open drafts on weekday mornings and evenings and does not apply

Architecture

┌──────────────────┐     ┌──────────────────┐     ┌──────────────────┐
│  Job URL form    │────►│  Fetch posting   │────►│  Fit score LLM   │
│  jobUrl + notes  │     │  HTML → text     │     │  structured JSON │
└──────────────────┘     └──────────────────┘     └────────┬─────────┘
                                                           │
                        score < 7                          │ score ≥ 7
                           │                               ▼
                           │                      ┌──────────────────┐
                           │                      │  Draft package   │
                           │                      │  letter + bullets│
                           │                      └────────┬─────────┘
                           ▼                               ▼
                  ┌──────────────────────────────────────────────┐
                  │  Google Sheets          status = draft_ready │
                  └──────────────────────┬───────────────────────┘
                                         │
                                         ▼
                  ┌──────────────────────────────────────────────┐
                  │  Gmail digest     you review, never applies  │
                  └──────────────────────────────────────────────┘

Reliability and guardrails

  • Prompts only use the posting plus a locked résumé profile — no invented employers, metrics, or skills
  • Parse nodes turn Continue On Fail off so bad JSON stops the run instead of writing a half row
  • Eval fixtures cover a strong .NET/React match, a stack mismatch, and a live-coding flag
  • The digest workflow only reads the sheet. It does not change status and it does not call the model
  • Nothing in either workflow submits an application

Key engineering decisions

  • Local Docker n8n instead of a hosted runner

    The workflow exports as JSON, credentials stay off the repo, and the demo costs nothing to host.

  • Cheap model for the fit score, stronger model for the draft

    Scoring is a structured JSON pass. The cover letter only runs when fitScore is 7 or higher.

  • Google Sheets plus email, not a database

    The row is the review queue. A separate weekday workflow reads draft_ready rows and never writes them.

Failure modes handled

  • OpenAI returns nested or fenced JSON — a Code node flattens output text and JSON.parse fails loud
  • Fit score under 7 — the draft step is skipped and nothing is emailed to an employer
  • No draft_ready rows — the digest workflow sends no email
  • Laptop asleep or n8n stopped — that digest slot is missed and the next weekday run lists the same open drafts
  • Posting asks for live coding — liveCodingRisk is set to likely so the review shows it

How to demo in 2 minutes

  1. 1docker compose up -d and open n8n at http://localhost:5678
  2. 2Import n8n/workflow.json and n8n/digest-workflow.json, then reconnect OpenAI, Sheets, and Gmail
  3. 3Open the form URL and paste a job posting
  4. 4Check the Applications sheet for the fit score and, at 7 or above, the draft
  5. 5Confirm the weekday digest only lists draft_ready rows and that no employer is emailed

Links