HAMMAD YOUSUF

AUTOMATION CASE STUDIES

5 min read · 2026-08-09

Building IBRAHIM: a B2B sales outreach agent running 150 touches a day

TL;DR

IBRAHIM is my production B2B sales outreach system: 11 specialised agents — prospecting, enrichment, drafting, cadence, follow-up, reply classification and CRM logging — orchestrated with Claude Code on a Python stack with Playwright and the Gmail API. It runs 150 personalised touches a day at a 21.8% reply rate. The design lesson: decompose outreach into narrow agents with explicit handoffs and hard deliverability guardrails, and keep a human gating every real conversation.

IBRAHIM is my autonomous B2B sales outreach system: 11 specialised agents that take a prospect from research through personalised first touch to follow-up and reply handling, running 150 outreach touches a day at a 21.8% reply rate. It is built with Claude Code on a Python stack, with Playwright for prospect research and the Gmail API for send and receive. This post is the build walkthrough — the agent decomposition, the orchestration between them, the guardrails that keep it from burning sender reputation, and the failure modes I hit on the way. If you are deciding between building something like this in-house or buying an AI SDR tool, this should give you a realistic picture of what building actually involves.

Why generic cold outreach tools plateau

Every send-infrastructure tool eventually hits the same ceiling: personalisation is a template with merge fields, follow-up is a fixed sequence with no judgment about whether a nudge makes sense, and nothing in the system knows when to stop. The result is outreach that is technically personalised and obviously automated — and prospects have learned to smell it. The insight behind IBRAHIM is that good outreach is not one task, it is a chain of distinct judgments: who is worth contacting, what is genuinely relevant to say to them, when to follow up, and when a reply needs a human. Each of those is a different job, so each got its own agent.

Decomposing outreach into 11 agents

The agents split along the natural seams of the work. Prospecting and research agents find and qualify targets against the ideal-customer profile. An enrichment agent gathers company context — what they do, recent activity, anything that makes a message specific rather than generic — using Playwright to research prospects the way a human SDR would with fifteen browser tabs. A drafting agent turns that enrichment into a message written for one recipient. A cadence agent owns timing and volume pacing. A non-response nudge agent decides whether a follow-up is warranted and drafts it in the context of the original thread. A reply classification agent reads inbound responses and routes them. A CRM logging agent records every touch, so the system's state lives in structured data rather than in an inbox. The handoffs are explicit: each agent consumes the previous agent's output as structured input, which means when a message is bad, I can see exactly which link in the chain failed — thin enrichment, weak drafting, or wrong targeting.

The command-centre layer

Autonomy without observability is how outreach systems destroy sender domains, so IBRAHIM has a command centre — a supervision layer where I see queued drafts, agent activity, and reply streams in one place. The autonomy boundary is deliberate: research, enrichment, drafting and logging run fully autonomously; sends run within hard rate and quality limits; and real conversations always gate through me. When the reply classifier flags genuine interest, that thread leaves the automated flow — a human closes, the machine prospects.

The build: stack and state

ONE TACTIC A WEEK

One tactic a week. No filler.

One correction to an earlier working title of this post: IBRAHIM is Python, not Node.js. The production stack is Claude Code orchestrating Python agents, Playwright for browser-based research, the Gmail API for send and receive, and a voice AI layer for spoken touchpoints. State between agent runs is persisted in structured storage rather than passed in memory — every prospect carries a record of every touch, draft and classification, which is what lets agents run on independent schedules and pick up exactly where the chain left off. The Gmail API integration handles both directions: outbound sends within pacing limits, and inbound polling that feeds the reply classifier.

Guardrails against burning the sender's reputation

Deliverability is the asset the whole system lives on, so the guardrails are hard limits, not suggestions. Volume is capped and paced across the day — 150 touches, never bursts. Bounces trigger automatic suppression: a dead address is never contacted again, and bounce-rate movement is watched because it is the earliest signal of list-quality rot. Every draft passes a personalisation-quality check before it can send; a message that reads templated or is under-supported by enrichment gets held for review instead of sent. Opt-outs are honoured immediately and permanently at the suppression layer, which also keeps the system aligned with anti-spam rules — low volume, genuine relevance, and instant opt-out handling are what separate outreach from spam, legally and practically.

Results, and what the numbers hide

The production numbers: 150 personalised touches a day, 11 agents live, 21.8% reply rate. The honest caveat is that a reply rate blends positive and negative responses — the operationally interesting part is what the classifier does next, sorting interest from polite decline from unsubscribe, and feeding that signal back into targeting. The volume number matters less than the fact that quality holds at that volume: the per-prospect enrichment step is the expensive part, in both LLM cost and time, and it is also the part that makes the reply rate possible. Cutting it to scale volume would be trading the system's actual advantage for a vanity number.

Lessons and tradeoffs

What I would tell anyone building this. First, autonomous personalisation still sounds robotic at the edges — the drafting agent is good when enrichment gives it something real to say, and stilted when it tries to manufacture relevance from thin data; the fix is holding thin-enrichment prospects back, not prompting harder. Second, running an LLM per prospect across enrichment, drafting and classification has real cost — decompose so your cheapest adequate model handles each step, and reserve the strongest model for drafting. Third, what broke early: bounce handling was reactive until it cost deliverability, which is why suppression is now automatic; and the first cadence logic followed up too eagerly, reading silence as an invitation instead of an answer. Every guardrail in the system is a scar from an early version. If you want the deeper architecture, the mission page covers the command centre in detail — and if you are weighing build versus buy: buy send infrastructure if outreach is a side channel; build the reasoning layer if outreach is core to how you grow.

Hammad Yousuf

AI Marketing Automation Engineer · Dubai, UAE

FAQ

Common questions

What language and framework does IBRAHIM run on?

Python, orchestrated with Claude Code, with Playwright for browser-based prospect research, the Gmail API for send and receive, and a voice AI layer for spoken touchpoints. State between agent runs is persisted as structured data so agents can run on independent schedules.

How does IBRAHIM personalise 150 sends a day without sounding templated?

A dedicated enrichment agent researches each prospect — company context and recent activity — before a separate drafting agent writes the message from that material. Prospects with thin enrichment are held back rather than sent generic copy, and a quality check gates every draft before send.

How is this different from tools like Instantly or Apollo?

Those are send infrastructure and lead databases — valuable, but the personalisation and follow-up logic is templated sequences. IBRAHIM is a reasoning layer: 11 agents making per-prospect judgment calls about targeting, message content, cadence and reply routing, with a human gating real conversations.

What happens when a prospect replies?

A reply classification agent reads the response and routes it: genuine interest leaves the automated flow and comes to me directly, declines and opt-outs update the suppression layer permanently, and neutral replies inform whether any further touch makes sense. Automated prospecting, human conversations.