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

  1. raw_lead — Scraped/imported, not yet enriched

  2. enriched — Enrichment Agent has scored and validated

  3. in_sequence — Active in email/voice/LinkedIn outreach

  4. engaged — Replied to email, answered call, accepted LinkedIn connection

  5. qualified — AI has confirmed fit (revenue range, marketplace, interest)

  6. bdr_handoff — Transferred to BDR queue in Five9

  7. demo_scheduled — Demo booked

  8. opportunity — In active sales process

  9. customer — Signed up

  10. disqualified — Wrong fit, not interested, do not contact

HubSpot Workflows

  • Auto-enroll in email sequence: When lifecycle stage moves to enriched and payout_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 engaged stage 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

marketplace-enrichment-agent

Strands or LangGraph

EventBridge daily 2am ET

Email Agent

marketplace-email-agent

Strands or LangGraph

EventBridge every 15 min + SES inbound webhook

Voice Agent Orchestrator

marketplace-voice-agent

Strands

EventBridge every 30 min (Tue–Thu) + Retell webhook

LinkedIn Agent

marketplace-linkedin-agent

LangGraph

EventBridge every 2 hours

Content Agent

marketplace-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

enrichment-context

Long-term

Enrichment Agent

Which sellers scraped, enrichment timestamps, score history

email-sequences

Long-term

Email Agent

Per-contact sequence position, send history, reply history, suppression state

voice-calls

Long-term

Voice Agent

Call attempt history, callback schedules, outcome per contact

linkedin-sequences

Long-term

LinkedIn Agent

Per-profile daily action counts, per-contact sequence step, acceptance status

content-calendar

Long-term

Content Agent

Published articles, keyword coverage map, scheduled drafts

cross-agent-leads

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)

tool-walmart-scraper Lambda — httpx + BeautifulSoup

~$0.000002/page

All pages; standard static HTML

2 (secondary)

Playwright → AgentCore Browser (CDP)

Low

Tier 1 returns needs_browser (JS-rendered page)

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

hubspot_create_contact

tool-hubspot-write

Create or update HubSpot contact

hubspot_get_contact

tool-hubspot-read

Read contact properties and lifecycle stage

hubspot_create_task

tool-hubspot-write

Create BDR task or alert in HubSpot

hubspot_update_stage

tool-hubspot-write

Move contact to new lifecycle stage

ses_send_email

tool-ses-send

Send email via SES from selected mailbox

ses_verify_email

tool-ses-verify

MX + SMTP email verification

retell_trigger_call

tool-retell-call

Trigger Retell AI outbound call

smartscout_query

tool-smartscout

Query SmartScout API for seller data

walmart_scrape_seller

tool-walmart-scraper

httpx + BeautifulSoup HTML scrape of a Walmart seller page (Tier 1); returns needs_browser flag if JS rendering is required

dynamo_check_suppression

tool-suppression

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_call or hubspot_update_stage to bdr_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 customer or disqualified stage


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

Edge Functions

  • Geolocation-based content personalization (show relevant case studies by region)

  • A/B test routing for landing pages

  • Bot detection for ad traffic quality

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_call tool.

  • 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.