Overview Workshop Introduction
DailiTech — Make it Simple 2026
Workshop · AI Track
Pick an 'AI' Brick
Learn how to add powerful AI features to your existing application — without rewriting a single line of existing code.
✓ Architecture ✓ Data Governance ✓ AI Agents ✓ Integration ✓ 4 hrs hands-on

The Story — Why We Are Building This

AI Brick Workshop Story
Click image to view full size

The Business Context

DailiTech is an e-commerce company. You are an engineer. The company has a working application: customers browse products, place orders, track purchases. All data lives in DynamoDB. The analytics team also has a Redshift data warehouse with historical trends, customer segments, and revenue analytics. Both systems are healthy and in production. Nobody wants to rewrite them.

The Request

One day the business team asks: "Can we have something that answers questions about our customers? Like, which segment is at risk? Who hasn't ordered lately? Can the AI even create an order for a customer who calls in?" The answer is yes — but not by rebuilding the application. The answer is the AI Brick pattern.

The Two Teams

Data Team (Producer)
"We own the Redshift warehouse. We publish curated, governed data. We approve who gets access."
AI / Engineering Team (Consumer)
"We build the AI agent. We subscribe to governed data. We connect AI to the existing app without touching it."

What You Will Build

Before: Working e-commerce app (no AI, no Redshift)

After: Same app + Redshift data warehouse + AI agent that reads analytics and can create orders, plugged in as /ai/ask endpoint

Existing Application API Gateway · Lambda DynamoDB (operational data) /products /orders /customers All existing routes unchanged Stack 0A + 0B · UNCHANGED Zero-ETL auto-sync Redshift DW ecommerce schema customer_360 view Orders · Customers AI reads from here ONLY Stack 0C · Analytics layer reads analytics only AI Brick · NEW POST /ai/ask → BFF Lambda AI Agent · AgentCore MCP AgentCore Runtime · Amazon Nova Bedrock Guardrails Reads analytics · Creates orders via existing /orders API (unchanged) Stack 3 + Stack 4 creates new orders via existing POST /orders API DynamoDB data syncs to Redshift via Zero-ETL · AI only reads Redshift · never touches DynamoDB directly
The AI Brick reads analytics from Redshift and acts through the existing API — both existing systems unchanged.
The AI Brick Concept: An AI Brick is not a replacement. It is an additive piece of architecture that you slot in beside existing systems. The existing API keeps running. The AI feature sits next to it. Pick it up, configure it, place it down.

Module 0 — Deploy the Existing Application

Duration
~20 min
Hands-On Level
Deploy stacks
Stacks
2 CloudFormation
Goal
Working app — no AI yet

In this module you deploy the existing e-commerce application — networking and the app itself. This is the "before" state: a real working API backed by DynamoDB, with no AI and no Redshift yet.

The data warehouse (Redshift) and governance layer (SageMaker) are deployed later in Module 2, when you start building the AI layer.

STEP 1 STEP 2 Stack 0A — Networking VPC & Subnets NAT Gateway · Internet Gateway Security Groups IAM Roles (all services) stack: aibrick-0a-networking Stack 0B — Application API Gateway · Lambda Functions DynamoDB Tables (orders, customers, products) S3 + CloudFront Webapp ✓ Working e-commerce app stack: aibrick-0b-application Module 0 result: working app only — Redshift + AI come in Module 2 & 3

2 CloudFormation stacks — networking first, then the application

Download Module 0 Templates

Download both YAML templates below, then deploy in order through the AWS CloudFormation console: Create Stack → Upload a template file.

Download stack-0a-networking.yaml Download stack-0b-application.yaml
01 Networking Foundation stack-0a-networking.yaml
Stack 0A - Networking
Stack 0A
VPC, Subnets, Gateways, Security Groups, IAM Roles

This stack creates the networking layer: VPC with public and private subnets, Internet Gateway, NAT Gateway for private subnet egress, Security Groups for ingress rules, and IAM roles and policies for all services.

Region: ap-southeast-1 (Singapore)

Deploy via AWS Console
AWS Console CloudFormation Create Stack Open →

Click Create stack, select Upload a template file, and upload stack-0a-networking.yaml.

Name your stack

Use stack name: aibrick-0a-networking

Accept defaults and deploy

Click through the next pages, then click Create stack at the end. Wait for status to become CREATE_COMPLETE.

02 E-Commerce Application stack-0b-application.yaml
Stack 0B - Application
Stack 0B
API Gateway, Lambda, DynamoDB, S3 Web App, CloudFront

This stack creates the working e-commerce application. It includes REST API Gateway, Lambda functions for product queries and order management, DynamoDB tables (products, orders, customers), and a static web app served via S3 + CloudFront.

Depends on: Stack 0A (values are fetched automatically via cross-stack exports)

No manual cross-stack values needed

Stack 0B fetches all networking values from Stack 0A automatically using CloudFormation cross-stack exports. The only parameter you set is ProjectName — just keep it the same as Stack 0A.

Deploy via AWS Console
AWS Console CloudFormation Create stack Upload template file Open →

Upload stack-0b-application.yaml and click Next.

Set the stack name and ProjectName

Stack name: aibrick-0b-application

Parameter ProjectName: leave it as aibrick (must match Stack 0A).

Click through to Create stack. Wait for CREATE_COMPLETE (~3 min).

Open the webapp from Outputs

Go to the Outputs tab of aibrick-0b-application. Copy the WebAppURL value and open it in a new browser tab.

You should see the AI Brick Shop with Products, Customers, and Orders tabs loading with real data. The API URL is automatically injected by the stack — no manual configuration needed.

Note the Outputs tab values

The Outputs tab shows WebAppURL (CloudFront) and ApiGatewayUrl (API endpoint). You don't need to copy these manually — later modules auto-detect them from CloudFormation. But it's good to know where they are.

📦 Redshift & SageMaker come later — in Module 2

The data warehouse (Stack 0C — Redshift) and governance layer (SageMaker Unified Studio — optional, manual setup) are set up in Module 2, when you begin building the AI layer. This keeps Module 0 clean — it only represents the existing application before any AI work.

Module 0 Checkpoint

Module 1 — Explore Your Application

Duration
~20 min
Stack
Stack 0B Outputs
Tools
curl / Postman
Goal
Understand the baseline app
Module 1 Architecture

Now that your infrastructure is deployed, let's explore the working e-commerce application. This is the "before" state — a fully functional API with no AI features yet. In later modules, you will add AI as a new layer on top.

The Application Architecture

The API is built on AWS Lambda and API Gateway. It exposes these endpoints:

Client curl / browser HTTP request HTTPS API Gateway GET /products POST /orders GET /customers/{id} REST API · prod stage ap-southeast-1 invokes Lambda Functions products-handler orders-handler customers-handler Python 3.12 3 functions · Stack 0B reads/writes DynamoDB aibrick-products · 30 items aibrick-orders · 200 items aibrick-customers · 50 items Source for Zero-ETL → Redshift On-demand · Stack 0B Existing application stack — all routes remain unchanged through Module 4
Your baseline e-commerce app (Stack 0B) — Client → API Gateway → Lambda → DynamoDB
Endpoint Method Purpose
/products GET List all products
/customers GET List all customers
/customers/{id} GET Get customer profile + their orders
/orders GET List all orders (newest first)
/orders POST Create a new order
/config GET App config (aiEnabled flag)

