Agent pipeline that scrapes 13 job boards plus your ICP companies' ATS portals (Greenhouse / Ashby / Lever), scores postings against your skills, finds hiring managers, and drafts personalized pitches. Anti-mass-apply.
Requires the Claude Code terminal CLI. The pipeline is driven by the
lead-0agent, which can only be launched as the primary agent from the CLI (claude --agent lead-0). It cannot be started from the Claude Desktop app or claude.ai/code. See Claude Desktop & claude.ai below.
git clone https://github.com/0xQuinto/dossier.git
cd dossier
claude --agent lead-0That's it. On first run, lead-0 detects missing setup and walks you through everything:
- Installing prerequisites (Python 3.12+, git, Homebrew, Node.js 20+)
- Setting up the virtual environment and dependencies
- Installing Playwright + Chromium for CV PDF rendering
- Configuring the
EXA_API_KEYcredential for contact research - Building your skills inventory and resume from your existing materials (CV, portfolio, GitHub, LinkedIn)
Manual alternative. python3 setup_wizard.py handles venv + deps + the EXA_API_KEY credential (exported to your shell profile) without the profile builder. (On Windows, if bare python opens the Microsoft Store, use the real interpreter; see Development.)
This pipeline runs only in the Claude Code terminal CLI. Both the Desktop app and claude.ai/code load this repo's .claude/ config (CLAUDE.md, settings, MCP servers, skills, and the agent files themselves), but neither lets you launch a custom agent as the main thread. There is no --agent equivalent or agent picker. Because lead-0 orchestrates by spawning subagents (scout-1, ranker-7, …) and a custom agent can only be made the main thread via the CLI, the orchestrator can't be started on those surfaces. The same applies to the on-demand agents (letter-5, pdf-9, applier-2, filler-10); they're custom agents too.
| Surface | Reads .claude/ config |
Launch lead-0 / on-demand agents |
Run the pipeline |
|---|---|---|---|
| Terminal CLI | ✅ | ✅ claude --agent <name> |
✅ |
| Claude Desktop (local) | ✅ | ❌ no agent launcher | ❌ use the CLI |
| claude.ai/code (cloud) | ✅ (cloned in) | ❌ no agent launcher | ❌ use the CLI |
- Claude Desktop is a full local Claude Code engine (runs bash, edits files, shares config with the CLI), but it has no UI to make
lead-0the primary agent. Run the pipeline from a terminal instead. The raw scraper (board-aggregator) still works in any shell. - claude.ai/code cloud sessions can be started from the CLI with
claude --remote "<task>"(push your commits first, since it clones from GitHub), but--remotecannot be combined with--agent, so it can't drivelead-0. Cloud sessions are fine for other repo tasks, just not this pipeline.
Docs: sub-agents (CLI-only) · Claude Code on the web · Desktop
Phase 1 — Scrape scout-1 runs board-aggregator CLI across 13 boards + ATS portal scan of your ICP companies
Phase 2 — Rank ranker-7 scores each posting against your skills inventory
Phase 3 — Research recon-3 finds hiring managers via Exa (parallel per company)
Phase 4 — Pitch (optional) scripter-11 drafts the video pitch, then composer-4 produces DM drafts + STAR+R stories — skipped by default, offered after the other phases finish
The pipeline orchestrator (lead-0) runs phases sequentially. Phase 3 spawns one subagent per company in parallel. Phase 4 is optional, skipped by default and offered once the other phases finish.
Two scrape sources, one merged feed:
- Generic boards. 13 public boards (Indeed, LinkedIn, RemoteOK, Himalayas, HN, crypto/web3 boards, 80,000 Hours, …). Wide net, noisy.
- Per-company ATS portals. Direct hits to Greenhouse / Ashby / Lever public APIs for the companies in
portals.yml. Narrow, high-signal, no auth needed. Scout-1 marks portals inactive after 30 days with no openings;discoverer-6adds new ones.
Portal discovery. If portals.yml is missing or has no active companies, lead-0 offers to run discoverer-6 to auto-discover companies matching your skills-inventory and populate it before Phase 1. You can also run discoverer-6 standalone anytime to expand the list.
Each run writes to a timestamped directory under research/runs/. The most recent run is symlinked at research/latest/.
On-demand agents (outside the pipeline):
applier-2generates copy-paste answers for application forms (human-in-the-loop)letter-5generates ATS cover letters (keyword injection + SOAR proof points)pdf-9generates tailored ATS PDF CVs (keyword injection + bullet reordering)filler-10submits via API for Lever/Ashby and delegates other ATSes to applier-2 for manual submission (human-in-the-loop)
Utilities:
scripts/tracker.pyis the application status tracker CLI (add, update, import-run, dedup, show)dashboard/is a Go TUI for browsing applications (Bubble Tea + Lipgloss)scripts/generate-pdf.mjsrenders the ATS PDF via Playwright
Every posting is checked against poteto/hiring-without-whiteboards (MIT), a community-maintained list of companies that run real-work interviews instead of whiteboard/LeetCode-style trivia. A match sets hww_listed: true on the posting and carries the list's own process note (hww_process) into the CSV, markdown, and compact index output. ranker-7 treats a match as a tie-breaker bonus, not a scoring dimension.
The list is cached at ~/.cache/board-aggregator/hww-readme.md and refetched after 7 days; pass --no-hww to skip the lookup entirely (no network call, no cache write).
Pass --hww-only to keep only postings whose company matched the list, dropping every other posting from the run's output. It requires --hww (the default) and errors if combined with --no-hww. Coverage caveat. --hww-only filters what the 13 boards + portal scanner already returned; it does not scrape the listed companies' own careers pages, so an HWW company that never posts on those boards will not appear even with the filter on.
Provenance caveat. The list is community-sourced and not independently verified by dossier. hww_listed is a lead worth weighing, not a verified claim about a company's actual interview process. Treat hww_process as a note to confirm, not a guarantee.
Seeded discovery. --hww-pool exports the list as JSON (name, url, location, process, remote) instead of scraping, honoring --remote-only/--include-onsite the same way the scrape path does. discoverer-6 can use that pool as its candidate list instead of an Exa name-discovery run, so Exa spend goes only toward validating each candidate's ATS board, not finding names; see its "HWW-seeded mode" in .claude/agents/discoverer-6.md. The budget is the same config.max_discovery_calls cap either way.
graph TB
subgraph Pipeline["Claude Agent Pipeline"]
Lead[lead-0<br/>Orchestrator]
Primer[primer-8<br/>Onboarding]
Scout[scout-1<br/>Scrape]
Ranker[ranker-7<br/>Rank]
Recon[recon-3<br/>Contacts]
Scripter[scripter-11<br/>Video Script]
Composer[composer-4<br/>DMs + Stories]
Discoverer[discoverer-6<br/>Discovery]
Applier[applier-2<br/>Forms]
Letter[letter-5<br/>Cover Letter]
PDF[pdf-9<br/>ATS PDF]
Filler[filler-10<br/>ATS Submit]
end
subgraph Scraper["board-aggregator CLI"]
CLI[Click CLI]
Scrapers["13 scrapers<br/>(generic boards)"]
PortalScanner["portal_scanner<br/>Greenhouse / Ashby / Lever"]
PortalsYml[("portals.yml<br/>ICP companies")]
end
Lead -->|"foreground (if needed)"| Primer
Lead -->|foreground| Scout
Lead -->|foreground| Ranker
Lead -->|"background ×N companies"| Recon
Lead -.->|"optional, per company"| Scripter
Lead -.->|"optional, per company"| Composer
Lead -->|"foreground (if portals empty)"| Discoverer
Lead -.->|on-demand| Applier
Lead -.->|on-demand| PDF
Discoverer -->|writes| PortalsYml
Scout --> CLI
CLI --> Scrapers
CLI --> PortalScanner
PortalScanner --> PortalsYml
- Create
board_aggregator/scrapers/your_board.py - Subclass
BaseScraperand implementscrape() - Decorate with
@register - Import in
board_aggregator/cli.py - Add a test with a fixture in
tests/
See board_aggregator/scrapers/remoteok.py for a minimal example.
git clone https://github.com/0xQuinto/dossier.git
cd dossier
python3 -m venv .venv
.venv/bin/pip install -e ".[dev]"
.venv/bin/pytestWindows note: bare
pythonoften resolves to the Microsoft Store stub, which exits with code 49 and prints "Python was not found" instead of running. Install real Python 3.12+ (winget install Python.Python.3.12or python.org), create the venv with it, and call the venv interpreter by path (.venv\Scripts\python.exe). SetPYTHONUTF8=1to avoid cp1252 mojibake in localized (non-English) Windows shells.
MIT. See LICENSE.