A weekly job-search agent for students. Fewer, better, you decide. Every Monday it reads the postings, picks twenty, explains each pick with a reason tag, and drafts materials that cite the student's own stories — then the student chooses a mode per job: Skip, Focus, Assist or Managed.
The agent proposes. The student decides. Nothing is sent that wasn't chosen, and nothing is written that isn't cited.
The UI never learns whether a report was produced by rules or by a model. Everything that will change lives behind three functions in lib/report.ts; everything that won't — accounts, schema, components — is built for real from day one.
Directions rank what the student wants; résumés bind to directions; stories are the evidence. A report row is a scored (user, job, week); choosing a mode turns it into an application whose paragraphs carry storyIds — the citation that the UI enforces.
Pull ATS feeds and school packs; dedupe by org + title; drop past deadlines.
seedJobsIfEmpty()Base score plus a boost for matching the student's ranked directions; penalty for none.
base + max(0, 10 − 2·rank)Four reasons, each with a one-line why: closes soon, strong match, big title, easy to get.
DL · MT · BT · EZFind up to two stories whose tags appear in the posting; they become the rationale's evidence.
storyIds: [3, 7]Deadlines within 7 days first, then score. Keep the quota.
.slice(0, quota)Materials are written only when a mode is chosen — one paragraph per cited story, one deliberately uncited.
ensureMaterials()A mode is set per job on the report. It is the only place where autonomy is granted, and it is granted one posting at a time.
Deletes any draft. The job stays in the report as declined so it isn't re-proposed.
The student writes; the agent supplies strategy, story chips and the posting's own words.
The agent drafts every paragraph with citations; the student edits and submits.
Phase 3: Playwright submits on Greenhouse / Lever / Ashby. Shown with a lock so the boundary is visible now.
Pathfinder's semantic layer sits on the Broadsheet base: same class names and data-* attributes in the design system and in React, so bundle.css applies unchanged. These are real, rendered from the tokens — hover a reason tag.
| Mocked now | Real version | Phase |
|---|---|---|
| seed.ts postings | Worker fetching Greenhouse / Lever / Ashby JSON + school packs | 1 |
| generateReport() | Embeddings + Claude rerank | 1 |
| ensureMaterials() | Claude drafting from the Story Bank, with storyIds citations | 1 |
| Résumé summary box | PDF upload + parsing | 2 |
| Autofill (disabled) | Browser extension | 2 |
| Managed (locked) | Playwright submit on Greenhouse / Lever / Ashby | 3 |
| SQLite | Supabase Postgres — swap lib/db.ts, keep the queries | — |
Accounts, schema, components and the mode boundary are real today. Three functions stand where the model will go.
— 2026 · Zhang Yichi