Skip to content

Latest commit

 

History

1 Commit

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Mailo — Multi-Agent Email-Marketing System on Amazon Bedrock AgentCore

CI

A production-shaped multi-agent GenAI system: a thin LLM orchestrator coordinates three containerized domain specialists over the A2A (agent-to-agent) protocol, with zero-trust per-request identity, policy-as-code authorization, per-user long-term memory, and online LLM-as-judge evaluation.

Built on Amazon Bedrock AgentCore with the Strands agent framework and Claude Sonnet 4.5.

Scope. This is an engineering showcase of agent architecture — orchestration, identity, authorization, memory, and evaluation. The three backend integrations (Klaviyo send, Shopify products, analytics) are mock Lambda tools, and account-specific identifiers (account ID, Cognito pool, ARNs) are placeholders. Deploying requires your own AWS account + Cognito; the unit tests and CI run with no AWS.


What it does

Mailo turns a request like "Research Bloom Petal and plan a Valentine's campaign with subject lines and a send time" into a complete campaign plan. Rather than one monolithic prompt, it splits the work across a coordinator and three specialists, each owning a domain and its own tools:

  • orchestrator — validates the user, reads per-user memory, plans, and delegates over A2A. A pure planner with no direct tool/Gateway access.
  • brand_intel — brand profile, competitor benchmarks, campaign metrics.
  • content_gen — subject lines, tone adjustment, product-led copy.
  • campaign_planning — audience segments, send-time recommendations, and the send itself (Cedar-gated).

Architecture

flowchart TD
    U["User (Cognito JWT)"] -->|Bearer + Session-Id| O["Orchestrator<br/>HTTP · CUSTOM_JWT · per-request agent"]
    O <-->|per-user read/write| M["AgentCore Memory<br/>/users/{sub}/preferences · /facts"]
    O -->|A2A + M2M Bearer + workload token| BI["brand_intel"]
    O --> CG["content_gen"]
    O --> CP["campaign_planning"]
    BI -->|MCP| GW
    CG -->|MCP| GW
    CP -->|MCP| GW["MCP Gateway<br/>Cedar policy engine (ENFORCE)<br/>recipients &lt; 5000"]
    GW --> L1["Analytics (Lambda · mock)"]
    GW --> L2["Shopify (Lambda · mock)"]
    GW --> L3["Klaviyo send (Lambda · mock)"]
Loading

Full walkthrough — request lifecycle, the two-client identity model, A2A vs MCP, Cedar, memory isolation, observability, and evaluation — in docs/ARCHITECTURE.md.

Engineering highlights

Area What's implemented
Agentic orchestration Thin LLM planner fanning out to three specialists over the A2A protocol; a fresh per-request agent (no singletons) so each request has its own identity and memory scope
Zero-trust identity Two-client Cognito model; per-request M2M OAuth token minting; specialists exchange the inbound workload token for their own Gateway bearer; tenant identity comes from the validated JWT sub, never the request body
Prompt-injection hardening A2A tool surface whitelisted to list + senddiscover_agent is dropped so the model physically cannot fabricate a specialist URL
Policy-as-code authz Cedar policy enforced at the Gateway (recipients < 5000) — holds even if the model is jailbroken, because it lives outside the prompt
Per-user memory AgentCore Memory (USER_PREFERENCE + SEMANTIC strategies) namespaced per user, with defense-in-depth isolation
Evaluation Custom LLM-as-judge + built-in evaluators, sampling 25% of live traffic continuously
Tooling via MCP Specialists reach Lambda backends through an MCP Gateway — discovery, auth, and Cedar enforcement all at the boundary
Ops Zero-instrumentation OpenTelemetry → CloudWatch; multi-stage non-root Docker; AWS CDK IaC

Tech stack

Python 3.12 · Strands Agents · Amazon Bedrock (Claude Sonnet 4.5) · Bedrock AgentCore (Runtime · Gateway · Memory · Identity/Token Vault · Cedar policies · Evaluations) · A2A · MCP · Cognito · AWS CDK · OpenTelemetry · pytest · GitHub Actions.

Repo layout

mailo/
  app/
    orchestrator/       # HTTP planner: A2A client, memory, JWT identity (identity.py)
    brand_intel/        # A2A specialist + Analytics tool
    content_gen/        # A2A specialist + Shopify tool
    campaign_planning/  # A2A specialist + Klaviyo send tool (Cedar-gated)
  agentcore/            # AgentCore project spec (agentcore.json) + CDK
  policies/             # Cedar policy (permit_send.cedar)
  tools/                # MCP tool schemas (klaviyo / shopify / analytics)
  tests/                # unit tests (run with no AWS)
scripts/                # deploy + auth helper scripts
docs/ARCHITECTURE.md    # full system walkthrough + diagrams

Tests

The security-critical logic (JWT identity extraction, A2A tool whitelist) is unit-tested and runs without AWS:

pip install pyjwt pytest
pytest

CI (GitHub Actions) runs ruff + pytest on every push.

Deploying to your own AWS account

Requires AWS credentials, Bedrock model access (Claude Sonnet 4.5), and a Cognito user pool with a human + M2M app client. Replace the placeholder identifiers in mailo/agentcore/agentcore.json and mailo/agentcore/aws-targets.json, copy mailo/agentcore/.env.local.example to .env.local with your M2M client credentials, then:

cd mailo
agentcore deploy
bash ../scripts/wire_specialists.sh   # re-merge orchestrator → specialist URLs after deploy

The full deploy ritual and the IAM/Cedar ordering notes are in docs/ARCHITECTURE.md.

What I built vs. scaffolded

The AgentCore CLI scaffolded the project skeleton and CDK. The engineering I authored: the orchestrator and all three specialists, the A2A delegation + tool whitelist, the per-request M2M / workload-token identity flow, the JWT-sub tenant identity, the MCP client lifecycle, the Cedar authorization, the per-user memory integration, the evaluation rubric, the unit tests + CI, and the architecture documentation.

About

Multi-agent email-campaign system on Amazon Bedrock AgentCore — A2A + MCP, zero-trust identity, Cedar policies, LLM-as-judge evals

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages