CareerOps
Guides

Scan Job Portals

Set up and run the portal scanner to find new job openings automatically.

This guide walks through setting up portals.yml and running the portal scanner to find new job openings automatically.

Before you start

Make sure you have completed the Getting Started guide. You need cv.md and modes/_profile.md in place before scanning is useful.

Set up portals.yml

portals.yml is the file that controls what the scanner looks for and where it looks. You create it once from the included template, then edit it to match your target roles.

Run this command from the project folder:

Terminal
cp templates/portals.example.yml portals.yml

Open portals.yml in any text editor. The file has three sections. The steps below walk through each one.

Configure your title filter

The title filter is how the scanner decides if a job is worth showing you. It checks the job title against two lists of keywords.

Find the title_filter section near the top of the file:

portals.yml
title_filter:
  positive:
    - "AI"
    - "ML"
    - "Product Manager"
  negative:
    - "Junior"
    - "Intern"
  seniority_boost:
    - "Senior"
    - "Staff"
    - "Lead"

Replace the positive list with keywords that match your target roles. A job must match at least one keyword from this list to pass through. The check is not case-sensitive, so "AI" also catches "ai engineer".

Replace the negative list with keywords that rule a job out. If any of these appear in the title, the job is skipped — even if it matched a positive keyword.

Leave seniority_boost as is unless you want to add or remove seniority levels. These keywords do not filter anything out — they just move matching jobs higher in the results.

Example: If you are looking for Rails engineering roles, your filter might look like this:

portals.yml
title_filter:
  positive:
    - "Rails"
    - "Ruby"
    - "Full Stack"
    - "Backend"
  negative:
    - "Junior"
    - "Intern"
    - "PHP"
    - "Java"
  seniority_boost:
    - "Senior"
    - "Staff"
    - "Lead"

Tip

Start with a small positive list of three to five keywords. You can always add more later. A long list makes it harder to see why a job passed or failed.

Add companies to track

The tracked_companies section is a list of specific companies you want the scanner to check every time. The scanner goes directly to each company's job page and reads the open roles.

Find the tracked_companies section near the bottom of the file. Each entry looks like this:

portals.yml
tracked_companies:
  - name: Anthropic
    careers_url: https://job-boards.greenhouse.io/anthropic
    api: https://boards-api.greenhouse.io/v1/boards/anthropic/jobs
    enabled: true

  - name: OpenAI
    careers_url: https://openai.com/careers
    enabled: true

To add a company, copy an existing entry and change the values:

FieldWhat to put
nameThe company name as you want it to appear in results
careers_urlThe direct URL to the company's job listings page
apiOptional. The Greenhouse API URL if the company uses Greenhouse. Leave it out if you are not sure.
enabledSet to true to include the company or false to skip it without deleting the entry.

To find a company's careers_url, go to the company's website, click Careers or Jobs, and copy the URL of the page that lists open roles. That is the URL to use.

To disable a company without deleting it, set enabled: false:

portals.yml
  - name: Stripe
    careers_url: https://stripe.com/jobs/search
    enabled: false

Note

Every company in tracked_companies must have a careers_url. Without it, the scanner has no page to visit and will skip that entry.

Review the search queries

The search_queries section runs broader web searches to find roles at companies not in your tracked list. The template includes many pre-built queries.

You do not need to change this section to get started. The pre-built queries cover major job boards including Greenhouse, Ashby, among others.

When you are ready to customize, each query looks like this:

portals.yml
search_queries:
  - name: Greenhouse — Rails Engineer
    query: 'site:job-boards.greenhouse.io "Rails Engineer" OR "Ruby on Rails" remote'
    enabled: true

To turn off a query you do not need, set enabled: false. To add a new one, copy an existing entry, give it a new name, and update the query text.

Run a scan

There are two ways to run a scan. Use the one that fits what you need.

Option A — Run the script directly

Terminal
npm run scan

Run this from the project folder. The script reads portals.yml, hits each company's API directly, and writes any new jobs to data/pipeline.md. It uses no AI tokens and runs in about 30 seconds.

This option only works for companies that use Greenhouse, Ashby, or Lever. Companies without one of those platforms are skipped.

Preview results before saving them:

Terminal
npm run scan -- --dry-run

This runs the full scan but does not write anything to disk. Use it to check your filter settings before committing results.

Scan a single company:

Terminal
npm run scan -- --company Anthropic

Replace Anthropic with any company name from your tracked_companies list. The match is not case-sensitive.

