A collection of Strands Agents examples deployed to Amazon Bedrock AgentCore.
This repository contains two agents with different deployment models:
| Agent | Description | Deployment |
|---|---|---|
agent/ |
RAG assistant with Knowledge Base, Memory, Gateway tools, Guardrails, and a Chainlit chat UI | Terraform + Docker → ECR → AgentCore Runtime |
sdk-agent/ |
Code interpreter agent using agentcore CLI | agentcore CLI (no Terraform) |
┌──────────────────────────────────────────────────────┐
Chainlit UI │ Amazon Bedrock AgentCore │
(ui/ - local or Docker) │ │
│ │ ┌────────────────────┐ ┌────────────────────────┐ │
│ invoke_agent │ │ AgentCore Runtime │ │ AgentCore Memory │ │
│ _runtime(ARN) │ │ (agent/ container)│──▶│ (long-term memory) │ │
└───────────────────▶│ │ │ └────────────────────────┘ │
│ │ ├─ Claude Sonnet │ │
│ │ ├─ KB (RAG via S3 │ ┌────────────────────────┐ │
│ │ │ Vectors) │ │ AgentCore Gateway │ │
│ │ ├─ Guardrails │──▶│ (MCP / IAM auth) │ │
│ │ └─ Gateway tools │ │ ├─ commit-message λ │ │
│ │ (via MCP) │ │ └─ kv-store λ │ │
│ └────────────────────┘ └────────────────────────┘ │
└──────────────────────────────────────────────────────┘
- AWS CLI configured with credentials for
eu-central-1 - Terraform >= 1.5.0
- Podman (or Docker) with buildx support for ARM64 cross-compilation
- uv for Python dependency management
make(GNU Make)- Bedrock model access enabled for:
anthropic.claude-sonnet-4-6-v1:0(or the cross-regioneu.anthropic.claude-sonnet-4-6variant)amazon.titan-embed-text-v2:0
strands-bedrock-agents/
├── Makefile # All build, publish, deploy, and infra commands
├── docker-compose.yml # Local development (agent + UI together)
├── agent/ # Full RAG agent (Terraform-managed)
│ ├── Dockerfile # ARM64 container for AgentCore Runtime
│ ├── pyproject.toml # Agent Python dependencies (uv)
│ ├── agent.py # Strands agent — deployed to AgentCore Runtime
│ └── prompts/
│ └── system_prompt.txt # Agent system prompt
├── sdk-agent/ # Lightweight agent (agentcore CLI-managed)
│ ├── agent.py # Strands agent with Code Interpreter
│ ├── pyproject.toml # Agent Python dependencies
│ ├── __init__.py
│ └── README.md # Standalone setup & deploy instructions
├── ui/ # Chainlit chat UI
│ ├── Dockerfile # UI container
│ ├── pyproject.toml # UI dependencies (chainlit, boto3)
│ └── app.py # Chainlit chat app
└── iac/ # Terraform infrastructure (for agent/)
├── versions.tf # Terraform + AWS provider
├── variables.tf # Input variables
├── main.tf # ECR, S3 Vectors, Knowledge Base
├── agentcore.tf # AgentCore Memory, Runtime, Gateway
├── guardrail.tf # Bedrock Guardrails (content/PII/topic filtering)
├── lambda.tf # Gateway Lambda targets (tools)
├── iam.tf # IAM roles and policies
├── outputs.tf # Terraform outputs
└── src/ # Lambda function source code
├── commit_message/ # Random commit message tool
└── kv_store/ # DynamoDB key-value store tool
All commands use the
Makefile. Runmake helpor see the top of the Makefile for a summary of available targets.
make tf-init
make tf-applyNote the outputs — you'll need them for the next steps. See Terraform Outputs for the full list.
Copy the example and fill in values from the Terraform outputs and your AWS credentials:
# AWS credentials
AWS_REGION=eu-central-1
AWS_ACCESS_KEY_ID=<your-key>
AWS_SECRET_ACCESS_KEY=<your-secret>
AWS_SESSION_TOKEN=<your-token>
# From terraform -chdir=iac output:
ECR_REPO_URL=<ecr_repository_url>
KNOWLEDGE_BASE_ID=<knowledge_base_id>
AGENTCORE_MEMORY_ID=<agentcore_memory_id>
AGENT_RUNTIME_ID=<agent_runtime_id>
AGENT_RUNTIME_ARN=<agent_runtime_arn>
AGENT_RUNTIME_ROLE_ARN=<from iac/iam.tf — the runtime role ARN>
AGENT_ENDPOINT_NAME=<project_name>_endpoint
AGENTCORE_GATEWAY_URL=<gateway_url>
GUARDRAIL_ID=<guardrail>
MODEL_ID=eu.anthropic.claude-sonnet-4-6# Build + push :latest to ECR
make publish
# Or with a version tag
make publish VERSION=v1.0.0# Update AgentCore Runtime + Endpoint to :latest
make deploy
# Or deploy a specific version
make deploy VERSION=v1.0.0# Build the UI image and run it locally on port 8000
# (connects to the deployed AgentCore Runtime via AGENT_RUNTIME_ARN)
make deploy-uiOpen http://localhost:8000 in your browser.
A full-featured RAG assistant deployed to AgentCore Runtime via Terraform. Features:
- Claude Sonnet 4.6 via Amazon Bedrock for inference
- Bedrock Knowledge Base (RAG) backed by S3 Vectors for document retrieval
- AgentCore Memory for long-term conversation memory across sessions
- AgentCore Gateway (MCP protocol) exposing Lambda-based tools:
get_commit_message— fetches a random funny commit message from whatthecommit.comkv_store— stores/retrieves key-value pairs in DynamoDB
- Bedrock Guardrails — content filtering (hate speech), PII blocking, topic denial (politics), profanity filter
- Streaming support via Server-Sent Events (SSE)
- Chainlit chat UI with support for both local (HTTP) and remote (AgentCore Runtime) invocation
A lightweight agent deployed using the agentcore CLI. Features:
- Code Interpreter tool via AgentCore (runs Python code to verify answers)
- Simple deployment without Terraform — uses
agentcore packageandagentcore deploy
See sdk-agent/README.md for full setup and deployment instructions.
This is the easiest way to run everything locally. The UI calls the agent directly via HTTP (bypassing AgentCore Runtime).
-
Make sure your
.envfile has at least the AWS credentials,KNOWLEDGE_BASE_ID, andAGENTCORE_MEMORY_IDset. -
Start both services:
make dev-
Open http://localhost:8000 in your browser. The UI calls the agent at
http://agent:8080inside the Docker network. -
To stop:
make dev-down# Build the ARM64 agent image locally
make build
# Run it manually (replace values with your own)
podman run --rm -p 8080:8080 \
-e AWS_REGION=eu-central-1 \
-e AWS_ACCESS_KEY_ID=<your-key> \
-e AWS_SECRET_ACCESS_KEY=<your-secret> \
-e KNOWLEDGE_BASE_ID=<knowledge-base-id> \
-e AGENTCORE_MEMORY_ID=<memory-id> \
strands-agent:local
# Health check
curl http://localhost:8080/ping
# Test invocation
curl -X POST http://localhost:8080/invocations \
-H "Content-Type: application/json" \
-d '{"prompt": "Hello, who are you?", "session_id": "test-session-1", "actor_id": "test-user"}'# Build and run the UI pointing to the deployed AgentCore Runtime
make deploy-uiOr manually:
podman build -t strands-ui:local ./ui
podman run --rm -p 8000:8000 \
-e AWS_REGION=eu-central-1 \
-e AWS_ACCESS_KEY_ID=<your-key> \
-e AWS_SECRET_ACCESS_KEY=<your-secret> \
-e AGENT_ENDPOINT_URL=http://host.containers.internal:8080 \
strands-ui:localAll Terraform commands are available via the Makefile:
make tf-init # terraform init
make tf-apply # terraform apply
make tf-destroy # empties S3 buckets first, then terraform destroyAfter make tf-apply, note the outputs:
| Output | Description | Used as |
|---|---|---|
ecr_repository_url |
ECR repository URL | ECR_REPO_URL in .env |
knowledge_base_id |
Bedrock Knowledge Base ID | KNOWLEDGE_BASE_ID env var |
data_source_bucket |
S3 bucket for uploading documents | Used with aws s3 cp |
data_source_id |
Knowledge Base data source ID | Used to trigger sync jobs |
agentcore_memory_id |
AgentCore Memory ID | AGENTCORE_MEMORY_ID env var |
agent_runtime_id |
AgentCore Runtime ID | AGENT_RUNTIME_ID in .env |
agent_runtime_arn |
AgentCore Runtime ARN | AGENT_RUNTIME_ARN in .env |
agent_runtime_endpoint_arn |
Runtime Endpoint ARN | Reference only |
gateway_id |
AgentCore Gateway ID | Reference only |
gateway_url |
AgentCore Gateway URL (MCP, IAM auth) | AGENTCORE_GATEWAY_URL env var |
guardrail |
Bedrock Guardrail ID | GUARDRAIL_ID env var |
make tf-destroyThis automatically empties the S3 data source and vectors buckets before running
terraform destroy.
# Build + push :latest
make publish
# Build + push :latest and a version tag
make publish VERSION=v1.2.0The
publishtarget handles ECR login, ARM64 cross-compilation, and tagging automatically.
After pushing a new image to ECR, update the AgentCore Runtime to pick it up:
# Deploy :latest
make deploy
# Deploy a specific version
make deploy VERSION=v1.2.0This does two things:
- Updates the AgentCore Runtime to point to the new container image (creates a new runtime version)
- Updates the Runtime Endpoint to serve the new version
Put any documents (PDF, TXT, MD, DOCX) into the S3 data source bucket:
aws s3 cp ./my-docs/ s3://<data_source_bucket>/ --recursiveThen trigger a Knowledge Base sync:
aws bedrock-agent start-ingestion-job \
--knowledge-base-id <knowledge_base_id> \
--data-source-id <data_source_id> \
--region eu-central-1The fastest way is:
make deploy-uiOr run it natively:
cd ui
uv sync
export AGENT_RUNTIME_ARN=<agent_runtime_arn>
export AWS_REGION=eu-central-1
chainlit run app.pyOpen http://localhost:8000 in your browser to chat with the agent.
| Variable | Required | Default | Description |
|---|---|---|---|
AWS_REGION |
No | eu-central-1 |
AWS region |
AWS_ACCESS_KEY_ID |
Yes (local) | — | AWS access key (not needed when using IAM roles) |
AWS_SECRET_ACCESS_KEY |
Yes (local) | — | AWS secret key |
AWS_SESSION_TOKEN |
Conditional | — | Required for SSO/assumed-role credentials |
ECR_REPO_URL |
Yes (publish/deploy) | — | ECR repository URL (from Terraform) |
KNOWLEDGE_BASE_ID |
No | — | Bedrock Knowledge Base ID (enables RAG) |
AGENTCORE_MEMORY_ID |
No | — | AgentCore Memory ID (enables long-term memory) |
AGENT_RUNTIME_ID |
Yes (deploy) | — | AgentCore Runtime ID (from Terraform) |
AGENT_RUNTIME_ARN |
Yes (UI remote) | — | AgentCore Runtime ARN (from Terraform) |
AGENT_RUNTIME_ROLE_ARN |
Yes (deploy) | — | IAM role ARN for the runtime |
AGENT_ENDPOINT_NAME |
Yes (deploy) | — | Runtime endpoint name |
AGENT_ENDPOINT_URL |
No | — | Direct HTTP URL for local agent (bypasses AgentCore) |
AGENTCORE_GATEWAY_URL |
No | — | Gateway URL for MCP tools |
GUARDRAIL_ID |
No | — | Bedrock Guardrail ID (enables content filtering) |
MODEL_ID |
No | anthropic.claude-sonnet-4-6-v1:0 |
Bedrock model ID for inference |
AGENT_OBSERVABILITY_ENABLED |
No | false |
Enable OpenTelemetry tracing to CloudWatch |
| Target | Description |
|---|---|
make dev |
Start agent + UI locally with podman compose |
make dev-down |
Stop local development containers |
make build |
Build the ARM64 agent image locally |
make publish |
Build + push :latest to ECR |
make publish VERSION=v1.2 |
Build + push :latest and :v1.2 to ECR |
make deploy |
Update AgentCore Runtime + Endpoint to :latest |
make deploy VERSION=v1.2 |
Update AgentCore Runtime + Endpoint to :v1.2 |
make deploy-ui |
Build UI image and run it locally on port 8000 |
make tf-init |
terraform init |
make tf-apply |
terraform apply |
make tf-destroy |
Empty S3 buckets + terraform destroy |
The agent runs inside the AgentCore Runtime container. It:
- Receives a
{ "prompt": "...", "session_id": "...", "actor_id": "..." }payload via/invocations - Loads conversation memory from AgentCore Memory for the given session (if
AGENTCORE_MEMORY_IDis set) - Calls the
retrievetool to search the Bedrock Knowledge Base for relevant context (ifKNOWLEDGE_BASE_IDis set) - Connects to the AgentCore Gateway via MCP to access Lambda-based tools (if
AGENTCORE_GATEWAY_URLis set) - Applies Bedrock Guardrails to filter content (if
GUARDRAIL_IDis set) - Sends the context + question to Claude Sonnet 4.6 for a response
- Supports both streaming (SSE with
Accept: text/event-stream) and non-streaming (JSON) responses - Saves the conversation turn to AgentCore Memory
- Returns
{ "output": { "message": "..." } }
The Chainlit app runs locally (or in a container). It:
- Assigns a unique
session_id(33+ chars) per chat session - Maintains the full conversation history in the Chainlit session
- Either calls
boto3.client('bedrock-agentcore').invoke_agent_runtime()(whenAGENT_RUNTIME_ARNis set) or calls the agent directly via HTTP with SSE streaming (whenAGENT_ENDPOINT_URLis set) - Streams the response tokens into the chat UI in real time
The AgentCore Gateway exposes Lambda functions as MCP-compatible tools that the agent can invoke:
get_commit_message— calls whatthecommit.com and returns a random funny commit messagekv_store— providesputandgetoperations on a DynamoDB table for persistent key-value storage
The gateway uses AWS IAM authorization — callers must sign requests with SigV4.
The agent optionally applies Bedrock Guardrails which provide:
- Content filtering — blocks hate speech (medium sensitivity)
- PII protection — blocks PII in input, anonymizes PII in output (names)
- Topic denial — blocks conversations about politics
- Profanity filter — blocks profane language