Work · Independent · Apr 2026–present

A GTM data stack from scratch

I built a revenue and GTM data stack from scratch and ran it in production: five ATS APIs re-checked at the source, technology detection from first-party signals, enrichment that quarantines unverified rows, and a thirteen-prompt LLM pipeline that drops any claim it cannot trace to the source page.

Problem

Vendor lists go stale. Cached indexes keep filled roles listed as open. A no-code canvas stops at the endpoint the vendor did not expose. Language models invent a CRM that was never on the page. I had already watched an extractor of mine read a truncated job description and almost report the wrong CRM into a live campaign.

Constraints

Production, not a demo. Every row needs a source. Unverified contact data does not ship. The operator, not the model, accepts the send. Built with Claude Code and Cursor as daily tools — custom skills, subagents, MCP integrations — with the rule that what an agent may settle without a human is decided up front.

What shipped

Numbers

351 companies live at the ATS. 456 contacts. 219 companies. 5,000+ accounts through the LLM pipeline. 13 prompts. Five ATS APIs. About 1,500 lines against the sending API.

Stack

Python, TypeScript, Next.js, React, Playwright, Clay CLI, Instantly, DNS and response-header fingerprinting, Anthropic Claude API, MCP.

Guardrail

Extractors abstain when confidence is low. Every row carries its evidence. A vendor name in copy is not an install. A truncated page is not a CRM. The human signs off where the agent would guess.