Option B — Run the AI-powered scan inside Claude Code

Open Claude Code in the project folder and type:

Claude Code
/career-ops scan

This version visits each company's job page directly using a browser, so it works even for companies that do not have a public API. It also runs the search_queries from your portals.yml to find roles at companies not in your tracked list.

Use this option when:

  • A company in your list does not use Greenhouse, Ashby, or Lever
  • You want to discover new companies, not just check known ones
  • The script scan missed something you expected to see

Tip

Option B uses Claude API tokens and takes longer than the script. For a quick daily check, Option A is faster.

Read the scan output

When the scan finishes, you will see a summary like this:

Terminal
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Portal Scan — 2026-04-13
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Companies scanned:     42
Total jobs found:      318
Filtered by title:     291 removed
Duplicates:            4 skipped
New offers added:      23

New offers:
  + Anthropic | AI Engineer | San Francisco, CA
  + ElevenLabs | Solutions Architect | Remote
  ...

→ Run /career-ops pipeline to evaluate new offers.

Here is what each line means:

LineWhat it tells you
Companies scannedHow many companies from tracked_companies were checked
Total jobs foundAll open roles seen across those companies, before any filtering
Filtered by titleJobs removed because the title did not match your title_filter
Duplicates skippedJobs already in your pipeline or tracker — not added again
New offers addedJobs that passed all filters and are new to you

If New offers added is 0, your title filter may be too strict. Try adding a keyword to your positive list and run the scan again.

Where new jobs go: Each new offer is added as a line in data/pipeline.md. That is the list of jobs waiting to be evaluated.

What data/scan-history.tsv does: Every URL the scanner sees — whether it was added, filtered, or skipped — gets logged here. This is how the scanner avoids showing you the same job twice across future scans. You do not need to edit this file.

Evaluate new offers from a scan

After a scan adds new offers to data/pipeline.md — your list of pending job offers — run the pipeline command to evaluate each one against your profile. This step uses Claude to read the job description, compare it against your cv.md and modes/_profile.md, and produce a scored summary for each role.

Open Claude Code in the project folder and type:

Terminal
/career-ops pipeline

Claude reads every pending URL in data/pipeline.md, visits each job posting, and evaluates it. Results come back in batches. Each batch shows a table like this:

Batch 1 done (Anthropic, ElevenLabs, Mistral):

#CompanyRoleScoreLegitimacy
024AnthropicAI Engineer4.8/5High Confidence
025ElevenLabsSolutions Architect4.1/5High Confidence — fast-growing
026Mistral AIProduct Manager3.2/5Proceed w/ Caution — role closed

Here is what each column means:

ColumnWhat it tells you
#The report number. Use it to find the full report in reports/ — for example, report 024 is reports/024-anthropic-2026-04-13.md
ScoreHow well the role fits your profile, from 1.0 to 5.0
LegitimacyWhether the posting looks real and active. "High Confidence" means the job is live and the details check out. "Proceed w/ Caution" means something raised a flag — read the note next to it.

To read the full evaluation for a role, you have two options:

  • Open the report file directly — find it in the reports/ folder using the number from the table.
  • Use the dashboard — run ./dashboard/career-dashboard from the project folder to browse all your reports in a terminal interface. You can filter by score and status, and open any report without leaving the terminal.

What to do next

When /career-ops pipeline finishes, each job has a score from 1.0 to 5.0. You can find the full report for any role in the reports/ folder. The score shows how well the role matches your profile.

Use the score as your starting point:

ScoreRecommended action
4.5 or higherStrong match. Run /career-ops apply right away.
4.0 – 4.4Good fit. Run /career-ops apply. You can also run /career-ops contacto first to reach out to someone on the team before applying.
3.5 – 3.9Could go either way. Run /career-ops deep to learn more before you decide.
Below 3.5Skip it unless you have a specific reason to apply.

Here is what each command does:

  • /career-ops apply — Opens the application form and writes answers tailored to your profile. It stops before submitting so you can review everything first.
  • /career-ops contacto — Finds a hiring manager or team member on LinkedIn and drafts a short outreach message for you to send.
  • /career-ops deep — Researches the company and the role in depth. Use this when you are on the fence and want more information before deciding.
  • /career-ops tracker — Shows the status of every role in your pipeline. Run this any time you want to see where things stand.

Tip

You do not have to go in order. If a role scores 4.8 but you have never heard of the company, run /career-ops deep first. The commands work on their own — use which ever one fits your situation.

On this page