System Architecture
Overview
The system operates as a hub-and-spoke model with HubSpot as the central hub and five AI agents as spokes. Every agent reads from HubSpot (contact data, lifecycle stage, engagement history) and writes back to HubSpot (activity logs, score updates, stage transitions). The BDR team interacts with the system through HubSpot + Five9.
Data Flow
flowchart TD
subgraph sources ["Marketplace Data Sources"]
SmartScout["SmartScout API\n(Amazon sellers)"]
Walmart["Walmart Catalog"]
end
subgraph enrichment ["Enrichment Pipeline"]
EA["Enrichment Agent\n(AgentCore Runtime)"]
Scoring["Lead Scoring Engine\npayout_pain_score 0–100"]
end
HubSpot[("HubSpot CRM\ncentral hub")]
subgraph outreach ["Outreach Agents (AgentCore Runtime)"]
EmailA["Email Agent\nSES sequences"]
VoiceA["Voice Agent\nRetell AI calls"]
LinkedInA["LinkedIn Agent\nconnection + DMs"]
end
subgraph channels ["Seller Touch Points"]
Inbox["Seller Inbox"]
Phone["Seller Phone"]
LinkedIn["Seller LinkedIn"]
end
subgraph outcomes ["Engagement Outcomes"]
Reply["Reply / Click"]
Transfer["Transfer / Callback"]
Accept["Accept / Reply"]
end
Five9["Five9\nBDR Queue"]
Demo["Demo Booked\n→ Deal Created"]
sources --> EA
EA --> HubSpot
HubSpot --> Scoring
Scoring -->|"score > 40 → enroll"| EmailA
Scoring -->|"score > 70 → call first"| VoiceA
Scoring --> LinkedInA
EmailA --> Inbox --> Reply
VoiceA --> Phone --> Transfer
LinkedInA --> LinkedIn --> Accept
Reply & Transfer & Accept --> HubSpot
HubSpot --> Five9 --> Demo
HubSpot Configuration
Custom Properties (Contact Level)
-
marketplace— enum: amazon, walmart, both -
estimated_annual_revenue— number -
seller_storefront_url— string -
primary_category— string (top product category) -
seller_since— date -
payout_pain_score— number (0–100, calculated by Enrichment Agent) -
trigger_event— enum: scaling_ads, payment_hold, seasonal_prep, new_launch, expanding_marketplace, none -
ai_enrichment_date— date (last enrichment run) -
ai_email_sequence— enum: cash_flow_calculator, seasonal_trigger, payment_hold_recovery -
ai_call_status— enum: not_called, attempted, connected, transferred, callback_scheduled, not_interested -
ai_call_summary— text (Retell AI conversation summary) -
source_channel— enum: email, voice, linkedin, paid_ad, organic_content, referral
Lifecycle Stages
-
raw_lead— Scraped/imported, not yet enriched -
enriched— Enrichment Agent has scored and validated -
in_sequence— Active in email/voice/LinkedIn outreach -
engaged— Replied to email, answered call, accepted LinkedIn connection -
qualified— AI has confirmed fit (revenue range, marketplace, interest) -
bdr_handoff— Transferred to BDR queue in Five9 -
demo_scheduled— Demo booked -
opportunity— In active sales process -
customer— Signed up -
disqualified— Wrong fit, not interested, do not contact
HubSpot Workflows
-
Auto-enroll in email sequence: When lifecycle stage moves to
enrichedandpayout_pain_score> 40 -
Trigger voice agent: When email sequence completes with no reply, or when
payout_pain_score> 70 (high-priority, call first) -
BDR alert: When AI voice agent completes a warm transfer or when email reply is classified as "interested"
-
Multi-channel escalation: email (no reply after sequence) → voice (no connect after 3 attempts) → LinkedIn (connection request)
-
Re-engagement: Contacts in
engagedstage with no activity for 30 days re-enter a nurture sequence -
Reporting: Daily digest of pipeline metrics to team Slack/email
AWS Architecture
Runtime Philosophy: AgentCore-First
The five AI agents are deployed on Amazon Bedrock AgentCore Runtime — not as Lambda functions. This is the foundational architectural decision.
Lambda functions were considered first but fall short for agent workloads in several ways: * 15-minute hard timeout — agents like the Enrichment Agent or LinkedIn Agent need to run for hours, not minutes * No built-in session management — tracking multi-turn context, sequence position, and cooldowns requires manually wiring DynamoDB state in every function * No native memory — cross-session persistence (e.g., "what emails have we sent to this contact?") has to be custom-built * No built-in credential management for outbound third-party services (LinkedIn, HubSpot, Retell) * No tracing at the agent reasoning level — CloudWatch shows function execution but not why the agent made a decision * No multi-agent coordination protocol — agent-to-agent handoffs require manual SQS/Step Functions wiring
AgentCore Runtime solves all of these natively: * Runs agents in isolated microVMs with up to 8-hour session lifetime * True session isolation — CPU, memory, and filesystem isolated per session * Versioned deployments with stable endpoint ARNs and zero-downtime rollouts * Supports any framework: LangGraph, Strands, CrewAI, LlamaIndex * Supports A2A (Agent-to-Agent) protocol for direct inter-agent communication * Supports MCP so Lambda-backed tools are accessible to agents without custom plumbing * Native OpenTelemetry observability — trace every reasoning step, not just function duration
Lambda’s role in this architecture is the tool layer — short, stateless utility functions that agents call as tools via AgentCore Gateway. Lambda is the right fit for: webhook receivers, SES sends, HubSpot CRUD, Retell API calls, email verification, and EventBridge trigger dispatchers. Lambda is not the right fit for running the agents themselves.
AgentCore Runtime: The 5 AI Agents
Each agent is a containerized Python application deployed to an AgentCore Runtime endpoint. The agent’s reasoning loop (LLM calls, tool selection, memory reads/writes) runs inside AgentCore. Tools are invoked via AgentCore Gateway → Lambda.
flowchart LR
subgraph triggers ["Triggers"]
EB["EventBridge\nschedules"]
HSwh["HubSpot Webhook"]
Vercel["Vercel Webhook"]
end
subgraph agentcore ["Bedrock AgentCore Runtime"]
EP["AgentCore Runtime\nEndpoint"]
subgraph services ["AgentCore Services"]
Mem[("AgentCore Memory\nsession context\ncross-agent state")]
Browser["AgentCore Browser\nNova Act / Playwright\nCDP over WebSocket"]
Gateway["AgentCore Gateway\nLambda-backed MCP tools"]
end
EP <--> Mem & Browser & Gateway
end
subgraph tools ["Lambda Tool Functions"]
HSTool["tool-hubspot-read/write"]
SESTool["tool-ses-send"]
RetellTool["tool-retell-call"]
ScoutTool["tool-smartscout"]
WalmartTool["tool-walmart-scraper"]
end
triggers --> EP
Gateway --> HSTool & SESTool & RetellTool & ScoutTool & WalmartTool
| Agent | AgentCore Runtime Name | Framework | Schedule / Trigger |
|---|---|---|---|
Enrichment Agent |
|
Strands or LangGraph |
EventBridge daily 2am ET |
Email Agent |
|
Strands or LangGraph |
EventBridge every 15 min + SES inbound webhook |
Voice Agent Orchestrator |
|
Strands |
EventBridge every 30 min (Tue–Thu) + Retell webhook |
LinkedIn Agent |
|
LangGraph |
EventBridge every 2 hours |
Content Agent |
|
Strands or LangGraph |
EventBridge weekly Monday 6am ET |
Each AgentCore Runtime:
* Is deployed as a Docker container (Python 3.12, bedrock-agentcore SDK + framework deps)
* Has a DEFAULT endpoint ARN that EventBridge/webhooks invoke via InvokeAgentRuntime
* Creates a new versioned snapshot on every deployment (instant rollback available)
* Runs each scheduled invocation as an isolated microVM session
AgentCore Services Used
AgentCore Memory
Replaces the manual DynamoDB state-tracking pattern for agent context. Each agent has both short-term and long-term memory stores:
| Memory Store | Scope | Used By | What It Holds |
|---|---|---|---|
|
Long-term |
Enrichment Agent |
Which sellers scraped, enrichment timestamps, score history |
|
Long-term |
Email Agent |
Per-contact sequence position, send history, reply history, suppression state |
|
Long-term |
Voice Agent |
Call attempt history, callback schedules, outcome per contact |
|
Long-term |
LinkedIn Agent |
Per-profile daily action counts, per-contact sequence step, acceptance status |
|
Long-term |
Content Agent |
Published articles, keyword coverage map, scheduled drafts |
|
Long-term, shared |
All 5 agents |
Canonical lead status readable by any agent — prevents duplicate outreach across channels |
Short-term memory (active session context) is managed automatically by AgentCore per runtimeSessionId.
AgentCore Browser
The browser infrastructure for tasks that genuinely require a browser — primarily LinkedIn enrichment, seller domain enrichment, and LinkedIn outreach actions. Both Nova Act (primary) and Playwright (fallback) connect to AgentCore Browser over a secure WebSocket/CDP connection. There is no self-managed headless Chrome, no Lambda Chromium layer, no ECS Fargate browser farm.
Not used for Walmart catalog scraping. Walmart seller pages are static HTML and are scraped with httpx in Lambda (pennies per crawl vs ~$0.02/page with a browser agent). AgentCore Browser is reserved for tasks where the page is JS-heavy or the structure is unpredictable — conditions that don’t apply to a structured catalog crawl. See the Walmart scraping tier table below.
How it works: . Agent opens an AgentCore Browser session . AgentCore Browser provisions an isolated, containerized cloud browser . Nova Act (primary) or Playwright (fallback) connects to it via WebSocket/CDP . Browser session runs up to 8 hours; recordings stored in S3 via AgentCore
Browser execution pattern (Nova Act primary → Playwright fallback): For tasks routed to AgentCore Browser, Nova Act is tried first. If Nova Act escalates (CAPTCHA, unknown UI state, timeout), the agent retries with Playwright on the same (or fresh) AgentCore Browser session.
sequenceDiagram
participant A as Agent
participant B as AgentCore Browser
participant NA as Nova Act (primary)
participant PW as Playwright (fallback)
participant S3 as S3 (recordings)
A->>B: start browser session
B->>NA: connect via CDP
NA->>B: execute task
alt success
B-->>A: task result
else CAPTCHA / unknown UI / timeout
B->>PW: connect via CDP (same session)
PW->>B: retry same task
B-->>A: task result
end
B->>S3: session recording (DOM + actions + network)
Walmart seller scraping — 3-tier cost-optimized approach: Nova Act at $4.75/hour makes it cost-prohibitive for high-volume catalog crawls. A 10,000-page initial pass at 15 seconds/page = ~$200 in browser compute. Walmart pages are structured HTML, so AI reasoning adds no value at that volume.
| Tier | Method | Cost | When Used |
|---|---|---|---|
1 (primary) |
|
~$0.000002/page |
All pages; standard static HTML |
2 (secondary) |
Playwright → AgentCore Browser (CDP) |
Low |
Tier 1 returns |
3 (last resort) |
Nova Act → AgentCore Browser |
~$0.02/page |
Tier 2 fails; unknown layout or CAPTCHA |
Log scrape_executor: httpx | playwright | nova_act per page to AgentCore Memory. A spike in Tier 2/3 activation rate signals a Walmart HTML change that warrants updating the Tier 1 selectors.
Key AgentCore Browser features used: * Persistent browser profiles — LinkedIn session cookies stored as a persistent profile per BDR account; no manual Secrets Manager cookie rotation on every task * Proxy routing — built-in proxy configuration for Playwright fallback path; no external proxy service needed * Live View — real-time session monitoring via AgentCore console for debugging * Session recording — DOM changes, actions, and network events logged to S3; used for compliance and debugging
AgentCore Gateway
Exposes Lambda-backed tool functions to agents via MCP-compatible endpoints. Agents call tools using natural language tool names; Gateway handles routing, auth, and rate limiting.
Lambda functions wrapped as Gateway tools:
| Tool Name (MCP) | Lambda Function | Purpose |
|---|---|---|
|
|
Create or update HubSpot contact |
|
|
Read contact properties and lifecycle stage |
|
|
Create BDR task or alert in HubSpot |
|
|
Move contact to new lifecycle stage |
|
|
Send email via SES from selected mailbox |
|
|
MX + SMTP email verification |
|
|
Trigger Retell AI outbound call |
|
|
Query SmartScout API for seller data |
|
|
httpx + BeautifulSoup HTML scrape of a Walmart seller page (Tier 1); returns |
|
|
Check email/voice suppression lists |
Gateway wraps each Lambda with a stable MCP endpoint. Agents never call Lambda ARNs directly.
AgentCore Identity
Manages all outbound credentials for agents. Replaces manual Secrets Manager lookups scattered across Lambda functions.
-
LinkedIn sessions — stored as persistent browser profiles in AgentCore Browser (user-delegated per BDR account)
-
HubSpot private app token — autonomous credential; retrieved by Gateway tools at invocation
-
Retell AI API key — autonomous credential for Voice Agent
-
SmartScout API key — autonomous credential for Enrichment Agent
-
SES SMTP credentials — autonomous per-mailbox credentials for Email Agent
-
Anthropic Claude API key — autonomous credential; shared across all agents
AgentCore Observability
Replaces Lambda-level CloudWatch logs with agent-level reasoning traces.
-
Every agent invocation produces an OpenTelemetry trace: each reasoning step, tool call, memory read/write, and browser action is a span
-
Traces visible in AgentCore console and forwarded to CloudWatch for unified dashboards
-
Per-agent dashboards: tool call success rates, memory hit/miss rates, browser task escalation rate, session duration
-
Alert thresholds: tool error rate > 5%, browser escalation rate > 10%, agent session timeout
AgentCore Policy
Guardrails on tool access to prevent agents from taking out-of-bounds actions:
-
Email Agent: cannot invoke
retell_trigger_callorhubspot_update_stagetobdr_handoff— only the Voice Agent can do that -
LinkedIn Agent: daily action count caps enforced at Policy layer (not just DynamoDB counters)
-
Content Agent: cannot write to HubSpot contacts — read-only access to
hubspot_get_contact -
All agents: cannot update contacts in
customerordisqualifiedstage
Lambda Functions (Tool Layer)
Lambda’s role is limited to short-lived, stateless utility executions invoked via AgentCore Gateway or directly by webhooks/EventBridge. Python 3.12 runtime. No agent reasoning logic lives in Lambda.
Tool functions (invoked via AgentCore Gateway):
* tool-hubspot-read — Read-only HubSpot contact/deal queries
* tool-hubspot-write — Create/update contacts, deals, tasks, lifecycle stages
* tool-ses-send — Send email via SES with mailbox rotation logic
* tool-ses-verify — MX + SMTP email address verification
* tool-retell-call — Trigger Retell AI outbound call via Retell API
* tool-smartscout — Query SmartScout API for Amazon seller data
* tool-walmart-scraper — Tier 1 Walmart seller page scraper; httpx + BeautifulSoup; returns structured JSON or needs_browser flag if page requires JS rendering. Costs ~$0.000002/page vs ~$0.02/page for browser-based approaches.
* tool-suppression — Read/write DynamoDB suppression and rate-limit tables
Webhook receivers (invoked directly, not via Gateway):
* webhook-ses-inbound — Receives inbound email via SES receipt rules → SNS → Lambda; pushes to Email Agent’s AgentCore Runtime endpoint
* webhook-retell — Receives Retell AI call completion events from Vercel → forwards to Voice Agent’s AgentCore Runtime endpoint
* webhook-hubspot — Receives HubSpot workflow triggers → dispatches to appropriate agent endpoint
EventBridge dispatchers (thin triggers only):
* dispatch-enrichment — Invoked by EventBridge; calls InvokeAgentRuntime on the Enrichment Agent endpoint
* dispatch-email-sender — Invoked by EventBridge every 15 min; calls Email Agent endpoint with send trigger
* dispatch-voice — Invoked by EventBridge every 30 min; calls Voice Agent endpoint
* dispatch-linkedin — Invoked by EventBridge every 2 hours; calls LinkedIn Agent endpoint
* dispatch-content — Invoked by EventBridge weekly; calls Content Agent endpoint
These dispatcher Lambdas are intentionally trivial — they exist only because EventBridge cannot invoke AgentCore Runtime endpoints directly. Each is under 20 lines of code.
Data Stores
-
AgentCore Memory — Primary store for all agent context, sequence state, and cross-agent shared lead status (see AgentCore Services section above)
-
DynamoDB — Used for operational data that AgentCore Memory is not suited for: per-mailbox email send quotas (checked at high frequency with atomic counters), SES bounce/complaint suppression lists, raw scrape deduplication keys, call attempt logs with timestamps
-
S3 — Generated content assets, email templates, call recordings (from Retell + AgentCore Browser), prospect list exports, content drafts pending review
-
SES — Transactional and cold outbound email (15 mailboxes across 5 domains; see email-agent.md)
EventBridge Schedules
All schedules invoke thin Lambda dispatcher functions which call InvokeAgentRuntime on the appropriate AgentCore endpoint.
-
Enrichment Agent: Daily at 2am ET
-
Email Agent (send trigger): Every 15 minutes, 8am–6pm ET Mon–Fri
-
Voice Agent: Every 30 minutes, 9am–5pm ET Tue–Thu
-
LinkedIn Agent: Every 2 hours, 7am–9pm ET Mon–Fri
-
Content Agent: Weekly on Monday at 6am ET
-
Lead scoring refresh: Every 6 hours (Enrichment Agent endpoint, scoring-only mode)
-
HubSpot sync check: Every 5 minutes (lightweight Lambda, no AgentCore session needed)
Vercel Deployment
Frontend Applications
-
Marketing site / Landing pages: Next.js app with dynamic pages for each ad campaign. Server-side rendering for SEO. Deploy on Vercel with automatic previews for each PR.
-
Cash Flow Calculator: Interactive React component embedded in landing pages. Takes monthly revenue as input, calculates locked capital, shows daily payout benefit. Captures email on results page → pushes to HubSpot.
-
Demo Booking Page: Embedded Calendly or custom scheduling component connected to BDR calendars in HubSpot.
API Routes (Vercel Serverless Functions)
-
/api/webhook/hubspot— Receives HubSpot workflow webhook triggers, dispatches to appropriate AWS agent -
/api/webhook/retell— Receives Retell AI call completion events, updates HubSpot -
/api/webhook/ses— Receives SES email events (bounces, complaints, deliveries) -
/api/calculator/submit— Handles cash flow calculator submissions, creates HubSpot contact -
/api/content/preview— Previews AI-generated content before publishing
Security & Compliance
-
Credentials: All outbound credentials (HubSpot token, Retell API key, Claude API key, SES credentials) managed by AgentCore Identity — never stored in Lambda environment variables or hardcoded in agent code.
-
Session isolation: Each AgentCore Runtime session runs in a dedicated microVM with isolated CPU, memory, and filesystem. No cross-session data leakage.
-
Browser isolation: Each AgentCore Browser session is ephemeral and isolated. Session memory is sanitized after termination.
-
Tool-level access control: AgentCore Policy guardrails enforce which tools each agent can access and under what conditions. Agents cannot exceed their defined scope.
-
SES sending domains: SPF, DKIM, and DMARC configured on all 5 sending domains.
-
TCPA compliance: Retell AI calls restricted to permitted hours via Voice Agent’s scheduling logic and AgentCore Policy guardrails on the
retell_trigger_calltool. -
PII handling: All prospect data stored in HubSpot (source of truth). AgentCore Memory stores behavioral context (sequence position, call outcomes) — not raw PII. DynamoDB stores suppression keys (hashed emails, phone hashes) — not plaintext.
-
Inbound auth: AgentCore Runtime endpoints protected via AWS IAM (SigV4) — only dispatcher Lambdas and webhook handlers with correct IAM roles can invoke agent endpoints.
Monitoring & Alerting
-
Agent reasoning traces: AgentCore Observability provides step-level OpenTelemetry traces for every agent invocation — visible in AgentCore console and forwarded to CloudWatch. Alert if any agent tool error rate exceeds 5%.
-
Browser automation: AgentCore Browser metrics in CloudWatch — session success rate, Nova Act escalation rate (alert if >10% for any agent), Playwright fallback activation rate. Session recordings in S3 for debugging.
-
Pipeline health: Daily HubSpot report showing leads by lifecycle stage, conversion rates, and pipeline velocity.
-
Email deliverability: SES reputation dashboard. Alert if bounce rate exceeds 2% or complaint rate exceeds 0.1% — auto-pause affected mailbox via Email Agent policy.
-
Voice agent: Retell AI dashboard for call completion rates, average duration, transfer rates. Alert if completion rate drops below 50%.
-
Lambda tool health: CloudWatch alarms on tool Lambda error rates and duration. These are short utility functions — any error rate > 1% warrants investigation since agent quality degrades immediately when tools fail.
-
Cost monitoring: AWS Cost Explorer alerts if daily spend exceeds 150% of expected. AgentCore Runtime, AgentCore Browser, and Lambda tool invocations all contribute to cost — monitor separately.