← All posts

Building Daily Role Finder

7 min read Claude Code · Python · Automation

Somewhere around week two of my Summer 2027 internship search, I did the math on checking career pages by hand: 277 target companies, even thirty seconds each, is over two hours a day of clicking through the same tabs looking for something new. That's not a job search, that's data entry. So I built a scheduled task that does it for me.

277Companies tracked
5Scan tiers
2Steps per run
9Tracker columns

01Why automate it

The instinct going in was a bookmarks folder and a daily habit. That works at ten companies. Past fifty it falls apart. My list kept growing too, as I added categories that actually fit a MechE hiring pipeline: national labs, rail, power/utility, construction, even operationally-focused industrial private equity. It reached 277 companies across five tiers.

Checking that by hand isn't just slow. It's unreliable. I'd lose track of which companies I'd already checked that week, skip the ones I was bored of, and miss postings that only stay live a few days before getting pulled. The fix wasn't a better spreadsheet habit. It was getting the checking off my plate: a task that runs on its own schedule, reads a file defining what “new and relevant” means, and surfaces only what changed.

02The target list: the brain of the system

Everything the task does traces back to one markdown file: Daily_Role_Finder_Target_List_v1.md. Despite the “v1” in the filename, it's internally versioned and carries its own changelog. It's on v11 now, after ten rebuilds, each one adding or cutting a category as my search evolved. It defines 277 companies and agencies across five tiers, ranked by fit:

TierCountWhat it covers
1 ★59Tightest fit: design-through-fabrication hardware, space/defense startups, humanoid robotics, EV/UAV players
283 (54 + 29)Major corporates, plus a government/national-lab/DoD civilian subsection (NASA, NAVSEA, DOE labs, USAJOBS agencies)
360Cast-wider-net industrial, manufacturing, chemical, rail, and construction firms
450International ME companies, with a work-authorization gate instead of the US-location rule
525Operationally-focused industrial private equity: engineer-led firms that place interns on portfolio-company operations work

Every entry carries a hard eligibility gate: internship/co-op token, Summer 2027 cycle, undergraduate-eligible, and (for Tiers 1–3 and 5) a US location. Entries get tagged “Custom — verify” when I know the company but haven't confirmed which applicant-tracking system they run. The scan notes the real system once it sees one and updates the file over time. Keeping all of this in one editable document means the task's behavior is entirely steerable from this file. Add a tier, tighten the gate, retag a company, and the scan adapts. Nothing about the task's own logic needs to change.

03Keeping state: a JSON file, not a database

Scanning all 277 companies with a full web search every day would be slow and expensive, so the task splits the work across days. That means remembering where it left off. It does that with the smallest tool possible: scan_rotation_state.json, a single object:

{"last_tier_scanned": 3, "last_rotation_date": "2026-09-24"}

Each run, the task reads this file, advances the tier by one, and writes it back. With five tiers the rotation is mod-5: Tier 1, 2, 3, 4, 5, back to 1. What I like about this in hindsight is that the rotation math isn't hardcoded into the task's instructions. The task counts how many tiers the target list document currently describes, so when I added Tier 5 (industrial PE) in v11, the rotation became mod-5 automatically. I didn't touch the task itself, only the file that defines what's being scanned.

04The scan itself

The scan runs in two tiers of effort, every time the task fires:

Splitting the work this way means Tier 1, my tightest-fit companies, never waits more than a day for even the cheap check. The expensive check cycles through the full list roughly once a work-week.

05Where the results land

Everything the scan finds ends up in one file: applied_tracker.xlsx, a plain spreadsheet with nine columns (Company, Role, Location, Tier, Tags, Link, Date Found, Status, Notes). No database. Nothing to host or maintain.

What writes to it is the more interesting part. Instead of a persistent script, each run produces a fresh Python file, update_tracker.py, with that day's findings hardcoded into a list of new rows, then runs it once with openpyxl. The script inserts new rows right after the header, newest first, and can patch an existing row in place too. One real example: a posting I'd already tracked through a LinkedIn aggregator link turned out to have a confirmed listing on the company's own Workday page. The script updated that row's link in place instead of adding a duplicate, with a comment stating the rule directly: always store the official ATS link over the aggregator link.

06How to set it up

None of this is specific to mechanical engineering or Summer 2027. The pattern is just a structured list of targets, a hard eligibility gate, tiers by fit, and a cadence rule. It works for any recurring “scan a changing set of sources” task. Here's a template to start from, and how to get Claude to fill it in for your own search.

The template

# [Your Search Name] — Target List v1

**For:** [Your name] — [School], [Major/field] ([minor, if any]), [class standing], expected [grad month/year]
**Focus:** [3–6 keywords describing the kind of role you want]
**Target:** [Summer/Fall/Spring year] [internships/full-time roles] ONLY · [undergrad-eligible / grad-eligible] · [US-based / open to international]
**Rebuilt:** [date] — [one line on what changed this version]

## The gate (hard)
All must hold:
- [Internship/co-op/full-time token]
- [Cycle: target year, or date range for undated postings]
- [Location constraint, and any exceptions per tier]
- [Class-standing / eligibility constraint]

## Cadence
Live scan cadence is governed by the `[your-task-name]` scheduled task, not this document — it rotates one tier per run so the deep-search pass stays affordable across the full list.

## Tier 1 ★ (highest fit)
| # | Company | Feed / Slug | Tags |
|---|---|---|---|
| 1 | [Company] | [Greenhouse/Workday/Ashby/Custom — slug or URL] | #tag |

## Tier 2 (strong fit)
| # | Company | Feed / Slug | Tags |
|---|---|---|---|

## Tier 3 (cast wider net)
| # | Company | Feed / Slug | Tags |
|---|---|---|---|

## Notes
"Custom — verify" entries have a confirmed company/career page but no confirmed ATS — note the real system once a scan sees it, and update this file over time.

Generating your own list with Claude

  1. State your constraints up front: role/field, school, class standing, graduation timeline, and the hard gate (work authorization, location, cycle). This is what makes Claude's filtering useful instead of generic.
  2. Seed it with 5–10 companies you already know fit. Claude tiers around real anchors far better than it invents a list from nothing. Give it examples of what “Tier 1” looks like to you.
  3. Ask it to research each company's actual ATS, not guess one. A good prompt asks explicitly for Greenhouse/Workday/Ashby/Lever/custom, and to mark anything unconfirmed rather than assume.
  4. Ask for tiers by fit, not alphabet or size: tightest-fit hands-on roles in Tier 1, cast-a-wider-net in the lowest tier.
  5. Have it write the cadence rule into the same document. That's what lets a scheduled task adapt automatically when you add or cut a tier later, without editing the task itself.

A prompt that does all five in one shot:

I'm a [major] student at [school], [class standing], graduating [month/year].
I want a tiered target-company list for a [role type] search, structured
for an automated daily scanner.

Focus areas: [list 3-6]
Hard eligibility gate: [internship/co-op only? cycle? location? class standing?]

Start from these companies I already know fit: [5-10 companies]

For each company, find:
- Whether they post through Greenhouse, Workday, Ashby, Lever, or a custom
  career site
- The direct feed/slug or career page URL if you can find one

Group companies into tiers by fit (tightest fit = Tier 1), tag each with
relevant keywords, and mark any unconfirmed ATS as "Custom — verify."
End the document with a Cadence section describing how a scheduled task
should rotate through the tiers so a daily scan stays affordable.

Once the list exists, point a Claude Code scheduled task at the file, the same way daily-role-finder-me reads mine. The list becomes the only thing you ever need to edit.