Pipeline Status
Search
Describe
Pre-grade
Grade
Notify
Build
Apply
Fetch Descriptions
POST
/jobs/describe
Headlessly fetch job descriptions (no auth needed)
Grade Job
POST
/jobs/grade
Detailed LLM grading of a single job
Apply to Job
POST
/jobs/apply
Initiate apply pipeline (policy-gated)

Format for Telegram
POST
/jobs/notify
Format graded jobs into Telegram payloads
Audit Log
GET
/audit
Recent LLM call log
Profile Pool Status
GET
/pool
Browser profile pool status
Period
vs
Profile
Pipeline Funnel
Labels: count · share of total %
Fit Score Distribution
All graded jobs (left) vs Easy Apply only (right). Segments: score buckets with count.
All Jobs
Easy Apply
Pipeline Conversion Flow
Cumulative reach funnel. Node labels show count · throughput · % change vs prior equivalent window. Hover an edge for conversion %.
Conversion Funnel Rates
% of jobs converting at each pipeline step. Bar = conversion rate. Labels: in → out (rate%).
Time to Apply
Hours from discovery to applied. Bar = job count per bucket. Summary stats below.
LLM Calls by Task Type
Labels: count · share of total %. Hover for avg latency.
LLM Call Volume — Last 30 Days
Bars: daily call count. Line: avg latency (ms). Right axis = milliseconds.
Top Companies
Right = discovered count. Left (cyan) = applied count. Tornado layout.
Top Locations
Right = discovered count. Left (cyan) = applied count. Tornado layout.
Easy Apply Ratio
Share of jobs with Easy Apply vs standard application
Daily Outcomes
Per day cascade: rejected (top) → below-threshold → skipped (by reason) → qualified-pending → applied (bottom). Absolute counts.
Skip Reasons
Why jobs were skipped (no longer accepting, no Easy Apply, etc.)
Artifact Browser

Cross-user search across every resume / cover-letter PDF the platform has ever generated — hot, trashed, archived, and policy-purged. Downloads + restores write to the impersonation audit log.

Run a search to populate.
LLM Analysis
Ask questions about your job applications and qualifications. The LLM analyzes your recent job history and resume context.
Verbosity:
Design Language — Fifth Element Aesthetic

This UI is grounded in the visual language of Luc Besson's The Fifth Element (1997) — specifically Jean-Paul Gaultier's costume design and the film's retro-futurist world-building. The goal is a lived-in, high-density future: not sterile sci-fi white, but layered, tactile, and slightly worn.

Core Palette

#0D0F1E
Deep Space
#1A1F3C
Mondoshawan Blue
#151829
Panel Dark
#FF6B1A
Leeloo Orange
#39FF14
Zorg Green
#FFD700
Ruby Rhod Yellow
#C0392B
Mangalore Red
#F0EEE6
Plasma White
#2E3566
Bandage Line

Components

Score Badges
Strong Fit Review Weak Fit Filtered
Pipeline Status
Discovered Grading Graded Resume Ready Awaiting You Rejected Blocked
Job Card
Senior Data Scientist
84 · Strong Fit
Acme Corp · Remote · $160k–$200k · Easy Apply
"Strong fit: consumer data background, Python, causal inference work."
⚑ no sponsorship mentioned
Approval Gate

Typography

Space Grotesk — angular, geometric letterforms for all UI chrome, headings, labels, and badge text. Draws from the film's utilitarian industrial stencil language.
IBM Plex Mono — all data output, terminal logs, scores, paths, and thinking traces. The machine's voice.

Structural Language

Panels use clip-path chamfered corners — the same angular, armor-panel geometry seen in Gaultier's bandage-wrap costumes and the film's industrial hardware. Every surface suggests function over decoration.

Scanline overlay references the film's omnipresent screen culture — the city is surveilled, everything is displayed, nothing is private.

Reference Material

Pinterest — 5th Element Aesthetic Board
Visual mood board: costume textures, set design, color grabs, Leeloo bandage-wrap palette
Dazed — A Closer Look at Gaultier's Fifth Element Costume Design
Deep-dive on Gaultier's design intent: the bandage dress, Zorg's shoulder armor, Korben's utilitarian uniform. Primary source for the angular/structural geometry in this UI.
Grailed / Dry Clean Only — The Fifth Element's Style Impact
How the film's fashion language spread into streetwear. Useful for understanding why the aesthetic feels contemporary despite being 1997 — high-contrast, functional, body-forward.

