Skip to content

🇺🇸 English · 🇧🇷 Português

Finding companies

moonlighter scans the companies you list in company_list.yaml; it does not find them for you. This page is a recipe for finding candidates by hand, using the public Common Crawl URL index, and checking each one before it goes on your list.

What works and what doesn't

A study on 2026-09-25 tried three public methods. Only the Common Crawl index gave many real company slugs cheaply: one or two requests yielded about 1,500 candidates each for Ashby and Workable, and 8 to 10 out of every 10 sampled were live boards. Search engines answered automated site: queries with a captcha on the first request, and no ATS publishes a directory of its customers.

The index is weeks old, so about 2 in 10 candidates are boards that no longer exist, and it has no usable entries for Lever. Recruitee and SmartRecruiters were not tried.

1. Pick the latest crawl

CRAWL=$(curl -s https://index.commoncrawl.org/collinfo.json | python3 -c "import json,sys; print(json.load(sys.stdin)[0]['id'])")
echo "$CRAWL"   # e.g. CC-MAIN-2026-39

2. List candidate slugs

For Ashby, Greenhouse and Workable the company slug is the first path segment of the board URL:

ATS URL pattern to query
Ashby jobs.ashbyhq.com/*
Greenhouse job-boards.greenhouse.io/* and boards.greenhouse.io/*
Workable apply.workable.com/* (drop the slug j, which is part of posting URLs)
curl -s "https://index.commoncrawl.org/$CRAWL-index?url=jobs.ashbyhq.com/*&output=json&fl=url&limit=5000" \
  | python3 -c "import json,sys,urllib.parse; print('\n'.join(sorted({urllib.parse.unquote(json.loads(line)['url'].split('/')[3]).lower() for line in sys.stdin if line.strip()})))" \
  > ashby-candidates.txt

For InHire the slug is the subdomain (<slug>.inhire.app): query url=*.inhire.app and take the host's first label instead of the path.

Be gentle with the index: its homepage asks users not to overload it. One request per ATS, run by hand, is the intended use; a response can come back cut off mid-list, so run it again if the list looks short.

3. Keep only the companies you want

A few thousand boards say nothing about which companies are worth your time, and every company on your list costs LLM calls on each scan. Filter the file down to names you recognise or care about before checking them.

4. Check each candidate is a live board

Ask the ATS's own public listing, the same one moonlighter's scanner uses. A 200 is a live board (it may have no openings today); a 404 is gone:

ATS Check
Ashby curl -s -o /dev/null -w '%{http_code}' https://api.ashbyhq.com/posting-api/job-board/SLUG
Greenhouse curl -s -o /dev/null -w '%{http_code}' https://boards-api.greenhouse.io/v1/boards/SLUG/jobs
Workable curl -s -o /dev/null -w '%{http_code}' https://apply.workable.com/api/v1/widget/accounts/SLUG
InHire curl -s -o /dev/null -w '%{http_code}' -H 'X-Tenant: SLUG' https://api.inhire.app/job-posts/public/pages
Lever curl -s -o /dev/null -w '%{http_code}' 'https://api.lever.co/v0/postings/SLUG?mode=json&limit=1'
while read -r slug; do
  code=$(curl -s -o /dev/null -w '%{http_code}' "https://api.ashbyhq.com/posting-api/job-board/$slug")
  [ "$code" = 200 ] && echo "$slug"
  sleep 1
done < ashby-candidates.txt

5. Add them to your list

Put each live slug under its ATS in company_list.yaml (see First scan). The next scan_and_evaluate picks them up; to look at one company right away without editing the list, ask for scan_company, or run moonlighter-scan --company ashby SLUG.