Test the API

Open CloudShell

All CLI commands in this workshop are run in AWS CloudShell. Open it from the AWS Console toolbar (top right, terminal icon) or use the link below.

AWS Console CloudShell Open →
Get your API endpoint
AWS Console CloudFormation Stacks Open →

Find the aibrick-0b-application stack. Open Outputs and copy the ApiGatewayUrl value (e.g., https://xyz.execute-api.ap-southeast-1.amazonaws.com/prod).

List products

Open your terminal and run:

# Auto-detect from CloudFormation, or replace manually from Stack 0B Outputs
export API_URL=$(aws cloudformation describe-stacks \
  --stack-name aibrick-0b-application --region ap-southeast-1 \
  --query "Stacks[0].Outputs[?OutputKey=='ApiGatewayUrl'].OutputValue" \
  --output text)

echo "API URL: $API_URL"

curl $API_URL/products

You should see a JSON array of 30 products in the ecommerce catalog.

Create a test order

Run:

curl -X POST $API_URL/orders \
  -H "Content-Type: application/json" \
  -d '{
    "customerId": "cust-001",
    "productId": "prod-001",
    "productName": "Electronics Item 1",
    "quantity": 2,
    "total": 39.99
  }'

The API creates the order in DynamoDB and returns the order details with a new orderId.

Check the DynamoDB tables
AWS Console DynamoDB Tables Open →

Browse the aibrick-products, aibrick-orders, and aibrick-customers tables and click "view table details" to see the actual data in each table.

Key Insight

This application is live and in production. Real customers are using it. The code is stable. You are not going to rewrite it. In the next modules, you will layer AI on top of it using the AI Brick pattern.

Explore the Webapp

Open the WebAppURL from Stack 0B Outputs in your browser. Try these:

Browse Products

Click any product card to see its details — price, stock level, category. There are 30 products across 5 categories.

Browse Customers

Click the Customers tab. Click any customer card to see their profile and recent orders. Notice the Gold/Silver/Bronze segments and total spend.

View Orders

Click the Orders tab. You will see 200 seeded orders with status badges (PLACED, SHIPPED, DELIVERED). Try the + Place Order button and scroll down to the end of order list to create a new order through the webapp.

Module 1 Checkpoint

Module 2 — Data Warehouse, Governance & Zero-ETL

Duration
~50 min
Stacks
0C + Zero-ETL Script
Tools
Redshift Query Editor V2
Goal
2 Redshift + Governance + Zero-ETL
Module 2 Architecture

This module builds the data foundation for AI. You will deploy two Redshift Serverless workgroups (Producer and Consumer), configure Zero-ETL from DynamoDB, and optionally set up SageMaker Unified Studio for data governance.

Architecture: 2 Redshift Serverless Workgroups

Producer Redshift — The Data Team's analytics warehouse with enriched data: customer segments, product performance, campaign history.

Consumer Redshift — The AI Team's warehouse with operational data (from DynamoDB via Zero-ETL) + subscribed analytics data from the Producer via SageMaker Catalog.

The AI Agent (Module 3) reads from the Consumer Redshift — which has both operational AND enriched data.

01 Deploy Two Redshift Serverless Workgroups + Zero-ETL stack-0c-datawarehouse.yaml
Stack 0C
Producer Redshift + Consumer Redshift + Zero-ETL

Creates two Redshift Serverless workgroups with different data and sets up DynamoDB Zero-ETL integration.

Download stack-0c-datawarehouse.yaml
Deploy via CloudFormation
AWS Console CloudFormation Create stack Upload template file Open →

Upload stack-0c-datawarehouse.yaml. Stack name: aibrick-0c-datawarehouse. Wait for CREATE_COMPLETE (~15-20 min).

Set up Zero-ETL (DynamoDB → Consumer Redshift)

Open CloudShell and run:

curl -sO https://aibrick-workshop-materials-594980084878.s3.ap-southeast-1.amazonaws.com/script/setup-zero-etl.sh
bash setup-zero-etl.sh

This sets resource policies on Redshift and DynamoDB, then creates Zero-ETL integrations. Takes ~2-3 min. The integrations will take 15-30 min to fully sync data.

Wait for integrations to become active

Check the status in CloudShell:

aws redshift describe-integrations --region ap-southeast-1 \
  --query "Integrations[?contains(IntegrationName,'aibrick')].{Name:IntegrationName,Status:Status}" \
  --output table

Wait until all 3 integrations show active status (~15-30 min). You can continue with other steps while waiting.

Create Redshift databases for Zero-ETL

Once integrations are active, open Redshift Query Editor V2:

AWS Console Redshift Query Editor V2 Open →

Steps:

  • For the first time access Redshift Query Editor V2 → Click Configure account
  • In the left sidebar, expand Serverless → click aibrick-consumer-wg
  • Click Create connection → select Temporary credentials using your IAM identity
  • Select any database (e.g., ecommerce) → click Create connection
  • Open a new query tab (click +)

Integration ID:

  • Integration ID can look up again in Amazon Redshift → Zero-ETL integrations → aibrick-{customers,orders,products}-zero-etl → Integration ID

The script output shows the exact SQL commands with your integration IDs. Copy and run each one:

-- Run each command one at a time
-- Replace the integration IDs with the ones from the script output
CREATE DATABASE aibrick_customers_db FROM INTEGRATION 'your-customers-integration-id';
CREATE DATABASE aibrick_orders_db FROM INTEGRATION 'your-orders-integration-id';
CREATE DATABASE aibrick_products_db FROM INTEGRATION 'your-products-integration-id';

After creating the databases, you can query the DynamoDB data in Redshift. Switch to one of the new databases and run:

-- Switch to the customers database and query
SELECT * FROM "aibrick_customers_db"."public"."aibrick-customers" LIMIT 10;
OPTIONAL SageMaker Unified Studio — Data Governance

These steps are optional. If you skip them, the AI agent in Module 3 will still work using the Redshift data loaded by Stack 0C. The instructor will demonstrate this flow during the session.

This section has 8 steps (A–H), all done manually in the AWS console and SageMaker portal. No CloudFormation stack needed.

Step A: Create the SageMaker Domain

Open SageMaker Unified Studio admin
AWS Console Amazon SageMaker Admin configurations Domains Open →
Create a new domain

Click Create domain.

  • Domain name: aibrick-domain
  • Under Single sign-on, select AWS IAM Identity Center (it should auto-detect your SSO instance)
  • Under Service role, select Create and use a new service role (or use an existing one if you have it)
  • Leave other settings as default
  • Click Create domain

Wait ~3-5 min for the domain to become Available. You will see the domain in the list once it is ready.

Step B: Enable Blueprints

Open the domain

Click on aibrick-domain in the domains list to open the domain details page.

Go to the Blueprints tab

Click the Blueprints tab. You will see a list of available blueprints.

Enable the Tooling blueprint

Find Tooling in the list. Click on it.

  • Click Enable blueprint (or Configure)
  • Under Enabled Regions, check ap-southeast-1
  • Leave Regional parameters empty
  • Click Save
Enable the RedshiftServerless blueprint

Go back to the Blueprints tab. Find RedshiftServerless. Click on it.

  • Click Enable blueprint
  • Under Enabled Regions, check ap-southeast-1
  • Click Save

Step C: Create a Project Profile

Go to the Project profiles tab

Still on the domain details page, click the Project profiles tab.

