Agentic BD,
built end to end.
Two AI systems replaced 39 hand-run HubSpot cadences, one drafts outbound overnight, one answers reps live in Slack. A human still approves every send. Since then the drafting agent learned to target whole accounts and work two channels at once, with four more systems built up around it.
Agentify the outbound motion that already worked. That was the brief.
39 HubSpot cadences were already live. The team's ask was narrow on paper: keep what worked, hand the repeatable part, research, scoring, drafting, to an agent, so reps spend their time on the reply instead of the write-up. It didn't stay that size for long. Account-level targeting, a second channel, a reporting layer Apollo's own sync couldn't produce, none of it existed yet, so it got built from scratch alongside the agent work, plus whatever contingency a live system throws at you once reps depend on it daily.
Foundation before sequence agents.
The original plan jumped straight to sequence agents. Auditing all 39 cadences showed the order was wrong: without viability scoring and triage, agents personalize emails to the wrong people. Foundation first.
Viability Scoring
Every company scored Red / Yellow / Green overnight. Reps know where to spend Apollo credits.
Cold-Lead Triage
New contacts auto-routed nightly, hobbyists to DevRel, technical titles to Sales. No noise in Sales views.
Contact Enrichment
Phone, mobile, LinkedIn filled on working contacts only. A timestamp stops credits burning on re-checks.
Draft Pre-Population
An agent writes a personalized draft into the CRM overnight. Reps review and approve instead of writing cold.
The Stark Agent.
Fork or star the repo at 2am. By morning a researched, personalized draft is waiting in the CRM, a rep only has to approve it.
A signal comes in, four sources get researched, Claude turns that into a hook and a confidence score, and the draft writes back to HubSpot with a 4-step Apollo cadence queued behind it. The SDR reviews in Slack and sends, the agent never touches a mailbox.
A drafted email is worthless if it lands in spam. So the send path sits on infrastructure I built and monitor: an email-validation layer that verifies every address before enrollment, and a TrulyInbox warmup monitor that ramps sender reputation and watches inbox placement across the sending pool in real time.
The engineering underneath
Research pulls GitHub (repos, forks, pinned via GraphQL), Firecrawl (company tone), Reo.dev (fit), LinkedIn (title). Email writes 3 subject variants and runs a humanness gate that rejects generic openers and regenerates once. Claude falls back to Gemini on auth errors, rate limits, or malformed JSON.
5 dedup guardrails run before any draft: do-not-contact flag · already in HeyReach · already in a live Apollo sequence (checked live) · AI review already pending/sent · prior verified send.
3 scheduled jobs on Cloud Run keep it self-healing: cadence scheduler (08:00 IST daily) · reply poller (every 4h, Apollo has no webhook) · reconcile sweep (06:00 IST nightly, syncs drift when an SDR edits Apollo directly).
Deliverability is its own layer: addresses run through a validation service before enrollment, and a warm-up system ramps sender reputation with SPF / DKIM / DMARC aligned and inbox placement monitored, so volume scales without tanking the domain.
Stark ABM — from developer signal to account.
One engineer forking the repo is a signal. Three engineers at the same company forking it is intent. A second branch off the same codebase, internally called Stark ABM, groups fork/star developers by employer, keeps only accounts with a team-level signal, and finds the whole buying committee through Apollo instead of emailing one developer and hoping. It stages drafts to Slack for SDR review, no autonomous enrollment yet, until the account-level scoring earns the trust the fork/star pipeline already has.
Every account gets one email thread and one LinkedIn thread, sequenced so neither channel steps on the other, an SDR still sends both from Apollo and HeyReach.
The ABM + omnichannel engineering
Fit scoring rejects false-positive decision-makers a title alone would catch, e.g. an Apollo contact titled “Founder” who is actually running the website, by scoring seniority tier, function (engineering scores well, sales/marketing/HR don't), deliverability, and geography together. Territory routing assigns the SDR and sending mailbox off the company's HQ, not the developer's personal location, and fails safe to one legacy mailbox on any lookup error rather than misrouting silently.
A real precedence bug, caught before it shipped wide: the existing dedup guard counted every LinkedIn touch as reason to block further email, which would have permanently frozen email steps 3–5 for every omnichannel lead, since step 1 of the ladder is itself a LinkedIn touch. Channel precedence now keys off its own per-lead state instead of the shared touch counter.
Two incidents that changed the code: a developer unsubscribed after an email asserted he'd forked the repo when he'd only starred it, so every fork claim is now verified against the GitHub API before an email can make it, downgrading to the safer “starred” copy when unproven. Separately, an Apollo reply alert in Slack linked to a dead contact because the handler built the URL from an unresolved merge-var token instead of the live contact id, resolved live by email instead, so the link is never wrong on a reply again.
Bounce recovery: when MillionVerifier flags an address invalid mid-cadence, the agent now tries an Apollo people-match on name + org + LinkedIn for a replacement, re-verifies it, and swaps in automatically instead of holding the lead, live-tested against 21 real bounced contacts.
Funnel visibility: a 5-stage funnel (identified → contactable → drafted → enrolled → replied) snapshots to Postgres on every run, built to answer a leadership question about fork/star-to-pipeline conversion that nobody could answer from HubSpot alone; building it surfaced that Reo's own segment API never populates a field the team assumed was reliable.
Signal sourcing widened from one repo to 10 complementary ecosystem repos (LangChain, LlamaIndex, CrewAI, AutoGen, and others), explicitly excluding direct competitors' repos to avoid poaching optics. Security hardening shipped alongside: request-size caps, an internal OIDC auth tier, a shared-token guard on the Apollo webhook, per-run LLM budget caps, prompt-injection sanitization, scrubbed error responses, a CORS allowlist, a non-root container image, and a CI test gate before any deploy.
The GTM Copilot, Iris.
A rep asks in Slack, “who's worth reaching out to this week?”, and Iris researches, checks the CRM, and drafts, without anyone leaving the thread.
A LangGraph ReAct agent decides which of 15 tools to call, remembers the thread so follow-ups don't re-run expensive searches, and shares its research + email code with the Stark Agent, so live answers and the overnight pipeline never disagree about the same developer. The same tool suite is now re-exposed over an authenticated MCP server, so Claude Code, Claude Desktop, and claude.ai connectors call it directly, no Slack round-trip.
The engineering underneath
MCP server: the whole 15-tool suite is re-exposed over an authenticated MCP server, so Claude Code, Claude Desktop, and claude.ai connectors run the same tools with no Slack round-trip. Dual auth in one gate, a static bearer and full WorkOS AuthKit OAuth 2.0 (JWKS RS256 verify, protected-resource discovery, tenancy gate by org / email domain), and the server fails closed, it refuses to start unauthenticated.
Call intelligence: search_calls and get_lead_timeline run hybrid retrieval over recorded-call summaries, Postgres full-text and pgvector fused with reciprocal-rank, then a Voyage rerank pass. One timeline call merges Apollo touches, every call, and the live deal stage into a single dated view.
Reflection + self-correction: high-stakes output (deep research, drafted emails) gets a second pass from Claude Haiku, and on a wrong ordering or filter it triggers exactly one corrective re-run, e.g. re-running a call search sorted by recency, then footnotes the fix. It never edits the reply directly.
Latency: the system prompt is an ephemeral cache block (0.1× reads on every ReAct round-trip), orchestration rules fire parallel tool calls and prefer one merged timeline over ~20 serial lookups, and a Haiku / Sonnet difficulty cascade keeps the cheap turns cheap.
Write gate: the one line Iris can't cross alone is writing to HubSpot or Apollo. She stages the write; it only fires after a rep replies with a passphrase in-thread.
Runtime: Slack Bolt over Socket Mode, plus the MCP transport, on Cloud Run kept warm so a reply never waits on a cold start. Tool output is scrubbed for prompt injection before the model sees it, and per-user rate limits and a per-run LLM budget cap spend. Every question, tool call, and latency logged to Postgres to tune on what reps actually ask.
The systems around the systems.
Stark and Iris get top billing, but they don't report on themselves. A live dashboard pulls every cadence's real Apollo numbers into one place and answers questions about that data in plain English, “who replied this month, and what did they say?” gets a real answer, not a support ticket.
It doubles as the team's build log: what shipped, what's still a draft, and the exact next fix, in priority order, no separate status doc to keep in sync.
The data platform underneath.
HubSpot is the system of record, but it's surrounded by the sync jobs that keep Reo.dev, Apollo, and HubSpot agreeing with each other, a Postgres warehouse for call and docs retrieval, and a stack of gates whose whole job is to stop a bad email before it sends.
The design principle behind all of it: a gate that protects deliverability fails closed, a gate that only adds information fails open. Getting that direction right per gate is most of what keeps outbound both safe and running unattended.
The gates, in the order they matter
Bounce circuit breaker rates the delta in bounces since the last run, not lifetime history, so a stale number can't false-fire. Past the threshold, every send path returns held and freezes until a human re-arms it, and if the lock state itself is unreadable, it fails closed too.
Email verification runs cheapest checks first, syntax, role-account, disposable domain, then a live DNS lookup, and only then spends a paid verification credit, persisting the verdict so nothing gets re-checked needlessly.
Geo hold is reversible by design: a blocked-country contact is held, not deleted, and pulled from the send queue without ever being marked permanently unreachable, so a policy change later doesn't become a data-loss event.
Employer verification blocks current employees and competitors outright, and flags job-changers, where the email domain no longer matches the employer, to a digest instead of silently dropping them.
What's still open, tracked with an owner and a cause instead of quietly absorbed: the upstream Reo connector populates a key GitHub-handle field on only a fraction of contacts, backfilled downstream in the meantime, and the HubSpot private app's schema-write scope is too narrow to introspect the portal at all, so new properties still ship as one-off scripts instead of a reproducible project upload.
Four more systems sit alongside the data platform, sourcing leads and closing reporting gaps neither agent can see on its own.
Apollo → HubSpot Reporting
Apollo's own sync covers ~55% of email and 6% of calls, so reports built on it lie. A weekly aggregate custom object reads Apollo's analytics API directly: 198 records, 30 weeks backfilled, 3 native HubSpot reports, 0 Apollo credits spent.
Replicated → HubSpot Sync
Self-hosted install signals had nowhere to land in the CRM. An HMAC-verified webhook upserts Contacts and Companies by email/domain; the same keyed row doubles as the idempotency guard, so a retried delivery can't duplicate.
Conference Target Research
89 named speakers and self-announced attendees across 3 conferences, $0 spent, no scraping or logins, cross-matched against the existing ICP account list. 4 rounds deep, including a live agenda page a homepage summary had hidden 42 more speakers behind.
Devin-User Hunting
JD-scraping hit a measured ceiling (2,051 raw rows → 51 real companies, 26 of them one-hit wonders), so sourcing pivoted to GitHub bot-commit exhaust and Windsurf/Cognition ecosystem adjacency. 77 devin-tier accounts, 331 agentic-adjacent.
Autonomous and interactive, sharing a brain.

“Nik helped us set the defining agentic vision around our outbound motion over a rapidly expanding open-source project. By threading GitHub activity, custom email messaging, strong deliverability, and a refined UI into one, Nik helped our BD team manage outbound efforts and set the stage for enterprise expansion. Outbound strategy is changing, and Nik helped us set the course on agent-native outbound.”
Clarke Shipley · GTM Leader / Sales Development Director, OpenHands · LinkedIn ↗

Smit Patel, Fractional Exec at OpenHands. Ex-VP at Postman, ex-Datadog, ex-COO at Pieces. Ran the engagement with me. LinkedIn ↗
Available as a reference on request
The rep's job becomes review-and-approve.
← Back to the systems