Design Rules

  • Orange (#FF6B1A) is active / interactive. Use sparingly — primary actions only. When it appears, it commands.
  • Green (#39FF14) is success / confirmed / safe. Terminal log text, pipeline completion, submitted state.
  • Yellow (#FFD700) is pending / requires review. Awaiting human action.
  • Red (#C0392B) is error / blocked / rejected. Quieter than magenta — deliberate, not panicked.
  • No rounded corners on structural elements — chamfered only. Softness contradicts the aesthetic.
  • All UI chrome uppercase or small-caps. Mixed case only in user-generated content (job titles, descriptions).
  • Glow effects are sparse — used to signal state (online, active, hover), never decoration.
  • Dense information layout — the city never has empty space. Panels should feel like instrument clusters.
  • Borders are structural, not decorative. They define the shape, like Gaultier's bandages define the body.
What is Job Gobbler?

Job Gobbler is a self-hosted job application automation service running on port 7432. It is orchestrated by n8n (4 workflows) and surfaces results via Telegram. The pipeline discovers LinkedIn job postings, scores them with a local LLM, and prepares tailored resumes — all without sharing data with third parties (except OpenRouter for resume writing).

Starting the service:

cd ~/development/job-gobbler
npm run dev

Listens on http://localhost:7432. n8n reaches it via host.docker.internal:7432.

Pipeline — How It Works
  1. Search

    n8n workflow 01 fires every 15 minutes and POSTs each search URL to /jobs/search sequentially. Playwright opens LinkedIn with your saved profile, scrolls the job list to hydrate all cards, and stores up to 50 new job IDs in SQLite.

  2. Describe

    /jobs/describe fetches each job's detail page via plain HTTPS (no browser, no auth needed). Parses title, company, salary, location, description text, applicant count, Easy Apply flag. Stored in description_text.

  3. Grade

    /jobs/grade-all scores all described jobs via a single-shot call to Qwen3-Coder-30B (local, ~800ms/job). Produces fitScore, scoreCause, riskFlags, and per-dimension scores.

  4. Telegram

    Graded results are formatted and sent to your Telegram chat. Approval buttons let you reject, prep resume, or proceed to apply.

Model Routing

All inference is local except resume/cover letter writing.

Task Model Location
job_ranking · fit_scoring · risk_flags Qwen3-Coder-30B LOCAL
form_extraction · structured_output Qwen3-Coder-30B LOCAL
visual_qa · screenshot_verification Gemma 4 27B LOCAL
resume_generation · cover_letter Gemini 2.5 Flash → DeepSeek fallback REMOTE

LM Studio endpoint: http://192.168.0.14:1234/v1

n8n Workflows
ID Name Trigger
01 Discovery Scheduler Every 15 min → search → describe → grade
02 Telegram Approval Router Telegram callback_data → status/apply/build
03 Direct Job Intake Telegram URL drop → scrape → grade → notify
04 Health Monitor Periodic → GET /health → alert if down

Push changes: cd n8n-workflows && ./sync.sh push

All Endpoints
Method Path Description
GET /health Service status, policy list, routing stats, audit summary
GET /pool Browser profile pool — free/busy/queued
GET /audit Recent LLM call log (filter by model, task, jobId)
GET /current-tab?url= Firefox bridge — scrape + grade the active tab URL
POST /jobs/search LinkedIn discovery — returns new job IDs stored in DB
POST /jobs/describe Headless fetch of job description pages (no auth)
POST /jobs/grade-all Single-shot 6-dim scoring (~800ms/job) via Qwen3-Coder-30B
POST /jobs/scrape Scrape any job URL via browser
POST /jobs/notify Format graded jobs into Telegram message payloads
POST /jobs/build Generate tailored resume + cover letter (PDF)
POST /jobs/apply Initiate apply pipeline — routes by detected platform
POST /jobs/fill LinkedIn Easy Apply form-filler (returns plan for approval)
POST /jobs/fill/approve Execute approved fill plan (submit button)
POST /jobs/status Update job status (rejected / approved / applied)
Database Schema

SQLite at data/jobs.db. Key columns:

job_id, source, url, title, company, location, easy_apply,
posted_at, applicant_count, status, pre_rank, fit_score,
score_cause, risk_flags, thinking_trace, description_text,
screenshot_path, created_at, updated_at

Status flow: newdescribedgradedapproved / rejected / applied

Search Configurations
Add Search URL