Pre-Configured Portal Providers and Search Queries in Career-Ops' portals.yml
The Career-Ops portals.yml configuration includes six pre-configured ATS providers (Greenhouse, Ashby, Lever, Workable, SmartRecruiters, and Recruitee) and dozens of customizable search queries targeting specific job boards and role keywords.
The portals.yml file (generated from templates/portals.example.yml) serves as the central configuration hub for the Career-Ops job-scanning subsystem. It defines both how the scanner retrieves structured data from company Applicant Tracking Systems and where it searches for new opportunities across public job boards. Understanding these pre-configured portal providers and search queries allows you to customize your automated job search without modifying the core source code.
Pre-Configured Portal Providers
The provider list defines the low-level adapters that scan.mjs uses to fetch structured job data from major ATS platforms. These identifiers are auto-loaded from the providers/ directory and mapped to specific URL patterns.
The six default providers implemented in santifer/career-ops are:
greenhouse– Targets Greenhouse ATS instances atjob-boards.greenhouse.io/<slug>orboards.greenhouse.io/<slug>.ashby– Handles Ashby ATS careers pages atjobs.ashbyhq.com/<slug>.lever– Parses Lever ATS listings fromjobs.lever.co/<slug>.workable– Connects to Workable career portals atapply.workable.com/<slug>.smartrecruiters– Supports SmartRecruiters atcareers.smartrecruiters.com/<slug>orjobs.smartrecruiters.com/<slug>.recruitee– Handles Recruitee-based sites using the pattern<slug>.recruitee.com.
When scan.mjs processes a careers_url entry in your tracked companies list, it auto-detects the correct provider based on these URL patterns before invoking the provider-specific fetchJobs() method.
Search Queries Configuration
The search_queries section contains WebSearch definitions that feed the scanner with URLs from public job boards. Each entry in templates/portals.example.yml follows a consistent YAML structure with three fields: name, query, and enabled.
A typical search query entry looks like this:
- name: Ashby — AI PM
query: 'site:jobs.ashbyhq.com "AI Product Manager" OR "Senior Product Manager AI" remote'
enabled: true
The full catalogue in the example file spans dozens of boards including Ashby, Greenhouse, Workable, Remotive, WeWorkRemotely, and region-specific aggregators for the EU and Turkey. Each query combines site-specific filters with role keywords to return only relevant positions.
How scan.mjs Consumes the Configuration
At runtime, scan.mjs performs a two-phase discovery process using the portals.yml configuration:
-
Provider Detection – For each company in
tracked_companies, it matches thecareers_urlagainst the provider patterns defined in theproviders/directory (e.g.,providers/greenhouse.mjs,providers/ashby.mjs). -
Search Execution – It iterates through the
search_querieslist and executes only those entries whereenabled: true, scraping the results to extract new job postings.
According to the Career-Ops source code, the providers/*.mjs files implement two critical functions: detect() to confirm URL compatibility and fetchJobs() to retrieve structured listing data.
Working with the Configuration Programmatically
You can inspect and manipulate the pre-configured providers and search queries using Node.js before running a scan.
List Available Providers
To see the built-in provider identifiers programmatically:
import fs from 'fs';
import yaml from 'js-yaml';
const portals = yaml.load(fs.readFileSync('templates/portals.example.yml', 'utf8'));
const providers = [
'greenhouse',
'ashby',
'lever',
'workable',
'smartrecruiters',
'recruitee',
];
console.log('Enabled providers:', providers);
Extract Active Search Queries
To filter for only the enabled search definitions:
import fs from 'fs';
import yaml from 'js-yaml';
const data = yaml.load(fs.readFileSync('templates/portals.example.yml', 'utf8'));
const enabledQueries = data.search_queries
.filter(q => q.enabled)
.map(q => ({ name: q.name, query: q.query }));
console.table(enabledQueries);
Setting Up Your Local portals.yml
Before running your first scan, copy the example configuration to the project root and customize it:
# Copy the template to create your runtime configuration
cp templates/portals.example.yml portals.yml
# Edit portals.yml to disable unwanted queries or adjust keywords
# Then execute the scanner
node scan.mjs
The scanner automatically picks up the provider definitions from providers/ and respects the enabled flags in your portals.yml file.
Summary
- Six Pre-Configured Providers: The
portals.ymltemplate includes built-in support for Greenhouse, Ashby, Lever, Workable, SmartRecruiters, and Recruitee ATS platforms. - Search Query Structure: Each query contains a human-readable name, a site-filtered query string, and an enabled boolean flag.
- File Architecture:
templates/portals.example.ymlserves as the reference configuration, whileportals.yml(created by copying the template) drives the runtime behavior ofscan.mjs. - Provider Implementation: Actual fetching logic resides in
providers/*.mjsfiles, which exposedetect()andfetchJobs()methods used by the scanner.
Frequently Asked Questions
What is the difference between portals.example.yml and portals.yml?
templates/portals.example.yml is the version-controlled reference file in the santifer/career-ops repository that contains all default providers and search queries. You create portals.yml by copying this template to your project root, then customize it to enable only the queries and companies you want to track. The scanner specifically looks for portals.yml at runtime, not the template file.
How do I disable a specific search query?
Open your local portals.yml file and locate the query entry under the search_queries section. Change the enabled field from true to false. The scanner in scan.mjs filters the list using filter(q => q.enabled) before execution, so disabled entries are skipped automatically without deleting the configuration.
Can I add a custom ATS provider that is not in the default list?
Yes, you can extend the system by creating a new file in the providers/ directory (e.g., providers/custom.mjs) that exports detect() and fetchJobs() functions following the existing provider pattern. However, you must also manually require this provider in scan.mjs or modify the auto-loading logic, as the default list only includes the six pre-configured providers.
Where are the provider implementations located?
The provider logic for each ATS resides in the providers/ directory at the repository root. Each provider (e.g., greenhouse.mjs, ashby.mjs, lever.mjs) contains the platform-specific parsing logic that handles URL detection and job data extraction. These modules are separate from the YAML configuration but are referenced by scan.mjs when processing URLs defined in portals.yml.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →