seeds/ — VC Portfolio Seed Fetchers
A complementary discovery path for startup job-seekers: pull a public VC portfolio company list and probe each company's ATS for openings, feeding results into the same pipeline as tracked companies in portals.yml.
What this does
scan-ats-full.mjs normally discovers companies by walking public ATS directories (Greenhouse, Lever, Ashby, Workday). The seeds/ layer adds a high-signal starting point for startup roles: rather than waiting for companies to appear in ATS directories, we seed the universe from well-known VC portfolios — giving you instant coverage of hundreds of YC/a16z-backed companies.
Flow:
VC portfolio API/page
↓ seeds/vc-portfolios.mjs
SeedCompany[]
↓ toPortalEntry()
PortalEntry (careers_url set to best-guess ATS URL)
↓ provider.detect() (same as portals.yml companies)
ATS provider fetches jobs
↓ title_filter / location_filter / dedup
data/pipeline.md
Usage
Via scan-ats-full.mjs (recommended)
# Seed from Y Combinator portfolio, last 7 days
node scan-ats-full.mjs --seeds yc --since 7
# Seed from both YC and a16z, dry-run preview
node scan-ats-full.mjs --seeds yc,a16z --dry-run
# Combine seeds + regular ATS sources
node scan-ats-full.mjs --seeds yc --ats greenhouse,lever --since 5
# npm shortcuts
npm run scan:seeds # yc + a16z
npm run scan:yc # YC only
Programmatic
import { fetchYCCompanies, fetchA16zCompanies, toPortalEntry, SEED_SOURCES } from './seeds/vc-portfolios.mjs';
// Fetch YC companies
const companies = await fetchYCCompanies();
console.log(companies[0]);
// → { name: 'Stripe', slug: 'stripe', url: 'https://stripe.com', source: 'yc', batch: 'W11' }
// Convert to a PortalEntry for ATS provider.detect()
const entry = toPortalEntry(companies[0]);
// → { name: 'Stripe', careers_url: 'https://job-boards.greenhouse.io/stripe', source: 'yc' }
// Using the registry
for (const [id, source] of Object.entries(SEED_SOURCES)) {
const companies = await source.fetch();
console.log(`${source.label}: ${companies.length} companies`);
}
Data sources
| Source | URL | Format | Auth |
|---|---|---|---|
| Y Combinator | https://api.ycombinator.com/v0.1/companies |
JSON API | None |
| a16z | https://a16z.com/portfolio/ |
Public HTML page | None |
- YC: Fetches up to 3 pages × 1000 companies. Covers all public YC batches.
- a16z: Parses the public portfolio page. Falls back gracefully if the page structure changes.
Security
- All slugs are validated against
SLUG_RE = /^[A-Za-z0-9._-]+$/before any URL interpolation — consistent with the guard inscan-ats-full.mjs. - Constructed ATS URLs go through the existing
entryOnHost()SSRF guard before reaching any provider. - No authentication tokens, no headless browser, no LLM API calls.
Adding more VC portfolios
- Add a
parseXyzPayload(payload)pure function (no network — testable with inline fixtures). - Add a
fetchXyzCompanies(opts?)async function that calls the public endpoint and returnsSeedCompany[]. - Register it in
SEED_SOURCES:
export const SEED_SOURCES = {
yc: { fetch: fetchYCCompanies, label: 'Y Combinator Portfolio' },
a16z: { fetch: fetchA16zCompanies, label: 'Andreessen Horowitz (a16z) Portfolio' },
// Add yours:
sequoia: { fetch: fetchSequoiaCompanies, label: 'Sequoia Portfolio' },
};
- Add test cases in
test-all.mjscovering yourparseXyzPayload()function.
Prior art
The VC-portfolio seeding approach is inspired by adityachaudhary99/job-hunt (02-seeds/fetch_yc.py, fetch_a16z.py), which was the original companion reference cited in issue #1370.