Create a new profile

Click Create project profile.

  • Name: Workshop
  • Description: Workshop profile (optional)
  • Under Environment configurations, click Add environment
  • Select Tooling
  • Leave Deployment mode as ON_CREATE
  • Click Create

The Workshop profile now includes Tooling. Any project created with this profile will have Compute capability.

Step D: Create Projects

Open the SageMaker portal

Go back to the domain details page. Copy the Domain URL (portal URL). Open it in a new browser tab. Click Sign in with SSO.

Create Producer project

Click Create project.

  • Name: Producer - Data Team
  • Description: Data Team - publishes analytics data (optional)
  • Project profile: select Workshop
  • Click Create

Wait ~1-2 min for the project to finish creating.

Create Consumer project

Go back to the home page. Click Create project again.

  • Name: Consumer - AI Team
  • Description: AI Team - subscribes to governed data (optional)
  • Project profile: select Workshop
  • Click Create

Wait ~1-2 min. Both projects now have Compute capability.

Verify Compute is available

Open either project. In the left sidebar, you should see a Compute section. If you see it, Tooling is working correctly.

Step E: Add Members to Projects

Add yourself as project member (if not already)

Open Producer - Data Team → click Members in the left sidebar.

  • If you are not listed, click Add member
  • Search for your SSO username → select it
  • Role: Project owner
  • Click Add

Repeat for Consumer - AI Team. This ensures you can manage data sources and subscriptions in both projects.

Step F: Get Redshift Credentials & Add Compute

Get the Redshift admin credentials from Secrets Manager, then add Redshift as a compute resource in each project.

Open Secrets Manager
AWS Console Secrets Manager Secrets Open →
Get Producer Redshift credentials

Find the secret that starts with redshift!aibrick-producer-ns (the exact name includes a random suffix).

  • Click on the secret name to open it
  • Scroll down to Secret value section
  • Click Retrieve secret value
  • Copy the username and password
  • Save both somewhere — you will need them below
Get Consumer Redshift credentials

Go back to the secrets list. Find the secret that starts with redshift!aibrick-consumer-ns.

  • Click on it → Retrieve secret value
  • Copy the username and password
Get your AWS Account ID

Open CloudShell and run:

aws sts get-caller-identity --query Account --output text

Copy the 12-digit account ID. You will use it in the JDBC URLs below.

Producer: Add Redshift compute

Go to the SageMaker portal. Open Producer - Data Team → click Compute in the left sidebar → Add compute → select Amazon Redshift Serverless.

  • Name: Producer-Analytics-RS
  • JDBC URL (replace YOUR_ACCOUNT_ID with your 12-digit account ID):
    jdbc:redshift://aibrick-producer-wg.YOUR_ACCOUNT_ID.ap-southeast-1.redshift-serverless.amazonaws.com:5439/analytics_warehouse
  • Authentication method: Username and password
  • Username: paste the Producer username from Secrets Manager
  • Password: paste the Producer password from Secrets Manager

Click Add compute. Wait for success (~30 sec).

Consumer: Add Redshift compute

Go back to the portal home. Open Consumer - AI TeamComputeAdd computeAmazon Redshift Serverless.

  • Name: Consumer-Ecommerce-RS
  • JDBC URL (replace YOUR_ACCOUNT_ID):
    jdbc:redshift://aibrick-consumer-wg.YOUR_ACCOUNT_ID.ap-southeast-1.redshift-serverless.amazonaws.com:5439/ecommerce
  • Authentication method: Username and password
  • Username: paste the Consumer username from Secrets Manager
  • Password: paste the Consumer password from Secrets Manager

Click Add compute. Wait for success.

Step G: Publish Data (Producer)

Open the Producer project

In the SageMaker portal, click on Producer - Data Team.

Create a data source

In the left sidebar, click Data → then click Data sources tab → click Create data source.

  • Name: Analytics Data
  • Data source type: Amazon Redshift Serverless
  • Compute: select Producer-Analytics-RS (the one you added in Step F)
  • Database: analytics_warehouse
  • Schema: select analytics
  • Check Publish on import (this auto-publishes tables to the catalog)

Click Create.

Run the data source

After creating, you will see the data source page. Click Run to start importing metadata.

Wait ~1-2 min. When complete, you should see the analytics tables listed: customer_segments, product_performance, campaign_history. These are now published to the catalog.

Step H: Subscribe to Data (Consumer)

Switch to the Consumer project

Go back to the portal home page. Click on Consumer - AI Team.

Discover and subscribe to Producer data

In the top navigation bar, click Discover → then Catalog.

  • You should see the analytics tables published by the Producer
  • Click on customer_segments → click Subscribe
  • Add a reason (e.g., AI agent needs analytics data) → click Submit
  • Repeat for product_performance and campaign_history
Approve subscriptions (as Producer)

Switch back to the Producer - Data Team project.

  • In the top navigation, click Govern
  • Click Subscription requests (or Subscriptions)
  • You should see pending requests from the Consumer project
  • Click Approve for each request

Once approved, the Consumer project has governed access to the Producer's analytics data. This demonstrates the data governance flow: publish → discover → subscribe → approve.

SageMaker Governance Complete

You have set up a full data governance flow: the Data Team publishes curated analytics, and the AI Team subscribes to it through a governed catalog. In a real organization, this ensures data quality, access control, and audit trails.

Explore the Data

Open Redshift Query Editor V2
AWS Console Redshift Query Editor V2 Open →

First time: click Configure account with defaults.

Connect to Consumer Redshift (aibrick-consumer-wg)

Expand Serverless → click aibrick-consumer-wgCreate connectionTemporary credentials using your IAM identity → database ecommerce.

SELECT * FROM ecommerce.customer_360 LIMIT 10;
Connect to Producer Redshift (aibrick-producer-wg)

Database: analytics_warehouse.

-- Customer segments with churn risk
SELECT customer_id, churn_risk_score, lifetime_value_prediction
FROM analytics.customer_segments
ORDER BY churn_risk_score DESC LIMIT 10;
Open SageMaker Unified Studio

Open the SageMaker portal URL (from the domain details page in the SageMaker admin console) → Sign in with SSO → explore both projects.

Module 2 Checkpoint

Module 3 — Build Your AI Agent with AgentCore

Duration
~60 min
Stack
stack-3-agentcore.yaml
No Docker
Lambda-based
Module 3 Architecture

This is the core module. You will deploy an AI agent that uses Bedrock AgentCore Gateway as an MCP (Model Context Protocol) server, with two Lambda functions as tools — one querying Redshift (which already contains DynamoDB data via Zero-ETL) and one that creates orders through the existing API Gateway. The agent itself is a Lambda function — no Docker, no ECR needed.

Why AgentCore Gateway?

AgentCore Gateway implements the MCP standard. Instead of calling Lambda with custom JSON, your agent uses a standardized protocol that any MCP-compatible AI can understand. This makes your tools reusable across different agents and frameworks.

