Architecture
Finds fresh jobs, tailors each resume.1,008 runs, June to October.
A Cloud Run job pulls fresh postings from 163 company boards and four aggregators, drops the roles I could never take, and has Gemini score the rest into a Google Sheet. A private console reads that Sheet, each tailored resume passes a judge before it reaches Drive, and the public demo runs the same console on fictional data.
40 min
from an empty Google Cloud project to a running pipeline and console, 3:14 to 3:54 AM on June 10
0
outreach emails it sends on its own. Every one waits in Gmail drafts for my click
5,093 jobs
tracked in the Sheet by July 23, with 22 to 58 fresh rows added each day
1,008 runs
of the pipeline, June 10 to October 8: every 30 minutes at first, then twice each morning
New York --:-- simulated
Hover a part to trace what it touches. Click it for its notes.
- Built by me
- Managed by Google
- Outside system
- Main data path
- On demand
- Credentials cross
When it breaks
What each failure does, and what it does not do.
-
A job source goes down
Each source runs in its own try block, so one dead API never kills a run. Its error shows in the digest's run notes.
src/jobpilot/pipeline.py:56
-
Gemini returns bad JSON
The batch gets one retry, then stays unscored and out of the Sheet, so the next run picks it up.
src/jobpilot/scorer.py:97
-
A posting has no description
Tailoring fetches the live posting page first. Under 200 characters it refuses and says why on the row, with a retry button.
src/jobpilot/tailor.py:140
What I tuned
Small choices that keep it fast and cheap.
-
2 GiB for 163 boards
The parallel board fetch ran out of memory at the 512 MiB default, so the job runs with 2 GiB.
.github/workflows/deploy.yml
-
Dedup on company and title
Location left the key after boards listed one role per city, 23 duplicate groups in 426 rows. When two sources carry a job, the higher fidelity one wins.
src/jobpilot/dedup.py:30
-
Fresh first
Company boards keep 14 days, aggregators 7, and undated postings are dropped. A July audit found 2,960 New rows older than 30 days in the Sheet.
src/jobpilot/config.py:65
Guards
Rules the code enforces, not rules people remember.
-
Drafts only
Outreach is created as Gmail drafts and nothing else. No published recipient email means no draft at all.
src/jobpilot/outreach.py:135
-
The tailor cannot invent
The prompt allows reordering, rephrasing and emphasis, never a new employer, title, date, metric or tool. Length stays within 5 percent of the master so it fits one page.
src/jobpilot/prompts/tailor_v1.txt
-
No personal data in git
My profile and resumes load from Secret Manager at run time. The public repo ships a Jane Doe template.
src/jobpilot/config.py:128
