Case study · Apr–May 2026
lead-gen-agent — multi-agent CLI
for B2B sales prospecting.
Four specialised Google ADK agents scan the top-100 German cities for owner-led EMS studios, extract contact data from imprint pages, and write qualified leads into a self-hosted Twenty CRM. Solo-built, in production, fail-soft by design.
- Stack
- Python 3.11+ · asyncio · uv
- Agent framework
- Google ADK 1.16+ · Gemini grounding
- CRM
- Twenty (self-hosted)
- Infrastructure
- Hetzner CX22 · €3.99/month
- 4 agents
- Find · Filter · Enrich · Write
- Top 100
- German cities (seeded shuffle)
- ~1.3k LOC
- Python 3.11+
- 27 runs
- production pipeline runs
01 · Situation
Classical lead lists were too coarse, too dirty, too expensive.
For the heysuma prospecting effort in the EMS segment we needed clean, owner-led studios with imprint-grade owner email — not generic "DACH fitness studios" purchased-list material. Lead vendors don't cover the long tail, and lists from 2024 are half-dead in 2026. So we built the research ourselves, agentically.
02 · Architecture
Four agents, one session state, structured hand-offs.
Rather than building one monolithic prompt, we chained four small,
focused ADK agents — a deliberate choice because ADK's
google_search tool can't coexist with other tools in
one agent instance. Hand-offs flow through typed Pydantic models and
a shared session state, not free text. Every transition is
deterministically testable, every error isolable.
03 · Outcome
27 production runs. Own CRM infrastructure for €3.99/month.
The agent has been running since April 2026 in regular batches, writing qualified leads into the Twenty CRM we operate ourselves on a €3.99 Hetzner VM — any number of users, full data sovereignty. Interrupted runs resume exactly where they stopped. We signed no external CRM licence and bought no lead list.
Agent topology
Four specialised agents. Cleanly separated responsibilities.
Built with the Google Agent Development Kit. Each agent has a tightly defined mandate, a Pydantic output schema, and can be tested, replaced or extended independently.
StudioFinderAgent
Searches with Gemini grounding for EMS studios in each city. Returns a structured candidate list — no free text, only Pydantic models.
ChainFilterAgent
Removes chains and franchise operations via blocklist plus LLM reasoning. Keeps the ICP filter (owner-led) intact.
StudioEnrichmentAgent
Visits each studio's imprint page, extracts owner, email, phone and full address. Robust against broken pages — fail-soft.
CRMWriterAgent
Local + remote dedup, writes Company → Person → Opportunity into Twenty CRM. Tenacity retries, clean logging on errors.
Engineering
Six decisions that make the tool dependable.
Self-hosting over CRM licences
Twenty CRM on a €3.99/month VM replaces classical CRM-SaaS licences — with unlimited users and full data sovereignty (GDPR, hosted in Germany).
Reentrant by design
An interrupted run resumes exactly where it stopped. Persistent state in state/progress.json, no duplicate writes.
Dry-run mode
With --dry-run, research and mapping run to completion without producing real CRM records. Payloads logged for inspection.
Structured hand-offs
Agents communicate only via Pydantic models (StudioCandidate, EnrichedStudio, CRMResult) and an ADK session state — every hand-off is deterministically testable.
Operational robustness
Twenty API schema changes, broken imprint pages or search rate-limits produce clean logging and skip, never a crash. Tenacity backoff plus rate-limiter.
Deterministic test samples
Seeded shuffle across all 100 cities yields representative, reproducible samples — dry-runs are comparable across iterations.
What this means for you
Agents as tools — not as gimmicks.
The lead-gen-agent shows that modern LLM agent frameworks like Google ADK are no longer a research project but production tools — when combined with classical engineering discipline: structured interfaces, idempotent pipelines, clean logging, cost-optimised infrastructure. We build such tools for you — prospecting pipelines, data enrichers, CRM integrations, workflow automation — in weeks, not months.