BFF Lambda POST /ai/ask (Module 4) AgentCore Runtime Amazon Nova Lite reasoning loop BedrockModel (Nova Lite) MCPClient auto-discovers tools aibrick-ai-agent MCP protocol AgentCore Gateway MCP Server (AWS managed) Routes tool calls by name AWS IAM auth 2 tool targets registered aibrick-mcp-gateway Bedrock AgentCore invokes redshift-mcp-tool Queries customer_360 view Segments · Revenue · History Lambda (Python) · READ ONLY order-action-tool Calls POST /orders on existing API Gateway Lambda (Python) · CREATES ORDER Redshift DW API GW /orders AI reads from Redshift only (Zero-ETL keeps it current) · Creates orders via the existing API — never touches DynamoDB directly
Two MCP tools: one reads analytics from Redshift, one creates orders through the existing API Gateway

Your Agent's Two MCP Tools

The AI agent does not connect to DynamoDB directly. DynamoDB data is already synced to Redshift via Zero-ETL — so the agent reads from Redshift only. To create new orders, the agent calls the existing API Gateway endpoint (which routes to Lambda and then DynamoDB). No new data paths are needed.

Tool LambdaConnects toWhat it does
aibrick-redshift-mcp-toolRedshift DWQueries customer_360 analytics view — segments, revenue, order history (DynamoDB data arrives here via Zero-ETL)
aibrick-order-action-toolAPI Gateway /ordersCreates new orders via the existing POST /orders endpoint — agent acts without any new DynamoDB access
01 Deploy Stack 3 — AgentCore Foundation stack-3-agentcore.yaml
Download stack-3-agentcore.yaml
AWS Console CloudFormation Create stack stack-3-agentcore.yaml Open →
Deploy the stack

Stack name: aibrick-3-agentcore. The only parameter is ProjectName — keep it as aibrick (same as all other stacks). All other values are fetched automatically via cross-stack exports. Wait for CREATE_COMPLETE (~5 min).

This creates three Lambda functions:

  • aibrick-redshift-mcp-tool — queries Redshift customer_360 view (DynamoDB data arrives here via Zero-ETL)
  • aibrick-order-action-tool — calls POST /orders on the existing API Gateway
  • aibrick-ai-agent — the AgentCore Runtime agent (Bedrock Amazon Nova Lite)
Note the Outputs tab values

After CREATE_COMPLETE, open the Outputs tab and copy these values — you will need them in the next steps:

  • RedshiftToolArn
  • OrderActionToolArn
  • AgentLambdaArn
  • GatewayRoleArn
02 Create the AgentCore Gateway AWS CLI
Open CloudShell and set environment variables
AWS Console CloudShell Open →
# Set your AWS account ID and region
export AWS_ACCOUNT=$(aws sts get-caller-identity --query Account --output text)
export AWS_REGION="ap-southeast-1"

# Set values from Stack 3 Outputs tab
export GATEWAY_ROLE_ARN="arn:aws:iam::${AWS_ACCOUNT}:role/aibrick-gateway-role"
export REDSHIFT_TOOL_ARN="arn:aws:lambda:${AWS_REGION}:${AWS_ACCOUNT}:function:aibrick-redshift-mcp-tool"
export ORDER_ACTION_ARN="arn:aws:lambda:${AWS_REGION}:${AWS_ACCOUNT}:function:aibrick-order-action-tool"
export AGENT_LAMBDA_ARN="arn:aws:lambda:${AWS_REGION}:${AWS_ACCOUNT}:function:aibrick-ai-agent"
Create the Gateway
GATEWAY_ID=$(aws bedrock-agentcore-control create-gateway \
  --name aibrick-mcp-gateway \
  --role-arn $GATEWAY_ROLE_ARN \
  --protocol-type MCP \
  --authorizer-type AWS_IAM \
  --description "MCP Gateway for AI Brick workshop agent tools" \
  --region $AWS_REGION \
  --query 'gatewayId' \
  --output text)

echo "Gateway ID: $GATEWAY_ID"
Wait for ACTIVE status — copy the Gateway URL
# Check status — repeat until status shows ACTIVE (about 1–2 min)
aws bedrock-agentcore-control get-gateway \
  --gateway-identifier $GATEWAY_ID \
  --region $AWS_REGION \
  --query '[status, gatewayUrl]' \
  --output text

Copy the gatewayUrl from the output — you will use it in the next step.

03 Register the Two MCP Tools AWS CLI
Register Redshift analytics tool
REDSHIFT_TARGET_ID=$(aws bedrock-agentcore-control create-gateway-target \
  --gateway-identifier $GATEWAY_ID \
  --name redshift-analytics-tool \
  --description "Query customer_360 analytics view in Redshift Serverless" \
  --credential-provider-configurations '[{"credentialProviderType":"GATEWAY_IAM_ROLE"}]' \
  --target-configuration '{"mcp":{"lambda":{"lambdaArn":"'$REDSHIFT_TOOL_ARN'","toolSchema":{"inlinePayload":[{"name":"top_customers_by_revenue","description":"Get top customers by revenue","inputSchema":{"type":"object","properties":{"limit":{"type":"number","description":"Number of results (default 10)"}},"required":[]}},{"name":"inactive_customers","description":"Find customers who have not ordered recently","inputSchema":{"type":"object","properties":{"days":{"type":"number","description":"Days since last order (default 30)"}},"required":[]}},{"name":"customers_by_segment","description":"Get stats by segment (Gold/Silver/Bronze)","inputSchema":{"type":"object","properties":{},"required":[]}},{"name":"top_products_by_revenue","description":"Get top selling products","inputSchema":{"type":"object","properties":{"limit":{"type":"number","description":"Number of results"}},"required":[]}},{"name":"revenue_by_category","description":"Revenue breakdown by category","inputSchema":{"type":"object","properties":{},"required":[]}}]}}}}' \
  --region $AWS_REGION \
  --query 'targetId' \
  --output text)

echo "Redshift Target: $REDSHIFT_TARGET_ID"
Register Order Action tool

This is what makes the agent powerful — it can now create real orders by calling your existing API:

ORDER_TARGET_ID=$(aws bedrock-agentcore-control create-gateway-target \
  --gateway-identifier $GATEWAY_ID \
  --name order-action-tool \
  --description "Create a new order via the existing e-commerce API" \
  --credential-provider-configurations '[{"credentialProviderType":"GATEWAY_IAM_ROLE"}]' \
  --target-configuration '{"mcp":{"lambda":{"lambdaArn":"'$ORDER_ACTION_ARN'","toolSchema":{"inlinePayload":[{"name":"create_order","description":"Create a new order for a customer","inputSchema":{"type":"object","properties":{"customer_id":{"type":"string","description":"Customer ID e.g. cust-001"},"product_id":{"type":"string","description":"Product ID e.g. prod-001"},"quantity":{"type":"number","description":"Quantity (1-100)"}},"required":["customer_id","product_id","quantity"]}}]}}}}' \
  --region $AWS_REGION \
  --query 'targetId' \
  --output text)

echo "Order Action Target: $ORDER_TARGET_ID"
Two Targets Registered

Your AgentCore Gateway now has two MCP tool targets. The agent calls tools via the Gateway's MCP endpoint; the Gateway routes each call to the correct Lambda and returns the result. DynamoDB data is not accessed directly — it is already synced to Redshift via Zero-ETL, so one Redshift tool covers all read needs.

04 Connect Agent Lambda to the Gateway AWS CLI
Get the Gateway URL

The gateway URL was returned in Step 02 when you checked the status. You can also retrieve it with:

GATEWAY_URL=$(aws bedrock-agentcore-control get-gateway \
  --gateway-identifier $GATEWAY_ID \
  --region $AWS_REGION \
  --query 'gatewayUrl' \
  --output text)

echo "Gateway URL: $GATEWAY_URL"
Update the Agent Lambda with the Gateway URL

This adds the GATEWAY_URL env var while keeping all existing variables intact:

# Get current env vars and merge with new ones
CURRENT_ENV=$(aws lambda get-function-configuration \
  --function-name aibrick-ai-agent \
  --region $AWS_REGION \
  --query 'Environment.Variables' \
  --output json)

NEW_ENV=$(echo $CURRENT_ENV | python3 -c "
import sys, json
env = json.load(sys.stdin)
env['GATEWAY_URL'] = '$GATEWAY_URL'
print(json.dumps({'Variables': env}))
")

aws lambda update-function-configuration \
  --function-name aibrick-ai-agent \
  --environment "$NEW_ENV" \
  --region $AWS_REGION \
  --query '[FunctionName, Environment.Variables.GATEWAY_URL]' \
  --output text

You should see the function name and gateway URL in the output, confirming the update.

05 Test Your AI Agent AWS CLI
Test an analytics question

This question makes the agent query the Redshift customer_360 view:

aws lambda invoke \
  --function-name aibrick-ai-agent \
  --payload '{"question": "Who are our top 5 customers by revenue and what did they order recently?"}' \
  --cli-binary-format raw-in-base64-out \
  --region $AWS_REGION \
  response.json && cat response.json
Test the action tool — create an order by natural language

This is the power of the AI Brick — the agent can take action through the existing API:

aws lambda invoke \
  --function-name aibrick-ai-agent \
  --payload '{"question": "Create an order for customer cust-001, product prod-005, quantity 2"}' \
  --cli-binary-format raw-in-base64-out \
  --region $AWS_REGION \
  response.json && cat response.json

The agent looks up the product name and price, then calls POST /orders on the existing API Gateway. You should see a response with the order ID, product name, total price, and status PLACED.

Verify the order was created

Check the orders list — your new order should appear at the top:

# Set API URL (if not already set)
export API_URL=$(aws cloudformation describe-stacks \
  --stack-name aibrick-0b-application --region $AWS_REGION \
  --query 'Stacks[0].Outputs[?OutputKey==`ApiGatewayUrl`].OutputValue' --output text)

curl $API_URL/orders | python3 -c "import sys,json; orders=json.load(sys.stdin); print(json.dumps(orders[0], indent=2))"

The AI created a real order through the existing application — without any new database access or API changes.

Observe reasoning in CloudWatch Logs
AWS Console Lambda aibrick-ai-agent Monitor View CloudWatch logs Open →

Watch the logs to see the agent's tool call sequence: it reasons, calls a tool, gets results, reasons again, and so on until it has a complete answer.

Module 3 Checkpoint

Module 4 — AI-Powered Application

Duration
~40 min
Stack
stack-4-integration.yaml
Goal
AI feature in the existing app
Module 4 Architecture
Click image to view full size

This is the payoff module. You will plug the AI agent into the existing application from Module 1 — without changing any existing code. A single new endpoint, POST /ai/ask, is added alongside all existing routes. The old application keeps running untouched.

User asks a question POST /ai/ask API Gateway GET /products (existing) POST /orders (existing) GET /customers (existing) POST /ai/ask ← NEW Bedrock Guardrail PII filter INPUT Topic block OUTPUT BFF Lambda applies BFF Lambda apply_guardrail() invoke AI Agent aibrick-bff AI Agent Lambda AgentCore Runtime AgentCore MCP 2 MCP Tools Reads + Acts ANSWER Existing routes untouched · AI Brick added as /ai/ask · Guardrails protect both input and output
Module 4 — the complete POST /ai/ask request flow through Guardrails, BFF Lambda, and AI Agent
Key Principle — Additive, Not Disruptive

All existing API endpoints remain unchanged. You are adding one new endpoint alongside them. The original app and the new AI feature coexist on the same API Gateway.

01 Deploy Stack 4 — BFF Lambda + Guardrails stack-4-integration.yaml
Download stack-4-integration.yaml
AWS Console CloudFormation Create stack stack-4-integration.yaml Open →
Deploy the stack

Stack name: aibrick-4-integration. The only parameter is ProjectName — keep it as aibrick (same as all other stacks). All other values are fetched automatically via cross-stack exports.

Check the IAM acknowledgment box. Click Create stack. Wait for CREATE_COMPLETE (~3 min).

This stack creates:

  • BFF Lambda (aibrick-ai-bff) — receives POST /ai/ask, runs Guardrails on both input and output, invokes the agent
  • Bedrock Guardrail (aibrick-guardrail) — blocks off-topic queries (financial advice, competitor mentions) and anonymizes PII (email, phone, names) in responses
  • API Gateway route — adds POST /ai/ask to the existing API without touching any existing routes
  • SSM Parameter — sets aiEnabled = true so the webapp shows the Ask AI tab
View the Guardrail in Bedrock console
AWS Console Amazon Bedrock Guardrails Open →

Click on aibrick-guardrail to see the configuration: PII filters (EMAIL, PHONE, NAME → anonymize), topic blocks (financial advice, competitor comparison, internal systems), and profanity filter.

02 Review the BFF Lambda Code Lambda Console
AWS Console Lambda aibrick-ai-bff Code Open →

The BFF Lambda is the gateway between your webapp and the AI agent. Its flow:

# 1. Apply Guardrail to INPUT (block banned topics)
allowed_in, _ = apply_guardrail(question, 'INPUT')
if not allowed_in:
    return {'statusCode': 400, 'body': json.dumps({'answer': "I can't help with that topic."})}

# 2. Invoke AI Agent Lambda
agent_response = lambda_client.invoke(
    FunctionName=AGENT_FUNCTION,
    Payload=json.dumps({'question': question})
)
answer = json.loads(agent_response['Payload'].read())['answer']

# 3. Apply Guardrail to OUTPUT (anonymize PII)
allowed_out, _ = apply_guardrail(answer, 'OUTPUT')
if not allowed_out:
    answer = "I found results but cannot display sensitive information."

return {'statusCode': 200, 'body': json.dumps({'answer': answer})}
03 Test the New AI Endpoint CLI + Browser
Set the API URL (auto-detect from CloudFormation)
export API_URL=$(aws cloudformation describe-stacks \
  --stack-name aibrick-0b-application \
  --region ap-southeast-1 \
  --query "Stacks[0].Outputs[?OutputKey=='ApiGatewayUrl'].OutputValue" \
  --output text)

echo "API URL: $API_URL"
Test a normal business question
curl -X POST "$API_URL/ai/ask" \
  -H "Content-Type: application/json" \
  -d '{"question": "Who are our top 5 customers by revenue?"}'

The AI agent queries the Redshift customer_360 view and returns a summary of top customers with their revenue and segments.

Test Guardrail — off-topic blocked
curl -X POST "$API_URL/ai/ask" \
  -H "Content-Type: application/json" \
  -d '{"question": "Should I invest in this company stock?"}'

The Guardrail blocks this — financial advice is a denied topic. You should see a message like "I cannot process that request."

Test the full power — analytics + action
curl -X POST "$API_URL/ai/ask" \
  -H "Content-Type: application/json" \
  -d '{"question": "Find Gold segment customers who have not ordered recently. What products did they like?"}'

This pulls segment data and order history from Redshift (synced from DynamoDB via Zero-ETL) and synthesizes a campaign-ready answer.

04 Test in the Webapp Browser
Open the webapp

Get the webapp URL from Stack 0B Outputs:

aws cloudformation describe-stacks \
  --stack-name aibrick-0b-application \
  --region ap-southeast-1 \
  --query "Stacks[0].Outputs[?OutputKey=='WebAppURL'].OutputValue" \
  --output text

Open the URL in your browser. Hard refresh the page (Ctrl+Shift+R or Cmd+Shift+R) to clear the cache.

Find the Ask AI tab

You should now see an Ask AI tab in the navigation bar (alongside Products, Customers, Orders). This tab only appears after Stack 4 is deployed because it sets aiEnabled = true.

Ask a business question

Click the Ask AI tab. Type a question like:

  • Who are our top customers by revenue?
  • Which customers haven't ordered in the last 30 days?
  • Show me revenue breakdown by product category

The AI reads from Redshift analytics (which contains DynamoDB data via Zero-ETL) and returns a natural language answer.

Create an order by natural language

This is the most powerful demo — the AI can take real action through the existing API. Type:

  • Create an order for customer cust-001, product prod-005, quantity 2

The AI agent looks up the product name and price, then calls POST /orders on the existing API Gateway. You should see a response with the order ID, product name, total price, and status PLACED.

Now click the Orders tab — your new order should appear at the top of the list. The AI created a real order without any new database access or API changes.

Test the Guardrail in the webapp

Try asking something off-topic:

  • Should I invest in this company? → blocked (financial advice)
  • How do we compare to Amazon? → blocked (competitor comparison)
  • What is our database password? → blocked (internal systems)

The Guardrail blocks these before they reach the AI agent.

Verify existing pages still work

Click through Products, Customers, and Orders tabs. Everything works exactly as before — the AI feature is purely additive.

What You Just Demonstrated

You added an AI feature to a production-grade application using one new Lambda, one new API route, and Bedrock Guardrails — without touching any existing code. The AI agent uses Redshift analytics data (synced from DynamoDB via Zero-ETL) to answer questions and can create orders through the existing API.

Module 4 Checkpoint

Module 5 — Strands Agent Upgrade NEW

Duration
~15 min
Prerequisites
Module 4 complete
New Services
Strands Agent Framework, AgentCore Runtime
Goal
Upgrade to Strands agent with AgentCore Runtime

Module 4 gave you a working AI feature. But the agent uses raw Bedrock Converse API. In this module we deploy a Strands Agent as a new Lambda and optionally run it on AgentCore Runtime — the original agent stays untouched. One CloudFormation stack, one CLI command, done.

What You Get After This Module

Agent code 5x shorter (Strands @tool decorators) · AgentCore Runtime (streaming, observability, no cold starts) · Same webapp experience · Easy cleanup (just delete Stack 5)

Step 1: Deploy Stack 5 (Strands Agent + Runtime Route)

Download aibrick-5-strands.yaml
AWS Console CloudFormation Create stack aibrick-5-strands.yaml Open →
Deploy the stack

Stack name: aibrick-5-strands. The only parameter is ProjectName — keep it as aibrick (same as all other stacks). All other values are fetched automatically via cross-stack exports.

Check the IAM acknowledgment box. Click Create stack. Wait for CREATE_COMPLETE (~3-5 min).

This stack creates:

  • Strands Agent Lambda (aibrick-strands-agent) — the upgraded AI agent using Strands framework with @tool decorators
  • BFF-Runtime Lambda (aibrick-ai-bff-runtime) — forwards questions to AgentCore Runtime with Guardrails
  • IAM Policy — adds bedrock:InvokeModelWithResponseStream for the agent
  • API Gateway route — adds POST /ai-runtime/ask to the existing API (for the Runtime tab)
  • SSM Parameter — sets runtimeEnabled = true so the webapp shows the ⚡ Ask AI (Runtime) tab
What stays unchanged

Stack 3's original agent Lambda and Stack 4's BFF + /ai/ask route remain untouched. This is purely additive — you can delete Stack 5 anytime to revert.

Step 2: Setup Strands Lambda Layer

Why a Lambda Layer?

The Strands agent Lambda needs the strands-agents Python package (plus dependencies like boto3 extensions). Since Lambda doesn't come with these pre-installed, we build them into a Lambda Layer — a zip package that gets mounted at /opt/python when the function runs. This keeps the agent code clean and the layer reusable.

Build and attach the Strands layer

This script does 3 things:

  • pip install — downloads strands-agents + dependencies for Linux (--platform manylinux2014_x86_64)
  • zip + publish — packages them as a Lambda Layer and publishes to your account
  • attach — updates the Strands agent Lambda to use the new layer
curl -sO https://aibrick-workshop-materials-594980084878.s3.ap-southeast-1.amazonaws.com/script/setup-strands-layer.sh
bash setup-strands-layer.sh

Wait for ✅ Done! message (~2-3 min for pip install + zip + publish).

Step 3: Configure BFF → Point to Strands Agent

Update BFF Lambda to use the new Strands agent
# Get the new Strands agent ARN from Stack 5 outputs
STRANDS_ARN=$(aws cloudformation describe-stacks \
  --stack-name aibrick-5-strands \
  --query 'Stacks[0].Outputs[?OutputKey==`StrandsAgentArn`].OutputValue' \
  --output text --region $AWS_REGION)

echo "Strands Agent ARN: $STRANDS_ARN"

# Get current BFF config (preserve existing env vars)
GUARDRAIL_ID=$(aws lambda get-function-configuration \
  --function-name aibrick-ai-bff --region $AWS_REGION \
  --query 'Environment.Variables.GUARDRAIL_ID' --output text)

# Update BFF to point to Strands agent
aws lambda update-function-configuration \
  --function-name aibrick-ai-bff \
  --environment "Variables={AI_AGENT_ARN=$STRANDS_ARN,GUARDRAIL_ID=$GUARDRAIL_ID,GUARDRAIL_VERSION=DRAFT,MAX_QUESTION_LENGTH=500}" \
  --region $AWS_REGION > /dev/null

echo "✅ BFF now points to Strands agent!"

Step 4: Test with curl

Test the Strands agent via /ai/ask endpoint

Use curl instead of aws lambda invoke to avoid JSON quoting issues in CloudShell:

# Get API URL
API_URL=$(aws cloudformation describe-stacks \
  --stack-name aibrick-0b-application \
  --query 'Stacks[0].Outputs[?OutputKey==`ApiGatewayUrl`].OutputValue' \
  --output text --region $AWS_REGION)

echo "API URL: $API_URL"

# Test 1: Analytics query
curl -s -X POST "$API_URL/ai/ask" \
  -H "Content-Type: application/json" \
  -d '{"question":"Who are the top 3 customers by revenue?"}' | python3 -m json.tool

# Test 2: Customer lookup
curl -s -X POST "$API_URL/ai/ask" \
  -H "Content-Type: application/json" \
  -d '{"question":"Show me details for customer cust-001"}' | python3 -m json.tool

# Test 3: Create order (action tool)
curl -s -X POST "$API_URL/ai/ask" \
  -H "Content-Type: application/json" \
  -d '{"question":"Create an order for customer cust-001, product prod-005, quantity 2"}' | python3 -m json.tool

Expected response format: {"answer": "..."}

Test via Webapp

Open webapp → click Ask AI tab → try the same questions. The Strands agent handles them with shorter, cleaner code.

Module 5 Checkpoint

Step 5: Deploy on AgentCore Runtime

Module 5 Full Architecture — User → CloudFront → API GW → Lambda BFF → AgentCore Runtime → MCP → Redshift
AgentCore Runtime Flow — Lambda BFF → AgentCore Runtime → AgentCore Gateway (MCP) → Redshift
Why Runtime?

AgentCore Runtime gives you: CloudWatch GenAI Observability (traces, latency, tool invocations) · always-warm container (no cold starts) · managed infrastructure (no Docker/ECR management after deploy). Same agent code runs on both Lambda and Runtime — zero code changes.

Download and run the setup script

This script installs the toolkit, downloads agent code, and prepares everything for deployment:

curl -sO https://aibrick-workshop-materials-594980084878.s3.ap-southeast-1.amazonaws.com/script/setup-agentcore-runtime.sh
bash setup-agentcore-runtime.sh

The script will:

  • Find your MCP Gateway URL automatically
  • Install bedrock-agentcore-starter-toolkit + dependencies
  • Download the runtime agent code
  • Create requirements.txt
  • Run agentcore configure (interactive — answer the prompts below)
  • Run agentcore deploy with env vars
Interactive prompts during configure

When prompted, answer:

  • requirements.txt → Enter (use detected)
  • Deployment type → Enter (Container)
  • Execution role → Enter (auto-create)
  • ECR Repository → Enter (auto-create)
  • OAuth → Enter (no, use IAM)
  • Headers → Enter (no)

Wait for ✅ Agent deployed on AgentCore Runtime! message (~5-10 min for Docker build). Note the Agent ARN from the output.

Test via CLI
# Quick test
agentcore invoke '{"prompt":"Who are the top 3 customers by revenue?"}'

# Check status
agentcore status
View Observability Dashboard
echo "https://$AWS_REGION.console.aws.amazon.com/cloudwatch/home?region=$AWS_REGION#gen-ai-observability/agent-core"

Open URL → view: Agent Traces · Latency · Tool Invocations

Restore BFF (before cleanup)

After testing, restore the BFF to point back to the original Stack 3 agent so the "Ask AI" tab works normally again:

# Restore BFF to original Stack 3 agent
ORIGINAL_ARN=$(aws cloudformation describe-stacks \
  --stack-name aibrick-3-agentcore \
  --query 'Stacks[0].Outputs[?OutputKey==`AiAgentArn`].OutputValue' \
  --output text --region $AWS_REGION)

GUARDRAIL_ID=$(aws lambda get-function-configuration \
  --function-name aibrick-ai-bff --region $AWS_REGION \
  --query 'Environment.Variables.GUARDRAIL_ID' --output text)

aws lambda update-function-configuration \
  --function-name aibrick-ai-bff \
  --environment "Variables={AI_AGENT_ARN=$ORIGINAL_ARN,GUARDRAIL_ID=$GUARDRAIL_ID,GUARDRAIL_VERSION=DRAFT,MAX_QUESTION_LENGTH=500}" \
  --region $AWS_REGION > /dev/null

echo "✅ BFF restored to original agent"
Full cleanup (delete stack, runtime)

See the Summary & Cleanup page for full cleanup instructions.

Step 6: Test Runtime in Webapp

What this does

Stack 5 already deployed the API Gateway route POST /ai-runtime/ask and the BFF-Runtime Lambda. The webapp shows an "⚡ Ask AI (Runtime)" tab when runtimeEnabled = true. You just need to update the Lambda's ARN after deploying the runtime in Step 6.

Update BFF-Runtime Lambda with your Runtime ARN

Auto-detect the Runtime ARN from your deployed agent:

# Auto-detect Runtime ARN
export RUNTIME_ARN=$(aws bedrock-agentcore-control list-agent-runtimes --region $AWS_REGION \
  --query "agentRuntimes[?contains(agentRuntimeName,'aibrick')].agentRuntimeArn" --output text)

echo "Runtime ARN: $RUNTIME_ARN"

# Update Lambda
GUARDRAIL_ID=$(aws lambda get-function-configuration \
  --function-name aibrick-ai-bff-runtime \
  --query 'Environment.Variables.GUARDRAIL_ID' \
  --output text --region $AWS_REGION)

aws lambda update-function-configuration \
  --function-name aibrick-ai-bff-runtime \
  --environment "Variables={RUNTIME_AGENT_ARN=$RUNTIME_ARN,GUARDRAIL_ID=$GUARDRAIL_ID,GUARDRAIL_VERSION=DRAFT,MAX_QUESTION_LENGTH=500}" \
  --region $AWS_REGION > /dev/null

echo "✅ BFF-Runtime updated"
Verify via curl
# Set API URL (if not already set)
export API_URL=$(aws cloudformation describe-stacks \
  --stack-name aibrick-0b-application --region $AWS_REGION \
  --query 'Stacks[0].Outputs[?OutputKey==`ApiGatewayUrl`].OutputValue' --output text)

curl -X POST "$API_URL/ai-runtime/ask" \
  -H "Content-Type: application/json" \
  -d '{"question":"How many customers are in each segment?"}'

Expected: {"answer": "...", "guardrail_triggered": false}

Test in webapp

Open the webapp and hard refresh. You should see the ⚡ Ask AI (Runtime) tab. Try these questions:

  • How many customers are in each segment? — tests Redshift analytics
  • Show me revenue breakdown by product category — tests aggregation query
  • Which customers haven't ordered in 30 days? — tests inactive customers query
  • Show me the top 5 products by revenue — tests product analytics

Then compare by asking the same question in both "Ask AI" and "⚡ Ask AI (Runtime)" tabs side by side.

View Observability Dashboard

Open the AgentCore Observability dashboard to see traces from your Runtime calls:

echo "https://$AWS_REGION.console.aws.amazon.com/cloudwatch/home?region=$AWS_REGION#gen-ai-observability/agent-core"

You'll see: Sessions · Traces · Total tokens · Error rate. Click on a trace to see the full breakdown: Bedrock model call → tool invocations → response time.

Lambda vs Runtime — What's different?

The "Ask AI" Lambda tab has no built-in observability dashboard. Runtime gives you this for free — no code changes needed. This is one of the key production benefits of AgentCore Runtime.

Summary & Cleanup

"You didn't replace your application. You picked up an AI Brick and placed it into your architecture — and it fit perfectly."

What You Built Today

FoundationVPC · Subnets · Security Groups · IAM Roles (Stack 0A)
ApplicationAPI Gateway · Lambda Functions · DynamoDB (50 customers, 30 products, 200 orders) · Webapp (Stack 0B)
DataS3 Data Lake · Redshift Serverless · ecommerce schema · customer_360 view (Stack 0C)
GovernanceSageMaker Unified Studio · producer project · consumer project · Data Subscription (Stack 0D)
AI AgentAgentCore Gateway (MCP) · Redshift Tool (READ) · Order Action Tool (WRITE via API GW) · AgentCore Runtime (Stack 3)
IntegrationBFF Lambda · POST /ai/ask · Bedrock Guardrail · AI panel in webapp (Stack 4)

Key Learnings

1. AI is Additive

You added AI by adding one Lambda and one API route. Every existing function, every existing endpoint, and every existing database was left completely untouched.

2. MCP Standardizes Tool Access

AgentCore Gateway implements the Model Context Protocol — your tools (Redshift analytics, Order Action) are reusable with any MCP-compatible AI agent, not just the one you built today.

3. Agents Can Read and Act

Your agent answered analytics questions AND created real orders through the same MCP interface — demonstrating that AI can be both advisor and executor. DynamoDB data flows to Redshift via Zero-ETL, so one Redshift tool covers all read needs.

4. Zero-ETL Removes Pipeline Complexity

DynamoDB Zero-ETL to Redshift removed the need for any streaming Lambda, Glue job, or pipeline. New orders flow into analytics automatically.

Cleanup — Delete Resources in Reverse Order

Avoid Ongoing Charges

Delete all resources when finished. Redshift Serverless and NAT Gateways incur charges even when idle. Follow these steps in order.

Step 0: Delete Module 5 resources (if completed)

If you completed Module 5 (Strands Agent + Runtime), restore the BFF and delete Stack 5. This also removes the /ai-runtime/ask route and the "Ask AI (Runtime)" tab.

export AWS_REGION="ap-southeast-1"

# 1. Restore BFF to original Stack 3 agent
ORIGINAL_ARN=$(aws cloudformation describe-stacks \
  --stack-name aibrick-3-agentcore \
  --query 'Stacks[0].Outputs[?OutputKey==`AiAgentArn`].OutputValue' \
  --output text --region $AWS_REGION)

GUARDRAIL_ID=$(aws lambda get-function-configuration \
  --function-name aibrick-ai-bff --region $AWS_REGION \
  --query 'Environment.Variables.GUARDRAIL_ID' --output text)

aws lambda update-function-configuration \
  --function-name aibrick-ai-bff \
  --environment "Variables={AI_AGENT_ARN=$ORIGINAL_ARN,GUARDRAIL_ID=$GUARDRAIL_ID,GUARDRAIL_VERSION=DRAFT,MAX_QUESTION_LENGTH=500}" \
  --region $AWS_REGION > /dev/null

# 2. Delete Stack 5 (removes Strands Lambda, BFF-Runtime, API route, SSM params)
aws cloudformation delete-stack --stack-name aibrick-5-strands --region $AWS_REGION
aws cloudformation wait stack-delete-complete --stack-name aibrick-5-strands --region $AWS_REGION

# 3. Destroy AgentCore Runtime
agentcore destroy --agent aibrick_agent_runtime

echo "✅ Module 5 cleanup complete — original agent restored, Runtime tab removed"

Or run the automated script: bash cleanup-module5.sh

Skip this step if you did not complete Module 5.

Step 1: Open CloudShell, set region and look up Gateway IDs
AWS Console CloudShell Open →
export AWS_REGION="ap-southeast-1"

# Find your gateway ID
GATEWAY_ID=$(aws bedrock-agentcore-control list-gateways --region $AWS_REGION \
  --query "items[?contains(name,'aibrick')].gatewayId" --output text)
echo "Gateway: $GATEWAY_ID"

# List target IDs
aws bedrock-agentcore-control list-gateway-targets \
  --gateway-identifier $GATEWAY_ID --region $AWS_REGION \
  --query "items[*].[name,targetId]" --output table
Step 2: Delete AgentCore Gateway targets and Gateway
# Delete all targets (repeat for each targetId from above)
for TID in $(aws bedrock-agentcore-control list-gateway-targets \
  --gateway-identifier $GATEWAY_ID --region $AWS_REGION \
  --query "items[*].targetId" --output text); do
  echo "Deleting target: $TID"
  aws bedrock-agentcore-control delete-gateway-target \
    --gateway-identifier $GATEWAY_ID --target-id $TID --region $AWS_REGION
done

# Then delete the gateway
aws bedrock-agentcore-control delete-gateway \
  --gateway-identifier $GATEWAY_ID --region $AWS_REGION
Step 3: Delete Zero-ETL databases and integrations

First drop the Zero-ETL databases in Redshift, then delete the integrations:

# Drop Zero-ETL databases in Consumer Redshift
aws redshift-data execute-statement \
  --workgroup-name aibrick-consumer-wg --database ecommerce \
  --sql "DROP DATABASE aibrick_customers_db FORCE; DROP DATABASE aibrick_orders_db FORCE; DROP DATABASE aibrick_products_db FORCE;" \
  --region $AWS_REGION

# Wait for the DROP to complete (~10 sec)
sleep 15

# Delete all Zero-ETL integrations (with wait between each)
for ARN in $(aws redshift describe-integrations --region $AWS_REGION \
  --query "Integrations[?contains(IntegrationName,'aibrick')].IntegrationArn" --output text); do
  echo "Deleting: $ARN"
  aws redshift delete-integration --integration-arn $ARN --region $AWS_REGION
  sleep 30
done

Wait ~1-2 min for all integrations to finish deleting before proceeding.

Step 4: Delete SageMaker Unified Studio (if created)
AWS Console Amazon SageMaker Admin configurations Domains Open →

If you created the SageMaker domain in Module 2:

  • Open aibrick-domain
  • Delete the Consumer - AI Team project first
  • Delete the Producer - Data Team project
  • Then delete the domain itself

Skip this step if you did not create the SageMaker domain.

Step 5: Delete CloudFormation stacks in reverse order

Delete stacks one at a time. Wait for each to reach DELETE_COMPLETE before deleting the next.

# Step 5a: Delete Stack 4 (Integration)
aws cloudformation delete-stack --stack-name aibrick-4-integration --region $AWS_REGION
aws cloudformation wait stack-delete-complete --stack-name aibrick-4-integration --region $AWS_REGION

# Step 5b: Delete Stack 3 (AgentCore Lambdas)
aws cloudformation delete-stack --stack-name aibrick-3-agentcore --region $AWS_REGION
aws cloudformation wait stack-delete-complete --stack-name aibrick-3-agentcore --region $AWS_REGION

# Step 5c: Delete Stack 0C (Redshift) — both workgroups auto-cleaned
aws cloudformation delete-stack --stack-name aibrick-0c-datawarehouse --region $AWS_REGION
aws cloudformation wait stack-delete-complete --stack-name aibrick-0c-datawarehouse --region $AWS_REGION

# Step 5d: Empty S3 bucket then delete Stack 0B (Application)
aws s3 rm s3://aibrick-webapp-$(aws sts get-caller-identity --query Account --output text) --recursive --region $AWS_REGION
aws cloudformation delete-stack --stack-name aibrick-0b-application --region $AWS_REGION
aws cloudformation wait stack-delete-complete --stack-name aibrick-0b-application --region $AWS_REGION

# Step 5e: Delete Stack 0A (Networking) — must be last
aws cloudformation delete-stack --stack-name aibrick-0a-networking --region $AWS_REGION
aws cloudformation wait stack-delete-complete --stack-name aibrick-0a-networking --region $AWS_REGION
If a stack gets stuck in DELETE_FAILED

This usually happens because an S3 bucket still has objects. Fix it:

# Find and empty the bucket, then retry delete
aws s3 ls | grep aibrick
aws s3 rm s3://BUCKET_NAME --recursive
aws cloudformation delete-stack --stack-name STACK_NAME --region $AWS_REGION
Workshop Complete

You have built a complete AI-augmented e-commerce platform on AWS. The architecture you built today is production-ready and follows AWS best practices for security, governance, and composable AI integration.

Workshop Complete Checklist