Tag Archives: Developer Tools

Automating the Experimentation Lifecycle with Kiro, AWS DevOps Agent, and LaunchDarkly

Post Syndicated from Greg Eppel original https://aws.amazon.com/blogs/devops/automating-the-experimentation-lifecycle-with-kiro-aws-devops-agent-and-launchdarkly/

Introduction

Continuous improvement depends on experimentation. Teams know that the fastest path to better outcomes is to test changes against real user behavior, measure results, and iterate. In practice, sustaining that cycle is slow and costly because the overhead compounds with each attempt.

Three barriers slow teams down:

1. Planning cost — Turning a proposed change into a testable experiment requires defining a feature flag strategy, coordinating implementation, and wiring everything together before any user sees new behavior.

2. Measurement disconnected from action — Once live, teams must configure metrics, define success criteria, monitor, and interpret results. When metrics regress, remediation traditionally depends on a human merging a fix or rolling back a deployment.

3. Stalled iteration — Without a record of which change caused which outcome, the next hypothesis is a guess, so iteration often does not happen and the goal stalls.

This post introduces a reference solution that closes the gap between defining a goal and reaching it. A team states an improvement goal (for example, increase add-to-cart rate by 10%), and agents plan the experiment, implement the change, deploy it behind a feature flag, measure its impact, and iterate on the result, all within defined safety boundaries. The solution connects Kiro for code generation, AWS DevOps Agent for orchestration and release readiness review, and LaunchDarkly for feature flag governance, experiments, and Guarded Releases for safe, metric-driven rollouts with automatic rollback. The architecture described here is a reference implementation you can build today. A more turnkey experience is planned for the future.

Pre-requisites

Step 1. Enable AWS DevOps Agent and Create an Agent Space. AWS DevOps Agent is available in the AWS regions listed here. Follow these steps to create your AWS DevOps Agent and create an Agent Space.

Step 2. Create your LaunchDarkly account. Create your LaunchDarkly account using the AWS Marketplace or through LaunchDarkly website.

Step 3. Enable the LaunchDarkly MCP Server in the Agent Space. AWS DevOps Agent connects to LaunchDarkly’s hosted MCP server as a client, giving it the ability to query flag state, read targeting rules, and list flags by project or environment.

Step 4 — Register the LaunchDarkly MCP server (account-level). MCP servers are registered at the AWS account level and shared among all Agent Spaces in that account.

  • Sign in to the AWS DevOps Agent console.
  • Navigate to the Capability Providers page (side navigation).
  • Find MCP Server under the Available providers section and choose Register.
  • Enter the MCP server details (see table below).
  • Choose Next.
    • Name: LaunchDarkly
    • Endpoint URL: https://mcp.launchdarkly.com/mcp/launchdarkly
    • Description: LaunchDarkly feature flag management MCP server
    • Enable Dynamic Client Registration: Select this checkbox to allow DevOps Agent to automatically register with LaunchDarkly’s authorization server

Step 4a — Configure the authorization flow

LaunchDarkly’s hosted MCP server uses OAuth for authentication:

  • Select OAuth 3LO (Three-Legged OAuth).
  • Choose Next.
  • Complete the OAuth authorization — you will be redirected to LaunchDarkly’s consent page to authorize the connection.
  • Choose Next.
  • Tip: Refer to the LaunchDarkly MCP server documentation for specific OAuth scope and credential details.

Step 4b — Review and submit

  • Review the MCP server configuration details.
  • Choose Submit.
  • AWS DevOps Agent validates the connection to LaunchDarkly’s MCP server.
  • On successful validation, the MCP server is registered at the account level.

Step 5 — Add the MCP server to your Agent Space

After the account-level registration, connect it to your specific Agent Space:

  • In the AWS DevOps Agent console, select your Agent Space (created in Section 1).
  • Go to the Capabilities tab.
  • In the MCP Servers section, choose Add.
  • Select the LaunchDarkly MCP server you just registered.
  • Configure tool access:
    • Allow all tools — makes all LaunchDarkly MCP tools available to the agent
    • Select specific tools — allowlist only the tools you need (recommended for production)
  • Choose Add.

Step 5 — Validate the connection. Run a test query to confirm the integration is working. In the DevOps Agent console, start a new investigation or chat session and ask: “List the feature flags in the <your-project-key> project in the production environment.” If the agent returns flag data from LaunchDarkly, the connection is active.

Solution overview

The automated experimentation lifecycle operates as a closed loop. A team states an improvement goal, and the system moves through a continuous cycle: decide what to try next, implement the change behind a feature flag, validate and deploy it, run an experiment to measure impact, roll it out safely, and feed the outcome back into the next iteration. The loop continues until the goal is met or the team decides to stop.

Flowchart showing the Plan-Prove-Iterate continuous improvement loop for AWS DevOps Agent. The Plan phase covers steps 1 through 5: generate hypothesis, create feature flag, implement behind flag, release readiness review, and merge PR to deploy. The Prove phase has two sub-phases: Experiment (50/50 split on 10% traffic measuring business KPIs) and Guarded Release (ramp from 20% to 40% with auto-rollback on regression). The Iterate phase covers steps 6 through 8: record outcome, generate report, and feed into next hypothesis, ending with a goal-met decision gate. An improvement goal banner reads "Increase add-to-cart rate by 15%."

End-to-end Plan-Prove-Iterate workflow showing how AWS DevOps Agent orchestrates hypothesis generation, feature-flagged implementation, experimentation, guarded rollout, and outcome recording in a continuous improvement loop.

Each component has a distinct responsibility. AWS DevOps Agent orchestrates the cycle: it runs on a schedule as a Custom Agent which is a user-defined agent with its own instructions, skills, and connected tools that executes autonomously without pausing for input unless something fails. AWS DevOps Agent supports Custom Agents as a way to encode a specific workflow, including its decision logic, safety constraints, and cadence, into an agent that runs end-to-end on its own. In this solution, the Custom Agent reviews goals, generates hypotheses informed by prior outcomes, coordinates implementation and validation, and drives iteration across multiple experiment cycles.”. Kiro CLI runs in headless mode inside the Experiment MCP Server container on Amazon Bedrock AgentCore, implementing code changes behind LaunchDarkly feature flags and opening pull requests without a human operating an IDE.

LaunchDarkly hosts feature flags, experiments, and Guarded Releases, monitors metrics in real time, and reverts flag state when a threshold is breached. It also exposes a hosted MCP server with tools the agent calls directly. The Experiment MCP Server (custom, built for this solution) exposes the remaining operations over MCP: code implementation through Kiro, PR merge, and deployment triggering.

The agent acts as an MCP client connected to these two servers. LaunchDarkly’s hosted MCP server provides flag management, experiment lifecycle, Guarded Release, and observability tools. The Experiment MCP Server provides code implementation, PR merging, and deployment tools. This design separates decision-making from execution: the agent decides what to do, the MCP servers handle how.

Plan / Prove / Iterate

The lifecycle operates in three phases.

Plan — The agent decides the next action for a goal, generates a hypothesis informed by prior outcomes when iterating, and creates a feature flag in LaunchDarkly. It then invokes Kiro CLI to implement the change behind the flag and open a pull request. AWS DevOps Agent validates the change through release readiness review. After a green review, the PR is merged and a GitHub Actions workflow deploys the application through AWS Amplify.

Prove — Two sequential phases run after deployment. First, a 50/50 experiment splits 10% of traffic on a business KPI (for example, add-to-cart rate) until statistical significance selects a winning variation. Then a Guarded Release ramps the winning variation from 20% to 30% to 40% and eventually to 100% while LaunchDarkly monitors operational guardrails (error rate, page-load-time-p95). If a guardrail threshold is breached, LaunchDarkly reverts the flag state automatically, requiring no redeployment. The experiment measures value (does the change improve the goal metric?); the Guarded Release measures safety (does the change hold up at scale?).

Iterate — After a rollout concludes, the agent queries LaunchDarkly’s Change History API to associate specific flag modifications with outcomes. The recorded outcome informs the next hypothesis, and the cycle repeats until the goal is met or the agent recommends waiting.

Extending the agent with a custom MCP server

AWS DevOps Agent reads code, reviews changes, and decides what to do next. It does not take action on its own. To move from decision to execution, you connect it to MCP servers that expose operations as tools.

LaunchDarkly’s hosted MCP server covers flags, experiments, and Guarded Releases. We needed operations it doesn’t cover — writing code, merging PRs, and deploying — so we built the Experiment MCP Server. It runs on Amazon Bedrock AgentCore and exposes five tools: create_task and get_task_status (invoke Kiro CLI to implement changes and open a PR), merge_pr, trigger_deployment, and get_deployment_status.

These are mutation operations. When the agent calls create_task, Kiro writes real code. When it calls merge_pr, that code lands in main. You are responsible for this server — what it exposes, which repos it can touch, which branches it can merge to. We scoped ours to one repository, one branch, and one Amplify application. Those constraints live in the MCP server’s code, not the agent’s prompt, because API-level scoping cannot be misinterpreted.

The Experiment MCP Server [CG1] is a Python application built on FastMCP, packaged as a container and deployed to Amazon Bedrock AgentCore over stateless HTTP so the platform can restart or replace the container without breaking in-flight requests. At startup, the container pulls credentials from AWS Secrets Manager, clones the target repository, and makes Kiro CLI available as a local binary. This single-container design keeps everything colocated: when the agent calls create_task, the server spawns Kiro CLI as a headless subprocess with direct filesystem access to the cloned repo rather than making a network call to a separate code-generation service. Kiro CLI receives a structured prompt containing the task description, the LaunchDarkly flag key, and the variation details, then writes the change, commits to a new branch, and pushes. The server opens a pull request through the GitHub API and returns the task ID immediately without waiting for Kiro to finish. The caller polls get_task_status, which long-polls against an S3-backed state store so task progress survives container restarts. Deployment tracking follows a similar pattern: trigger_deployment dispatches a GitHub Actions workflow and returns the real GitHub run ID, and get_deployment_status reads live status directly from GitHub, so there is nothing to lose if the container cycles between calls. The overall design principle is that the MCP server coordinates work and delegates persistence to external systems (S3 for task state, GitHub for deployment state, Secrets Manager for credentials) rather than holding anything in memory that a restart would erase.

How the agent works

The agent runs on a schedule. Each run, it evaluates the current state of each goal and picks one of three actions: create a new experiment (no active rollout exists), iterate on a prior result (a rollout completed and the goal is not yet met), or wait (an experiment or rollout is still in progress).

The entry point for the system is an outcome, not a task list. The team picks a business metric from the available set — add-to-cart rate, checkout conversion, bounce rate, or page-load-time-p95 — and sets a target improvement, for example “increase add-to-cart rate by 10%.” Error rate is reserved as a safety guardrail during the Guarded Release phase and cannot be chosen as the primary success metric, because the system needs an independent operational signal to decide whether a winning variation is safe to scale. Beyond the metric and the target, all other inputs are optional. The agent infers the current baseline, the areas of the application in scope for changes, and any constraints from the codebase and production data. If those assumptions are off, the team corrects them before any code is written. The team states where they want to end up, and the agent works backward from there.

Ecommerce demo store product listing page showing a grid of six products: Wireless Headphones at $149.99, Bluetooth Speaker at $79.99, USB-C Hub at $49.99, Mechanical Keyboard at $129.99, Leather Wallet at $59.99, and Canvas Backpack at $89.99. Each product card displays a product photo with name and price below. The page header shows "Demo Store" with Products and cart navigation links.

Demo Store product listing page used as the test surface for the add-to-cart experimentation cycles. Product cards currently show the control layout (no inline Add to Cart button).

For new goals, the agent explores the target repository and proposes a code change likely to move the metric. For iterations, it reads prior outcomes and adjusts its approach based on what worked and what did not. Before any code change, the agent creates a feature flag in LaunchDarkly (boolean, OFF by default, named with a convention like exp-add-to-cart-*) so every change ships behind a flag from the start.

Implementation runs through Kiro CLI in headless mode. The agent calls create_task, Kiro clones the repository, writes the change behind the feature flag, and opens a pull request.

GitHub merged pull request titled "feat: add inline Add to Cart button on listing page (atc-on-listing)" by gteppel. The PR merged 1 commit into main from experiment/atc-on-listing with 2 files changed. The description lists changes to page.tsx and a new ListingAddToCartButton.tsx component, explains flag-true and flag-false behavior, documents the atc-on-listing feature flag key with two variations, and notes TypeScript verification.

Merged GitHub PR implementing the feature-flagged inline Add to Cart button on the product listing page, controlled by the atc-on-listing LaunchDarkly flag.

AWS DevOps Agent then runs a release readiness review on the PR. If the review fails, the agent retries up to three times before stopping to ask for help. After a green review, the PR is merged and a GitHub Actions workflow deploys through AWS Amplify.

AWS DevOps Agent Release Readiness Review report for "Add to Cart Urgency Boost," completed on August 26, 2026. The report shows a recommended action of Standard Deployment, zero critical issues, commit d60dc4c, and 3 detected changes (all additions). The analysis section confirms all new behavior is gated behind the LaunchDarkly flag exp-add-to-cart-urgency-boost with a safe default of false. Recommendations include guarded rollout starting at a small treatment percentage, confirming the flag exists in LaunchDarkly, monitoring add-to-cart and checkout conversion metrics, and verifying treatment audience overlap.

AWS DevOps Agent Release Readiness Review for the Add to Cart Urgency Boost experiment. The automated review found zero critical issues and recommended standard deployment with a guarded rollout.

Proving the change

Once deployed, the flag is toggled on and the experiment begins. The agent creates a 50/50 experiment across 10% of traffic, splitting on the goal’s business KPI. In production, experiment data comes from real users interacting with your application, with metrics emitted through OpenTelemetry to LaunchDarkly. For this reference implementation, we built a synthetic traffic generator that simulates user sessions across both treatment and control variations, producing the conversion events and operational metrics that drive experiment decisions. It runs alongside the demo application and generates enough volume to reach statistical significance within minutes rather than days. The synthetic traffic generator is a demo convenience, not a production requirement. Any application that emits the right events to LaunchDarkly will work with this architecture.

The agent checks for results on each Custom Agent execution until statistical significance is reached. In an interactive chat session, you prompt the agent to check when you are ready. If the treatment wins, the agent proceeds to the Guarded Release. If it loses, the agent archives the flag and records the outcome for the next iteration.

LaunchDarkly experiment results dashboard showing Exposures and Summary panels. Exposures panel shows 17,977 user contexts over 1 hour with a 50/50 split between Control (no listing CTA) and Treatment (listing CTA). Summary panel shows a Healthy status, 1-day duration on August 26 2026, Treatment shipped as the winning variation with a relative difference of plus 1.0 and 100% probability to beat control. The experiment was stopped because Treatment beat control with plus 98.7% relative lift, statistically significant.

LaunchDarkly experiment summary for the inline Add to Cart listing CTA test. Treatment won decisively with 98.7% relative lift in add-to-cart conversion and 100% probability to beat control.

The Guarded Release ramps the winning variation from 20% to 30% to 40% while LaunchDarkly [1] applies sequential testing to the operational guardrail metric, halting the rollout as soon as the data shows a statistically significant regression against the original variation.. If a guardrail threshold is breached at any stage, LaunchDarkly reverts flag state at runtime without a redeployment. Guarded Releases and automatic rollback serve as the runtime safety net: if something goes wrong after deployment, the system reverts flag state without waiting for a human to intervene.

To validate the safety net in the reference implementation, we triggered a simulated error-rate spike during the ramp. LaunchDarkly detected the regression within the monitoring window, halted the rollout, and reverted the flag to its pre-rollout state automatically. No human intervened, no redeployment ran, and the application returned to the control behavior within seconds. The screenshot below shows the Guarded Release dashboard after the rollback.

LaunchDarkly Guarded Release dashboard showing an automatic rollback triggered by an error rate regression. A red banner states the default rule rolled back automatically after detecting a regression for Error Rate, ended August 27 at 10:23 AM. The error rate chart shows the treatment (true) variation at 0.507% versus control (false) at 0.498% with a sample size of approximately 500 per variation. The system rolled back to serving the false variation.

LaunchDarkly Guarded Release auto-rollback event. The system detected an error rate regression during the ramp phase and automatically rolled traffic back to the control variation.

After recording the rollback and feeding the outcome into the next iteration, the agent adjusted its approach and proposed a revised implementation that avoided the latency regression. The second attempt followed the same pipeline: hypothesis, feature flag, implementation, review, deployment, experiment, and Guarded Release. This time, monitoring completed with no regressions detected. LaunchDarkly rolled the winning variation forward to full traffic, with add-to-cart conversion lifting from 20.1% to 37.9% across the treatment population, confirming the experiment result held at scale.

LaunchDarkly Guarded Release dashboard showing successful monitoring completion. A green banner states monitoring completed on the default rule, ended August 27 at 10:48 AM. The Add to Cart metric chart shows the treatment (true) variation at 37.9% conversion versus control (false) at 20.1%, a lift of plus 17.7 percentage points. No regressions were detected, and the default rule rolled forward to serve the true variation. Sample sizes are 821 (true) and 864 (false).

LaunchDarkly Guarded Release monitoring completion. The Add to Cart metric showed a 17.7 percentage point lift with no regressions, so the system graduated the treatment to 100% of traffic.

After each cycle, the agent generates a report documenting the hypothesis, experiment results, rollout outcome, and a recommendation for the next iteration. This report feeds into the next decision, so no context is lost between cycles.

Add-to-Cart Experimentation Log showing a cycle summary table with three experiment cycles. Goal is to increase the add-to-cart metric by 10% in the default project and production environment. Cycle C tested adding an Add to Cart button directly to the listing page, resulted in a Winner outcome with plus 22.6% lift (significant, probability to beat baseline 98%), and was rolled out to 100%. Cycle B tested changing the button color from blue to green/orange, resulted in Inconclusive with plus 2.1% lift (not significant, approximately 120 units). Cycle A tested changing button placement on the detail page, resulted in Inconclusive with minus 1.4% lift (not significant, approximately 98 units).

Experimentation cycle summary showing three hypothesis-test iterations. Only Cycle C (inline Add to Cart on listing page) reached statistical significance and was promoted to production. The two cosmetic experiments (button color and placement) were inconclusive.

Safety boundaries

The system operates within defined constraints. The agent validates every change through release readiness review before merge. It creates a feature flag before writing any code, so every change can be toggled off without a redeployment. Guarded Releases enforce operational guardrails at runtime with automatic rollback. The agent retries failed validations up to three times, then stops and asks for help rather than proceeding. All credentials are stored in AWS Secrets Manager and referenced by name only, never exposed in agent logs or tool calls.

Getting started

To implement this workflow, you need AWS DevOps Agent enabled in your AWS account, a LaunchDarkly account (start with a free 30-day AWS trial), and a target application and repository. The reference uses a Next.js app deployed through AWS Amplify. Experiments are available on every LaunchDarkly plan, including the free Developer plan. Guarded Releases, which automate progressive rollouts with automatic rollback, require a LaunchDarkly Enterprise plan with the Guardian add-on. Without Guarded Releases, the workflow still runs experiments and reports results. You manage the rollout manually instead. If your plan does not include Guarded Releases, update the agent skill definition below to remove the Guarded Release actions.

Setup requires three steps. First, add the LaunchDarkly remote MCP server to your AWS DevOps Agent space. Second, deploy the Experiment MCP Server container to an AgentCore runtime, storing API keys and tokens in AWS Secrets Manager. Third, create your custom agent with the orchestration skill. Use the experimentation skill in AWS DevOps Agent to guide you through defining goals, connecting the MCP servers, and writing the orchestration instructions. The full orchestration skill is included below.

---
name: "experiment-orchestration"
description: "Orchestrates automated experimentation lifecycle using LaunchDarkly Guarded Rollouts, an AI coding agent for implementation, and GitHub Actions for deployment."
---
 
# Automated Experimentation
 
Use this skill when you have a goal you want to move through experimentation (e.g., "increase checkout conversion by 15%", "decrease page load time by 20%").
 
**Core principle: experiment first, then guarded rollout.** Always prove a change on a small, fixed slice of traffic via an A/B experiment before ramping it up through a guarded rollout. Never start a guarded rollout blind — it exists only to scale a change the experiment has already shown to work.
 
**Execution mode:** once the goal is confirmed (Step 1), run Steps 2–8 end-to-end. Async operations (code implementation, release review, deployment, experiment monitoring, rollout monitoring) should be checked periodically, not tight-polled — see the waiting note in each step. Only stop and ask the user something if a step fails unrecoverably (repeated failed release reviews, deployment failure, or an inconclusive/losing experiment result).
 
**The final report (Step 8) is mandatory, not optional.** The moment an experiment or rollout reaches a terminal outcome — winner, loser, inconclusive, or rollback — produce the full report in the same turn you announce the outcome. Don't let a casual "it worked! ????" substitute for the structured report.
 
## Step 1: Goal Clarification
 
Before doing anything, get answers to:
 
1. **What metric measures success?** *(Required)* e.g. conversion rate, page load time, bounce rate. Reserve your error-rate metric as a safety guardrail — never use it as the primary success metric.
2. **What's the target improvement?** *(Required)* e.g. 15% increase, 200ms decrease.
3. **What's the current baseline?** *(Optional — infer from production metrics if not given)*
4. **What parts of the app are in scope?** *(Optional — infer from the codebase if not given)*
5. **Any constraints?** *(Optional)* e.g. no changes to the payment flow.
 
Questions 1–2 are required before proceeding; infer 3–5 where possible and confirm your assumptions with the user before implementing.
 
## Step 2: Hypothesis Generation
 
Explore the target repository/codebase to find a plausible change:
 
1. Search and read the relevant code paths.
2. Think through what UI/UX or logic change could plausibly move the chosen metric.
3. Check whether this hypothesis (or something close to it) has already been tried and failed — look at flag history or archived flags with similar naming. Avoid repeating a known failure.
4. Present the hypothesis to the user before proceeding, along with your reasoning and any inferred assumptions from Step 1.
 
**Before finalizing a flag key, check for collisions:** look up any candidate flag key first.
- Already fully shipped (100% one variation, no split) → already decided, pick a different hypothesis.
- Actively running an experiment → mid-flight, don't compete with it, pick a different hypothesis.
- Doesn't exist → safe to create.
 
## Step 3: Implementation
 
1. Create a boolean feature flag, OFF by default in all environments. Name it with a clear pattern like `exp-<metric>-<short-description>` (e.g. `exp-checkout-conversion-cta-color`), lowercase with hyphens, ~50 chars max.
2. Hand off implementation to your coding agent/tool of choice, with clear instructions to gate the change behind the exact flag key from step 1.
3. This step is asynchronous — check status periodically rather than looping tightly on it.
4. Once implementation completes, move to Step 4 with the resulting branch/PR. If it fails, report the error and stop.
 
## Step 4: Release Readiness
 
Run your standard release/risk review on the PR before merging.
 
- If it passes: merge the PR.
- If it fails: feed the review's specific feedback back into implementation and retry. Cap retries at a small fixed number (e.g. 3 attempts total) — if it still hasn't passed, stop and report the last failure to the user rather than retrying indefinitely.
 
*(If your environment genuinely has no review capability available — e.g., a fully unattended automation context — you can skip straight to merge, but treat that as a deliberate, narrow exception you call out explicitly, not a default. Skipping review removes your only gate against shipping broken code.)*
 
## Step 5: Deployment
 
Deployment typically won't fire automatically on merge if your workflow is manually-triggered (`workflow_dispatch`-only) — you'll need to trigger it explicitly.
 
1. Trigger the deploy workflow on the merge target branch. Treat "already an in-progress deployment for this ref" as expected de-duplication, not an error — don't re-trigger.
2. Poll for status, but let your polling tool's own internal long-poll do the waiting rather than looping tightly yourself.
3. Watch for a "stale" status specifically: if a deployment reports "running" for far longer than normal, cross-check the actual CI run history by commit SHA/timing before assuming it's still in progress — a background poll process may have died without updating the record.
4. **Trigger a deployment at most once per attempt.** If you're unsure whether a previous trigger succeeded, check status first — never re-trigger just because you're unsure.
5. On timeout: stop, check the CI run directly, report the situation, ask how to proceed.
6. On explicit failure: stop and report — do not proceed to the experiment.
7. On success: proceed immediately to Step 6.
 
## Step 6: Experiment Phase (fixed 10%)
 
Prove the change on a small, fixed slice of traffic. Do **not** start a guarded rollout here — that's Step 7, and only after this proves out.
 
1. Turn the flag ON.
2. Configure a fixed 50/50 split across 10% of traffic (a flat allocation, not a staged ramp) on your chosen randomization unit (typically "user"). The remaining 90% of traffic is excluded from the experiment entirely. 
3. Create an experiment with:
   - Exactly one primary metric: the success metric from Step 1.
   - Guardrail metric(s): always include your error-rate metric; add a performance metric (e.g. p95 page load time) too if this is a performance-focused change.
   - Treatments: control (off) at 50%, treatment (on) at 50%, allocated to 10% of total traffic.
4. Start the experiment/data collection.
5. Move to Step 7 to monitor toward a decision.
 
## Step 7: Monitoring & Outcome
 
Check status periodically — don't tight-loop. In an interactive session, check once and report progress, then pick back up later. In an unattended/scheduled context, check once per invocation and persist your progress somewhere durable between runs.
 
**Phase 1 — Prove the experiment at 10% (gate before any rollout):**
 
Watch for statistical significance on the primary metric:
 
- **Significant + positive lift** → experiment proven. Stop the experiment iteration and move to Phase 2.
- **Significant + negative lift** → declare a loser, archive the flag, skip Phase 2, go straight to the Step 8 report.
- **No significance after a reasonable ceiling (e.g. 30 minutes)** → report "inconclusive, need more traffic" and stop; don't proceed to Phase 2.
 
Never declare a winner off a single data point or before your stats engine confirms significance.
 
**Phase 2 — Guarded rollout ramp (only after Phase 1 proves the change):**
 
Start a guarded rollout with:
- The winning ("on") variation as the test, the original as control.
- Same randomization unit as the experiment.
- **Exactly 3 monitored stages, capped well below 100%** — e.g. 20% → 30% → 40%, ~60 minutes monitoring each. Don't add a stage at or above 100%; Guarded-rollout implementations reject stages above 50% audience allocation, and the rollout auto-promotes to 100% itself once the final monitored stage completes cleanly — no explicit 100% stage needed.
- The same primary + guardrail metrics as the experiment, each configured to notify and auto-rollback on regression.
 
Track stage progression. If the rollout rolls back or stops at any point, treat it as a regression: declare failed, clean up the flag (deprecate/archive it), and go to the Step 8 report.
 
Once the final stage completes cleanly and auto-promotes to 100%, declare a winner and go to the Step 8 report.
 
**Retrying after a rollback:** a rollback isn't always caused by your monitored metrics genuinely regressing — it can also be triggered by an unrelated application error surfacing mid-ramp. Before blindly restarting after the user says they've fixed something:
1. Confirm the flag's current state (should be back to 100% control, nothing stuck mid-rollout).
2. Check the change history timing between "advanced to next stage" and "reverted." A rollback within seconds of advancing is inconsistent with a full metric-window regression and points to an external cause instead.
3. If the flag is cleanly reverted and the external cause is confirmed fixed, it's safe to restart the guarded rollout from scratch with the same parameters.
4. Don't silently retry without this check, and don't refuse to retry just because a prior attempt rolled back — a genuinely fixed external cause is a legitimate reason to retry. A metric-driven loser is not — don't retry that.
 
**On any terminal outcome, immediately produce the Step 8 report in the same turn** — a one-line "it worked!" note is fine as a lead-in, but the structured report must follow, not wait for a follow-up request.
 
## Step 8: Report
 
Runs automatically the instant Step 7 reaches a terminal outcome (winner + auto-promoted to 100%; loser; inconclusive; or rollback/failure). Use this exact structure:
 
```
## Experiment Report: [Goal Description]
 
**Date:** [YYYY-MM-DD]
**Goal:** [metric] [direction] by [target]%
**Status:** [achieved / in progress / stalled]
 
### Hypothesis
[What we tried and why]
 
### Implementation
- Flag: [flag_key]
- Files modified: [list]
- Branch: [branch name]
 
### Release Readiness
- [reviewed, passed after N attempt(s) / skipped, per your environment's process]
 
### Experiment Phase (10% fixed split)
- Status: [proven / loser / inconclusive]
- Duration: [time]
- Metric change: [before] → [after] ([+/-]%)
- Statistical significance: [value, confidence interval]
 
### Guarded Rollout Phase (if reached)
- Status: [completed / rolled_back / not started]
- Duration: [time]
- Stages reached: [N of 3 monitored stages]
- If rolled back and retried: [root cause, outcome of retry]
 
### Safety Metrics
- error-rate: [baseline] → [final] ([no regression / regression detected])
- [other guardrails]: [baseline] → [final] ([status])
 
### Next Steps
[What to do next based on the outcome]
```
 
## Safety Rules (the non-negotiables)
 
- Always present the hypothesis before implementing.
- Always run a release/risk review before merging, unless your environment has a deliberate, explicitly-called-out exception.
- **Always prove a change via a fixed small-percentage experiment before starting any guarded rollout** — never ramp blind.
- Always include an error-rate (or equivalent "don't break prod") metric as a guardrail, separate from your success metric.
- Add a performance guardrail (e.g. p95 latency) for performance-focused changes.
- Every rollout metric should be configured to both notify AND auto-rollback on regression — don't rely on notification alone.
- **Cap guarded rollout stages well below 100%** (most platforms reject stages ≥50% audience allocation) and let the platform auto-promote to 100% after the final stage — don't try to add an explicit 100% stage.
- Distinguish a metric-driven rollback (don't retry) from an external-cause rollback (safe to retry once fixed) before restarting a rolled-back rollout.
- The final report is automatic and mandatory on every terminal outcome — never defer it to a follow-up ask.

Conclusion

This post described how AWS DevOps Agent, Kiro CLI, and LaunchDarkly connect into a closed-loop system that turns an improvement goal into a series of measured, safe experiments. The agent runs autonomously on a schedule: it generates hypotheses informed by prior outcomes, creates feature flags before any code change, invokes Kiro CLI in headless mode to implement changes behind those flags, validates through release readiness review, deploys through GitHub Actions and AWS Amplify, and hands off to LaunchDarkly for experiment measurement and guarded rollout. If a guardrail is breached at any point during the rollout, LaunchDarkly reverts flag state at runtime without a redeployment. After each cycle, the agent records what happened and feeds it into the next decision.

This directly addresses the three barriers that slow experimentation:

● Planning cost is reduced because the agent handles hypothesis generation, flag creation, implementation coordination, and validation. The team defines the goal; the system handles the wiring.

● Measurement disconnected from action is addressed because LaunchDarkly monitors metrics in real time and reverts flag state automatically when a guardrail is breached, requiring no redeployment and no waiting for a human to notice.

● Stalled iteration is solved because every outcome is recorded and fed into the next hypothesis automatically. The system does not forget what it learned, and it does not stall between iterations.

The architecture is available to implement today as a reference. The orchestration skill included in this post encodes the full 8-step workflow: goal clarification, hypothesis generation, implementation, release readiness, deployment, experiment, monitoring, guarded rollout, and reporting. Teams define their improvement goal, connect the LaunchDarkly MCP server and the Experiment MCP Server to a DevOps Agent custom agent, and let the system iterate toward the target within the safety boundaries they configure. A more turnkey experience is planned for the future.

Authors

Greg Eppel

Greg Eppel is a Principal Specialist for DevOps Agent and has spent the last several years focused on Cloud Operations and helping AWS customers on their cloud journey.

Jonathan Nolen

Jonathan Nolen is the CPO at LaunchDarkly, the leading platform for Runtime Control for AI software development.

He first joined LaunchDarkly in 2018 and has led the Product, Engineering and Design teams. Currently he is leading the team to build critical infrastructure that helps thousands of customers deliver at agentic speed and still ship software safely. Jonathan was at Atlassian from 2005 until 2018. He helped grow the company from 25 employees to over 2,500 and contributed to multiple Atlassian products. Jonathan and his team also built the Atlassian Marketplace, which in 2024 had done over $3 billion of business for the Atlassian community.

From clickops to governed IaC: CloudFormation drift detection in practice

Post Syndicated from Leen Alattas original https://aws.amazon.com/blogs/devops/from-clickops-to-governed-iac-cloudformation-drift-detection-in-practice/

AWS environments that have grown organically over time often share a common characteristic: infrastructure provisioned through the AWS Management Console, SDKs, or CLI without corresponding Infrastructure as Code (IaC) templates. This practice is commonly referred to as “ClickOps,” a term describing any infrastructure change made outside of a codified, version-controlled workflow. Whether changes happen through the console, the AWS CLI, or application SDKs, the result is the same: resources exist without a declarative template to describe their intended state. 

Over time, these manual changes accumulate, creating environments where Amazon Virtual Private Cloud (Amazon VPC) configurations, Amazon Elastic Compute Cloud (Amazon EC2) instances, and Amazon Simple Storage Service (Amazon S3) buckets exist without a single AWS CloudFormation template to describe them. 

Organizations that find themselves in this position have a clear opportunity. CloudFormation’s IaC Generator provides a practical starting point for bringing existing infrastructure under declarative management. It scans an AWS account and produces CloudFormation templates from existing resources, solving the first and most fundamental challenge: you cannot govern infrastructure you cannot see. 

However, generating a template is only the beginning. What follows is the operational thinking behind turning a generated template into something a team can govern and automate: the decisions, trade-offs, and organizational habits that determine whether IaC adoption succeeds long-term. 

IaC Generator: making the invisible visible 

CloudFormation’s IaC Generator scans an AWS account and produces CloudFormation templates from existing resources: Amazon VPCs, subnets, Amazon EC2 instances, Amazon S3 buckets, AWS Identity and Access Management (IAM) roles, and more. It solves the foundational problem of any ClickOps-to-IaC migration: establishing visibility into what exists and how it is configured. 

How it works at a high level 

Scan — IaC Generator discovers resources in the account by querying AWS Cloud Control API, identifying what exists regardless of how it was provisioned. 

Generate — It produces CloudFormation templates that represent the current state of those resources, mapping properties, dependencies, and relationships. 

Review — Teams evaluate the generated templates, reconcile any gaps, and decide how to bring each resource under management. 

This process eliminates weeks of manual documentation work. Instead of engineers mapping infrastructure by hand, IaC Generator produces a baseline in minutes. For a team managing 200+ resources across multiple VPCs, this can compress a multi-sprint effort into a single planning session. 

Understanding what the generator produces 

The generated templates capture the current state of resources, including every manual configuration and accumulated change. Before acting on a generated template, teams should understand what it represents and what it does not. 

Important: IaC Generator does not cover all resource types supported by CloudFormation. Before committing to an import path for any resource, verify that the resource type is supported. Coverage continues to expand, but teams should confirm support for their specific resource types before planning their migration approach. 

The generated template provides an inventory of infrastructure and surfaces implicit dependencies that were never documented. However, a template in a repository does not prevent out-of-band changes, enforce review processes, or protect against drift. Visibility is the prerequisite for control, not a substitute for it. 

Import or recreate: making the right decision for each resource 

When bringing existing resources under CloudFormation management, teams must decide on a per-resource basis whether to import a resource into a stack or to recreate it cleanly. The right choice depends on the specific characteristics of each resource: its criticality, how much operational disruption is acceptable, the complexity of its dependencies, and the technical limitations of the tooling. CloudFormation does not support partial adoption of an existing resource: a resource is either fully imported into a stack or newly provisioned through a stack. This is what makes the decision binary and per-resource rather than incremental. 

A note on configuration drift in this context: configuration drift occurs when the actual state of a resource diverges from what is defined in a template. A resource that was provisioned manually may be in a perfectly valid operational state, but it has no template against which to measure compliance. The goal of importing is to establish that baseline, not to imply the current configuration is inherently flawed.

Factor  Import existing resource  Recreate with new stack 
Resource criticality  High: production, live data, tight dependencies  Lower: dev/test, stateless, easily replaceable 
Manual changes  Significant: many out-of-band modifications  Minimal: resource is close to desired state 
Downtime tolerance  Zero: any interruption is unacceptable  Acceptable: brief maintenance window tolerable 
Template fidelity  Lower: generated template may be imperfect  Higher: full control over the final template 
Dependency complexity  High: cross-service dependencies difficult to isolate  Lower: resource can be isolated and rebuilt cleanly 

Technical limitations to consider 

Beyond operational factors, the IaC Generator has technical constraints that should inform the import-versus-recreate decision: 

  • Resource type coverage: Not all resource types supported by CloudFormation are supported by IaC Generator. Before committing to an import path, verify that the specific resource types are supported. If a critical resource type is not covered, the template must be written manually. 
  • Write-only properties: Some resource properties (such as passwords or secrets) are write-only and cannot be read back during scanning. Generated templates show placeholder values for these, requiring manual reconciliation. In production environments, this may require integration with AWS Secrets Manager or a similar secrets management solution. 
  • Hard-coded values: Generated templates produce literal values rather than parameterized inputs. Plan for a refactoring pass to introduce parameters, mappings, and conditions. 
  • Cross-account and cross-region references: IaC Generator operates within a single account and region. Resources with dependencies spanning accounts or regions require additional manual template work. 

For production resources, stateful workloads, and resources with complex dependency graphs, import is generally the appropriate default. The import operation brings resources under CloudFormation management without recreating them, preserving their current state. The trade-off is that the generated template becomes the starting point, and teams must reconcile any gaps between that template and actual resource state before making subsequent changes. 

Recreation is more appropriate when a resource can tolerate a brief maintenance window, when accumulated manual changes make a clean start more efficient than reconciliation, or when the architecture is being redesigned as part of the migration. 

The most effective approach is to segment the inventory by resource type, criticality, and configuration complexity, then match the strategy to each segment. An Amazon VPC that has been modified extensively over three years presents a different challenge than an Amazon S3 bucket created last month. 

Organizing stacks for operational reality 

A common challenge after bringing resources under CloudFormation management is determining the appropriate stack boundaries. Placing all resources into a single monolithic stack creates operational risk: changes to VPC and subnet infrastructure can inadvertently affect application resources, a rollback on an application deployment can revert infrastructure changes, and accountability becomes diffuse. When ownership is unclear, incident response slows. 

Organizing stacks around lifecycle, ownership, and change frequency addresses this challenge. The key principle is to group resources that share the same rate of change and the same responsible team: 

When these criteria conflict, ownership takes precedence: a shared resource should reside in the stack owned by its primary responsible team, with cross-stack references providing access to consuming teams. 

  • VPC and subnet infrastructure changes infrequently and is typically managed by a platform or infrastructure team. 
  • Application infrastructure changes frequently and is managed by the application teams that deploy to it. 
  • Security controls warrant their own stacks under security team ownership, insulated from application deployment cycles. 

Cross-stack references, through CloudFormation exports and imports, preserve these boundaries while maintaining relationships between stacks. A VPC stack exports Amazon VPC and subnet IDs; application stacks import them. This separation means that application deployments do not modify network configuration, and VPC or subnet changes do not require redeploying application stacks. 

Note: this separation does not eliminate all cross-cutting concerns. Changes to security groups or network ACLs, for example, may still require coordination with application teams. The goal is to reduce unintended coupling, not to eliminate all interdependency. 

This structure makes governance at scale tractable. When stacks have clear boundaries and named owners, drift detection becomes actionable. Teams know exactly who owns a drifted resource and who needs to respond. 

Drift detection: moving from reactive to continuous 

Defining drift: Configuration drift occurs when the actual state of a resource diverges from what is declared in its CloudFormation template. Drift can originate from manual console changes, AWS CLI or SDK operations, automated processes that modify resources outside of CloudFormation, or any action that bypasses the IaC workflow. Drift is not inherently a failure; it often reflects legitimate operational decisions made under time pressure. The challenge is maintaining awareness of these changes so they can be evaluated and reconciled deliberately. 

CloudFormation’s native drift detection tells teams whether resources match their templates. What it cannot do on its own is provide continuous monitoring. Manual, on-demand checks are valuable, but they are reactive. By the time a team runs one, the drift may have already caused a downstream issue. 

Automating drift detection with Amazon EventBridge 

Continuous drift detection requires three capabilities: scheduled detection runs, event capture when drift is found, and routing of alerts to the appropriate team. Amazon EventBridge provides the orchestration layer that connects these capabilities: 

  • Schedule drift detection: Configure an EventBridge rule with a cron expression to trigger the DetectStackDrift API on critical stacks at regular intervals (for example, every 6 hours for production stacks, daily for non-production). This is a custom configuration, not a built-in default; teams define the schedule based on their operational requirements. 
  • Capture drift events: CloudFormation emits events to the default EventBridge event bus when drift detection completes. Create rules that filter for CloudFormation Stack Drift Detection Status Change events where the drift status is DRIFTED. 
  • Automated remediation (with caution): For well-understood, low-risk drift patterns in non-production environments, EventBridge can trigger an AWS Lambda function that applies a drift-aware change set. However, automated remediation in production environments requires careful consideration. See the guidance below on remediation policy. 

Remediation policy: a deliberate decision 

Whether drift triggers a notification or an automated correction should be a deliberate, documented policy decision. Several factors argue for caution with automated rollbacks: 

  • Drift is typically detected well after it occurred. The change was not random; a person or process determined it was necessary at the time. 
  • Automatically reverting a change without understanding why it was made can reintroduce the problem it was intended to solve. 
  • In production environments, the safest default is to alert the owning team and let them evaluate whether the drift should be reconciled into the template or reverted. 

Automated remediation is most appropriate in controlled environments (development, staging) or for narrowly-scoped, well-understood drift patterns where the risk of unintended consequences is minimal. 

Drift-aware change sets 

Drift-aware change sets extend drift awareness into the deployment pipeline. Before applying changes, a drift-aware change set evaluates the actual current state of a stack rather than the last known state. This is critical when someone made a manual change under operational pressure but has not yet reconciled it. A routine deployment should not silently overwrite a deliberate operational decision. 

This capability supports the position that drift should generally be reconciled deliberately rather than reverted automatically. When a drift-aware change set reveals unexpected state, the deploying team can pause, investigate, and decide whether to incorporate the drift into the template or proceed with the planned change. 

Over time, drift data provides organizational insight beyond individual resource compliance. The same resource drifting repeatedly, or the same team consistently making out-of-band changes, points to gaps in process, tooling, or team capacity. That signal is valuable only if someone is reviewing it systematically. 

The operational maturity journey 

Moving from ClickOps to fully governed CloudFormation management is not a single migration event. The progression moves through four recognizable stages: 

 

Level  Stage  What it means 
Level 1  Visibility  The team knows what exists. IaC Generator provides templates that represent the infrastructure. Necessary, but not sufficient. 
Level 2  Control  Resources are under CloudFormation management. Changes route through templates and change sets. Drift is detectable. 
Level 3  Automation  Drift detection runs on schedule. CI/CD pipelines incorporate drift awareness. Governance is a property of the deployment process. 
Level 4  Governance  Compliance policies are enforced automatically. Drift outside defined parameters triggers remediation or escalation. Infrastructure state is continuously validated against policy. 

Moving from visibility to control is primarily an organizational challenge. It requires three deliberate shifts: 

  1. Ownership

Every CloudFormation stack needs a named team responsible for its drift state. Establish this accountability through: 

  • A mandatory team-owner tag applied to every stack. 
  • Integration with AWS Service Catalog to enforce ownership metadata from provisioning onward. 
  1. Process

Changes need to be routed through CloudFormation, not around it. Any change made outside of the IaC workflow (whether through the console, CLI, or SDK) is a potential source of drift. Governance controls include: 

  • AWS CloudTrail with EventBridge rules that flag API calls made outside of CloudFormation. 
  • A defined reconciliation window (for example, 24 hours for production hotfixes) that acknowledges operational reality while maintaining accountability. 
  1. Feedback loops

Point-in-time drift snapshots are useful, but trends over time are more valuable for identifying systemic issues. Build feedback mechanisms that surface patterns: 

  • Use Amazon Athena to query historical drift data for recurring patterns. 
  • Feed drift metrics into existing operational review cadences. 

Conclusion 

IaC Generator makes the invisible visible. It turns infrastructure provisioned outside of IaC workflows into CloudFormation templates that can be versioned, reviewed, and automated. The template is not the destination; it is the starting point for building infrastructure that teams can change with confidence and govern at scale. 

The real work is organizational: assigning stack ownership, routing changes through CloudFormation, building continuous drift awareness, and treating drift data as a signal about process gaps rather than as a compliance checkbox. Organizations that approach this as a cultural shift alongside a technical migration are the ones that sustain the gains long-term. 

Getting started 

For teams ready to implement this approach, the following resources provide step-by-step guidance: 

  • Implement drift notification routing: Use AWS Chatbot with EventBridge to route alerts to team channels, or trigger ticket creation via AWS Lambda. 

Leen AlAttas is a Technical Account Manager in the AWS Enterprise Support organization based in Riyadh, Saudi Arabia, where she has spent the past year helping enterprise customers optimize their cloud operations. She specializes in security and works closely with organizations to strengthen their AWS security posture. 

John Chebib is a Senior Technical Account Manager at AWS based out of Bahrain. He works with customers providing technical assistance and architectural guidance on various AWS services. He brings several years of experience in data analytics and architectural roles for various large-scale enterprises.

Automate SageMaker HyperPod incident triage and root-cause-analysis with AWS DevOps Agent

Post Syndicated from Tomonori Shimomura original https://aws.amazon.com/blogs/devops/automate-sagemaker-hyperpod-incident-triage-and-root-cause-analysis-with-aws-devops-agent/

Introduction

Large-scale machine learning workloads: training, fine-tuning, and inference run on clusters of hundreds to thousands of GPU instances for days or weeks at a stretch. Keeping operational visibility across a fleet of this size is a constant challenge: hardware health events, node lifecycle transitions, capacity fluctuations, and workload-level issues appear in the event stream around the clock, including nights and weekends.

Amazon SageMaker HyperPod is a purpose-built managed cluster service that lets you run distributed model training, fine-tuning, and inference across hundreds of accelerated instances. It provides built-in resiliency that automatically detects and replaces faulty hardware, so long-running jobs can continue with minimal interruption.

For teams operating these clusters, the scale still creates a fundamental tension: you need continuous visibility into your fleet, but you can’t afford to keep engineers watching the event stream 24/7. 

What HyperPod resiliency already handles

SageMaker HyperPod’s built-in resiliency layer automatically detects and self-heals instance-level GPU failures. When the Health Monitoring Agent (HMA) identifies a bad GPU, the HyperPod resiliency layer drains, reboots, or replaces the node depending on the error type, and the job resumes without human intervention. This is exactly what you want: routine hardware failures are handled automatically so your training runs keep going. 

This solution does not replace HMA or any part of HyperPod’s resiliency. It adds an autonomous investigation layer on top, using the cluster events and health signals that HMA and HyperPod already produce as its input. 

Operational conditions where a human still wants to be in the loop 

With that self-healing in place, there are operational conditions where a human still wants to be in the loop or decide: 

  • Configuration issues: a lifecycle-script change you made, a misconfigured mount, or a networking/security change that causes provisioning failures on every new node. 
  • Capacity conditions: a replacement waiting on capacity in the pool, where the operator needs to know recovery is in flight and can decide whether to intervene. 
  • Recurring hardware faults: each fault self-heals correctly, but the same GPU error signature recurring across three or more replacements on one instance group in a week is a pattern worth surfacing to an operator as a single signal. 
  • Workload-level conditions: Pods stuck in CrashLoopBackOff for hours, nodes sitting NotReady, or GPU allocation chronically low. 

Without automation, these conditions push operators into round-the-clock manual triage: correlating events across the SageMaker control plane, Amazon EKS, and Amazon CloudWatch, and deciding whether HyperPod is still recovering or needs a hand. 

Opportunity: AWS DevOps Agent as a 24/7 companion 

AWS DevOps Agent provides an autonomous incident-response platform that can be taught a domain’s operational model through custom skills. By wiring your HyperPod cluster into DevOps Agent, you get a 24/7 companion that complements HyperPod’s self-healing. It watches for the operational conditions that still need a human decision, triaging them, root-causing them, and delivering a clear verdict with recommended actions. 

By design, DevOps Agent is configured to run in observe-and-report mode for this integration – it is not granted SSM, SSH, or action-taking permissions against your cluster or its nodes. The agent reads cluster events, control-plane state, Kubernetes objects, and CloudWatch logs to reconstruct what happened; every corrective action (node reboots, replacements, drains) continues to be performed by HyperPod’s own resiliency layer or by an operator responding to the emailed verdict. This read-only boundary is deliberate: it keeps the agent’s blast radius zero while still delivering the correlation and triage value. 

​​In this post, you will learn how to connect any SageMaker HyperPod cluster (either the EKS or Slurm Orchestrator option) to AWS DevOps Agent. Conditions are auto-detected, triaged, root-caused from cluster state and CloudWatch logs, and emailed as a clear verdict. You will also see how the solution can be extended to detect additional conditions specific to your workloads.​ 

Solution Overview 

What this solution delivers 

This solution wires any SageMaker HyperPod cluster into AWS DevOps Agent so that operational conditions calling for a human decision are auto-detected, triaged, root-caused, and delivered as a human-readable verdict email. Specifically, you get: 

  • Autodetection of HyperPod conditions that complement resiliency self-healing, from the live SageMaker event stream and a periodic Kubernetes-state audit. 
  • Triage + root-cause analysis by the DevOps Agent, taught HyperPod’s operational model via two custom skills. It reconstructs the incident timeline and decides whether HyperPod is still recovering or needs an operator. 
  • Human-readable verdict emails: Monitor (recovery in flight, here’s the ETA), Escalate (you need to act, here’s why and what to do), or Resolved (auto-recovery closed the loop). Noise is filtered out. 
  • Extensibility: customize what conditions are detected (by modifying the periodic-audit Lambda) and how the agent reasons about them (by editing the plain-English skills). 

The following screenshot shows the DevOps Agent incident response dashboard with example verdict emails for three common fault types: 

DevOps Agent incident response dashboard showing investigation list and timeline, with three email verdict examples for GPU NVLink fault, lifecycle-script bootstrap failure, and insufficient-capacity errors

DevOps Agent incident response dashboard showing investigation list and timeline, with three email verdict examples for GPU NVLink fault, lifecycle-script bootstrap failure, and insufficient-capacity errors

Architecture 

The whole solution deploys one AWS CloudFormation stack per cluster. Two event paths feed the DevOps Agent, and one path carries its verdicts back out to you. 

Architecture diagram showing the event flow from HyperPod Health Monitoring Agent through EventBridge to DevOps Agent and email notification

Architecture diagram showing the event flow from HyperPod Health Monitoring Agent through EventBridge to DevOps Agent and email notification

This architecture shows a 1:1 relationship between a HyperPod cluster and a DevOps Agent space, and the deployment instructions in this post follow that model. If you need to associate multiple clusters with a single Agent Space, you can customize the CloudFormation template and the ClusterFilter parameter to widen the allowlist of cluster names forwarded by the webhook bridge.

Event flow 

  1. Event-driven issue detection: HyperPod emits cluster-state, node-health, and capacity events to Amazon EventBridge. The webhook bridge Lambda drops routine Info-level noise, maps the rest into a DevOps Agent investigation payload, signs it with HMAC-SHA256 using a shared secret stored in AWS Secrets Manager, and POSTs it to the agent’s generic webhook. 
  1. Polling-based issue detection: A periodic-audit Lambda checks Kubernetes state (CrashLoopBackOff pods, NotReady nodes) every 15 minutes and fires only when it finds a real issue, plus a daily heartbeat confirming the pipeline is alive. On a healthy cluster, nothing is POSTed, so no investigation runs and no cost is incurred. 
  1. Investigation: DevOps Agent receives the payload and runs two custom skills: the triage skill decides whether to link (duplicate), skip (noise), or proceed (investigate). The RCA skill reconstructs the timeline using describe-cluster, list-cluster-nodes, list-cluster-events, kubectl, and CloudWatch logs (HMA health monitoring, lifecycle scripts), then classifies the incident as Suppress, Monitor, Escalate, or Resolved. 
  1. Notification: An Amazon Lambda function sends notification emails via Amazon SES. It listens on the aws.aidevops event stream for investigation completions, reads the verdict from the agent’s journal, and sends an email with the headline, what happened, likely cause, and recommended action. Suppress verdicts are filtered to avoid noise on healthy clusters. 

​​Getting started​ 

For a step-by-step walkthrough to deploy this solution, visit the DevOps Agent Integration guide. Once you have the solution running, the following sections explain how to customize detection, reasoning, and notifications for your environment. 

Prerequisites 

  • An AWS account with AWS CLI v2 configured for the target region. 
  • An existing SageMaker HyperPod cluster (EKS or Slurm orchestrator). 
  • IAM permissions to create roles, deploy CloudFormation, manage Secrets Manager, and call devops-agent:* and eks:CreateAccessEntry. 
  • For email notifications: a verified Amazon SES sender identity. You can verify an email address in the Amazon SES console or with the AWS CLI. After running the command below, the address owner will receive a verification email and must click the confirmation link:

    aws ses verify-email-identity --email-address [email protected]

    Recipients must also be verified if your SES account is still in sandbox mode. 

Deploying with CloudFormation

The solution deploys as a single CloudFormation stack. Clone the awsome-distributed-ai repository, create a params.json with your cluster name and email settings, and run: 

cd 1.architectures/5.sagemaker-hyperpod/tools/devops-agent

# 1. Set up a Python env with boto3 >= 1.43.25
python3 -m venv .venv && source .venv/bin/activate && pip install 'boto3>=1.43.25'

# 2. Fill in your cluster name and email addresses
cp deploy/params.example.json deploy/params.json
# edit: HyperPodClusterName, EmailSender, EmailRecipients 

# 3. Deploy
make deploy

This provisions the Agent Space with read-only EKS access (auto-discovered from the cluster’s orchestrator ARN), the EventBridge rule and webhook bridge Lambda, the periodic-audit scheduler, and the email notifier. For Slurm-orchestrated clusters, the EKS access step is skipped automatically. 

The webhook bridge — mapping HyperPod events to DevOps Agent 

An EventBridge rule captures HyperPod events and invokes a Lambda function. The Lambda forwards all Warn and Error level events, normalizing each into a DevOps Agent investigation payload. It extracts the failure message, instance group, and event metadata, then signs it with HMAC using a shared secret stored in AWS Secrets Manager, and POSTs it to the agent’s generic webhook endpoint. Info-level events are dropped at the bridge to avoid creating investigations for routine status updates. 

A cluster allowlist parameter lets you scope which HyperPod clusters trigger investigations, useful when multiple clusters share the same account and region. 

How the skills are defined — teaching the agent HyperPod’s operational model 

AWS DevOps Agent skills are plain-English instructions that teach the agent how to reason about a domain. This solution includes two complementary skills: 

Triage skill — LINKED / SKIPPED / PROCEED (view the skill document) 

The triage skill runs first on every incoming task. It decides whether to link the event to an existing investigation, skip it, or proceed to a full investigation. 

  • Why triage matters — a concrete example: When a single node fails, HyperPod’s replacement process emits multiple events in quick succession: “lost orchestration-ready status,” “provisioning started,” “capacity request initiated.” Without triage, each event would spawn a separate investigation. The triage skill recognizes these events belong to the same incident (same instance group + overlapping time window) and links them, so only one investigation runs. This saves investigation compute and avoids duplicate emails. 
  • When to SKIP: When a node is already being replaced and a follow-up “lost orchestration-ready status” event arrives with a generic “Request to service failed” message, the triage skill recognizes that a replacement is already in progress for that instance group and skips the event. No new investigation is created for what is simply a progress update of an existing recovery. 

RCA skill — timeline reconstruction and verdict (view the skill document) 

When triage produces PROCEED, the RCA skill takes over. It reads cluster state, events, and logs, reconstructs an incident timeline, and classifies the situation into one of four verdicts:

 RCA Flowchart showing the four phases of root-cause analysis: data gathering, timeline reconstruction, classification, and recurrence check

RCA Flowchart showing the four phases of root-cause analysis: data gathering, timeline reconstruction, classification, and recurrence check

  • Phase 1 — Data gathering: The skill reads describe-cluster, list-cluster-nodes, list-cluster-events, and CloudWatch log streams (HMA health monitoring, lifecycle scripts) to collect the raw facts. 
  • Phase 2 — Timeline reconstruction: It orders events chronologically and identifies the fault chain: what triggered what, which nodes were affected, and what recovery actions HyperPod took. 
  • Phase 3 — Classification: Based on the timeline, recurrence statistics, and HyperPod’s resiliency behavior, it assigns a verdict: 
    • Suppress — a non-issue (for example, a transient event that has already resolved). 
    • Monitor — recovery is in flight; here’s the expected resolution window. 
    • Escalate — you need to act; here’s the root cause and recommended action. 
  • Resolved — auto-recovery closed the loop; no action needed. 
  • Phase 4 — Recurrence check: The skill computes sliding-window statistics over the one week cluster event history. When thresholds are crossed, the verdict escalates to alert the operator of a systemic pattern. For example, the same GPU error signature on the same instance group three or more times in a week, or five or more replacements fleet-wide in 24 hours. 

The verdict is written to the agent’s investigation journal along with a human-readable report containing what happened, the likely cause, and recommended operator actions. 

The periodic-audit Lambda — Kubernetes state monitoring 

The periodic-audit Lambda fires every 15 minutes and inspects Kubernetes Pod/Node state directly (via the EKS API server). It checks for: 

  • Pods in CrashLoopBackOff (default: flagged when restart count reaches five and the last crash is within 15 minutes) 
  • NotReady nodes (default: flagged when a node has been NotReady for at least 15 minutes and at least 10% of nodes are affected) 

Namespace-aware filtering controls which pods are checked: 

  • Pods in kube-public and kube-node-lease are ignored entirely by default. 
  • Pods in kube-system, aws-hyperpod, and amazon-cloudwatch are tagged as system-workload issues (distinct from user-workload issues in the verdict). 

All thresholds and namespace lists are configurable via the CloudFormation stack parameters. 

The Lambda POSTs a webhook event to DevOps Agent only when a real issue is found. On a healthy cluster, nothing is POSTed, so no investigation runs and no cost is incurred. A separate daily heartbeat schedule confirms the monitoring pipeline itself is alive. The heartbeat is visible in the DevOps Agent console but deliberately not emailed on healthy runs — so silence in your inbox means the cluster is healthy, not that the pipeline is broken. 

Note: HyperPod infrastructure faults (node health, capacity errors, lifecycle-script failures) are handled event-driven by the webhook bridge. They come from the native HyperPod event stream in EventBridge. The periodic audit deliberately does not duplicate that path; it only covers Kubernetes workload state, which is not in the HyperPod event stream. 

Closing the loop — the email notifier

An EventBridge rule on the aws.aidevops event stream captures investigation lifecycle events. The email-notifier Lambda processes these events through the following steps: 

  1. Event filtering: Only “Investigation Completed” events are processed (one email per investigation lifecycle). The event payload contains the agent_space_id, task_id, and execution_id. 
  2. Dedup: The Lambda checks an S3 marker at s3://<bucket>/emailed/<execution_id>. If present, this investigation has already been emailed and the event is dropped. This prevents duplicate emails when the same completion event is re-emitted. 
  3. Fetching the investigation context: The Lambda calls two DevOps Agent APIs: 
    • get_backlog_task(agentSpaceId, taskId) — retrieves the task metadata (title, priority, timestamps). 
    • list_journal_records(agentSpaceId, executionId) — retrieves the investigation’s findings, symptoms, and investigation gaps from the agent’s journal. 
  4. Suppress-verdict filtering: If the investigation produced a Suppress verdict or no findings at all, no email is sent. 
  5. Email composition: The Lambda composes a single HTML email from the journal records: a short headline followed by a one-paragraph summary covering what happened, the likely cause, and the recommended action. 
  6. Send via SES: The formatted email is sent to the configured recipients. After successful delivery, the S3 dedup marker is written. 

The operator also has access to the full investigation in the DevOps Agent web console (see following “Viewing investigations” section). 

Viewing investigations in the DevOps Agent console 

For readers new to AWS DevOps Agent, here’s how to navigate to your investigations: 

  1. Open the AWS DevOps Agent console. 
  2. Select your Agent Space (named hyperpod-<cluster-name>-devops-agent by default). 
  3. From the Launch web app drop-down, choose an option to open the DevOps Agent web app. 
  4. Select Incidents from the left navigation pane to open the Incident Response Dashboard. It lists all investigations with their subject, status, and timestamp. 
  5. Select any investigation to see its full timeline, journal records, and the verdict report. 

Asking the agent directly — the DevOps Agent Chat UI 

Beyond the automated emails, you don’t have to wait for the next investigation to get answers about your cluster. You can open the DevOps Agent’s AI chat at any time and ask follow-up questions in plain English. The agent answers from the live cluster state, the investigation history, and the skills it has been taught. 

For example: 

  • “I got an email about a GPU failure in my cluster. Did it get resolved now with HyperPod’s resiliency?” — The agent checks the current cluster state, confirms whether the replacement succeeded, and provides a timeline of what happened (HMA detection → replacement initiated → node back in service), along with anything to watch for. 
  • “Are there unhealthy Pods on my cluster?” — The agent inspects the Kubernetes state and reports any CrashLoopBackOff pods or NotReady nodes. 
  • “I just triggered scaling up. Check if it is progressing well.” — The agent looks at the cluster’s current node counts vs. target counts and reports whether provisioning is on track. 
AWS DevOps Agent chat interface showing a natural language query about cluster health

AWS DevOps Agent chat interface showing a natural language query about cluster health

The chat conversations are stored per Agent Space, so you can revisit past interactions alongside the automated investigations. This makes the Agent Space a single pane of glass for both automated incident response and ad-hoc troubleshooting of your HyperPod cluster. 

Extending the solution — detection vs. reasoning 

The solution has two extension points, which serve different purposes: 

  1. Extending detection (what conditions are caught): 
    • Event-driven path: The webhook bridge Lambda drops Info-level events and forwards all Warn and Error level HyperPod events to DevOps Agent. This typically does not need modification. It already catches all actionable events. 
    • Polling-based path: The periodic-audit Lambda checks Kubernetes state. To detect additional conditions (for example, GPU allocation below a threshold or specific Pod labels stuck in error states), add that logic to the Lambda code. 
  2. Extending reasoning (how the agent investigates and classifies): edit the plain-English skill definitions. For example, you can teach the RCA skill new classification rules, add domain-specific context about your workload’s expected behavior, or adjust the recurrence thresholds. 

Detection is code; reasoning is natural language. Both are in the repo and designed to be customized independently. 

Investigation feedback 

After each investigation completes, a Feedback button appears in the DevOps Agent console. Clicking it opens the Investigation feedback dialog, where you can: 

  • Rate whether the root cause was correct 
  • Indicate whether human steering was needed during the investigation 
  • Provide written feedback explaining what could be improved 

This structured feedback is stored per investigation. An auto-learning mechanism that uses this feedback to improve future investigations is actively being developed. 

DevOps Agent APIs used by this solution 

For readers interested in the programmatic integration, here are the key DevOps Agent APIs this solution calls:

Component API Purpose
Webhook provisioner (deployment) register_service Register the generic webhook service with DevOps Agent
Webhook provisioner (deployment) associate_service Associate the webhook with the Agent Space
Skill uploader (deployment) list_assets Check if a skill already exists
Skill uploader (deployment) create_asset / update_asset Upload or update the triage and RCA skill definitions
Email notifier (runtime) get_backlog_task Retrieve task metadata (title, priority, timestamps)
Email notifier (runtime) list_journal_records Retrieve findings, symptoms, and gaps from the investigation journal
Teardown disassociate_service / deregister_service / delete_asset Clean up on stack deletion

Cleaning up 

To remove all resources created by this solution, run: 

make teardown-stack

This deletes the CloudFormation stack, removes the Agent Space, EKS access entries, secrets, and email configuration.

Additionally, if you no longer need the prerequisite resources, you can revert their setup, for example, deleting the verified Amazon SES email address identities you created for notifications.

Cost considerations 

​​​This solution is designed to be near-zero cost on a healthy cluster and scales proportionally with fault volume. Cost scales with fault volume, not node count directly. At large scale (100+ nodes), the triage skill becomes critical. A single hardware fault can generate 5-10 correlated EventBridge events, most of which are filtered by the webhook bridge Lambda before reaching the agent. Where triage adds value is linking and deduplicating across similar faults that affect multiple instances, or repeated faults on the same instance over time, consolidating them into a single investigation instead of many. As an example, a 500-node training cluster might see 20-50 investigations per month after filtering and deduplication.​​ 

  1. ​​​Filtering and triage are your cost savers at scale. The webhook bridge filters correlated events from a single node failure (5-10 EventBridge events reduced to 1 forwarded event), eliminating redundant investigations at the source. Triage then links similar faults across multiple instances into a single investigation. For example, if 5 nodes hit the same GPU error in a window, triage consolidates them into 1 investigation instead of 5 (saving 4 × $4 = $16). The bigger the cluster, the more both layers save.​​ 
  2. Investigation duration grows sub-linearly. A 1000-node cluster investigation doesn’t take 100x longer than a 10-node one. The agent queries describe-cluster and list-cluster-events once regardless of size. The data returned is bigger, but the API call count is similar. 
  3. CloudWatch Logs queries are the variable. On large clusters, the agent may query more HMA log streams, which takes longer agent-seconds AND incurs CloudWatch Logs Insights charges on your account (not part of DevOps Agent pricing). 

DevOps Agent (the primary cost driver): Estimates based on 2 accelerator instances in a cluster 

Component Pricing Your cluster estimate
Investigations $0.0083/agent-second ~$4/investigation (at 8 min avg)
Chat (on-demand SRE tasks) $0.0083/agent-second ~$0.25/chat query (at 30 sec avg)
Daily heartbeat $0.0083/agent-second ~$1-2/day (short investigation confirming health)

On a healthy cluster with no faults, only the daily heartbeat fires, approximately $30-60/month in DevOps Agent time. On a cluster experiencing 5 real faults per week (typical for a large GPU fleet), expect ~20 investigations/month × $4 each = $80/month in investigation costs.

Free tier and credits:

New DevOps Agent customers receive a 2-month free trial (20 hours of investigations, 20 hours of chat per month). Enterprise Support customers receive monthly credits equal to 75% of their AWS Support charge toward DevOps Agent usage. 

Supporting infrastructure (secondary costs): 

Component Monthly Cost Estimates
Lambda invocations ~96/day (15-min audit) + event-driven = well within free tier
S3 (skills + dedup markers) < $0.01 (a few MB total)
Secrets Manager (1 secret) $0.40
EventBridge rules Negligible (per-event pricing)
SES emails $0.10/1000 emails — at most 1 per investigation
CloudWatch Logs (Lambda) < $1 (minimal log volume)

Total estimated monthly cost: 

Scenario DevOps Agent Infrastructure Total
Healthy cluster (no faults) ~$30-60 (heartbeat only) < $2 ~$32-62/month
Moderate faults (5/week) ~$80-120 < $2 ~$82-122/month
Heavy faults (20/week) ~$320-400 < $5 ~$325-405/month

How cluster size impacts cost 

Factor Small cluster (1-10 nodes) Large cluster (100-1000 nodes)
Fault frequency Rare (maybe 1-2/week) Constant (NVIDIA reports ~1 fault/2-3 hours at 10K GPU scale)
Events per fault Few (1 node replacement = 3-5 events) More (cascading replacements, capacity queuing)
Investigation duration Shorter (less state to read, fewer events in timeline) Longer (more nodes to describe, more events to correlate, larger CloudWatch log groups to query)
Triage value Low (few duplicates) High (one fault generates many correlated events — triage links them into 1 investigation)
Periodic audit Fast (few pods/nodes to check) Slower (more K8s state to inspect)
Cluster Size Faults/month Investigations Est. Agent Cost
1-10 nodes (your test) 2-5 2-5 + heartbeat $8-20/mo + ~$30 heartbeat
10-50 nodes (typical prod) 5-20 5-15 (triage dedup) $20-60/mo + ~$30 heartbeat
100-500 nodes (large training) 50-200 20-50 (heavy triage) $80-200/mo + ~$45 heartbeat
1000+ nodes (frontier) 200-700 50-100 (massive dedup) $200-500/mo + ~$60 heartbeat

Cost control levers: 

  1. Disable the periodic audit (EnablePeriodicAudit: false) to eliminate the heartbeat cost. Live event bridging still works. 
  2. Triage (LINK/SKIP decisions) runs at task creation time. No investigation cost is billed for deduplicated or skipped events. 
  3. Suppress verdicts filter email notifications but the investigation still runs. If you want to eliminate that cost, tune your EventBridge rule to drop more event types at the bridge level. 

Comparison to manual monitoring: 

Without automation, each fault requires an on-call engineer to manually correlate events across CloudWatch, EKS, and the SageMaker console, typically 30-45 minutes of triage before they even know whether HyperPod is self-healing or needs intervention. This solution delivers a root-caused verdict in minutes at ~$4 per investigation, while providing 24/7 coverage without human wake-ups. The cost savings compound with cluster scale: at 20 faults per month, that’s 10-15 hours of engineering triage replaced by automated verdicts. 

Conclusion 

In this post, we showed how to build an end-to-end agentic incident-response pipeline for SageMaker HyperPod using AWS DevOps Agent. The solution complements HyperPod’s built-in resiliency by watching for the operational conditions where a human still wants to be in the loop: configuration issues affecting provisioning, capacity-bound recoveries, recurring hardware fault patterns, and workload-level conditions. It delivers clear, root-caused verdicts to the operator’s inbox. 

The broader takeaway is a reusable pattern: teaching an AI agent a domain’s operational model through plain-English skills, so it can distinguish “the system is recovering on its own” from “this needs a human decision.” This pattern applies beyond HyperPod to any event-driven AWS service where operational conditions benefit from automated correlation and triage. 

What’s next 

​​​To deploy the solution, follow the step-by-step instructions in the DevOps Agent Integration guide on the AI on SageMaker HyperPod site. Once it’s running, you can customize it for your environment:​​ 

  • Adjust the CloudFormation parameters: tune the periodic-audit schedule, CrashLoopBackOff thresholds, NotReady node percentages, namespace filtering, and email recipients. No code changes required. 
  • Extend detection: modify the periodic-audit Lambda to check for additional Kubernetes conditions specific to your workloads (for example, GPU allocation below a threshold, specific Pod labels stuck in error states). 
  • Extend reasoning: edit the triage or RCA skill definitions to adjust classification rules, add domain context about your expected cluster behavior, or tune the recurrence thresholds. 
  • Add notification channels: connect Slack or PagerDuty via DevOps Agent’s built-in integrations or via a sibling EventBridge rule on the same aws.aidevops event stream. 

The skills are plain English. Iterate on them the same way you’d iterate on a runbook. 

About the authors

Tomonori Shimomura is a Principal Solutions Architect on the Amazon SageMaker AI team, where he provides in-depth technical consultation to SageMaker AI customers and suggests product improvements to the product team. Before joining Amazon, he worked on the design and development of embedded software for video game consoles, and now he leverages his in-depth skills in Cloud side technology. In his free time, he enjoys playing video games, reading books, and writing software.

Mayank Gupta is a Senior AI/ML Specialist with deep expertise in machine learning frameworks and enterprise AI architecture. He brings strong hands-on experience with AWS AI services, including SageMaker AI and SageMaker AI HyperPod, and leads the design and delivery of end-to-end AI solutions spanning model development, distributed training, and production-scale deployment. With deep experience in performance optimization and scalable ML architectures, Mayank partners with customers to translate complex business challenges into secure, high-impact, production-ready AI systems that drive measurable outcomes.

Deepthi Madamanchi is a Principal Technical Account Manager at AWS focused on AI Models, where she leads frontier AI segment through building and operating multi-thousand-node GPU clusters for foundation model training and inference. She specializes in distributed training, high-throughput networking, GPU fleet optimization, Amazon Bedrock adoption, helping them optimize performance, reliability, and cost efficiency from experimentation through production. In her free time, Deepthi explores functional health, experiments with new recipes, and travels with her family.

Dushyant Dubaria is a Senior Technical Account Manager on the AWS Frontier AI Startup team, where he supports frontier AI model builder companies deploying and operating large-scale GPU training infrastructure on Amazon SageMaker HyperPod and Amazon EKS. He specializes in distributed training orchestration, storage at petabyte scale (Amazon FSx for Lustre, Amazon S3), high-throughput networking, and operational resilience including cluster health monitoring, capacity planning, and proactive incident management for multi-thousand-node clusters. He helps organizations achieve reliable, high-performance ML workloads from initial cluster deployment through sustained production training. In his free time, he enjoys building automation tools, exploring new AI technologies, and playing cricket.

Shreyas Adiyodi is a Product Manager at AWS based out of Seattle. He is focused on enabling Gen AI model development on SageMaker HyperPod, partnering with customers to simplify cluster provisioning, accelerate foundation-model training, and strengthen security and compliance. Outside of work, he enjoys chess, MMA and watching movies.

How Company 3 Streamlines Studio Image Management with EC2 Image Builder and AWS CDK

Post Syndicated from Natalie White original https://aws.amazon.com/blogs/devops/how-company-3-streamlines-studio-image-management-with-ec2-image-builder-and-aws-cdk/

Guest post in collaboration with Company 3 Director of New Technology, Phil Wortas, and Senior New Technology Engineer, Matthew Galloway

Introduction

Company 3 provides specialized services for the entertainment industry, including post-production services, visual effects, and color grading for feature films, commercials, and television content. Their teams collaborate globally to Increase workflow efficiency and expand their roster of diverse movie-making talent.

Company 3’s New Technology team uses Amazon EC2 Image Builder to vend Amazon Machine Images (AMIs) and container images for compute environments where artists create and render content. Image Builder is a fully managed AWS service that helps you automate the creation, management, and deployment of customized, secure, and up-to-date server images. Company 3 also uses the AWS Cloud Development Kit (CDK) to scale the creation of consistent Image Builder components and recipes.

At scale, the respective concepts of versioning between Image Builder resources and CDK infrastructure as code made it challenging to reuse prior components and recipes, and update existing references with new version numbers over time. This challenge led to creative workarounds, collaborative problem-solving with AWS, and ultimately, product improvements that benefit the entire AWS community.

This blog follows their journey from manual version management, through creative workarounds, to native EC2 Image Builder features that solved the problem for good. Along the way, we’ll show how auto-versioning and CDK L2 constructs can simplify your own image pipelines.

Process flow diagram of Artists, Support Engineers, and New Technology Platform Engineers provisioning new studio environments. (1) Artists request new environments. (2) Automation determines whether a matching environment configuration (EC2 AMI) exists. If it does, (3) the new environment is provisioned for the Artist to securely access. If it does not, (4) a Support Engineer creates or update an (5) CDK definition of an EC2 Image Builder Pipeline to provision the correct environment. The CDK (6) generates a CloudFormation template and assets that are used to (7) create the Pipeline. This Pipeline (8) generates a new EC2 AMI, from which the rendering instance can be (9) provisioned and (10) provided for the Artist to securely access.

Figure 1: Personas and process flow

The Challenge: When Infrastructure-as-Code Gets Complicated

While Image Builder has historically supported semantic versioning for Components and Recipes, there was no mechanism to automatically detect version changes or update existing references to the latest version of a component using the CDK. This is because Image Builder only supported Layer 1 (L1) CDK constructs. Layer 1 constructs map directly to CloudFormation resources and their corresponding service APIs, but do not provide features that create a layer of abstraction above those foundational create / update / delete operations.

Version changes to Components and Recipes are a frequent occurrence because these resources are immutable; every change to them requires a new version. Version numbers are a part of these resource’s Amazon Resource Name (ARN), so changes must be propagated throughout the associated CDK code to correctly reference the latest version of each resource.

Figure 2 shows an architecture diagram of an EC2 Image Builder Pipeline, which consists of Infrastructure configuration, Components, Recipes, and distribution settings. Components and Recipes each have their own separate version numbers and are immutable. This Pipeline generates EC2 AMIs, which are tied to the recipe version used to generate them, and are used to provision EC2 rendering instances.

Figure 2: EC2 Image Builder Anatomy and Version Propagation

Figure 1, Step 5 represents a Platform Engineer having to update an existing Component. Figure 2 shows the required changes broken out by each of the comprising Image Builder resources:

  1. Update the Component configuration
  2. Increment the Component version
  3. Update the Recipe with the new Component version ARN
  4. Increment the Recipe version
  5. Update the Recipe version ARN in the Pipeline.

Manual version propagation across dozens of components via this multi-step process was error prone, wasn’t scalable, and created a risk of deployment failures and version churn due to version mismatches.

The team needed to prevent unnecessary update requests to Image Builder when components didn’t change but the recipes they were associated with did, orchestrate version propagations when the versions did need to change, and track component versions as they deployed updates across their infrastructure.

Short-term Workaround: Using Hashes to Identify Changes

Faced with these limitations, the customer’s engineering team got creative. Their first approach involved appending MD5 hashes to component names. This allowed them to track changes and force CDK updates and version increments when content changed, while preventing unnecessary update calls when the content of the component didn’t change but the rest of the resources in the CDK Stack did.

However, this approach had drawbacks. Component names became unwieldy and difficult to maintain. More importantly, the hash-based naming convention didn’t align with semantic versioning best practices that the rest of their infrastructure followed. The team knew they needed a better solution long-term.

Long-term Automation: Collaboration with AWS

Working with their AWS Solutions Architect and EC2 Image Builder Developer Support, Company 3 developed a more elegant solution using CDK Custom Resources. This approach eliminated hash-based naming and automated the propagation of version updates, but it came with technical debt.

The version increments themselves were still manual, and the solution required custom resources to create and maintain the suite of resources being deployed. The mesh of custom resources required specialized knowledge to maintain, which made it difficult to onboard new team members, and distracted engineers from focus on core business value of delivering the right studio environments to artists.

Managed Abstraction: AWS Launches Product Improvements

EC2 Image Builder auto-versioning

In November 2025, EC2 Image Builder introduced native auto-versioning capabilities that transformed how teams manage Component versions.

Components with the same name and semantic version now auto-increment build versions (eliminating steps 2-4 from Figure 2 when developers use ‘x’ as a wildcard placeholder (e.g., 1.2.x). Additionally, Pipelines can resolve to the highest available version of Components and Recipes, which ensures they are using the latest compatible versions without manual updates, eliminating step 5.

These enhancements eliminated the version propagation burden entirely, allowing Company 3 developers to focus only on the substantive changes to Components requested by Artists and Support Engineers.

CDK Layer 2 Constructs

The second major improvement came with comprehensive Layer 2 (L2) constructs for EC2 Image Builder (RFC 0789). L2 Constructs provide a layer of abstraction that default to best practice configuration, automatic least-privilege IAM Role and Policy provisioning, and convenience methods that make it easier to create and link to other AWS resources. These constructs transformed the developer experience and alleviated the need for custom resources. The EC2 Image Builder L2 Construct is currently in alpha stabilization phase, and sourcing customer feedback and adoption before migrating to the core CDK library per the CDK contribution process.

Before the L2 construct release, orchestrating an Image Builder Pipeline took over 50 lines of code, and required manual least-privilege IAM role creation, instance profile setup, and Pipeline configuration across 6 separate CloudFormation resources.

// Using L1 constructs
const instanceProfileRole = new iam.Role(stack, 'EC2InstanceProfileForImageBuilderRole', {
  assumedBy: iam.ServicePrincipal.fromStaticServicePrincipleName('ec2.amazonaws.com'),
  managedPolicies: [
    iam.ManagedPolicy.fromAwsManagedPolicyName('AmazonSSMManagedInstanceCore'),
    iam.ManagedPolicy.fromAwsManagedPolicyName('EC2InstanceProfileForImageBuilder'),
  ],
});

const instanceProfile = new iam.InstanceProfile(stack, 'EC2InstanceProfileForImageBuilder', {
  role: instanceProfileRole,
});

const bucket = new s3.Bucket(stack, 'ImageBuilderLoggingBucket', {
 bucketName: `ec2imagebuilder-logs-${stack.region}-${stack.account}`,
  enforceSSL: true,
});

const l1InfrastructureConfiguration = new imagebuilder.CfnInfrastructureConfiguration(stack, 'L1InfrastructureConfiguration', {
  name: 'l1-infrastructure-configuration',
  instanceProfileName: instanceProfile.instanceProfileName,
  instanceMetadataOptions: { httpTokens: 'required' },
  logging: {
    s3Bucket: bucket.bucketName,
    s3KeyPrefix: 'imagebuilder-logging',
  },
});
const l1ImageRecipe = new imagebuilder.CfnImageRecipe(stack, 'L1ImageRecipe', {
  name: 'l1-image-recipe',
  version: '1.0.0',
  parentImage: `arn:${stack.partition}:imagebuilder:${stack.region}:aws:image/amazon-linux-2023-x86/x.x.x`,
  components: [
    {
      componentArn: `arn:${stack.partition}:imagebuilder:${stack.region}:aws:component/update-linux/x.x.x`,
    },
  ],
});

const l1ImagePipeline = new imagebuilder.CfnImagePipeline(stack, 'L1ImagePipeline', {
  name: 'l1-image-pipeline',
  imageRecipeArn: l1ImageRecipe.attrArn,
  infrastructureConfigurationArn: l1InfrastructureConfiguration.attrArn,
});

Using the ImagePipeline L2 construct allows the developer to provision a Pipeline in fewer than 10 lines of code while leveraging best practice configuration the construct sets by default.

// Equivalent, using L2 constructs
const l2ImagePipeline = new imagebuilder.ImagePipeline(stack, 'L2ImagePipeline', {
  recipe: new imagebuilder.ImageRecipe(stack, 'L2ImageRecipe', {
    baseImage: imagebuilder.AwsManagedImage.amazonLinux2023(stack, 'AL2023'),
    components: [
      {
        component: imagebuilder.AwsManagedComponent.updateOS(stack, 'UpdateOS', {
          platform: imagebuilder.Platform.Linux,
        }),
      },
    ],
  }),
});

The Impact: From Workarounds to Best Practices

For Company 3, these improvements meant they could retire their custom constructs entirely. The L2 constructs provided everything their custom solution did, plus additional capabilities.

The EC2 Image Builder service manages the complexity of version updates by default, and they gained enhanced security through AWS-managed secure defaults like IMDSv2 requirements and least-privileged IAM roles.

Perhaps most importantly, new team members can understand the infrastructure code in minutes rather than hours, dramatically accelerating onboarding.

Conclusion

The impact extends far beyond one customer. Every AWS user working with EC2 Image Builder and CDK now benefits from simplified workflows, automatic version management, and security best practices by default. What started as one team’s challenge became a catalyst for improvements that make everyone’s work easier and more secure. The evolution of EC2 Image Builder’s CDK support demonstrates AWS’s commitment to listening to customers and continuously improving the developer experience.

For teams currently managing EC2 Image Builder Pipelines manually or with L1 CDK constructs or with custom solutions, the path forward offers significant benefits. Explore how you can use EC2 Image Builder, its new auto-versioning capabilities, and its CDK L2 Constructs to automate your complex AMI Pipeline provisioning architecture via these resources:

EC2 Image Builder Documentation

EC2 Image Builder Auto-versioning Documentation

CDK L2 Constructs for EC2 Image Builder (currently in alpha stabilization)

EC2 Image Builder CDK Sample GitHub Repository

Authors

Rochelle Lakey

Rochelle Lakey is a Senior Solutions Architect specializing in Media and Entertainment at AWS helping customers architect and optimize their cloud infrastructure. She brings 28 years of managed services experience bridging traditional data centers and modern cloud computing. Rochelle is passionate about guiding organizations through their digital transformation journeys.

Phil Wortas

Phil Wortas is Director of New Technology at Company 3, where his team serves as the cloud infrastructure and platform engineering backbone for a global post-production and VFX organization. Together they focus on reducing manual toil through automation and IaC, so the creative teams they support can stay focused on the work that matters.

Matthew Galloway

Matthew Galloway is a Senior New Technology Engineer at Company 3, working within the cloud infrastructure team. He specializes in AWS deployment automation and developing tools that streamline and enhance artist workflows across the organization. Matthew’s work is driven by a commitment to reducing friction for creative teams, ensuring they have the reliable, efficient infrastructure that they need.

Tarun Belani

Tarun Belani is a Senior Software Development Engineer on the EC2 Image Builder team at Amazon Web Services, where he works on the service’s APIs and backend systems. He designed and built the AWS CDK L2 constructs for EC2 Image Builder.

Natalie White

Natalie White is a Principal Solutions Architect at Amazon Web Services. While her primary customers are in the Healthcare and Life Sciences industry, she leverages her prior Software Development experience as a specialist in AWS CDK and Infrastructure as Code automation, AI-DLC, and GenAI for Developer Productivity across all industries.

Better tools made Copilot code review worse. Here’s how we actually improved it.

Post Syndicated from Napalys Klicius original https://github.blog/ai-and-ml/github-copilot/better-tools-made-copilot-code-review-worse-heres-how-we-actually-improved-it/


Give an agent better tools and it should do better work. That’s the instinct, anyway.

When you open a pull request, Copilot code review reads the diff and explores the surrounding code to find the problems that matter before they ship. To do that, it used its own code exploration tools. So when we swapped in the better-maintained, shared tools that power the Copilot CLI, grep, glob, and view, we expected a clean upgrade.

Instead, in our benchmarks, we found that the cost of reviews was higher and fewer issues were being caught.

But the tools weren’t the problem. The instructions were. Once we rewrote them for the way a reviewer actually reads a pull request, the regression flipped into a win: roughly 20% lower average review cost, while maintaining the same review quality.

This is the story of how adjusting the workflows around the tools led us to a fix.

Same tools, wrong instincts

If you’ve built on top of an agent framework, you’ve probably inherited its tools too. They work, so you keep them, until the day your use case drifts far enough from what they were designed for that they quietly start working against you. That’s the situation we were in. Before trying to use the shared CLI tools, Copilot code review used its own code exploration tools. That tool layer was inspired by earlier agentic systems, including ideas from SWE-agent-style repository navigation and GitHub Copilot Autofix: list directories, search files, search directories, and read code. Those tools worked, but they were specific to Copilot code review, and they were designed for how models behaved at the time. Earlier agentic coding models made fewer tool calls and were worse at automatically pulling in necessary context. This meant it was more important to include all relevant information in the few tool calls that the model made.

Meanwhile, the Copilot CLI harness has a shared set of Unix-inspired code exploration tools: grep, glob, and view. That harness is also used by a growing number of Copilot agent products, including GitHub Copilot cloud agent, so harness improvements can benefit more than one product. We wanted to clean up and share infrastructure where possible, so we experimented with using the tools from the Copilot CLI harness in Copilot code review. The goal was to reduce duplicated tool implementations, create one shared place to improve code exploration tools, and make it easier to carry those improvements across Copilot products.

On paper, the migration looked simple:

Old Copilot code review GitHub Copilot CLI Purpose
list_dir  glob  Discover candidate files and directories before opening code. 
search_file and search_dir  grep  Search code for matching text, symbols, or call sites. 
read_code  view  Read the relevant file contents once a path or range is known. 

The existing review tools were not thin wrappers. When searching for a directory or reading a code range, they could return the matched or requested lines plus extra surrounding code context. That added token cost, but it also matched how earlier models often benefited from having nearby context included automatically.

Initially, we hoped this would be a simple migration: swap one set of tools for another. But when we tested the shared tools in offline benchmarks, the review agent became less efficient and less effective. Average cost increased, and the number of useful comments dropped.

The trace revealed a browsing loop

Our internal Copilot code review benchmarks were useful because they show more than a final score. They show the path the agent took, including which tools it called, how much output came back, where errors happened, and whether it was narrowing toward evidence or widening the search.

When we first tried the shared Copilot CLI tools in offline benchmarks, the agent often behaved as if it was browsing a repository instead of investigating a pull request. It would search broadly, guess likely paths, read broadly, find more things to search, and carry that extra context forward.

Diagram showing the flow before — a simplified illustration of the general-purpose behavior we observed: widening the search, guessing paths, and accumulating context.
Figure 1: Before — a simplified illustration of the general-purpose behavior we observed: widening the search, guessing paths, and accumulating context.

That pattern is understandable. Broad exploration can be useful when the task is “understand this repo.” But it’s not how a reviewer would usually review a pull request.

When I review a pull request, I start from the diff and ask targeted questions:

  • Where is this function called?
  • Is this config key used anywhere else?
  • Is there a test or helper with the same pattern?
  • What is the smallest nearby code range that explains this behavior?

I do not want to open a large part of the repository before I know what I am looking for. I want the minimal context needed to answer the question, without overloading the review with unrelated code.

That matters because every tool result becomes part of the agent’s working context. Extra file contents can be carried forward into later reasoning, increasing cost and sometimes making the review less focused. A tool result is not a disposable printout; for an agent, it’s extra tokens that stay in the context window.

The traces made that difference visible. The shared tools were not the problem. The instructions were giving the agent the wrong instincts to do an efficient and effective review.

The tools themselves worked, but their instructions were tuned for their use within the Copilot CLI and implied the wrong workflow: the agent used grep, glob, and view like a broad coding assistant instead of a reviewer. A coding assistant may map a whole area before making a change to ensure it doesn’t break some other corner of the code. On the other hand, a reviewer usually starts from the diff, asks whether the change introduced a problem, and then looks for the narrowest nearby evidence required to confirm or dismiss it.

General coding-assistant tool instructions, like the ones used by Copilot CLI or Copilot cloud agent, make sense for an interactive assistant. A developer may ask it to understand a repository, plan a change, edit files, and continue over multiple turns.

Copilot code review has a narrower job: start from a pull request diff, gather enough surrounding evidence to decide whether a change introduces a real issue, and avoid loading context that is not needed for that review question.

It was therefore clear that we couldn’t simply replace the previous Copilot code review tools with the tools from the Copilot CLI without additional prompting work. The problem became: how do we design tool instructions that use these shared tools effectively in a code review setting?

Rewriting the tool instructions for a reviewer’s workflow

The next iterations made the guidance specific to code review. The workflow we wanted Copilot code review to follow was:

  1. Start from the diff and form specific review questions.
  2. Use glob when the path is uncertain and grep to find candidate files, symbols, and call sites.
  3. Batch cheap discovery before reading files.
  4. Use view only when the agent knows which file or line range it needs.
  5. Batch focused reads instead of alternating between one search and one read.

In oversimplified form, this was the behavior we encoded:

Generic posture: Use the available tools to inspect repository context that may be relevant.

Review-shaped guidance: Start from the diff. Narrow first with grep and glob; read exact evidence with view. If grep fails to find relevant context, retry with a simpler escaped search. If a path is wrong, pivot to glob instead of guessing nearby paths.

For example, imagine the diff changes an authorization helper that decides whether an operation is allowed. A relevant review question is not “show me the full contents of every file that calls this helper.” It could instead be the narrower: “are any request-handling callers relying on the old behavior?”

The intended path is short:

start from the helper changed in the diff 
grep for callers of that helper 
glob for likely route, handler, or controller files 
view the most relevant caller ranges 
decide whether any caller changes the risk

The guidance also changed how the agent recovered from failed searches. If an input made grep fail, the better next step was one simpler, corrected search. If a path was wrong, the better next step was glob, not guessing neighboring paths and reading whatever happened to exist. That nudged the agent away from letting a small tool failure turn into a larger exploration loop.

Diagram showing the flow after: a simplified illustration of the review-shaped behavior the prompt guided toward: stay anchored to the diff, narrow with grep and glob, then read focused ranges with view.
Figure 2: After — a simplified illustration of the review-shaped behavior the prompt guided toward: stay anchored to the diff, narrow with grep and glob, then read focused ranges with view.

The change was small in wording and large in effect. It changed the rhythm of the agent from “browse, read, search again” to “ask, narrow, read, decide.”

Benchmarks let us debug behavior, not just scores

The shared harness gave us the tools. The internal Copilot code review benchmarks gave us the feedback loop.

We could run the same review examples, compare tool traces, update the instructions, and run again. That let us ask concrete questions:

  • Did the agent narrow first, or read broadly first?
  • Did it batch independent searches?
  • Did it call view only when it had a reason?
  • Did a tool-instruction change reduce tool errors, or just move them somewhere else?
  • Did the trace stay focused on evidence from the diff?
  • Did the review still preserve the quality metrics we cared about?

The most useful signal was not “the instructions are better.” It was more concrete. The agent was making a similar number of tool calls, but spending more of them on relevant evidence instead of repeatedly expanding the search.

That connected product-level outcomes to understandable engineering behavior. Instead of guessing why a score moved, we could inspect the workflow that produced it.

The result: roughly 20% lower average review cost

In production, the tuned behavior showed roughly 20% lower average review cost compared with the control. Importantly, it did not show a quality signal that could block shipping.

The reduction did not come from the tools by themselves, it came from the workflow around them. Shared code exploration tools, Copilot code review custom tool instructions, and internal benchmarks made the agent’s behavior visible enough to tune.

That framing matters when building with agents. It can be tempting to treat tools as implementation details by swapping one tool for another, then comparing the final answer. But for an agent, the tool surface is part of the product experience. It changes what the agent notices, how it searches, how much context it carries forward, and when it decides it has enough evidence.

Tool descriptions and system instructions are closer to API documentation. Unclear API docs can leave a developer confused and lead to inefficient or wrong decisions. Unclear tool prompting can do the same for an LLM; a small wording change can affect cost, quality, and the shape of the investigation because it changes how the agent spends its attention.

Same tools, different job

We also tried to apply the same kind of focused tool instructions in the CLI, where it did not produce the same kind of win. That is a useful counterexample, and an important guardrail for the lesson.

Copilot code review is anchored to a diff and a review question. Copilot CLI handles broader, interactive coding tasks where exploration can be part of the job. There may be no single diff anchor, the user may change direction over multiple turns, and the right context may not be obvious at the start. The same grep, glob, and view tools can support both products, but the workflow around those tools has to match the product.

The takeaway is that shared tools scale when the instructions and benchmarks match the job.

Try it out yourself using GitHub Copilot code review.

The post Better tools made Copilot code review worse. Here’s how we actually improved it. appeared first on The GitHub Blog.

Introducing OAuth Support for AWS MCP Server

Post Syndicated from Vaibhav Chowla original https://aws.amazon.com/blogs/security/introducing-oauth-support-for-aws-mcp-server/

AWS MCP Server using the same credentials and sign-in methods that you already use for connecting to the AWS Management Console or AWS Command Line Interface (AWS CLI) through a familiar browser-based experience powered by industry-standard OAuth. This new sign-in path supports AWS Identity and Access Management (IAM) federation, AWS IAM Identity Center, and root or IAM users.

In addition, AWS is introducing several new security and governance tools, including: new global condition keys for OAuth, token introspection and revocation, dynamic client registration, new AWS CloudTrail elements, and a new API for headless OAuth connectivity. All of this is compatible with your existing IAM configuration including permissions, roles, and federated access.

In this post, you’ll learn how to connect your agents to the AWS MCP Server, understand how AWS Sign-In authorizes agent access, and manage access using new security and governance capabilities.

How to connect an agent to the AWS MCP Server

This walkthrough uses Claude Code, but the same steps apply to any agent that supports Model Context Protocol (MCP) such as Kiro, Codex, and Gemini. See Setting up the AWS MCP Server for how to connect the AWS MCP Server to an agent.

Prerequisite permissions

To connect an agent to the AWS MCP Server, you’ll need the IAM permissions required for OAuth-based sign-in. The following AWS CLI command adds a managed policy with required permissions to your IAM role (remember to replace <MyRole> with your IAM role):

aws iam attach-role-policy \
  --role-name <MyRole> \
  --policy-arn arn:aws:iam::aws:policy/AWSMCPSignInOAuthAccessPolicy

Step 1: Configure the AWS MCP Server on your agent

Run the following command to add the AWS MCP Server endpoint to your agent’s configuration as shown in Figure 1:

claude mcp add --transport http aws-mcp https://aws-mcp.us-east-1.api.aws/mcp

Figure 1: Adding the AWS MCP Server endpoint to Claude Code

Figure 1: Adding the AWS MCP Server endpoint to Claude Code

Step 2: Review the authorization request

The first time your agent needs to access the AWS MCP Server, it opens a browser and redirects you to an AWS Sign-In page, shown in Figure 2. Authenticate as you would on AWS console or AWS CLI, review the authorization request, and approve access. You should receive an Authorization successful message.

Figure 2: Review authorization request

Figure 2: Review authorization request

Note that if you already have an active AWS Sign-In session (e.g., because you previously signed in to the console earlier in the day), you can reuse that session without needing to sign in again.

Step 3: Start using AWS tools

After connecting your agent to the AWS MCP Server, you can begin invoking tools provided by the server. To verify that Claude Code is connected to the AWS MCP Server, start Claude Code and run the following command:

/mcp

The command displays the configured MCP servers and confirms that the AWS MCP Server is connected and ready to use with your AWS credentials.

Figure 3 shows an example of a successful connection to the AWS MCP Server.

Figure 3: Verifying the AWS MCP Server connection in Claude Code

Figure 3: Verifying the AWS MCP Server connection in Claude Code

After the connection is established, you can ask Claude Code to invoke tools provided by the AWS MCP Server. For example, enter the following prompt:

Deploy a sample serverless web application into my development AWS account

Claude Code uses the AWS MCP Server to identify the active AWS account, confirm the target account, and describe the deployment it plans to perform before invoking AWS services on your behalf.

Figure 4 shows Claude Code confirming the active AWS account and outlining the resources that will be deployed.

Figure 4: Using Claude Code to deploy a sample serverless application through the AWS MCP Server

Figure 4: Using Claude Code to deploy a sample serverless application through the AWS MCP Server

Authorization models and how they work

AWS Sign-In supports two authorization models for connecting agents to the AWS MCP Server:

  • Interactive authorization for developer’s AI agents using browser based authentication
  • Non-interactive (headless) authorization for applications and AI agents that already have AWS credentials and don’t have access to a browser

Note that authorizing an agent allows it to access the AWS MCP Server on your behalf. It doesn’t grant the agent additional AWS permissions. Every request is still evaluated using your existing IAM policies, SCPs, RCPs, permission boundaries, and other organizational controls.

Interactive access

In the interactive case, the agent first discovers the AWS Sign-In OAuth server and then registers itself as an OAuth client using Dynamic Client Registration (DCR). It then redirects you to an AWS Sign-In page where you authenticate and authorize access (step 2 in the preceding section). After successful authorization, AWS Sign-In then issues short-lived access tokens and refresh tokens that authorize the agent to access the AWS MCP Server on your behalf. AWS Sign-In automatically manages token issuance and token refresh, enabling authorized agents to continue accessing the AWS MCP Server without requiring you to repeatedly sign in.

The interactive authorization model supports three distinct sign-in methods: native AWS IAM credentials for individual developers, managed access through AWS IAM Identity Center for enterprises, and seamless federated access via third-party providers like Okta and Ping Identity for larger organizations

OAuth server metadata and DCR

Before an agent can request authorization, it must discover the AWS Sign-In OAuth endpoints and register itself as an OAuth client. AWS Sign-In supports OAuth metadata discovery and DCR, allowing supported agents to configure themselves automatically without requiring developers to manually provision OAuth client IDs and client secretsWhen an agent connects to the AWS MCP Server for the first time, it retrieves the AWS MCP Server’s protected resource metadata (RFC 9728) and the AWS Sign-In OAuth metadata (RFC 8414). The agent then uses RFC 7591)) to register with AWS Sign-In, obtain a client ID, and initiate the standard OAuth authorization code flow.

AWS Sign-In supports OAuth discovery and DCR for agents running on local workstations and supported hosted environments. For the current list of supported agents and environments, see Supported redirect URIs for the AWS MCP Server.

Non-interactive access to the AWS MCP Server

Non-interactive (headless) authorization is for agents and applications that run without a browser or human in the loop, and thus don’t require interactive sign-in. This allows agents that already have AWS credentials to obtain OAuth access tokens and connect to the AWS MCP Server. The following is an example of how to obtain an access token.

aws signin create-oauth2-token-with-iam \ 
--grant-type client_credentials \ 
--resource aws-mcp.amazonaws.com \  
--region us-east-1 
{ 
"accessToken": "ASOA****************************************...", 
"tokenType": "Bearer", 
"expiresIn": 3600 
}

In the non-interactive case, AWS Sign-In implements the OAuth client credentials grant using AWS security credentials instead of a static client secret. Applications authenticate to the AWS Sign-In token endpoint using SigV4 creds, and AWS Sign-In returns a short-lived OAuth access token that can be used to access the AWS MCP Server.

Please note you may have to update the SDK and AWS CLI, please refer to CLI guide.

Managing OAuth access

AWS Sign-In extends the existing IAM authorization model with capabilities for governing OAuth access to the AWS MCP Server. Administrators can use familiar IAM policies together with new OAuth-specific controls.

Granting OAuth permissions

OAuth access is governed using IAM policies and requires the following IAM actions:

  • signin:AuthorizeOAuth2Access – Allows users to sign in interactively using the OAuth authorization code flow
  • signin:CreateOAuth2Token – Allows applications to obtain OAuth access tokens by exchanging authorization codes, refresh tokens, or using client credentials

When an application requests access, AWS Sign-In creates an OAuth authorization grant between the agent and the AWS MCP Server. This grant is represented as an IAM resource, which the preceding AWS Sign-In actions are authorized against.

arn:aws:signin:us-east-1:012345678910:service-principal/aws-mcp.amazonaws.com

OAuth authorization grants are represented as IAM resource enabling administrators to use standard IAM policy constructs, including global condition keys, together with OAuth-specific condition keys to control how authorization grants are created and used.

Governing OAuth access

AWS Sign-In introduces OAuth-specific condition keys that allow administrators to govern how agents obtain OAuth authorization. The following examples demonstrate common governance patterns.

To restrict OAuth authorization to localhost:

In addition to accessing the AWS MCP Server with agents on your local workstation, AWS supports signing into the AWS MCP Server on select hosted providers through dynamic client registration. Click here to view the list of supported remote providers. Many organizations want to allow developers to authorize agents running on their local workstations while preventing OAuth tokens from being delivered to untrusted redirect URIs or using unsupported authorization flows. The following policy allows only the OAuth authorization code and refresh token flows for the AWS MCP server and restricts token delivery tolocalhost.

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": [
        "signin:AuthorizeOAuth2Access",
        "signin:CreateOAuth2Token"
      ],
      "Resource": "arn:aws:signin:*:*:service-principal/aws-mcp.amazonaws.com",
      "Condition": {
        "StringLike": {
          "signin:OAuthRedirectUri": "http://localhost:*"
        },
        "StringEquals": {
          "signin:OAuthGrantType": [
            "authorization_code",
            "refresh_token"
          ]
        }
      }
    }
  ]
}

To deny access for a specific OAuth session

Use the aws:SignInSessionArn global condition key to deny authorization associated with a specific sign-in session. This allows administrators to contain a suspicious or compromised authorization session without affecting other active sessions.

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Deny",
      "Action": [
        "*"
      ],
      "Resource": "*",
      "Condition": {
        "ArnEquals": {
          "aws:SignInSessionArn": "arn:aws:signin:us-east-1:111122223333:session/abc123-example-session-id"
        }
      }
    }
  ]
}

These examples demonstrate common governance patterns. Additional IAM and SCP examples are available in the AWS Sign-In condition keys reference.

Revoking OAuth tokens

AWS Sign-In provides OAuth token introspection and token revocation APIs that allow administrators to build custom tools for token validation and revocation. Access to these APIs is controlled through the signin:IntrospectOAuth2Token and signin:RevokeOAuth2Token permissions. IAM principals with permissions are allowed to introspect and revoke tokens for the same account.

The introspection API can be used to determine whether a token is active and obtain information about the associated authorization. The revocation API allows administrators and security tools to revoke individual refresh tokens without affecting other active sessions. For example, if an organization needs to invalidate access for a specific OAuth authorization, account admins can revoke the associated refresh token without affecting other active sessions.

Monitoring OAuth activity

OAuth-related activities are recorded in AWS CloudTrail, including authorization requests, token issuance, token revocation, and token introspection events. CloudTrail logs also capture details such as the OAuth client, target the AWS MCP Server, redirect URI, authorization flow, and associated sign-in session. In addition, AWS API calls made using OAuth access tokens include the associated aws:SignInSessionArn context, allowing organizations to correlate API activity with the originating OAuth sign-in session.

This allows security teams to monitor OAuth usage, investigate authorization activity, detect anomalous behavior, and integrate OAuth events into existing auditing, compliance, and incident response workflows alongside other AWS activity.

Here’s a CloudTrail sample for an AuthorizeOAuth2Access event:

{
    "eventVersion": "1.11",
    "userIdentity": {
        "type": "AssumedRole",
        "principalId": "AROATJHQDX737YZP****:testuser",
        "arn": "arn:aws:sts::111111111111:assumed-role/Admin/testuser",
        "accountId": "111111111111",
        "sessionContext": {
            "sessionIssuer": {
                "type": "Role",
                "principalId": "AROA2IRT4N5U4RDHM2LG4",
                "arn": "arn:aws:iam::111111111111:role/Admin",
                "accountId": "111111111111",
                "userName": "Admin"
            },
            "attributes": {
                "creationDate": "2026-06-09T05:06:39Z",
                "mfaAuthenticated": "false"
            }
        }
    },
    "eventTime": "2026-06-09T05:09:00Z",
    "eventSource": "signin.amazonaws.com",
    "eventName": "AuthorizeOAuth2Access",
    "awsRegion": "us-west-2",
    "sourceIPAddress": "192.0.0.2",
    "userAgent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/149.0.0.0 Safari/537.36",
    "requestParameters": {
        "resource": "https://aws-mcp.us-west-2.api.aws/mcp",
        "redirect_uri": "http://127.0.0.1:60432/oauth/callback",
        "code_challenge_method": "S256",
        "client_id": "arn:aws:signin:us-west-2::external-client/dcr/609544da-aasa-49a4-ab11-c2r457fa999"
    },
    "responseElements": null,
    "additionalEventData": {
        "success": "true"
    },
    "requestID": "4fb4ff7b-6yu7-9090-78i9-9c0088a65134",
    "eventID": "bb05b222-31ec-4237-b8e7-8eb26d4fd48b",
    "readOnly": true,
    "eventType": "AwsApiCall",
    "managementEvent": true,
    "recipientAccountId": "111111111111",
    "eventCategory": "Management",
    "tlsDetails": {
        "tlsVersion": "TLSv1.3",
        "cipherSuite": "TLS_AES_128_GCM_SHA256",
        "clientProvidedHostHeader": "us-west-2.oauth.signin.aws"
    }
}

Here’s a CloudTrail sample for a CreateOAuth2Token event:

{
    "eventVersion": "1.11",
    "userIdentity": {
        "type": "AssumedRole",
        "principalId": "AROATJHQDX737YZP7****:testuser",
        "arn": "arn:aws:sts::111111111111:assumed-role/Admin/testuser",
        "accountId": "111111111111",
        "sessionContext": {
            "sessionIssuer": {
                "type": "Role",
                "principalId": "AROA2IRT4N5U4RDHM****",
                "arn": "arn:aws:iam::111111111111:role/Admin",
                "accountId": "111111111111",
                "userName": "Admin"
            },
            "attributes": {
                "creationDate": "2026-06-09T05:06:39Z",
                "mfaAuthenticated": "false"
            },
            "signInSessionArn":""
            
        }
    },
    "eventTime": "2026-06-09T05:10:04Z",
    "eventSource": "signin.amazonaws.com",
    "eventName": "CreateOAuth2Token",
    "awsRegion": "us-west-2",
    "sourceIPAddress": "192.0.0.2",
    "userAgent": "curl/8.7.1",
    "requestParameters": {
        "resource": "https://aws-mcp.us-west-2.api.aws/mcp",
        "client_id": "arn:aws:signin:us-west-2::external-client/dcr/609544da-b3dd-49a4-ab11-c2e98d7fa999"
    },
    "responseElements": null,
    "additionalEventData": {
        "signInSessionArn": "arn:aws:signin:us-west-2:111111111111:session/daff060f-7871-5tg6-67yu-a07bbdabe61a",
        "grant_type": "refresh_token",
        "success": "true"
    },
    "requestID": "44d6d7ce-e4r5-4cbf-0909-bfb8a8295a76",
    "eventID": "f79cc63f-b383-4e3c-a1e5-97c7db1ab833",
    "readOnly": true,
    "eventType": "AwsApiCall",
    "managementEvent": true,
    "recipientAccountId": "111111111111",
    "eventCategory": "Management",
    "tlsDetails": {
        "tlsVersion": "TLSv1.3",
        "cipherSuite": "TLS_AES_128_GCM_SHA256",
        "clientProvidedHostHeader": "us-west-2.oauth.signin.aws"
    }
}

Additional audit events and logging details for calls made using OAuth access tokens to the AWS MCP Server can be found in Logging AWS MCP Server API calls using AWS CloudTrail.

Conclusion

AWS Sign-In support for OAuth enables you to securely connect to the AWS MCP Server using industry-standard authorization. This release simplifies application and agent integration with AWS while supporting your existing IAM setup, governance, and auditing capabilities.

To learn more, see Sign-In with OAuth 2.0 in the AWS Sign-In User Guide and Setting up the AWS MCP Server in the Agent Toolkit for AWS User Guide.

If you have feedback about this post, submit comments in the Comments section below.


Vaibhav Chowla

Vaibhav Chowla

Vaibhav is a Senior Technical Product Manager at AWS, specializing in AWS Identity products. He focuses on enhancing user authentication and security, helping customers of all sizes solve complex identity and access management (IAM) challenges. Outside of technology, Vaibhav enjoys traveling and exploring new cultures and cuisines.

Jaimin Bhatt

Jaimin Bhatt

Jaimin is a Principal Software Engineer at AWS. He works on AWS Identity and Access Management (IAM) across sign-in, threat detection, and the authentication and authorization that secures access to AWS. Jaimin is an active participant in multiple industry standards bodies. Previously, he led work on data perimeter controls for AWS Management Console sign-in, multi-session support for the console, a simplified AWS CLI sign-in experience, and the internal Amazon identity provider.

Ankur Joshi

Ankur Joshi

Ankur is a Software Development Manager on the AWS Identity Sign-In team. His team focuses on delivering secure and resilient authentication mechanisms and access controls for AWS customers.

Ship infrastructure faster with CloudFormation and CDK pre-deployment validation on every stack operation

Post Syndicated from Idriss Laouali Abdou original https://aws.amazon.com/blogs/devops/ship-infrastructure-faster-with-cloudformation-and-cdk-pre-deployment-validation-on-every-stack-operation/

AWS CloudFormation helps you model and provision cloud infrastructure as code using JSON or YAML templates, or through tools like the AWS Cloud Development Kit (CDK). Whether you create stacks directly, use change sets for preview, or deploy through CI/CD pipelines and AI agents, fast feedback on template errors is critical to development velocity.

Previously, CloudFormation introduced pre-deployment validation during change set creation, catching property syntax errors, resource name conflicts, and S3 bucket emptiness constraints before execution.

Today, we are announcing that pre-deployment validation now runs automatically on every CreateStack and UpdateStack operation, so every deployment path benefits from pre-deployment checks with no configuration required. We are also introducing three new validation checks (Service Quotas limit exceeded, AWS Config Recorder conflicts, and ECR repository delete readiness), a new DisableValidation parameter for operation-level control, and the cdk validate command that leverages CloudFormation pre-deployment validation as part of the CDK developer experience.

In this blog post, we will walk you through how these capabilities work in practice. You will learn how to:

  • Catch property syntax errors and resource name conflicts on CreateStack and UpdateStack before any resources are provisioned
  • Review new WARN-mode validations (service quotas, Config Recorder, ECR delete readiness) during change set creation
  • Use cdk validate to get a validation report with construct-level source tracing
  • Control validation behavior with the DisableValidation parameter when you need to skip checks

Key Capabilities

  • Pre-deployment validation on all stack operations: Property syntax validation and resource name conflict detection (Resource Already Exists) now run in hard-fail mode on CreateStack and UpdateStack, in addition to CreateChangeSet. Errors are caught before any resources are provisioned.
  • Three new validation types: Service Quota validation, AWS Config Recorder conflict detection, and ECR Repository delete readiness checks are now available as warnings during change set creation.
  • CDK validate command: The cdk validate command leverages CloudFormation pre-deployment validation and provides a report with construct-level source tracing that maps errors back to your CDK code.
  • DisableValidation parameter: Operation-level control to skip pre-deployment validation when you need to prioritize deployment speed or bypass a known issue.

How It Works

Understanding Validation Modes

CloudFormation pre-deployment validation operates in two modes that determine how validation failures are handled:

  • FAIL mode stops the stack operation when validation detects errors, ensuring problematic templates cannot proceed to deployment. This applies to property syntax errors and resource name conflicts on CreateStack, UpdateStack, and CreateChangeSet operations.
  • WARN mode allows the operation to proceed despite validation findings, providing warnings that you can review and address before execution. This applies to service quota limits, AWS Config Recorder conflicts, and ECR repository delete readiness checks on CreateChangeSet.

What happens when validation fails:

  • CreateStack: Operation stops before any resources are provisioned.
  • UpdateStack: Operation stops, stack remains in its current state with no resources modified.
  • CreateChangeSet: Change set is not executable. Change set status shows FAILED.

The following scenarios demonstrate how pre-deployment validation works across different stack operations.

Scenario 1: Property Validation on CreateStack

CloudFormation evaluates each resource property definition before provisioning begins. The following template contains several common resource property errors:

Template (dashboard-stack.yaml)

AWSTemplateFormatVersion: "2010-09-09"
Description: Dashboard stack with property validation errors

Resources:
  Dashboard04:
    Type: "AWS::CloudWatch::Dashboard"
    Properties:
      DashboardName: "MyDashboard"

  LogStream08:
    Type: "AWS::Logs::LogStream"
    Properties:
      LogGroupName: "/aws/my-app"
      LogStreamName:                        # Expected string, found JSONArray
        - "stream-1"
        - "stream-2"

  MetricFilter03:
    Type: "AWS::Logs::MetricFilter"
    Properties:
      LogGroupName: "/aws/my-app"
      SomeUnsupportedProperty: "value"      # Unsupported property
      MetricTransformations:
        - MetricName: "ErrorCount"
          MetricNamespace: "MyApp"
          MetricValue: "1"

Step 1: Create Stack

aws cloudformation create-stack \
    --stack-name "dashboard-stack" \
    --template-body file://dashboard-stack.yaml

The command returns the stack ARN and operation begins. Pre-deployment validation runs automatically before any resources are provisioned.

Step 2: Check Validation Results

Use the describe-events API to review validation results:

aws cloudformation describe-events \
    --stack-name "dashboard-stack"

Example output:

The stack creation stopped before any resources were provisioned. Each validation error includes the logical resource ID, resource type, and a precise status reason describing the property issue.

{
    "OperationEvents": [
        {
            "EventId": "ed0f6cc4-3f85-4ad9-abc3-1f9aad2ab931",
            "StackId": "arn:aws:cloudformation:us-west-1:1234:stack/dashboard-stack/6877f3c0-73e6-11f1-a1e1-02ff57e5af93",
            "OperationId": "68790530-73e6-11f1-a1e1-02ff57e5af93",
            "OperationType": "CREATE_STACK",
            "EventType": "VALIDATION_ERROR",
            "LogicalResourceId": "MetricFilter03",
            "PhysicalResourceId": "",
            "ResourceType": "AWS::Logs::MetricFilter",
            "Timestamp": "2026-06-29T18:14:49.255000+00:00",
            "ValidationFailureMode": "FAIL",
            "ValidationName": "PROPERTY_VALIDATION",
            "ValidationStatus": "FAILED",
            "ValidationStatusReason": "Unsupported property [SomeUnsupportedProperty]",
            "ValidationPath": "/Resources/MetricFilter03/Properties/SomeUnsupportedProperty"
        },
        {
            "EventId": "4f9f12ce-498c-4d79-af31-730238b85139",
            "StackId": "arn:aws:cloudformation:us-west-1:1234:stack/dashboard-stack/6877f3c0-73e6-11f1-a1e1-02ff57e5af93",
            "OperationId": "68790530-73e6-11f1-a1e1-02ff57e5af93",
            "OperationType": "CREATE_STACK",
            "EventType": "VALIDATION_ERROR",
            "LogicalResourceId": "LogStream08",
            "PhysicalResourceId": "",
            "ResourceType": "AWS::Logs::LogStream",
            "Timestamp": "2026-06-29T18:14:49.255000+00:00",
            "ValidationFailureMode": "FAIL",
            "ValidationName": "PROPERTY_VALIDATION",
            "ValidationStatus": "FAILED",
            "ValidationStatusReason": "Property [LogStreamName] expected type: String, found: JSONArray",
            "ValidationPath": "/Resources/LogStream08/Properties/LogStreamName"
        },
    ]
}

Console Experience

In the CloudFormation console, navigate to your stack’s Events tab and click the operation ID (or the link in the banner or status reason column) to open the Operation view page. The page will open directly on the Deployment validations tab to see the validation results table:

  • LogStream08 (AWS::Logs::LogStream) – FAIL: Property [LogStreamName] expected string, found: JSONArray
  • MetricFilter03 (AWS::Logs::MetricFilter) – FAIL: Unsupported property [SomeUnsupportedProperty]
Figure 1 - Deployment validations tab showing property validation failures on CreateStack

Figure 1: Deployment validations tab showing property validation failures on CreateStack

Figure 2 Deployment validations tab showing property validation failures on CreateStack

Figure 2: Deployment validations tab showing property validation failures on CreateStack

Scenario 2: Resource Name Conflict on UpdateStack

Resource name conflict detection (RAE) identifies when your template specifies a resource name that already exists in your account. This validation now runs on CreateStack and UpdateStack operations in addition to CreateChangeSet.

Template (update-bucket.yaml)

AWSTemplateFormatVersion: "2010-09-09"
Description: Update stack adding a bucket with a conflicting name

Resources:
  ExistingFunction:
    Type: "AWS::Lambda::Function"
    Properties:
      FunctionName: "my-existing-function"
      Runtime: "python3.12"
      Handler: "index.handler"
      Role: !Sub "arn:aws:iam::${AWS::AccountId}:role/lambda-role"
      Code:
        ZipFile: |
          def handler(event, context):
              return {"statusCode": 200}

  ConflictingBucket:
    Type: "AWS::S3::Bucket"
    Properties:
      BucketName: "production-data-bucket"   # Already exists in the account

Update Stack

aws cloudformation update-stack \     
     --stack-name "my-app-stack" \     
     --template-body file://update-bucket.yaml

Validation output (via describe-events):

{
    "OperationEvents": [
        ...
        {
            "EventId": "bde0f986-3b47-48d8-91bc-f384195f842a",
            "StackId": "arn:aws:cloudformation:us-west-1:1234:stack/my-app-stack-blog-test/164ff580-73e5-11f1-ab70-026546ec19e3",
            "OperationId": "65e641d0-73e5-11f1-abdb-06073274cc09",
            "OperationType": "UPDATE_STACK",
            "EventType": "VALIDATION_ERROR",
            "LogicalResourceId": "ConflictingBucket",
            "PhysicalResourceId": "",
            "ResourceType": "AWS::S3::Bucket",
            "Timestamp": "2026-06-29T18:07:36.139000+00:00",
            "ValidationFailureMode": "FAIL",
            "ValidationName": "NAME_CONFLICT_VALIDATION",
            "ValidationStatus": "FAILED",
            "ValidationStatusReason": "Resource of type 'AWS::S3::Bucket' with identifier 'production-data-bucket-blog-test-208004920468' already exists.",
            "ValidationPath": "/Resources/ConflictingBucket"
        },
        ...
    ]
}

The update stops before any resources are modified. You can either rename the resource in your template or remove the existing resource that causes the conflict.

Figure 3 - Resource Name Conflict on UpdateStack Event tab

The deployment validation view below provide moe detail about the error, include status reason and path to the resource.

Figure 3 - Resource Name Conflict on UpdateStack Deployment validation

Figure 3: Resource Name Conflict on UpdateStack

Scenario 3: Service Quota Warning on CreateChangeSet

Service Quota validation is one of three new warning-mode validations available during change set creation. It checks whether creating or updating resources would exceed your AWS service quotas.

Create Change Set

aws cloudformation create-change-set \
    --stack-name "vpc-stack" \
    --change-set-name "add-subnets" \
    --template-body file://vpc-with-many-subnets.yaml

Validation output:

{
    "EventId": "3ba6f27b-4d3c-4e73-bac2-8d8cbf71a6d3",
    "StackId": "arn:aws:cloudformation:us-west-1:1234:stack/vpc-quota-test/492a84d0-73ee-11f1-a714-02e5a60ac85d",
    "OperationId": "b55e1e8f-28d1-4cbe-a6c3-59c92707e180",
    "OperationType": "CREATE_CHANGESET",
    "EventType": "VALIDATION_ERROR",
    "LogicalResourceId": "VPC1",
    "PhysicalResourceId": "",
    "ResourceType": "AWS::EC2::VPC",
    "Timestamp": "2026-06-29T19:11:12.727000+00:00",
    "ValidationFailureMode": "WARN",
    "ValidationName": "SERVICE_QUOTA_VALIDATION",
    "ValidationStatus": "FAILED",
    "ValidationStatusReason": "Service quota will be exceeded: AWS::EC2::VPC current usage 1/5, creating 6 would exceed limit",
    "ValidationPath": "/Resources/VPC1"
}

Because this validation operates in WARN mode, the change set is created successfully. You can review the warning, request a quota increase through the Service Quotas console, and then proceed with execution. The two other new warning validations (AWS Config Recorder conflict detection and ECR Repository delete readiness) follow the same pattern.

Figure 4 - Service Quotas Warning on CreateChangeSet

Figure 4: Service Quota Warning on CreateChangeSet

Scenario 4: CDK Validate Experience

The cdk validate command provides a unified validation experience that combines multiple validation sources into a single report with construct-level source tracing. Under the hood, cdk validate synthesizes your CDK app, creates a change set to invoke server-side pre-deployment validation, collects the results via DescribeEvents, and produces a report that maps errors back to your CDK source code with construct-level tracing.

Each error traces back to the specific construct and source file location in your CDK code, not just the CloudFormation logical resource ID. This construct-level tracing is what makes cdk validate uniquely valuable: you see the exact line in your code that needs to change.

Scenario 5: Controlling Validation with DisableValidation

Pre-deployment validation is enabled by default on all stack operations. If you need to skip validation for a specific operation, use the DisableValidation parameter.

When to disable validation:

  • When you have already validated your template through other means (cdk validate, cfn-lint, CI/CD checks)
  • When you need to minimize operation latency for time-sensitive deployments

CLI usage:

# Skip validation on create-stack
aws cloudformation create-stack \
    --stack-name "my-stack" \
    --template-body file://template.yaml \
    --disable-validation

# Skip validation on update-stack
aws cloudformation update-stack \
    --stack-name "my-stack" \
    --template-body file://template.yaml \
    --disable-validation

Important: Disabling validation means common errors will not be caught until resource provisioning is attempted. Use this option only when you understand the trade-off between deployment speed and early error detection.

AI Agents and Automated Workflows

Pre-deployment validation gives AI agents and automation tools the fast feedback loop they need to self-correct. When an agent provisions infrastructure and the template has an error, validation returns a structured error in seconds rather than waiting minutes for a full provision-and-rollback cycle to complete. The agent can parse the error, fix the template, and retry immediately.

With cdk validate, agents get construct-level source tracing that maps errors directly to the line of CDK code that needs to change, enabling fully automated fix-and-retry loops without human intervention.

To get started with the agent experience, install the CloudFormation agent skill from the AWS Agent Toolkit. This skill gives AI agents the ability to create stacks, validate templates, and iterate on errors using pre-deployment validation feedback.

Getting Started

Pre-deployment validation runs automatically on all CreateStack, UpdateStack, and CreateChangeSet operations with no configuration required. To start benefiting:

  • Create or update a stack as you normally would. Validation runs automatically.
  • Review validation results using the DescribeEvents API, the CloudFormation Console Events tab (click the operation ID, then the Deployment validations tab), or the cdk validate command.
  • Fix identified issues in your template and retry the operation.
  • Optionally disable validation using --disable-validation for specific operations

Required IAM permissions for validation checks

Validation on CreateStack and UpdateStack (property syntax validation and resource name conflict detection) requires no additional IAM permissions beyond what is needed for the stack operation itself. For the new validation checks available during change set creation, your IAM role needs the following additional permissions:

Service Quota Check:

  • cloudwatch:GetMetricData
  • lambda:GetAccountSettings
  • servicequotas:GetServiceQuota
  • ec2:DescribeSecurityGroups
  • iam:GetAccountSummary

Config Recorder Check:

  • config:ListConfigurationRecorders

S3 Bucket Empty Check:

  • s3:ListBucketV2

ECR Repository Delete Readiness Check:

  • ecr:ListImages

If these permissions are not granted, the corresponding validation checks will be skipped without blocking the operation.

For CDK users:

# Run unified validation before deploying 
cdk validate

Best Practices

  • Use cdk validate as your primary pre-deployment check. It leverages CloudFormation pre-deployment validation in a single command, giving you comprehensive coverage before any deployment is attempted.
  • Place CreateChangeSet as the first pipeline stage. For pipelines that use change sets, this ensures pre-deployment validation fires at the pipeline entry point. CDK Pipelines integrates this by default.
  • Let validation run by default. The few seconds of validation time pay for themselves by preventing full provision-and-rollback cycles that take minutes or longer.
  • Use DisableValidation intentionally. Reserve it for cases where you have already validated through other means or need to bypass a known false positive. Do not disable validation globally.
  • Integrate validation into PR/CI workflows. Run cdk validate or cfn-lint as part of your pull request checks to catch errors before code is merged, preventing invalid templates from reaching deployment pipelines.
  • Monitor validation warnings. WARN-mode validations (service quota, Config Recorder, ECR delete readiness) indicate potential issues that may cause failures at execution time. Address them proactively.

Conclusion

Pre-deployment validation on all stack operations represents a significant step forward in CloudFormation’s shift-left validation strategy. By catching common deployment errors in seconds before any resources are provisioned, this capability eliminates unnecessary rollback cycles and accelerates development workflows across the board.

Combined with the cdk validate command, which provides a unified validation experience with construct-level tracing, and the DisableValidation parameter for operation-level control, teams now have a complete toolkit for managing the trade-off between validation coverage and deployment speed. AI agents and automated pipelines benefit from structured, machine-readable feedback that enables immediate self-correction, turning what were once multi-minute debugging cycles into second-level iteration loops.

Pre-deployment validation is available in all AWS Regions where CloudFormation is supported. No configuration or opt-in is required. To learn more, visit the Validate stack deployments User Guide.

Blog Authors Bio:

Idriss Laouali Abdou

Idriss is a Sr. Product Manager Technical on the AWS Infrastructure-as-Code team based in Seattle. He focuses on improving developer productivity through AWS CloudFormation and StackSets Infrastructure provisioning experiences. Outside of work, you can find him creating educational content for thousands of students, cooking, or dancing.

Olivia Biswas

Olivia is a Software Development Manager on the AWS Infrastructure-as-Code team based in Seattle, where she leads developer productivity initiatives through CloudFormation. During her tenure at Amazon, she has built several customer-obsessed software solutions within Alexa and Buy With Prime. Outside of work, she is a globe trotter who enjoys baking, dancing, reading, and watching documentaries.

Subha Velayutham

Subha is a Senior Software Engineer on the AWS Infrastructure-as-Code team, where she builds features to improve developer productivity. Outside of work, she enjoys reading, traveling, and experimenting with new creative hobbies.

Feature Flag Orchestration with AWS DevOps Agent and LaunchDarkly

Post Syndicated from Greg Eppel original https://aws.amazon.com/blogs/devops/feature-flag-orchestration-with-aws-devops-agent-and-launchdarkly/

Introduction

Organizations that use feature flags alongside incident response tooling often connect the two manually. When an outage occurs, engineers must identify which flags are relevant, decide whether to disable them, and coordinate the change across teams. This manual process adds latency at the moment it matters most.

You can use AWS DevOps Agent and its MCP server feature to connect to LaunchDarkly’s hosted MCP server, enabling feature flag recommendations during both proactive deployment review and reactive incident response workflows. Once connected, DevOps Agent can query flag state, read targeting rules, and surface recommendations directly within the workflows where engineers make decisions.

This post walks through two primary use cases:

  1. Pre-deployment review where the release management capabilities in AWS DevOps Agent evaluate changes and a DevOps Agent Skill recommends feature flag coverage before code ships.
  2. Incident response where DevOps Agent queries LaunchDarkly flag state via MCP and recommends containment actions during active incidents.

We also cover the connection architecture, a reusable DevOps Agent Skill for pre-deployment flag validation, and links to get started.

Defense: Release Management and Proactive Flag Recommendations

Five-step sequence diagram of the pre-deployment review workflow: PR Submitted, DevOps Agent Readiness Review Analyzes PR, Flag Gate Skill recommends a LaunchDarkly flag, Recommendation Surfaced, Developer Reviews.

Figure 1: DevOps Agent’s readiness review identifies high-risk PRs and recommends LaunchDarkly feature flag coverage before code ships.

The release management capabilities (now in public preview) in AWS DevOps Agent evaluate code changes before they ship to production.

It performs functional testing in an AWS-managed verification environment, assesses risks to cross-codebase dependencies, evaluates adherence to your organization’s standards and best practices, and mathematically verifies that access control configurations in CloudFormation do not deviate from Well-Architected best practices.

AWS DevOps Agent is designed to be extended and customized to fit your tools, standards, and practices. Using the product’s primitives, you can add Skills that enhance its capabilities. For example, when a high-risk change is identified, a custom Skill can evaluate whether the change has adequate feature flag coverage, operating on deployment metadata and code analysis to identify gaps and surface a recommendation to the developer, such as recommending feature flags with LaunchDarkly when needed.

What the Skill Evaluates

The release readiness flag Skill classifies code changes into risk tiers (Critical, High, Moderate) based on what’s being modified — payments, authentication, database schemas, third-party integrations, new API endpoints, performance-sensitive paths, and more — and recommends feature flags proportional to the risk level.

Screenshot of the AWS DevOps Agent Knowledge panel on the Skills tab, showing a custom skill named "high-risk-feature-flag-recommendations" with a description that reads "Evaluates code changes during release readiness reviews to identify high-risk modifications and recommends wrapping them in LaunchDarkly feature flags for safer rollouts."

Figure 2: The high-risk-feature-flag-recommendations Skill configured in AWS DevOps Agent’s Knowledge panel.

What the Recommendation Includes

When the Skill identifies a gap, it surfaces a recommendation containing:

  • Risk context: Why the change is flagged as high-risk (e.g., “This deployment modifies payment authorization logic across 3 downstream services with no existing rollback mechanism.”)
  • Suggested flag configuration: A proposed LaunchDarkly flag key, variations, and default targeting rules aligned with the deployment plan.
  • Rollout strategy: A recommended phased rollout (e.g., internal users first, then 5% of traffic, then full rollout) that matches the risk profile.
  • Kill-switch behavior: What happens when the flag is turned off — the fallback code path, cleanup considerations, and data consistency implications.

Example Scenario

Consider a team deploying an update to a tax calculation service. The change modifies the tax rate computation logic, affecting all order totals across multiple regions. AWS DevOps Agent evaluates the deployment and classifies it as high-risk. The pre-deployment flag gate Skill then identifies:

  • The change touches critical-path tax calculation code.
  • No feature flag wraps the new computation behavior.
  • The blast radius covers all active checkout sessions.

The Skill surfaces a recommendation: “This deployment modifies tax calculation logic with no existing feature flag coverage. Recommend wrapping the new tax computation in a LaunchDarkly flag (tax-calculation-v2) with a phased rollout targeting internal test accounts first, followed by 5% of production traffic.” 

The developer can then action the recommendation, creating the flag in LaunchDarkly, adjusting the suggested configuration to fit their rollout plan, or noting the justification for proceeding without one as part of the deployment record.

Screenshot of the AWS DevOps Agent Report tab showing a policy violation titled "Checkout pricing changes deployed without a LaunchDarkly feature flag." The report includes risk context, evidence from a repo grep showing no existing flag, a suggested fix with sample Node.js code using the LaunchDarkly SDK, and a recommended phased rollout strategy.

Figure 3: AWS DevOps Agent release management report identifying checkout pricing changes deployed without LaunchDarkly feature flag coverage, including a suggested fix with sample code.

Closing the Loop with Kiro IDE

DevOps Agent’s release management capabilities identify when a deployment needs feature flag coverage. Paired with Kiro IDE, this recommendation becomes actionable without leaving the development workflow.

Kiro connects to LaunchDarkly’s MCP server directly, providing flag integration capabilities during development. When a developer builds a new feature in Kiro, the IDE can query LaunchDarkly via MCP to check whether a flag already exists for that feature and generate code with the flag evaluation built in from the start.

Together, this creates one continuous flow: DevOps Agent identifies the risk and recommends flag coverage → the developer, working in Kiro, generates the flag and wraps the code in a single action → the deployment ships with coverage already in place. No context-switching between tools, no manual flag creation in a separate console.

Developers can also use Kiro’s flag integration independently during feature development, even before a deployment triggers a release management review. The two operate as layered coverage: if Kiro catches it during development, DevOps Agent validates the targeting rules match the rollout plan at deployment time. If the developer bypasses Kiro or uses a different toolchain, DevOps Agent still identifies the gap.

Offense: Flag Recommendations During Incident Response

During an active incident, speed of containment directly affects customer impact. DevOps Agent participates in incident response workflows by querying LaunchDarkly to understand current flag state, then recommending containment actions based on what it finds.

Sequence diagram: Incident Detected, DevOps Agent correlates with flag change, queries LaunchDarkly via MCP (value changed to 30ms from 2000ms), recommends reverting to 2000ms, engineer confirms action.

Figure 4: DevOps Agent identifies a flag change (30ms from 2000ms) as the probable cause, queries LaunchDarkly for state, and recommends reverting the value.

When you detect an incident, DevOps Agent correlates the affected service with recent deployments. It queries LaunchDarkly to identify feature flags associated with those deployments and their current state (enabled, targeting rules, rollout percentage). If a relevant flag is enabled, the agent recommends disabling it as a containment option before suggesting a full rollback.

Flag-based containment provides an alternative containment option that can help reduce the time to resolution. Disabling a flag may return behavior to the previous state, which can be faster than a full deployment rollback in some scenarios

Example Scenario

An alert fires indicating sustained 5XX errors on the bot-service. The on-call engineer engages DevOps Agent, which:

  1. Correlates the HTTP 503 errors with a LaunchDarkly feature flag change: bot-mutation-orchestration-timeout-ms was changed from the default 2000ms to 30ms (the “low latency” variation), applied to all traffic.
  2. Identifies that the 30ms timeout budget is insufficient for inter-service HTTP calls during bot creation and deletion orchestration, which require DynamoDB reads/writes plus IoT Core calls, causing ReadTimeout exceptions.
  3. Recommends reverting the bot-mutation-orchestration-timeout-ms flag to its default variation (2000ms) as the containment action, noting this will restore sufficient timeout budget without requiring a code deployment.

The engineer reviews the recommendation, updates the flag variation in LaunchDarkly, and the error rate returns to baseline within minutes.

Screenshot of the AWS DevOps Agent Root cause tab showing an investigation summary. The Impact section reports bot-service ALB returning sustained 5XX errors since 18:52Z with 136 errors in 10 minutes. The Root causes section, highlighted with a red border, identifies that the LaunchDarkly feature flag "bot-mutation-orchestration-timeout-ms" was changed to 30ms from the default 2000ms, causing ReadTimeout exceptions.

Figure 5: AWS DevOps Agent investigation summary identifying a LaunchDarkly feature flag timeout change as the root cause of sustained 5XX errors

Step-by-Step Mitigation Plans

When DevOps Agent identifies a root cause, it generates a structured mitigation plan with concrete, executable steps. Rather than a generic recommendation, the agent provides:

  1. Prepare — Document the current error baseline (with ready-to-run CLI commands, e.g., CloudWatch get-metric-statistics) and confirm the problematic configuration is still active before making changes.
  2. Execute — Revert the specific change (in this case, reverting the LaunchDarkly feature flag bot-mutation-orchestration-timeout-ms from 30ms back to the 2000ms default) with clear instructions on which variation to target.
  3. Verify — Validate that error rates return to baseline after the change, confirming the mitigation was effective.

Each step includes sub-steps with specific commands, API paths, and success criteria — giving the on-call engineer a clear, auditable runbook rather than a vague recommendation.

Screenshot of the AWS DevOps Agent Mitigation plan tab showing a plan titled "Revert LaunchDarkly feature flag 'bot-mutation-orchestration-timeout-ms' from 30ms to 2000ms default value." The plan includes Step 1: Prepare, with sub-steps to document the current 5XX error baseline using an AWS CLI command and confirm the flag is still serving the problematic 30ms value.

Figure 6: Structured mitigation plan generated by AWS DevOps Agent with executable steps to revert the feature flag and verify resolution.

Below, the LaunchDarkly targeting configuration shows the bot-mutation-orchestration-timeout-ms flag with its available variations. During the incident, the engineer reverted from the “low latency” variation back to “default” to restore the 2000ms timeout budget.

Screenshot of the LaunchDarkly console showing the targeting configuration for the "bot-mutation-orchestration-timeout-ms" flag in the Production environment. The flag is set to Off, serving the "default" variation to all traffic. A dropdown menu displays the available variations: 1, 0, default (selected), low latency, and moderate.

Figure 7: LaunchDarkly targeting configuration for the bot-mutation-orchestration-timeout-ms flag showing available variations including the default and low latency values.

Connecting to LaunchDarkly via MCP

As described in the introduction, DevOps Agent uses its MCP server feature to connect to LaunchDarkly’s hosted MCP server. This section covers the architecture and setup steps.

LaunchDarkly’s MCP server exposes flag management operations as agent-callable tools through the Model Context Protocol (MCP) standard. DevOps Agent connects as a client, giving it the ability to query flag state, read targeting rules, and list flags by project or environment without custom integration code.

Architecture

The connection follows this flow:

  1. DevOps Agent identifies a need for flag-related context (e.g., during incident response).
  2. DevOps Agent calls LaunchDarkly’s hosted MCP server using standardized MCP tool definitions.
  3. LaunchDarkly MCP Server translates the request into LaunchDarkly API calls and returns structured responses (flag state, targeting rules, rollout percentages).
  4. DevOps Agent uses the response to formulate recommendations presented to the engineer.

Registration and Configuration

To set up the connection:

  1. Register LaunchDarkly’s hosted MCP server endpoint with DevOps Agent.
  2. Configure authentication credentials (LaunchDarkly API key with appropriate scopes).
  3. Validate connectivity by running a test flag query.

For the full setup walkthrough, including detailed configuration steps and permissions requirements, refer to LaunchDarkly’s companion blog post (link placeholder).

The same LaunchDarkly MCP server connection is available in Kiro IDE for flag-aware code generation during development; see the Defense section above for how Kiro completes the pre-deployment workflow.

Example Skill: High-Risk Feature Flag Recommendations

AWS DevOps Agent Skills are modular instruction sets that extend the agent’s capabilities with specialized domain knowledge and investigation methodologies tailored to your infrastructure and operational workflows. AWS DevOps Agent supports a subset of the Agent Skills specification. The format is flexible, but this example is structured into the following sections:

  • Risk Classification Criteria — defines what constitutes Critical, High, and Moderate risk changes
  • Feature Flag Recommendation Format — specifies the output structure: flag name, flag type, targeting strategy, and kill switch guidance
  • Example Recommendations — provides reference examples so the agent produces consistent, actionable output
  • Integration Notes — describes how recommendations surface during release readiness reviews
  • What NOT to Flag — explicitly scopes out low-risk changes to reduce noise

Below is the full Skill used in this example:


# High-Risk Code Feature Flag Recommendations

When performing a release readiness review, use this skill to identify high-risk code changes and recommend LaunchDarkly feature flags for safer, controlled rollouts.

## Risk Classification Criteria

Evaluate code changes against these risk categories:

### Critical Risk (Always recommend feature flag)
- **Payment/billing logic** — any changes to checkout, payment processing, subscription handling, or pricing calculations
- **Authentication/authorization** — login flows, session management, permission checks, OAuth/SSO integrations
- **Database schema changes** — migrations, new columns, index changes, especially on high-traffic tables
- **Data deletion or mutation** — bulk updates, cascading deletes, data transformations
- **Third-party API integrations** — new external service dependencies or changes to existing integrations
- **Core business logic** — order processing, inventory management, user registration flows

### High Risk (Strongly recommend feature flag)
- **New API endpoints** — especially public-facing or partner APIs
- **Performance-sensitive paths** — changes to hot paths, caching logic, query optimizations
- **Feature rewrites** — replacing existing functionality with new implementations
- **Concurrency changes** — threading, async processing, queue handling modifications
- **Configuration changes** — environment variables, feature toggles, service endpoints

### Moderate Risk (Consider feature flag)
- **UI changes to critical flows** — checkout pages, login screens, dashboard views
- **Logging/monitoring changes** — new metrics, log format changes, tracing modifications
- **Error handling changes** — exception handling, retry logic, fallback behaviors

## Feature Flag Recommendation Format

When recommending a feature flag, provide:

### 1. Flag Name
Use a descriptive, lowercase, hyphenated name:
- `enable-new-payment-processor`
- `use-v2-auth-flow`
- `rollout-order-service-refactor`

### 2. Flag Type
Recommend the appropriate LaunchDarkly flag type:
- **Boolean** — simple on/off for feature enablement
- **Multivariate** — when you need multiple variations (A/B testing, gradual migrations)
- **Number/String** — for configuration values that might need adjustment

### 3. Targeting Strategy
Recommend an appropriate rollout strategy:
- **Percentage rollout** — start at 1-5%, monitor, then increase (default for most changes)
- **User segment targeting** — internal users first, then beta users, then general availability
- **Environment targeting** — enable in staging/canary before production

### 4. Kill Switch Guidance
Explain what happens when the flag is turned off:
- What code path executes when disabled
- Any cleanup or rollback considerations
- Data consistency implications

## Example Recommendations

### Example 1: Payment Processing Change

**Code Change:** Refactored payment gateway integration to support new processor

**Recommendation:**
```CRITICAL RISK: Payment processing changes detected

Recommend wrapping in LaunchDarkly feature flag:
- Flag name: `enable-stripe-v2-integration`
- Flag type: Boolean
- Default: OFF (use existing payment flow)

Rollout strategy:
1. Enable for internal test accounts first
2. Expand to 1% of production traffic
3. Monitor payment success rates and error logs
4. Gradually increase to 100% over 1-2 weeks

Kill switch behavior: Reverts to existing payment processor immediately. 
In-flight transactions will complete with their original processor.
```

### Example 2: New API Endpoint

**Code Change:** Added new `/api/v2/orders` endpoint with different response format

**Recommendation:**
```HIGH RISK: New API endpoint with breaking response format

Recommend wrapping in LaunchDarkly feature flag:
- Flag name: `enable-orders-api-v2`
- Flag type: Boolean
- Default: OFF (return v1 format)

Rollout strategy:
1. Enable for specific API clients by client_id targeting
2. Coordinate with consuming teams before enabling
3. Run both versions in parallel during migration period

Kill switch behavior: Returns v1 response format. Ensure v1 
serialization logic remains in codebase until flag is permanent.
```

### Example 3: Database Migration

**Code Change:** Adding new index to high-traffic `orders` table

**Recommendation:**
```CRITICAL RISK: Database schema change on high-traffic table

Recommend wrapping dependent code in LaunchDarkly feature flag:
- Flag name: `use-orders-status-index`
- Flag type: Boolean  
- Default: OFF (use existing query patterns)

Rollout strategy:
1. Deploy migration to create index (can be done independently)
2. Deploy code that uses new index behind flag
3. Enable flag in staging, verify query performance
4. Enable in production during low-traffic window
5. Monitor query latency and database load

Kill switch behavior: Queries fall back to non-indexed path.
May see temporary performance degradation but no data loss.
```

## Integration Notes

When the release readiness review identifies high-risk changes:

1. **Surface the risk level** clearly in the review summary
2. **Provide the flag recommendation** with copy-paste ready configuration
3. **Explain the rollout strategy** appropriate for the risk level
4. **Document the kill switch behavior** so operators know what to expect

## What NOT to Flag

Not every change needs a feature flag. Avoid recommending flags for:
- Pure refactoring with no behavior change
- Test file additions or modifications
- Documentation updates
- Dependency version bumps (unless major version with breaking changes)
- Code formatting or linting fixes

Activating the Skill

DevOps Agent loads Skill metadata at the start of each workflow and loads the full Skill content when it determines relevance. To ensure the feature flag Skill is consistently applied during release readiness reviews, add a directive to your DevOps Agent Instructions (Agent.md), which is loaded in full at the start of every session:

“When performing release readiness reviews, always load and apply the high-risk-feature-flag-recommendations skill to evaluate code changes for risk and recommend LaunchDarkly feature flags where appropriate.”

This guarantees the agent loads and applies the Skill for every release readiness review rather than relying on relevance detection to surface it.

Getting Started

To begin using feature flag orchestration with AWS DevOps Agent and LaunchDarkly:

  1. Enable AWS DevOps Agent in your AWS account to start building Skills and connecting MCP servers
  2. Set up the LaunchDarkly MCP server: Follow the LaunchDarkly MCP server documentation for installation and configuration instructions.
  3. Read the companion post: LaunchDarkly’s blog post explores why feature flags are essential infrastructure for SRE agents and how the LaunchDarkly MCP Server connects to AWS DevOps Agent for pre-deployment review and incident response workflows.

Conclusion

Feature flag orchestration with AWS DevOps Agent and LaunchDarkly reduces the manual coordination required during both deployment review and incident response. A DevOps Agent Skill surfaces flag recommendations before high-risk changes ship, and during incidents, the agent queries LaunchDarkly to recommend flag-based containment, providing faster resolution with less disruption than full rollbacks.

For developers using Kiro IDE, the same LaunchDarkly MCP server enables flag-aware code generation during development, shifting flag coverage left to the point of authorship. Together, these workflows provide layered coverage: individual developers build with flags, DevOps Agent’s release management capabilities validate coverage at deployment time, and DevOps Agent uses flag state during incident response.

Authors

Greg Eppel

Greg Eppel is a Principal Specialist for DevOps Agent and has spent the last several years focused on Cloud Operations and helping AWS customers on their cloud journey.

Carl Caum

Carl Caum is a Senior Product Manager for DevOps Agent focused on accelerating safe software delivery through agentic solutions.

Debug deployment failures faster with the Deployments tab in AWS Elastic Beanstalk

Post Syndicated from Ben Lazar original https://aws.amazon.com/blogs/devops/debug-deployment-failures-faster-with-the-deployments-tab-in-aws-elastic-beanstalk/

Introduction

When a deployment fails, finding the root cause often means piecing together information from multiple sources. You wait for the deployment to finish, request a log bundle, download it, and then search through files like eb-engine.log and cfn-init.log to find the error. If you’re not familiar with Elastic Beanstalk’s log file structure, you might not know which file to check first, and the process can take longer than fixing the actual problem.

Elastic Beanstalk now provides a Deployments tab in the environment dashboard that gives you a consolidated view of your deployment history and real-time deployment logs. You can see what’s happening during a deployment as it runs, and when something fails, the deployment log shows you the error output directly in the console.

In this post, you create an Elastic Beanstalk environment, trigger different types of deployments, deploy a broken application to see how the Deployments tab surfaces errors, and then fix and redeploy. By the end, you’ll know how to use deployment logs to diagnose failures without connecting to instances over SSH or downloading log bundles.

Solution overview

The Deployments tab displays a history of recent deployments for your environment, including application deployments, configuration updates, and environment launches. Each deployment has a detail page with two tabs: Events, which shows a filtered timeline of events for that deployment, and Deployment Logs, which shows a consolidated log from the instance.

Deployment logs capture each step of the deployment process: dependency installation, application builds, .ebextensions commands, platform hooks, and application startup output. The logs are designed to be concise. On success, you see summary messages showing which steps ran and completed. On failure, the log includes up to 50 lines of output from the failed step, so you can see what went wrong without searching through verbose output.

During a deployment, one instance uploads its log to Amazon Simple Storage Service (Amazon S3) as the deployment progresses. The Elastic Beanstalk console reads from Amazon S3, which means you can monitor progress in real time without connecting to the instance. After the deployment completes, the console fetches the final log to ensure you see the complete output. For environments with multiple instances, the deployment log is captured from one representative instance. To view logs from all instances, use the Request Logs feature.

Prerequisites

Before getting started, ensure that you have the following:

  • An AWS account with permissions to create Elastic Beanstalk environments and associated resources (Amazon Elastic Compute Cloud (Amazon EC2) instances, Amazon S3 buckets, security groups). For the minimum AWS Identity and Access Management (IAM) permissions required, see Managing Elastic Beanstalk service roles. Follow the principle of least privilege and avoid using AWS account root or unrestricted administrator credentials.
  • The default Elastic Beanstalk instance profile, aws-elasticbeanstalk-ec2-role. New AWS accounts may not have this role created automatically. If your environment fails to launch because the role is missing, see Instance profile for Amazon EC2 instances in your Elastic Beanstalk environment.
  • A supported Elastic Beanstalk platform version. Deployment logs are available on Amazon Linux 2 and Amazon Linux 2023 platform versions released on or after March 11, 2026, and on Windows Server platform versions 2.23.0 and later.
  • AWS Command Line Interface (AWS CLI) installed and configured with appropriate permissions. See Installing the AWS CLI.
  • A Bash-compatible shell (Bash or Zsh). The commands in this walkthrough use Bash syntax (heredocs, &&, and shell variables).

Walkthrough

Follow the steps below to create an environment, explore the Deployments tab, deploy a broken application, and then fix it.

Open your terminal and set the following variables. Replace the values with your own unique Amazon S3 bucket name and the latest Node.js solution stack for your Region. This walkthrough uses us-east-1. You can substitute your preferred Region, but use the same Region consistently across all commands in the walkthrough. To find the latest solution stack, run aws elasticbeanstalk list-available-solution-stacks.

S3_BUCKET="your-unique-bucket-name"

# Replace with the latest Node.js solution stack for your Region
SOLUTION_STACK_NAME="64bit Amazon Linux 2023 v6.11.1 running Node.js 22"

Setting up the application

This walkthrough uses two versions of a Node.js application. The first version is a working HTTP server. The second version introduces a dependency on a non-existent npm package, simulating a common deployment failure where a dependency cannot be installed.

Create a project directory:

mkdir deployments-tab-demo && cd deployments-tab-demo

Create the working application file:

cat << 'EOF' > workingapp.js
const http = require('http');

const server = http.createServer((req, res) => {
  res.writeHead(200, { 'Content-Type': 'application/json' });
  res.end(JSON.stringify({ status: 'healthy', message: 'App is running' }));
});

const port = process.env.PORT || 8080;
server.listen(port, () => {
  console.log(`Server running on port ${port}`);
});
EOF

Create the working package.json:

cat << 'EOF' > working-package.json
{
  "name": "deployments-tab-demo",
  "version": "1.0.0",
  "description": "Sample app for Deployments tab walkthrough",
  "main": "app.js",
  "scripts": {
    "start": "node app.js"
  }
}
EOF

Create the broken package.json with a non-existent dependency:

cat << 'EOF' > broken-package.json
{
  "name": "deployments-tab-demo",
  "version": "2.0.0",
  "description": "Sample app for Deployments tab walkthrough",
  "main": "app.js",
  "scripts": {
    "start": "node app.js"
  },
  "dependencies": {
    "this-package-does-not-exist-abc123": "^1.0.0"
  }
}
EOF

Create the working application source bundle:

cp workingapp.js app.js
cp working-package.json package.json
zip -r nodejs-working-app.zip app.js package.json

Create the broken application source bundle:

cp broken-package.json package.json
zip -r nodejs-broken-app.zip app.js package.json

Step 1: Create an environment and explore the Deployments tab

Create an Amazon S3 bucket and upload the source bundles. This walkthrough uses default bucket settings for simplicity. For production workloads, enable server-side encryption and restrict bucket access to only the principals that need it.

aws s3 mb s3://$S3_BUCKET --region us-east-1

aws s3 cp nodejs-working-app.zip s3://$S3_BUCKET/nodejs-working-app.zip
aws s3 cp nodejs-broken-app.zip s3://$S3_BUCKET/nodejs-broken-app.zip

Create the Elastic Beanstalk application and the working version:

aws elasticbeanstalk create-application \
--application-name deployments-tab-demo \
--description "Deployments tab walkthrough" \
--region us-east-1

aws elasticbeanstalk create-application-version \
--application-name deployments-tab-demo \
--version-label v1-working \
--source-bundle S3Bucket="$S3_BUCKET",S3Key="nodejs-working-app.zip" \
--region us-east-1

Create the environment:

aws elasticbeanstalk create-environment \
--application-name deployments-tab-demo \
--environment-name deployments-tab-demo-env \
--solution-stack-name "$SOLUTION_STACK_NAME" \
--version-label v1-working \
--option-settings \
Namespace=aws:elasticbeanstalk:environment,OptionName=EnvironmentType,Value=SingleInstance \
Namespace=aws:autoscaling:launchconfiguration,OptionName=IamInstanceProfile,Value=aws-elasticbeanstalk-ec2-role \
--region us-east-1

Don’t wait for the environment to finish creating. Instead, open the Elastic Beanstalk console right away, navigate to your environment, and choose the Deployments tab.

You should see one deployment in the history table with a status of In Progress and a type of Environment Creation. The table also shows the request ID, start time, and duration (which updates as the deployment runs). Choose the Request ID link to open the deployment detail page.

Elastic Beanstalk environment overview page showing the new Deployments tab selected, with a Deployment history table listing one in-progress Environment Creation deployment.

Figure 1 – Deployments tab history table showing the in-progress Environment Creation deployment

The detail page has a summary section with the deployment metadata and two tabs below it:

  • Events shows a filtered timeline of events for this deployment. As the environment creation progresses, new events appear automatically.
  • Deployment Logs shows the consolidated deployment log from the instance.

Select the Deployment Logs tab. At first, the tab may show a message indicating that the log is not yet available. This is expected. The deployment log is written on the EC2 instance and uploaded to Amazon S3, so it won’t appear until the instance launches and begins the deployment process. Once the instance is running, log entries start appearing and the tab refreshes automatically to show new entries as they are written. You can watch dependency installation, platform hooks, and application startup happen in real time.

Deployment details page showing a Deployment summary card (Request ID, Status: In progress, Type: Environment Creation) with the Deployment Logs tab selected and a "Waiting for logs..." placeholder.

Figure 2 – Deployment Logs tab showing “log not yet available” message during early environment creation

After the environment creation completes, the deployment status changes to Succeeded and the log shows the final state. Because this deployment succeeded, the log contains only summary messages for each step. Take notice of how the log captures each phase of the deployment in order: .ebextensions commands, dependency installation (npm), container commands, and then the application startup. Pay attention to the Application Output section near the end of the log. It shows the initial stdout from your application process, confirming that it started and is listening on the expected port. This section is useful for verifying that your application launched correctly after a deployment.

You can also check the environment status from the CLI:

aws elasticbeanstalk describe-environments \
--environment-names deployments-tab-demo-env \
--query 'Environments[0].{Status:Status,Health:Health}' \
--region us-east-1
Successful deployment details page with green "Environment successfully launched" banner, Deployment summary showing Status: Succeeded, and the Deployment Logs tab displaying streamed eb-engine and eb-hooks log entries.

Figure 3 – Deployment detail page showing the completed Deployment Logs tab with successful log output

Step 2: Trigger a configuration update

To see how different deployment types appear in the Deployments tab, add an environment variable to your environment:

aws elasticbeanstalk update-environment \
--environment-name deployments-tab-demo-env \
--option-settings \
Namespace=aws:elasticbeanstalk:application:environment,OptionName=APP_ENV,Value=production \
--region us-east-1

While the update is in progress, go back to the Deployments tab in the console. You should see a second deployment appear in the history with a status of In Progress and a type of Environment Update. Choose the request ID to open the detail page, and select the Deployment Logs tab. The log updates automatically as new entries are written, so you can watch the deployment progress in real time.

After the update completes, the deployment status changes to Succeeded. You now have two deployments in your history, each with its own type and duration.

Elastic Beanstalk environment page after a successful configuration update, showing Health: Ok and a Deployment history table with two Succeeded entries: a Configuration Update and an Environment Creation.

Figure 4 – Deployments tab showing two deployments: Environment Creation and Environment Update

Step 3: Deploy a broken application

This is where the Deployments tab shows its value. Create and deploy a broken application version that references a non-existent npm package:

aws elasticbeanstalk create-application-version \
--application-name deployments-tab-demo \
--version-label v2-broken \
--source-bundle S3Bucket="$S3_BUCKET",S3Key="nodejs-broken-app.zip" \
--region us-east-1

aws elasticbeanstalk update-environment \
--environment-name deployments-tab-demo-env \
--version-label v2-broken \
--region us-east-1

As soon as the deployment starts, go back to the Deployments tab in the console. You should see a new Application Deployment with a status of In Progress. Choose the request ID to open the deployment detail page and select the Deployment Logs tab.

Watch as the log streams in real time. You will see the deployment start, .ebextensions commands run, and then npm install begin. Shortly after, the error appears with the relevant output from the failed step, showing the exact npm error indicating that the package could not be found. The deployment status changes to Failed.

Elastic Beanstalk automatically rolls back to the previous working version, so your environment returns to a healthy state. Without the Deployments tab, diagnosing what went wrong would still require requesting a log bundle, downloading it, extracting it, and searching through the log files. With the Deployments tab, the diagnosis is immediate. There is no need to connect to the instance via SSH or download log bundles. The error is right there in the console.

Deployment details page for a failed Application Deployment, showing Status: Failed in the summary and Deployment Logs containing yum package errors ("No package eb-noti-abc123-1.0.0 available").

Figure 5 – Deployment detail page showing the failed deployment error and npm install output

Compare this to the successful deployment logs from Step 1. The successful log showed only summary messages. The failed log automatically includes the detailed error output. This smart verbosity means you don’t have to search through verbose logs on success, but you get the detail you need on failure.

Step 4: Deploy a fixed version

Although Elastic Beanstalk rolled back to the working version automatically, let’s deploy it explicitly to see what a successful application deployment log looks like after a failure:

aws elasticbeanstalk update-environment \
--environment-name deployments-tab-demo-env \
--version-label v1-working \
--region us-east-1

After the deployment completes, open the deployment detail page from the Deployments tab. The deployment log shows only summary messages for each step. The npm step completes without errors, the application starts, and the deployment finishes. Compare this to the failed deployment log from Step 3, where the error and detailed npm output appeared automatically.

Elastic Beanstalk environment Deployments tab showing a Deployment history of four entries — two Application Deployments (one Succeeded, one Failed), one Configuration Update, and one Environment Creation.

Figure 6 – Deployments tab showing all four deployments with their statuses

Cleaning up

To avoid ongoing charges, terminate the environment and delete the associated resources.

Terminate the environment:

aws elasticbeanstalk terminate-environment \
--environment-name deployments-tab-demo-env \
--region us-east-1

Delete the application (after the environment is terminated):

aws elasticbeanstalk delete-application \
--application-name deployments-tab-demo \
--terminate-env-by-force \
--region us-east-1

Delete the S3 bucket used for source bundles:

aws s3 rb s3://$S3_BUCKET --force --region us-east-1

Remove the local project directory. Before running the following command, make sure your current working directory is not inside deployments-tab-demo:

rm -rf deployments-tab-demo

Conclusion

The Deployments tab in AWS Elastic Beanstalk gives you a single place to view your deployment history and read deployment logs, including while a deployment is still running. When a deployment fails, the log shows you the error output from the failed step directly in the console, so you can identify the root cause without connecting to instances over SSH or downloading log bundles.

Deployment logs are available on Amazon Linux 2 and Amazon Linux 2023 platform versions released on or after March 11, 2026, and on Windows Server platform versions 2.23.0 and later, in all AWS Commercial Regions and AWS GovCloud (US) Regions. To get started, update your environment to a supported platform version and navigate to the Deployments tab in the Elastic Beanstalk console.

To learn more about deployment logs, see Viewing deployment logs in the AWS Elastic Beanstalk Developer Guide. For more information about AWS Elastic Beanstalk, visit the product page.

Ben Lazar

Ben Lazar is a Software Development Engineer II at Amazon Web Services (AWS) on the Elastic Beanstalk team. He maintains the Elastic Beanstalk platforms that customers use to run their web applications.

How AWS DevOps Agent uses multi-agent reasoning to find root causes

Post Syndicated from Harish Mandhadi original https://aws.amazon.com/blogs/devops/how-aws-devops-agent-uses-multi-agent-reasoning-to-find-root-causes/

Confirmation bias is one of the most common reasons incident investigations take longer than they should. An on-call engineer gets alerted, forms a theory based on initial triage and experience, finds one piece of supporting evidence, and stops looking. The actual root cause — buried in a different service, a different signal, a different time window — goes undiscovered for longer than it should.

Modern distributed systems don’t lack telemetry. They lack reasoning — the ability to generate multiple explanations simultaneously, actively challenge each one, and converge on the true cause only when the evidence conclusively supports it.

AWS DevOps Agent, an autonomous agent, solves this with a multi-agent architecture that decomposes incident operations into specialized capabilities — each optimized for a different operational priority. But investigating an incident effectively requires starting with broader architectural context — which resources exist, how they relate to each other, and how they change with every deployment. That architectural understanding is what makes the difference between an agent that searches blindly through telemetry and one that reasons about your system.

In this post, we go inside the investigation lifecycle to explain how AWS DevOps Agent reasons through complex incidents — from the topology foundation that gives it architectural awareness, through autonomous triage and deep multi-hypothesis investigation, to the learning loop that prevents future incidents. Understanding how these capabilities connect is what turns the AWS DevOps Agent from a black box into a trusted member of your on-call rotation.

The Incident Lifecycle

AWS DevOps Agent organizes incident response into multiple capabilities that mirror how the best SRE teams operate — each purpose-built for a different operational priority, all sharing a common architectural foundation.

ncident lifecycle with stages: Triage, Investigation, Mitigation, and Learning, connected by an Application Topology Graph and Investigation Journal
The topology graph provides the architectural foundation. The Topology Graph feeds context across the lifecycle and the Investigation Journal runs as a continuous audit trail beneath it. Each capability above it is purpose-built for a different operational priority.

    • Triage — Correlates incoming signals with related alerts and enriches investigations with correlation context. Optimized for speed.
    • Investigation — Deep multi-phase root cause analysis with parallel hypothesis generation and counter-evidence validation. The core reasoning engine.
    • Mitigation — Generates immediate remediation actions based on the root cause identified by Investigation.
    • Prevention — Analyzes patterns across historical incidents to prevent future occurrences.

All capabilities share a critical dependency: the application topology graph. Before we follow an incident through the lifecycle, let’s look at how that foundation is built.

Topology: The foundation everything depends on

Before the agent can investigate an incident, it needs to understand your architecture — not just a static inventory of resources, but a living map of how they relate, how they communicate at runtime, and how they connect back to the code that deploys them.

Topology engine showing four discovery sources feeding a Knowledge Graph, which powers a learned topology created by the understanding-your-agentspace skill
The topology engine builds this understanding through complementary discovery approaches: AWS CloudFormation stack analysis (including AWS CDK since it synthesizes to AWS CloudFormation), tag-based discovery through AWS Resource Explorer, behavioral mapping through CloudWatch Application Signals and third-party platforms like Dynatrace, Datadog etc. that reveals runtime communication patterns, and CI/CD pipeline integration like GitHub Actions, GitLab CI/CD that links resources back to deployment processes and specific code changes.

The result is a learned topology — built and continuously refined by the understanding-your-agentspace skill — that captures static infrastructure relationships, runtime communication patterns, and deployment lineage. When Investigation needs to trace a failure through dependencies, it follows the graph’s edges. When Mitigation needs to assess the impact radius of a proposed fix, it checks the graph’s relationship map. Without this foundation, the agent would be searching blindly through telemetry. With it, the agent reasons about your system with architectural context – following dependencies, checking blast radius, and correlating with recent changes.

All of this operates within an Agent Space — a logical container scoped to a team, service, or application. Each Agent Space maintains its own topology graph, investigation history, and integrations in full isolation from other spaces.

With the architectural foundation in place, let’s follow an incident through the lifecycle.

Triage: Fast classification and correlation

When an incident arrives — whether from CloudWatch Alarms, third-party tools like ServiceNow, PagerDuty, or Grafana, or through manual initiation — Triage activates first.

Triage receiving signals from different sources and correlating them to enrich investigations with context.Triage is optimized for speed — high volume, short duration. It correlates incoming signals with related alerts and enriches investigations with correlation context.

A key part of Triage is correlation: the agent automatically correlates related alarms to identify when they originate from the same event. This accelerates incident response by immediately understanding which alarms are related and which require separate investigation — reducing noise and enabling teams to focus on the most critical issues first. In a complex distributed system, a single root cause can generate alerts across different services and monitoring tools; without correlation, each alert would spawn its own investigation, fragmenting the response team’s attention. With it, the agent funnels related evidence into a single, comprehensive investigation.

Correlation isn’t a one-way door. If the agent links alerts that an operator believes are unrelated, the operator can unlink them and spawn a separate investigation. The agent makes the initial correlation decision at machine speed; the human retains full control to override it.

Once Triage has correlated the incoming signals and enriched the investigation with context, the Investigation capability begins its deep analysis.

Investigation: The Reasoning Engine

Investigation is the centerpiece — where AWS DevOps Agent’s architecture diverges from conventional AI-assisted troubleshooting. It follows a structured methodology that mirrors how experienced DevOps engineers work: acquire context about what’s affected and what changed, collect evidence across every connected data source, generate multiple competing hypotheses simultaneously, subject each to both supporting and counter-evidence validation, and converge on root cause only when the evidence demands it. Operators can steer the investigation at any point through natural language, with the journal recording how those inputs influenced the agent’s reasoning.

Context Acquisition and Data Collection

Every investigation starts with two questions: what’s affected and what changed recently?

The agent parses the incoming signal to understand scope — which resources show symptoms, what time window matters, and what the operator already knows. It then walks the topology graph outward from those resources, mapping the blast radius: direct dependencies, upstream producers, downstream consumers. It pulls recent deployment activity from connected CI/CD pipelines and checks whether the current pattern resembles anything it has investigated before.

With that situational map in hand, the agent casts a wide evidence net. It pulls time-series metrics alongside a healthy baseline so it can spot deviations, not just absolute values. It queries log streams across connected observability platforms — CloudWatch, Splunk, Datadog — filtered to the relevant resources and error signatures. It collects distributed traces showing how requests flowed through affected paths. It also captures configuration state and assembles a chronological timeline of deployments, config changes, scaling events, and alarm triggers.

Triage Agent correlating triggers with past incident history to enrich the Investigation phase, which draws on additional historical context.

Hypothesis Generation

With evidence collected, the agent generates multiple competing root-cause theories simultaneously — each one a different lens on the same data.

Some hypotheses come from pattern matching: the symptoms resemble a known failure signature from previous investigations. Others emerge from anomaly detection: a metric that was stable for weeks just deviated sharply from its baseline. The agent also checks temporal correlation with recent deployments, evaluates whether upstream or downstream services are showing their own problems, and looks at resource constraints — connection pools, CPU headroom, quota limits — that could explain degradation under load.

The investigation methodology: Context Gathering, Hypothesis Generation, and Root Cause Determination with Journal and  Interactive Steering.The agent pursues multiple hypotheses simultaneously, validating each with both supporting evidence and counter-evidence before surfacing them to operators. As the agent builds the causal chain, it classifies validated hypotheses as either a ’cause’ or ‘root cause’ based on their connection to the incident, and labels unconnected findings as hypothesis.

Evidence Gathering and Root Cause Determination

The agent validates multiple hypotheses simultaneously, testing each against both supporting and counter-evidence before surfacing them to operators.

Here’s what that looks like in practice. An e-commerce platform’s checkout service — the critical path between a customer clicking “Place Order” and payment processing — starts showing latency spikes during peak traffic. Orders are timing out, and the on-call team is getting paged.

The agent generates three hypotheses: a config change was pushed 20 minutes before onset, the payment gateway is returning slow responses, and the database connection pool is nearing capacity. All three are plausible — an engineer under pressure might pick whichever one they check first and run with it. The agent checks all three simultaneously. It examines the config change and finds it only affected logging verbosity — it couldn’t have impacted request latency. Theory eliminated. It confirms the payment gateway is indeed slow, but digs deeper and discovers that slowness started after the checkout latency began — the gateway is a symptom, not the cause. Theory eliminated. The connection pool, at 94% capacity, correlates with the exact onset time — and nothing contradicts it. That’s the root cause.

The agent then synthesizes evidence across remaining hypotheses — distinguishing correlation from causation, identifying primary and contributing causes, and flagging ambiguity when evidence isn’t conclusive.

With root cause established, the investigation’s final output is a structured mitigation plan — and this is where the agent’s safety-first design becomes critical.

Mitigation: Safe by default

The mitigation plan follows a deliberate structure: remediation strategy, step-by-step procedures, validation checks to verify system state before applying changes, success criteria to assess whether the fix worked, and rollback procedures to reverse it if something goes wrong.

AWS DevOps Agent generates mitigation plans but does not execute remediation actions on the operator’s behalf — the agent’s write capabilities are restricted to ticket and support case creation. The plans themselves can recommend write actions including specific commands, configuration changes, or code modifications, but execution remains with the operator. Every plan includes rollback procedures to reverse the mitigation if it introduces new problems. The agent uses topology awareness to assess the blast radius before recommending any change — the same graph that helped trace the root cause now helps understand the impact of the proposed fix.

This is a deliberate design choice. In production incident response, the most dangerous moment isn’t when you’re investigating — it’s when you’re applying a fix under pressure. By separating the recommendation from the execution, the agent helps ensure that a human reviews the plan, validates the rollback procedure, and makes the conscious decision to proceed.

Prevention: From reactive to proactive

The most valuable pattern the agent finds isn’t in any single incident — it’s across incidents. The Prevention capability clusters past incidents by shared root causes, even when their surface symptoms looked completely different. A latency spike in your API, a timeout in your batch processor, and an error rate in your notification service might all trace back to the same database scaling issue — but without pattern analysis, they appear as three unrelated incidents.

Prevention feedback loop flowing from Past Incidents through Pattern Analysis and Recommendations to Operator Feedback, which loops back to refine future recommendations
These patterns produce targeted recommendations across observability enhancements like monitoring gaps, alert tuning, and tracing coverage; testing and validation improvements like deployment validation and chaos engineering practices; code resilience patterns like retry logic, circuit breakers, and error handling; infrastructure optimization like capacity planning, autoscaling, and right-sizing; and governance guardrails like pipeline bake time suggestions, test validation gates, and pipeline integration tests.

Recommendations aren’t static. Operators accept them into their backlog or reject them with natural language feedback that refines future suggestions. Recommendations persist until operators explicitly act on them, keeping teams in control of their backlog.

Investigation can help reduce mean time to resolution. Prevention can help reduce incident count. Over time, fewer incidents compound into significant engineering hours saved — and the agent’s recommendations become more targeted with every cycle. The more it investigates, the more it prevents. The more it prevents, the fewer incidents your team faces.

Conclusion

AWS DevOps Agent connects these capabilities into an operational flywheel. The topology graph gives every stage architectural awareness — Investigation follows it to trace failures, and Mitigation checks it to assess blast radius. Investigation findings flow into Prevention, which clusters them to find patterns that individual incidents can’t reveal. Prevention recommendations improve the environment, which changes what the next investigation encounters — each cycle can make the system stronger and the next incident faster to resolve.

If you’ve been on call, you know the pressure — it’s late in the night, you’re switching between dashboards, notifications are flooding in, and you’re weighing whether the fix you’re about to apply could make things worse. AWS DevOps Agent is built to help in that moment — competing theories have already been tested against counter-evidence, the reasoning is documented in an immutable journal, and the mitigation plan includes rollback procedures.

The topology graph, investigation history, and prevention recommendations persist across team changes. Operational context that once lived only in an engineer’s head now lives in the system — available to whoever is on call next.

We’d love to hear how you approach incident investigation — what’s worked, what hasn’t, and what you’d want an AI agent to handle. Share your thoughts in the comments below.

Create your first Agent Space within AWS DevOps Agent in the AWS Management Console and start your first investigation.

Harish Mandhadi

Harish Mandhadi is a Sr Technical Account Manager at AWS, where he provides strategic technical guidance to retail industry customers with a focus on resilience and agentic AI domains. Outside of work, Harish enjoys spending time outdoors doing activities like motorcycle riding, crossfit and spending time with his family.

Modernizing Excel VBA to Python at Scale with AWS Transform custom

Post Syndicated from Somnath Chatterjee original https://aws.amazon.com/blogs/devops/modernizing-excel-vba-to-python-at-scale-with-aws-transform-custom/

Learn how AWS Transform custom can help migrate Excel VBA applications to modern Python code while overcoming context window limitations, preserving functional equivalence, and enabling cloud-native deployment—turning weeks of manual rewriting into hours of AI-guided transformation.

Introduction

Many organizations maintain dozens of Excel VBA applications built over decades, containing business-critical logic trapped in workbooks—budget planning tools, demand planning, inventory management, financial modeling, and engineering calculations. Manual migration typically costs thousands of dollars per workbook and takes weeks, while traditional AI tools fail on large codebases that exceed context windows.

This post demonstrates how you can migrate VBA to Python using AWS Transform custom, addressing three key challenges: processing large codebases through intelligent chunking, converting legacy code to maintainable Python while preserving functionality, and validating equivalence through automated testing. You can reuse the transformation across similar projects or apply it to entire portfolios.

With AWS Transform custom, you can accelerate migration timelines, eliminate transcription errors, and scale from single applications to enterprise portfolios.

Solution Overview

The following diagram illustrates how AWS Transform custom migrates VBA source code to Python output through a four-step process powered by an AI agentic system.

Architecture diagram showing how AWS Transform custom migrates VBA source code to Python output through a four-step process powered by an AI agentic system

Figure1:AWS Transform custom VBA to Python migration architecture

AWS Transform custom provides an interactive workflow where you describe your migration requirements. The system interprets your intent and iteratively refines the transformation definition until it meets your specifications. As the system processes your code, it improves the quality of each subsequent run. Once you finalize a transformation, you can publish it to a registry so your team can reuse it across multiple projects without starting from scratch.

Migration Approach

The migration follows a three-phase process that takes you from defining your transformation through execution and validation and finally scaling across your portfolio.

In the first phase, transformation definition creation, you start an interactive session with AWS Transform custom to describe your migration requirements. You can reference your VBA code, API documentation, and target framework guides as context. The system uses these inputs to automatically generate transformation rules and patterns, which you can iteratively refine through build validation until the definition accurately captures your migration logic.

In the second phase, execution and validation, AWS Transform custom applies the transformation to your codebase. It intelligently chunks large codebases into logical modules and processes them in dependency-aware order, so cross-module references remain intact. Throughout execution, the system continuously validates builds and tests, automatically detecting and correcting errors as they arise.

In the third phase, scale and reuse, you publish your finalized transformation to the registry, making it available for your team to apply across similar projects. You can run campaign-based bulk executions across multiple repositories, extract knowledge items for continuous improvement, and integrate the transformation into your CI/CD pipelines.

Key capabilities

AWS Transform custom addresses the core challenges you face when migrating large VBA codebases to Python.

For context window management, the system automatically segments your codebase into logical modules, tracks cross-module dependencies, preserves interface contracts across chunks, and maintains state throughout the transformation. This means you can process codebases that far exceed standard AI context window limits without losing coherence between modules.

For intelligent code restructuring, AWS Transform custom recognizes VBA idioms and maps them to Python equivalents. It refactors procedural code into object-oriented designs, replaces Windows-specific APIs with cross-platform libraries, and applies proper encapsulation and separation of concerns. The result is a clean, maintainable Python that follows modern coding standards.

For functional equivalence preservation, the system generates automated tests based on the original VBA behavior and runs regression testing after each transformation step. It benchmarks performance metrics such as timing and resource usage and validates edge cases to confirm that your transformed Python code produces the same results as the original VBA application.

Prerequisites

Before you begin, you need an AWS account with the appropriate permissions to use AWS Transform custom. Start by configuring authentication and setting up the AWS CLI for your environment.

To create an IAM user for AWS Transform, follow the step-by-step instructions for creating an IAM user and managing IAM policies in the IAM User Guide.

Setup using AWS CLI:

# Create policy
cat > transform-policy.json << 'EOF'
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": ["transform-custom:*"],
      "Resource": "*"
    }
  ]
}
EOF

aws iam create-policy \
  --policy-name AWSTransformCustomPolicy \
  --policy-document file://transform-policy.json

# Attach to your IAM user (replace with your username and account ID)
aws iam attach-user-policy \
  --user-name YOUR_USERNAME \
  --policy-arn arn:aws:iam::YOUR_ACCOUNT_ID:policy/AWSTransformCustomPolicy

Local Environment Setup

  • Operating System: Linux, macOS, or WSL (Windows Subsystem for Linux)
  • Node.js: Version 20 or higher (required for AWS Transform CLI installation via npm)
  • Git: Required for all target repositories
  • Internet Access: Required for AWS Transform service communication

AWS Transform CLI Installation

Follow the official AWS Transform Custom Getting Started Guide for complete installation and setup instructions, including:

  • Platform requirements (Linux, macOS, or WSL)
  • Installation script usage
  • Authentication configuration
  • Network requirements and firewall rules

Source Code Repository

  • VBA application source code (Excel workbook with macros or exported .bas files)
  • Git repository initialized in source directory
  • Build/test commands defined (if applicable)

Target Environment Setup (for Python migration)

  • Python 3.8 or higher installed
  • Virtual environment tool (venv or virtualenv)
  • Target framework dependencies (e.g., pygame for game applications, tkinter/PyQt6 for GUI, pandas for data processing, openpyxl for spreadsheet operations)

Walkthrough: VBA to Python Migration

Animated demonstration of the VBA to Python migration workflow using AWS Transform custom

Figure2:AWS Transform custom CLI executing a VBA to Python transformation

Step 1: Prepare Your VBA Application

Initialize Git Repository

AWS Transform Custom requires your code to be in a Git repository. If your code isn’t already in Git:

cd your-vba-project
git init
git add .
git commit -m "Initial VBA code"

Step 2: Create Transformation Definition

Start AWS Transform Interactive Session

Provide Migration Context

Screenshot showing the AWS Transform custom interactive session interface for providing migration context

Figure3:AWS Transform custom interactive session with migration context

When you start the interactive session, provide a natural language description of your migration goal, such as “Migrate VBA application to Python.” Specify the target framework you want to use, for example, pygame for GUI applications or pandas for data processing. You should also include document references to give the system the context it needs — this includes your VBA code files, Python framework documentation, and any API migration guides relevant to your project.

Example conversation:

User: I want to migrate a VBA application to Python.
AWS Transform: I’ll help you create a transformation definition. Let me analyze the VBA patterns and generate Python equivalents…

Define Scope and Entry Criteria

Before creating your transformation, review your existing codebase to understand its structure, patterns, and dependencies. Identify the code type and technology stack you are working with, such as an Excel VBA game that uses Windows API calls. Check the transformation registry for existing similar transformations to avoid duplicating work. From there, define a clear objective and scope for your transformation, and document the entry criteria that determine what code qualifies. Outline detailed implementation steps with specific technical mappings, establish validation and exit criteria for measuring success, and name your transformation appropriately so your team can discover and reuse it.

Iterative Refinement

After you provide your migration context, AWS Transform custom generates an initial transformation definition.You can review this definition at: ~/.aws/atx/custom/<session-id>/artifacts/tp-staging/transformation_definition.md.

Examine the generated rules and provide feedback on patterns, edge cases, or missing scenarios. AWS Transform custom incorporates your feedback and regenerates the definition, allowing you to iterate until the transformation accurately captures your migration logic.

Key Patterns to Address

During the transformation definition process, you should account for the common patterns that differ between VBA and Python. AWS Transform custom maps VBA ColorIndex values to standard RGB tuples and converts Range objects to Python data structures such as lists and arrays. Do While loops in VBA translate to event-driven loops in Python. The transformation replaces Windows API calls with cross-platform libraries that provide portable alternatives. VBA UserForms map to Python GUI frameworks like tkinter or PyQt6, where form controls become Python widgets. VBA Property Get/Let constructs convert to Python @property and @setter decorators. Finally, VBA’s 1-based array indexing must be adjusted to Python’s 0-based indexing throughout your codebase.

Step 3: Execute Transformation

Apply Transformation to Codebase

# Execute transformation interactively
atx custom def exec \
  --transformation-name "VBA-to-Python-Migration" \
  --code-repository-path "./your-vba-project" \
  --build-command "python3 -m py_compile **/*.py"

# Execute transformation non-interactively
atx custom def exec \
  --transformation-name "VBA-to-Python-Migration" \
  --code-repository-path "./your-vba-project" \
  --build-command "python3 -m py_compile **/*.py" \
  --trust-all-tools \
  --non-interactive

What Happens During Execution

When you run the transformation, AWS Transform custom begins with agent planning. It analyzes your codebase structure, identifies all VBA components and their dependencies, and generates a step-by-step transformation plan with logical ordering — for example, data models first, then business logic, then UI. Each step in the plan has a clear scope and validation criteria.

Next, the system performs automatic code chunking. It analyzes your codebase size and complexity, then segments the code into logical modules such as constants, game logic, rendering, and controller. These chunks are processed in dependency order based on the plan, and the system manages the context window by focusing on one module at a time.

Throughout execution, AWS Transform custom tracks dependencies by mapping relationships between VBA subroutines, verifying that dependent code references remain valid, and maintaining interface contracts across modules.

The transformation proceeds incrementally, converting one module at a time. After each module is transformed, the system validates the build. If a failure occurs, it automatically rolls back and retries the transformation for that module before moving on.

Sample Output:

Analyzing codebase structure...
Identified 4 logical modules: constants, core_logic, rendering, main_controller
Transforming module 1/4: constants
 - Converting VBA Enums to Python IntEnum
 - Mapping ColorIndex values to RGB tuples
 - Generating color constants
 ✓ Build validation passed
Transforming module 2/4: core_logic
 - Converting collision detection subroutines
 - Refactoring global variables to class attributes
 - Translating VBA arrays to Python lists
 ✓ Build validation passed
Transforming module 3/4: rendering
 - Replacing Range object manipulation with pygame rendering
 - Converting cell-based drawing to pixel-based graphics
 - Implementing screen update logic
 ✓ Build validation passed
Transforming module 4/4: main_controller
 - Converting Do While loop to pygame event loop
 - Replacing GetAsyncKeyState with pygame.event.get()
 - Implementing game state management
 ✓ Build validation passed
Transformation complete! Generated 5 Python modules.

Review Transformed Code

After the transformation completes, check the generated Python files to verify the output. You can review the transformation logs at ~/.aws/atx/custom/<conversation-id>/logs/ to understand the decisions the system made during each step. Examine the build validation results to confirm that the transformed code compiles and passes all checks.

Step 4: Validate Functional Equivalence

Automated Test Generation

AWS Transform generates validation tests based on original VBA behavior:

test_validation.py – Verifies core logic:

# Example generated test (conceptual)
def test_collision_detection():
 """Verify collision logic matches VBA behavior"""
 # Test cases extracted from VBA code analysis

def test_scoring_calculation():
 """Ensure scoring algorithm is preserved"""

def test_state_transitions():
 """Validate game state changes"""

test_performance.py – Benchmarks non-functional requirements:

def test_frame_rate():
 """Verify rendering meets 60 FPS target"""

def test_response_time():
 """Ensure input handling latency matches VBA"""

Run Validation Suite

# Execute all tests
python3 -m pytest tests/

# Run with coverage
python3 -m pytest --cov=. tests/

Manual Validation Checklist

  • Application launches without errors
  • UI renders correctly (layout, colors, sizing)
  • User interactions work as expected (keyboard, mouse)
  • Core functionality produces correct results
  • Performance meets requirements (no lag, smooth rendering)
  • Edge cases handled properly (boundary conditions, invalid inputs)

Step 5: Refine and Iterate

As you refine your transformation, you may encounter a few common issues. Here is how you can address them and provide feedback to AWS Transform custom.

Timing and performance differences can occur when the Python application runs faster or slower than the VBA original. To fix this, adjust timing constants and frame rate limiters. For example, if you notice the game runs too fast because VBA used Sleep(500) for piece drops, you can provide that feedback. AWS Transform custom corrects this by replacing time.sleep() with pygame.time.Clock.tick(60).

Color rendering mismatches happen when colors in the Python output don’t match the VBA version. This is typically caused by incorrect RGB mappings for VBA ColorIndex values. If you notice that ColorIndex 3 should be pure red (255,0,0) but is showing as dark red, provide that feedback. AWS Transform custom updates the COLOR_MAP dictionary with accurate RGB values.

Collision detection bugs may appear when pieces move through walls or other pieces. This requires refining boundary checking and collision logic. For instance, if rotation near walls allows pieces to go out of bounds, you can report this issue. AWS Transform custom adds boundary validation before rotation commits to resolve it.

Continual learning in action

Each time you provide a correction, AWS Transform custom captures it as a knowledge item. Future transformations automatically incorporate these fixes, so the same issues don’t recur. With each execution, the system improves quality for similar migrations across your portfolio.

Step 6: Publish and Scale

Save Transformation as Draft (for testing)

atx custom def save-draft \
  --name "VBA-to-Python-Migration" \
  --source-directory "~/.aws/atx/custom/<session-id>/artifacts/tp-staging"

Publish to Registry (for team-wide use)

atx custom def publish \
  --name "VBA-to-Python-Migration" \
  --description "Migrate Excel VBA applications to Python with pygame rendering" \
  --source-directory "~/.aws/atx/custom/<session-id>/artifacts/tp-staging"

Apply to Multiple Projects

# Apply to each project individually
atx custom def exec -n "VBA-to-Python-Migration" -p ./project1 -c "python3 -m py_compile **/*.py" --trust-all-tools --non-interactive
atx custom def exec -n "VBA-to-Python-Migration" -p ./project2 -c "python3 -m py_compile **/*.py" --trust-all-tools --non-interactive

CI/CD Integration

# Example GitHub Actions workflow
name: VBA Modernization
on:
  push:
    branches: [main]
jobs:
  transform:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v2
      - name: Run VBA to Python transformation
        run: |
          atx custom def exec \
            --transformation-name "VBA-to-Python-Migration" \
            --code-repository-path "." \
            --build-command "python3 -m py_compile **/*.py" \
            --non-interactive \
            --trust-all-tools

Benefits

By using AWS Transform custom, you can reduce tech debt and accelerate enterprise modernization at scale. The service supports diverse transformation use cases beyond VBA to Python, adapting to the specific needs of your codebase and target platform. With continual learning and improvement, each transformation builds on the corrections and knowledge items from previous runs, delivering higher quality results over time. Once you define a transformation, you can apply it everywhere — across similar projects, teams, and entire application portfolios — without recreating the migration logic from scratch.

Architecture Evolution

Before migration, your legacy VBA application is constrained to a Windows-only execution environment, tightly coupled to the Excel runtime. The code follows a procedural style with a global state, and testing and deployment are manual processes.

After migration with AWS Transform custom, your application follows a modular architecture with clean separation of concerns across constants, logic, rendering, and controller layers. The code uses object-oriented design with proper encapsulation and runs cross-platform on Windows, macOS, and Linux. The transformed application is cloud-ready, with a structure that supports containerization through Dockerfile generation, serverless adaptation with decoupled logic and rendering, and standard Python packaging through requirements.txt and setup.py. It also integrates with modern DevOps workflows, including automated testing with pytest, CI/CD pipeline compatibility, and version control through Git.

You can deploy the transformed application in several ways: containerized with Docker and Kubernetes for scalable web applications, serverless with AWS Lambda for event-driven processing, as a standalone desktop executable with PyInstaller, or as a web application with FastAPI or Flask wrappers for browser access.

The following screenshot shows the transformed Tetris application running as a Python pygame application.

Screenshot of the transformed Tetris application running as a Python pygame application

Figure4:Transformed Tetris game running as a Python pygame application

Transformation definition creation

When creating your transformation definition, provide comprehensive context by including your VBA code, target framework documentation, and migration guides. Focus on documenting application behavior by describing what the application does functionally, not just its code structure. Identify platform-specific dependencies such as Windows APIs, Excel features, and ActiveX controls that require special handling during migration. Define clear success criteria including performance targets, functional requirements, and test coverage expectations. Be explicit about construct mappings in your transformation definition — the more specific you are, the more consistent the output.

Execution strategy

Start with a pilot project by testing your transformation on a smaller, representative application before applying it broadly. Validate incrementally by reviewing each module transformation before proceeding to the next. Capture corrections as feedback by documenting issues and fixes so the system can incorporate them through continual learning. Iterate on edge cases to refine the transformation for corner cases and error conditions that may not surface during initial runs.

Quality assurance

Generate comprehensive automated test suites from the original VBA behavior to verify functional equivalence. Run performance benchmarking to confirm that non-functional requirements match the original application. Conduct manual validation through user acceptance testing to verify UI and UX consistency. After any refinements, run the full test suite for regression prevention to ensure that fixes in one area haven’t introduced issues elsewhere.

Scaling across your portfolio

When you are ready to scale, categorize your applications by similarity — for example, data processing, UI-heavy, or calculation-focused workbooks. Create transformation variants with customized definitions for each category. Use campaigns for bulk execution to process multiple applications in parallel. Monitor and aggregate results across your portfolio to track success rates, identify common issues, and measure time savings.

Cleanup

Archive Conversation Logs

# Conversation logs are in ~/.aws/atx/custom/<conversation-id>/
# Archive for future reference before cleanup
tar -czf vba-migration-logs.tar.gz ~/.aws/atx/custom/<conversation-id>/

Remove Temporary Files

# Remove conversation data and transformation session artifacts (kept for 30 days automatically)
rm -rf ~/.aws/atx/custom/<conversation-id>

# Remove draft transformations (if not needed)
atx custom def delete --name "VBA-to-Python-Migration-Draft"

Manage Published Transformations

# List your transformations
atx custom def list

# Delete transformations no longer needed
atx custom def delete --name "VBA-to-Python-Migration-Old-Version"

# Update transformation tags for organization
atx custom def tag --transformation-name "VBA-to-Python-Migration" \
  --tags "team:platform-engineering,language:python,status:production"

Knowledge Items Management

# List knowledge items for transformation
atx custom def list-ki --transformation-name "VBA-to-Python-Migration"

# Review and approve valuable knowledge items
atx custom def get-ki --transformation-name "VBA-to-Python-Migration" --id <ki-id>

# Enable approved knowledge items
atx custom def update-ki-status \
  --transformation-name "VBA-to-Python-Migration" \
  --id <ki-id> \
  --status ENABLED

# Delete low-quality knowledge items
atx custom def delete-ki --transformation-name "VBA-to-Python-Migration" --id <ki-id>

Conclusion

In this post, you learned how AWS Transform custom can help you migrate Excel VBA applications to Python at scale. With AWS Transform custom, you can reduce weeks of manual migration work to hours. Intelligent chunking handles large codebases that exceed standard AI context window limits, while continuous validation and automated testing preserve functional equivalence throughout the process. Because transformations are reusable, and the system learns from each execution, you gain compound efficiency with every subsequent migration. The transformed applications are cloud-ready, supporting containerization, serverless deployment, and modern DevOps workflows.

AWS Transform custom is a strong fit when you are modernizing a portfolio of dozens or hundreds of similar legacy applications, when functional equivalence must be guaranteed for quality-critical migrations, or when you have repeatable migration patterns across multiple projects.

Next Steps

The transformation demonstrated in this post — VBA to Python migration with context window management, automated restructuring, and functional validation — is a template you can apply to other modernization challenges, such as mainframe COBOL to Java, Progress ABL to Spring Boot, or .NET Framework to .NET Core. The principles remain consistent: intelligent code analysis, dependency-aware processing, continuous validation, and transformation reuse.

Call to Action

Get Started with AWS Transform Custom

Documentation and Resources:

Explore AWS-Managed Transformations: Access pre-built transformations for common migration patterns:

  • AWS SDK Java v1 to v2: AWS/java-aws-sdk-v1-to-v2
  • Python Version Upgrades: AWS/python-version-upgrade
  • Node.js Version Upgrades: AWS/nodejs-version-upgrade
  • Java Version Upgrades: AWS/java-version-upgrade

Estimate Your Migration: Use the AWS Pricing Calculator to estimate costs for your specific modernization project.


Ankit Srivastava

is a Strategic Technical Account Manager at Amazon Web Services (AWS), where he serves as a trusted advisor to global enterprise customers. With over 15 years of experience in cloud architecture, DevOps and distributed systems, Ankit helps organizations navigate cloud transformation, architecture modernization, and harness the power of Generative AI on AWS.

Somnath Chatterjee

is an accomplished Senior Technical Account Manager at Amazon Web Services (AWS), Somnath is dedicated to guiding customers in crafting and implementing their cloud solutions on AWS. He collaborates strategically with customers to help them run cost-optimized and resilient workloads in the cloud. Beyond his primary role, Somnath holds specialization in the compute, SAP and Developer Experience technical field community. With over 14 years of experience in the information technology industry, he excels in cloud architecture and helps customers achieve their desired outcomes on AWS.

Troubleshooting environment with AI analysis in AWS Elastic Beanstalk

Post Syndicated from Chandu Utlapalli original https://aws.amazon.com/blogs/devops/troubleshooting-environment-with-ai-analysis-in-aws-elastic-beanstalk/

Introduction

AWS Elastic Beanstalk simplifies the process of deploying and scaling web applications. You upload your code, and Elastic Beanstalk handles capacity provisioning, load balancing, auto scaling, and application health monitoring.

Elastic Beanstalk now offers AI Analysis to help troubleshoot environment health issues. When you request an analysis, Elastic Beanstalk triggers a script on the Amazon EC2 instance in your environment. The script collects environment events, health data, and instance logs, sends them to Amazon Bedrock for analysis, and uploads the results to Amazon S3. The result is a set of step-by-step troubleshooting recommendations tailored to your environment’s specific issues, helping you reduce mean time to resolution (MTTR).

In the Elastic Beanstalk console, the AI Analysis button appears on the environment overview page when your environment’s health status changes to Warning, Degraded, or Severe. AI analysis is also accessible from the logs page in the console, the AWS CLI, or the EB CLI.

Prerequisites

Before getting started, ensure that you have the following:

  • An AWS account with access to AWS Elastic Beanstalk and Amazon Bedrock.
  • A supported Elastic Beanstalk platform version – AI analysis is available on Amazon Linux 2 and AL2023 based platform versions released on or after February 16, 2026. Update your environment to a supported platform version if needed.
  • Instance profile with required permissions – The managed policies AWSElasticBeanstalkWebTier, AWSElasticBeanstalkWorkerTier, and AWSElasticBeanstalkMulticontainerDocker now include the necessary permissions for AI analysis. Attach one or more of these managed policies to your environment’s instance profile based on your environment tier. If you use a custom instance profile, ensure it includes the following permissions:
    • bedrock:InvokeModel
    • bedrock:ListFoundationModels
    • elasticbeanstalk:DescribeEvents
    • elasticbeanstalk:DescribeEnvironmentHealth
  • AWS CLI installed and configured with appropriate permissions. See Installing the AWS CLI.
  • Anthropic use case details – AI analysis uses Anthropic Claude models through Amazon Bedrock. Anthropic requires you to submit a one-time use case details form before you can invoke their models. To submit this form, select an Anthropic model from the model catalog in the Amazon Bedrock console, or call the PutUseCaseForModelAccess API. You only need to do this once per AWS account. If you submit the form from the AWS Organizations management account, it automatically covers member accounts in the organization. For more information, see Access Amazon Bedrock foundation models.
  • GovCloud Regions – If you are using AWS GovCloud (US) Regions, you must enable access to the latest Anthropic Claude Sonnet and/or Opus model in Amazon Bedrock before using AI analysis. For instructions on enabling model access in GovCloud Regions, see Manage access to Amazon Bedrock foundation models. For information about the latest available Anthropic Claude Sonnet and/or Opus model, see Supported Regions and models for inference profiles.

Solution Overview

In the following sections, we demonstrate how to use AI Analysis to diagnose a Node.js application that fails after a deployment.

  1. Create a working environment: Deploy a Node.js application to Elastic Beanstalk using the code snippets provided below.
  2. Break the environment: Update the application with code that requires missing environment variables. This causes the environment health status to transition to Degraded.
  3. Use AI Analysis: Request an AI Analysis from the Elastic Beanstalk console or the AWS CLI to identify the root cause of the health degradation.
  4. Apply the fix and verify: Apply the recommendations generated by AI Analysis and confirm that the environment health returns to Ok.

The following figure shows how AI Analysis works:

Figure 1 – AI Analysis architecture
Figure 1 – AI Analysis architecture

  1. You initiate a request through the Elastic Beanstalk console (AI Analysis button) or the AWS CLI (RequestEnvironmentInfo API with InfoType set to “analyze”).
  2. Elastic Beanstalk collects environment data, analyzes it using Amazon Bedrock (a fully managed service that provides access to foundation models through API), and stores the results in Amazon S3.
  3. You retrieve the results through the console or the RetrieveEnvironmentInfo API using CLI.

Walkthrough

Follow the steps below to set up the sample application, break it, troubleshoot with AI Analysis, and restore the environment to a healthy state.

To try this feature, open your terminal and follow the steps below to create a sample Elastic Beanstalk environment. First, set the following variables. Replace the values with your own unique S3 bucket name and the latest Node.js solution stack for your region. To find the latest solution stack, run aws elasticbeanstalk list-available-solution-stacks.

S3_BUCKET="your-unique-bucket-name"

SOLUTION_STACK_NAME="64bit Amazon Linux 2023 v6.9.0 running Node.js 22"

Setting up the application

We use two versions of a simple Node.js application. The first version (v1-working) is a basic HTTP server that responds to requests successfully. The second version (v2-broken) introduces a dependency on environment variables that are not configured in the Elastic Beanstalk environment, simulating a common deployment issue.

Create a project directory:

mkdir test-app && cd test-app

Create the working application file (v1-working):

cat << 'EOF' > workingapp.js
const http = require('http');

const server = http.createServer((req, res) => {
    res.writeHead(200, { 'Content-Type': 'application/json' });
    res.end(JSON.stringify({ status: 'healthy', message: 'App is running' }));
});

const port = process.env.PORT || 8080;
server.listen(port, () => {
    console.log(`Server running on port ${port}`);
});
EOF

Create the broken application file (v2-broken):

cat << 'EOF' > brokenapp.js
const http = require('http');

// Application requires these environment variables to function
const VAR_1 = process.env.TEST_VARIABLE_1;
const VAR_2 = process.env.TEST_VARIABLE_2;
const VAR_3 = process.env.TEST_VARIABLE_3;

if (!VAR_1 || !VAR_2 || !VAR_3) {
    throw new Error(
        `Missing required environment variables. ` +
        `TEST_VARIABLE_1: ${VAR_1 ? 'set' : 'MISSING'}, ` +
        `TEST_VARIABLE_2: ${VAR_2 ? 'set' : 'MISSING'}, ` +
        `TEST_VARIABLE_3: ${VAR_3 ? 'set' : 'MISSING'}`
    );
}

const server = http.createServer((req, res) => {
    res.writeHead(200, { 'Content-Type': 'application/json' });
    res.end(JSON.stringify({ status: 'healthy', db: VAR_1 }));
});

const port = process.env.PORT || 8080;
server.listen(port, () => {
    console.log(`Server running on port ${port}`);
});
EOF

Create the package.json:

cat << 'EOF' > package.json
{
  "name": "test-app",
  "version": "1.0.0",
  "description": "Sample app that requires environment variables",
  "main": "app.js",
  "scripts": {
    "start": "node app.js"
  }
}
EOF

Create the working application source bundle:

cp workingapp.js app.js

zip -r nodejs-working-app.zip app.js package.json

Create the broken application source bundle:

cp brokenapp.js app.js

zip -r nodejs-broken-app.zip app.js package.json

Step 1: Create a working environment

First, create the Elastic Beanstalk application and deploy the working version.

Create an S3 bucket:

aws s3 mb s3://$S3_BUCKET --region us-east-1

Upload the working application source bundle:

aws s3 cp nodejs-working-app.zip s3://$S3_BUCKET/nodejs-working-app.zip

Create the Elastic Beanstalk application:

aws elasticbeanstalk create-application \
    --application-name test-app \
    --description "Test application" \
    --region us-east-1

Create the application version:

aws elasticbeanstalk create-application-version \
    --application-name test-app \
    --version-label v1-working \
    --source-bundle S3Bucket="$S3_BUCKET",S3Key="nodejs-working-app.zip" \
    --region us-east-1

Create the environment with the working version:

aws elasticbeanstalk create-environment \
    --application-name test-app \
    --environment-name test-app-env \
    --solution-stack-name "$SOLUTION_STACK_NAME" \
    --version-label v1-working \
    --option-settings \
        Namespace=aws:elasticbeanstalk:environment,OptionName=EnvironmentType,Value=SingleInstance \
        Namespace=aws:autoscaling:launchconfiguration,OptionName=IamInstanceProfile,Value=aws-elasticbeanstalk-ec2-role \
    --region us-east-1

Once your environment is created, verify the health:

aws elasticbeanstalk describe-environment-health \
    --environment-name test-app-env \
    --attribute-names All \
    --region us-east-1

Output:

{
    "EnvironmentName": "test-app-env",
    "HealthStatus": "Ok",
    "Status": "Ready",
    "Color": "Green",
    "Causes": [
        "Initialization completed 31 seconds ago and took 2 minutes."
    ],
    "ApplicationMetrics": {
        "RequestCount": 0
    },
    "InstancesHealth": {
        "NoData": 0,
        "Unknown": 0,
        "Pending": 0,
        "Ok": 1,
        "Info": 0,
        "Warning": 0,
        "Degraded": 0,
        "Severe": 0
    },
    "RefreshedAt": "2026-03-25T16:39:11Z"
}

Figure 2 – Environment health showing Ok (Green) status after initial deployment
Figure 2 – Environment health showing Ok (Green) status after initial deployment

Step 2: Break the environment

Now, deploy the broken version that requires missing environment variables.

Upload the broken version:

aws s3 cp nodejs-broken-app.zip s3://$S3_BUCKET/nodejs-broken-app.zip

Create the broken application version:

aws elasticbeanstalk create-application-version \
    --application-name test-app \
    --version-label v2-broken \
    --source-bundle S3Bucket="$S3_BUCKET",S3Key="nodejs-broken-app.zip" \
    --region us-east-1

Deploy the broken version:

aws elasticbeanstalk update-environment \
    --environment-name test-app-env \
    --version-label v2-broken \
    --region us-east-1

Within seconds of the deployment completing, the environment health transitions from Ok to Degraded:

aws elasticbeanstalk describe-environment-health \
    --environment-name test-app-env \
    --attribute-names All \
    --region us-east-1

Output:

{
    "EnvironmentName": "test-app-env",
    "HealthStatus": "Degraded",
    "Status": "Ready",
    "Color": "Red",
    "Causes": [
        "Impaired services on all instances."
    ],
    "ApplicationMetrics": {
        "RequestCount": 0
    },
    "InstancesHealth": {
        "NoData": 0,
        "Unknown": 0,
        "Pending": 0,
        "Ok": 0,
        "Info": 0,
        "Warning": 0,
        "Degraded": 0,
        "Severe": 1
    },
    "RefreshedAt": "2026-03-25T16:43:19Z"
}

Figure 3 – Environment health showing Degraded (Red) status with the AI Analysis button visible
Figure 3 – Environment health showing Degraded (Red) status with the AI Analysis button visible

Step 3: Use AI Analysis

Request AI analysis from the AWS CLI or the Elastic Beanstalk console. Both methods produce the same results. The CLI approach is useful for automation and scripting, while the console provides a visual workflow where you can view results directly on the environment page. We’ll cover both options below.

Using the AWS CLI

Request the analysis:

aws elasticbeanstalk request-environment-info \
    --environment-name test-app-env \
    --info-type analyze \
    --region us-east-1

Once the request environment operation is completed, retrieve the results:

aws elasticbeanstalk retrieve-environment-info \
    --environment-name test-app-env \
    --info-type analyze \
    --region us-east-1

The response includes an EnvironmentInfo array with a Message field containing a pre-signed S3 URL to the analysis results:

{
    "EnvironmentInfo": [
        {
            "InfoType": "analyze",
            "Ec2InstanceId": "i-1234567890abcdef0",
            "SampleTimestamp": "2026-03-20T20:49:22.763Z",
            "Message": "https://elasticbeanstalk-us-east-1-123456789012.s3.us-east-1.amazonaws.com/resources/environments/logs/analyze/..."
        }
    ]
}

Download and view the analysis:

ANALYSIS_URL=$(aws elasticbeanstalk retrieve-environment-info \
    --environment-name test-app-env \
    --info-type analyze \
    --region us-east-1 \
    --query 'sort_by(EnvironmentInfo, &SampleTimestamp)[-1].Message' \
    --output text)

curl -s "$ANALYSIS_URL"

Figure 4 – AI analysis output retrieved via AWS CLI
Figure 4 – AI analysis output retrieved via AWS CLI

Using the Elastic Beanstalk console

When your environment’s health status is Warning, Degraded, or Severe, the AI Analysis button appears in the environment overview section of the Elastic Beanstalk console.

  1. Navigate to the Elastic Beanstalk console.
  2. Select your environment (test-app-env).
  3. On the environment overview page, locate the AI Analysis button that appears when the health status indicates an issue.
  4. Choose AI Analysis to initiate the analysis.

Video 1 – Requesting AI analysis from the Elastic Beanstalk console
Video 1 – Requesting AI analysis from the Elastic Beanstalk console

If you want to restart the analysis workflow, you can click on the Reanalyze button to start a new analysis.

Step 4: Apply the fix and verify

The AI analysis identified that the application crashes because the environment does not have three required environment variables configured: TEST_VARIABLE_1, TEST_VARIABLE_2, and TEST_VARIABLE_3. As recommended by the AI analysis, set these environment variables to resolve the issue:

aws elasticbeanstalk update-environment \
    --environment-name test-app-env \
    --option-settings \
        Namespace=aws:elasticbeanstalk:application:environment,OptionName=TEST_VARIABLE_1,Value=value1 \
        Namespace=aws:elasticbeanstalk:application:environment,OptionName=TEST_VARIABLE_2,Value=value2 \
        Namespace=aws:elasticbeanstalk:application:environment,OptionName=TEST_VARIABLE_3,Value=value3 \
    --region us-east-1

After the environment update completes, the application starts successfully and the environment health returns to Ok:

aws elasticbeanstalk describe-environment-health \
    --environment-name test-app-env \
    --attribute-names All \
    --region us-east-1

Output:

{
    "EnvironmentName": "test-app-env",
    "HealthStatus": "Ok",
    "Status": "Ready",
    "Color": "Green",
    "Causes": [
        "Configuration update completed 72 seconds ago and took 54 seconds."
    ],
    "ApplicationMetrics": {
        "RequestCount": 0
    },
    "InstancesHealth": {
        "NoData": 0,
        "Unknown": 0,
        "Pending": 0,
        "Ok": 1,
        "Info": 0,
        "Warning": 0,
        "Degraded": 0,
        "Severe": 0
    },
    "RefreshedAt": "2026-03-25T17:42:47Z"
}

Figure 5 – Environment health restored to Ok (Green) after setting environment variables
Figure 5 – Environment health restored to Ok (Green) after setting environment variables

Note: The steps in this walkthrough can also be performed using the EB CLI. For more information, see the EB CLI Command Reference.

Best practices

Consider these recommendations to get the most out of AI analysis for your environments.

  1. Use supported platform versions: Ensure your environment is running an Amazon Linux 2 or AL2023 platform version released on or after February 16, 2026. Update your platform if you don’t see the AI Analysis option.
  2. Implement fixes incrementally: If the analysis recommends multiple actions, implement them one at a time to isolate which change resolves the issue.
  3. Review data privacy considerations: The analysis sends environment events and logs to Amazon Bedrock running in your account. For more information about how Amazon Bedrock handles your data, see the Amazon Bedrock security documentation.

Cleaning up

Terminate the environment:

aws elasticbeanstalk terminate-environment \
    --environment-name test-app-env \
    --region us-east-1

Delete the application (after the environment is terminated):

aws elasticbeanstalk delete-application \
    --application-name test-app \
    --terminate-env-by-force \
    --region us-east-1

Delete the S3 bucket used for source bundles:

aws s3 rb s3://$S3_BUCKET --force --region us-east-1

Remove the local project directory:

rm -rf test-app

Conclusion

AI-powered environment analysis in AWS Elastic Beanstalk significantly reduces the time and effort required to diagnose environment health issues. Instead of manually parsing through log files and cross-referencing documentation, you can now get targeted, actionable recommendations with a click of the AI Analysis button in the console or an API call.

Whether you prefer using the Elastic Beanstalk console for visual workflows or the AWS CLI/EB CLI for scripting and automation, AI analysis provides a consistent experience that helps you quickly identify root causes and resolve issues.

To learn more about AI-powered environment analysis, see the AWS Elastic Beanstalk Developer Guide. To learn more about AWS Elastic Beanstalk, visit the product page.

About the Author

Chandu Utlapalli

Chandu is a Software Development Engineer at AWS, working on the Elastic Beanstalk service. He focuses on building scalable cloud solutions and integrating AI capabilities to enhance developer productivity and cloud operations. Outside of work, Chandu enjoys playing cricket.

Standardizing construct properties with AWS CDK Property Injection

Post Syndicated from Marco Frattallone original https://aws.amazon.com/blogs/devops/standardizing-construct-properties-with-aws-cdk-property-injection/

Standardizing CDK construct properties across a large organization requires repetitive manual effort that scales poorly as teams and repositories grow. Development teams working with AWS Cloud Development Kit (AWS CDK) must apply the same configuration properties across similar resources to meet security, compliance, and operational standards but manual configuration leads to drift, maintenance burden, and compliance gaps. In this post, you learn how to use Property Injection, a feature introduced in AWS CDK v2.196.0, to automatically apply default properties to constructs without modifying existing code.

The Challenge of Infrastructure Standardization

Organizations implementing infrastructure as code face a fundamental tension between developer productivity and operational consistency. CDK provides abstractions for defining cloud resources, but ensuring compliance with organizational security policies, compliance requirements, and operational standards requires repetitive manual configuration.
Consider this scenario: an organization’s security policy requires that all SecurityGroups disable outbound traffic by default. Development teams must apply these settings to every SecurityGroup:


new SecurityGroup(stack, 'api-sg', {
  vpc: myVpc,
  allowAllOutbound: false,        // Required by security policy
  allowAllIpv6Outbound: false     // Required by security policy
});

new SecurityGroup(stack, 'db-sg', {
  vpc: myVpc,
  allowAllOutbound: false,        // Same configuration repeated
  allowAllIpv6Outbound: false     // Same configuration repeated
});

This manual approach creates four specific problems:

  • Configuration drift: Teams omit required properties or apply them inconsistently
  • Maintenance burden: Policy updates require coordinated changes across multiple repositories and teams
  • Developer friction: Repetitive configuration tasks slow development velocity and increase cognitive load
  • Compliance gaps: Manual processes introduce human error, creating security or compliance violations

Custom construct libraries address these challenges but require refactoring every construct instantiation in existing code and create learning curves for development teams already familiar with standard CDK patterns.

Introducing Property Injection

AWS CDK Property Injection addresses these challenges by automatically applying default properties to constructs without requiring changes to existing code.

Property Injection is a feature introduced in AWS CDK v2.196.0 that intercepts construct creation and automatically applies organizational defaults. With this approach, you can enforce standards consistently while preserving existing development workflows and code patterns.

After implementing Property Injection, the same SecurityGroup creation requires only the vpc parameter, security defaults are applied automatically:

// Your existing code remains unchanged
new SecurityGroup(stack, 'my-sg', {
  vpc: myVpc
  // Security defaults applied automatically by Property Injection
});

The key benefits of this approach include:

  • Zero-impact adoption: Existing CDK code continues to work without modification
  • Centralized policy management: Standards are defined once and applied automatically
  • Consistent enforcement: Policies are applied uniformly across all applications and teams
  • Reduced maintenance overhead: Policy updates require changes in only one location
This diagram shows the five-step Property Injection process in a clear two-column format. The left column outlines each process step, while the right column shows the corresponding implementation details with properly formatted TypeScript code. The flow demonstrates how CDK intercepts SecurityGroup creation, applies organizational security defaults through property injectors, merges them with developer-specified properties, and creates a fully configured SecurityGroup that meets both developer requirements and organizational standards.

Figure 1: CDK Property Injection Mechanism

Property Injection operates transparently within CDK, intercepting construct creation to apply predefined defaults before merging them with any properties explicitly provided by developers. This ensures that organizational standards are consistently applied while maintaining the flexibility for developers to override defaults when specific use cases require it.

Understanding the Implementation Approach

Property Injection works by implementing the IPropertyInjector interface, which allows you to define default properties for specific construct types. These injectors are registered with CDK stacks and automatically apply their defaults during construct instantiation.
The implementation follows three steps: define the defaults you want to apply, register the injector with your stack, and let CDK handle the automatic application of these defaults to matching constructs.

Implementation Guide

This section shows you how to implement Property Injection for SecurityGroup constructs.

Step 1: Create a Property Injector

Create a class that implements the IPropertyInjector interface:

import { IPropertyInjector, InjectionContext } from 'aws-cdk-lib';
import { SecurityGroup, SecurityGroupProps } from 'aws-cdk-lib/aws-ec2';

export class SecurityGroupDefaults implements IPropertyInjector {
  readonly constructUniqueId: string;

  constructor() {
    this.constructUniqueId = SecurityGroup.PROPERTY_INJECTION_ID;
  }

  inject(originalProps: SecurityGroupProps, context: InjectionContext): SecurityGroupProps {
    return {
      // Apply organizational defaults
      allowAllIpv6Outbound: false,
      allowAllOutbound: false,
      // Original properties override defaults when specified
      ...originalProps,
    };
  }
}

Step 2: Add the Injector to Your Stack

Apply the injector to your CDK stack:

import { Stack } from 'aws-cdk-lib';
import { SecurityGroupDefaults } from './security-defaults';

const stack = new Stack(app, 'MyStack', {
  propertyInjectors: [
    new SecurityGroupDefaults()
  ]
});

Step 3: Use Constructs Normally

Create constructs as usual. The injector applies defaults automatically:

// This SecurityGroup receives the injected defaults:
// - allowAllOutbound: false
// - allowAllIpv6Outbound: false
new SecurityGroup(stack, 'my-sg', {
  vpc: myVpc
});

// You can override defaults when necessary
new SecurityGroup(stack, 'special-sg', {
  vpc: myVpc,
  allowAllOutbound: true  // Overrides the injected default
});
This side-by-side comparison shows the difference between manual configuration and Property Injection. The left side (Before) shows three SecurityGroup definitions, each requiring manual specification of allowAllOutbound: false and allowAllIpv6Outbound: false, leading to repetitive code, inconsistency risk, and maintenance burden. The right side (After) shows the same SecurityGroups created with the VPC parameter alone after a one-time Property Injection setup, demonstrating the DRY principle, consistent defaults, and reduced maintenance.

Figure 2: CDK Code Before vs After Property Injection

Property Injection vs L2 Constructs

You can achieve the same enforcement of default properties by creating custom L2 constructs with built-in defaults. However, Property Injection is better suited for standardizing existing codebases without refactoring, while L2 Constructs are better suited for new projects where you want custom APIs and multi-resource abstractions.

This decision tree guides the selection between Property Injection and L2 Constructs for CDK standardization. Starting with existing CDK applications, it evaluates willingness to accept potential breaking changes from new defaults. If breaking changes are acceptable or no existing code exists, it assesses whether custom APIs, naming improvements, or multi-resource patterns are needed beyond simple defaults. The tree leads to three outcomes: Property Injection (blue) for transparent defaults with existing code compatibility, L2 Constructs (orange) for custom APIs and purpose-built abstractions, or a Hybrid approach (green) combining both techniques for maximum flexibility.

Figure 3: Decision Tree – Property Injection vs L2 Constructs

Implementation Comparison

Consider an application with multiple SecurityGroup instantiations that need standardized security defaults.

L2 Construct approach requires creating a custom construct and updating each instantiation:

// Step 1: Create custom L2 construct
export class SecureSecurityGroup extends SecurityGroup {
  constructor(scope: Construct, id: string, props: SecurityGroupProps) {
    super(scope, id, {
      allowAllOutbound: false,
      allowAllIpv6Outbound: false,
      ...props
    });
  }
}

// Step 2: Update each instantiation throughout your codebase
// Change from:
new SecurityGroup(stack, 'sg1', { vpc: myVpc })
new SecurityGroup(stack, 'sg2', { vpc: myVpc })
new SecurityGroup(stack, 'sg3', { vpc: myVpc })

// To:
new SecureSecurityGroup(stack, 'sg1', { vpc: myVpc })
new SecureSecurityGroup(stack, 'sg2', { vpc: myVpc })
new SecureSecurityGroup(stack, 'sg3', { vpc: myVpc })

Property Injection approach requires one-time stack configuration:

// Step 1: Add injector to stack configuration
stack.propertyInjectors = [new SecurityGroupDefaults()];

// Step 2: Existing SecurityGroup calls receive defaults automatically
new SecurityGroup(stack, 'sg1', { vpc: myVpc })  // Gets defaults
new SecurityGroup(stack, 'sg2', { vpc: myVpc })  // Gets defaults  
new SecurityGroup(stack, 'sg3', { vpc: myVpc })  // Gets defaults

Key Differences

Property Injection works with existing construct calls, requiring no changes to how developers instantiate SecurityGroups or other constructs. This approach overrides constructs from external libraries and can be implemented without modifying existing code. Developers continue using familiar CDK APIs without learning new interfaces.

L2 Constructs require updating all constructor calls throughout your codebase. This approach cannot modify third-party construct creation since you must change each instantiation to use your custom construct. Implementation requires refactoring existing code and developers must learn your custom construct APIs instead of standard CDK interfaces. L2 constructs serve multiple purposes beyond complex business logic – simple L2 constructs provide domain-specific naming conventions and cleaner APIs, while complex L2 constructs orchestrate three or more resources and implement business rules.

When to Choose Each Approach

Choose Property Injection when you need to standardize existing infrastructure. Property Injection excels in scenarios where you already have CDK applications deployed and need to apply consistent defaults retroactively. Property Injection works transparently with existing code, requiring no changes to how developers instantiate constructs. This makes it useful when you have existing CDK applications that you want to standardize without disrupting current development workflows.

Property Injection also solves the challenge of applying defaults to constructs from third-party libraries. Since you cannot modify external library code, Property Injection enforces organizational standards on any construct type, regardless of its source. Additionally, when you want to implement standards without changing existing code, Property Injection operates at the framework level, automatically applying defaults during construct instantiation without requiring developers to modify their existing implementations.

Choose L2 Constructs when you need custom APIs or multi-resource patterns. L2 Constructs provide the right abstraction when you want to create purpose-built interfaces that differ from standard CDK APIs. This includes simple wrappers with domain-specific naming, complex business logic, validation rules, or multi-resource orchestration patterns. L2 Constructs excel when you want to create opinionated APIs that simplify common patterns by hiding complexity behind intuitive interfaces.

L2 Constructs suit new application development where you can design the API from the start. This approach creates purpose-built abstractions that match your organization’s specific use cases and terminology. Unlike Property Injection, which applies defaults to existing construct APIs, with L2 Constructs you can design entirely new APIs that directly represent your business domain and operational patterns.

Implementation Patterns

Stack Integration Methods

The CDK provides two methods for adding Property Injectors to stacks:

This diagram demonstrates two methods for adding Property Injectors to CDK stacks. Method 1 (blue) shows adding injectors directly in the Stack constructor’s propertyInjectors array. Method 2 (orange) shows using PropertyInjectors.of(stack).add() after stack creation. Both methods produce identical results with green checkmarks indicating success. The diagram includes usage examples showing normal SecurityGroup instantiation (blue) that inherits defaults automatically, and override scenarios (orange) where developers explicitly override injected defaults. The bottom section shows the resulting CloudFormation output: default SecurityGroups have empty egress rules (green), while overridden ones include outbound traffic rules (orange).

Figure 4: CDK Stack Integration Methods

Method 1: Stack Constructor

const stack = new Stack(app, 'MyStack', {
  propertyInjectors: [new SecurityGroupDefaults()]
});

Method 2: PropertyInjectors.of()

const stack = new Stack(app, 'MyStack');
PropertyInjectors.of(stack).add(new SecurityGroupDefaults());

Both methods produce the same result. Choose the method that best fits your existing code structure. For more details, see the PropertyInjectors API documentation.

Organization-Wide Implementation

For organization-wide standardization, create a shared library of injectors:

// @myorg/cdk-injectors package
export const ORGANIZATION_INJECTORS: IPropertyInjector[] = [
  new SecurityGroupDefaults(),
  new LambdaFunctionDefaults(),
  new S3BucketDefaults(),
];

// Teams import and use the shared injectors
import { ORGANIZATION_INJECTORS } from '@myorg/cdk-injectors';

const stack = new Stack(app, 'TeamStack', {
  propertyInjectors: ORGANIZATION_INJECTORS
});

Scope Hierarchy

Property Injectors can be applied at different levels in the CDK construct tree:

This diagram illustrates the three-level hierarchy of Property Injector scopes in CDK with integrated resolution examples. The App level (blue) shows a BucketInjector ‘b1’ that applies globally, with an example showing how Stack2 buckets use this injector. The Stage level (green) demonstrates a FunctionInjector ‘f1’ that applies to all stacks within the stage, including an example of Stack1 functions using this injector. The Stack level (orange) shows two stacks: Stack1 with its own BucketInjector ‘b2’ that overrides the app-level injector, and Stack2 with no injectors that inherits from parent scopes. The Resolution Rules box (green) explains that CDK searches from most specific (stack) to most general (app), with the first match winning per construct type. Arrows show the hierarchical relationship between scopes.

    Figure 5: CDK Scope Hierarchy & Injector Resolution
  • App level: Applies to all stacks in the application
  • Stage level: Applies to all stacks within a specific stage
  • Stack level: Applies only to constructs within a specific stack

CDK searches for applicable injectors starting from the construct’s immediate parent scope and moving upward. The first matching injector for each construct type is used.

Best Practices

When implementing Property Injection, begin with high-impact constructs like SecurityGroups, VPCs, and Lambda functions that require repetitive configuration.

These constructs have the highest frequency of misconfiguration and the most direct compliance impact, making them the most valuable targets for early adoption.

Document your defaults by explaining what properties your injectors provide and why. Include examples and link to relevant policies that drive the requirements. With this documentation, developers can understand standards and make informed override decisions.

Write automated tests using CDK testing utilities to verify that injectors apply expected defaults. Test both standard scenarios and cases where developers override properties to prevent regressions when updating injector logic.

Version injectors carefully using semantic versioning principles because changes affect all applications. Coordinate updates across teams and provide migration guides for breaking changes or changes to default values.

Design override mechanisms so that developers can handle edge cases while benefiting from organizational standards. Property Injection operates as defaults, not restrictions, so design injectors to merge gracefully with developer-specified properties.

Limitations and Considerations

Property Injection operates as a default mechanism rather than a compliance enforcement system. Developers retain the ability to override injected properties, which means organizations cannot rely solely on Property Injection for strict compliance requirements. For teams that need mandatory compliance, combine Property Injection with CDK Aspects or AWS Config rules to validate and enforce standards.

The feature works exclusively with L2 constructs, as documented in the official AWS CDK guidance. The IPropertyInjector interface targets specific L2 construct types, and L1 (CloudFormation) constructs use different instantiation patterns that bypass the property injection mechanism entirely. Organizations with L1 construct usage need alternative standardization approaches.

Property Injection introduces debugging complexity because injected properties do not appear directly in application code. Developers troubleshooting construct behavior must understand which injectors apply to specific construct types and how those injectors modify properties. This hidden behavior requires documentation that lists each injector, the properties it sets, and the policy it enforces, along with clear naming conventions to maintain code clarity.

The feature requires CDK v2.196.0 or later, which affects adoption timelines for organizations using older CDK versions. Teams must plan upgrade paths and test compatibility before implementing Property Injection across their applications.

Conclusion

Property Injection provides a mechanism for applying consistent default properties to CDK constructs without requiring changes to existing code. This approach reduces repetitive configuration, improves consistency, and simplifies maintenance of CDK applications.
Property Injection is the right choice for organizations that need to standardize construct configurations across existing codebases while preserving developer workflows. When combined with proper testing and documentation, Property Injection becomes a reliable foundation for infrastructure governance across your organization.

About the authors:

Put Cheung

Put Cheung is a Senior Software Development Engineer at AWS Security. He is a part of a team that is making it easier for builders to configure AWS Resources securely. AWS CDK Property Injection is an important step toward this goal.

Rico Huijbers

Rico Huijbers is a Software Engineer at Amazon Web Services. He is extremely lazy and is therefore on a quest to eradicate the need for repetitive manual work from software engineering. Rico loves working on AWS CDK—it’s the tool he wishes he had 5 years earlier.

Marco Frattallone

Marco Frattallone is a Senior Technical Account Manager at AWS focused on supporting Partners. He works closely with Partners to help them build, deploy, and optimize their solutions on AWS, providing guidance and leveraging best practices. Marco focuses on helping Partners adopt emerging AWS services and translate technical capabilities into business outcomes. Outside work, he enjoys outdoor cycling, sailing, and exploring new cultures.

Choosing between Amazon ECS Blue/Green Native or AWS CodeDeploy in AWS CDK

Post Syndicated from Franco Abregu original https://aws.amazon.com/blogs/devops/choosing-between-amazon-ecs-blue-green-native-or-aws-codedeploy-in-aws-cdk/

Blue/green deployments on Amazon Elastic Container Service (Amazon ECS) have long been a go-to pattern for shipping zero-downtime deployments. Historically, the recommended approach in the AWS Cloud Development Kit (AWS CDK) was to wire ECS to AWS CodeDeploy for traffic shifting, lifecycle hooks, and tight integration with AWS CodePipeline.

In July 2025, Amazon ECS launched built-in blue/green deployments. This allows you to operate directly within the ECS service, without requiring the use of Amazon CodeDeploy.

This post explains what changed, how the new ECS-native blue/green model compares to CodeDeploy, and how to decide which path to take in your CDK projects.

Figure1: Amazon ECS blue/green deployment with AWS CodeDeploy

Figure1: Amazon ECS blue/green deployment with AWS CodeDeploy

Why blue/green on ECS, and what was launched in July 2025

In a blue/green deployment, two production environments are maintained: blue, the current environment, and green, the new environment. This strategy allows you to validate the new version of your environment before it receives production traffic.

The ECS service team saw an opportunity to simplify the deployment process by creating lifecycle hooks, bake time, and managed rollback directly within ECS. With this shift, the complexity of coordinating blue/green deployments through CodeDeploy is consolidated into a single service. This consolidation not only simplifies the deployment pipeline but also reduces the number of moving parts, making it easier to maintain and troubleshoot over time.

Conceptually, ECS-native blue/green provisions a replacement task set registered to a separate target group (blue target group in figure 2) behind your Elastic Load Balancing listener. When you approve the cutover, ECS performs an all-at-once traffic shift to the green revision (green target group in figure 2), then holds both revisions during a configurable bake period before retiring blue or rolling back if alarms or hooks fail.

Figure 2: Amazon ECS Native Blue Green DeploymentFigure 2: Amazon ECS Native Blue Green Deployment

Unlike CodeDeploy, which requires fine-grained configuration of traffic shifting strategies, ECS native deployments are intentionally simpler, designed to cover the most common blue/green use cases without the operational overhead of managing a multi-phase canary.

Two paths in CDK: ECS-native blue/green vs. CodeDeploy blue/green

With CDK, you now have two ways to achieve blue/green on ECS. One is the ECS-native path that keeps deployment configuration on the CDK ECS module and its related load balancer resources. You configure lifecycle hooks that invoke AWS Lambda functions at specific deployment stages, you set a bake time, and you optionally use a test listener or Amazon ECS Service Connect header rules to validate traffic to the green revision before production cutover. The CodeDeploy path creates a CodeDeploy application and deployment group bound to your ECS service and Application Load Balancer (ALB), lets you choose canary, linear, or all-at-once policies, and typically plugs into AWS CodePipeline for orchestration.

A key functional difference is how the traffic shifts. ECS-native blue/green performs an immediate all-at-once switch to green, followed by a bake period; CodeDeploy supports canary and linear shifting in addition to all-at-once. If you require progressive exposure by percentage, CodeDeploy remains the way to go. If you want a simpler, service-centric model with fewer moving parts, ECS-native is now the default choice.

Currently, the AWS CDK includes L2 support for ECS-native blue/green so that you can model these settings directly without custom CloudFormation or escape hatches. If your stack already uses the Deployment Controller Type. CODE_DEPLOY path, you can continue to do so; migration options exist (outlined later in this post).

Figure 3: Amazon CodeDeploy blue/green deployment traffic shift

Figure 3: Amazon CodeDeploy blue/green deployment traffic shift

Decision guide: choosing the right path

AWS CodeDeploy offers more refined functionality for managing deployments through its integration with AWS CodePipeline to support multi-stage workflows across services, regions, and accounts, and provides a clear audit trail for change management. AWS CodeDeploy offers policies that can shift traffic in defined increments (for example, 5% or 10%) with automated metric checks and optional approvals. This deployment pattern supports coordinating multiple environments with formal governance, or teams that want data-driven promotions based on alarms and checkpoints. Because of its integration with AWS CodePipeline, you can have several stages for different services for ECS Blue/Green (CodeDeploy) and coordinate the deployment of multiple dependent services in a single release.

Utilize ECS-native to achieve a compact operational footprint by consolidating deployments and operations into a single service. The ECS service supports zero-downtime deployments through Blue/Green deployment (shifting the traffic all at one time) and enables quick rollbacks with configurable settings for minimumHealthyPercent and maximumPercent. Application Load Balancer (ALB) draining and task health checks ensure a balance between speed and safety. Additionally, the built-in deployment circuit breaker automatically halts and reverts problematic rollouts, minimizing operational issues.

How to implement in ECS native in CDK

To utilize ECS-native blue/green in CDK, start with an Amazon ECS service (Fargate or EC2), an Application Load Balancer, and two target groups managed by ECS during deployments. In your service definition, you’ll opt into the blue/green deployment type, set a bake time, and attach lifecycle hooks. Hooks can run Lambda functions at stages such as before scale-up or after production traffic shift, letting you run synthetic tests, warm caches, or gate on external checks. If you’re using Amazon ECS Service Connect, you can route “dark” test traffic to green by sending requests with a specific header during the pre-cutover phase.

const service = new ecs.FargateService(this, "Service", {
      cluster,
      taskDefinition,
      desiredCount: 3,
      securityGroups: [serviceSG],
      vpcSubnets: {
        subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS,
      },
      deploymentStrategy: ecs.DeploymentStrategy.BLUE_GREEN,
      bakeTime: Duration.minutes(30),
      propagateTags: ecs.PropagatedTagSource.SERVICE,
      deploymentAlarms: {
        alarmNames: [
          this.stackName + "-Http-500-Blue",
          this.stackName + "-Http-500-Green",
          "Synthetics-Alarm-trivia-game-" + props.stage,
        ],
        behavior: ecs.AlarmBehavior.ROLLBACK_ON_ALARM,
      },
      lifecycleHooks: [
        new ecs.DeploymentLifecycleLambdaTarget(
          preTrafficHook,
          "PreTrafficHook",
          {
            lifecycleStages: [
              ecs.DeploymentLifecycleStage.POST_TEST_TRAFFIC_SHIFT,
            ],
          }
        ),
      ],
      minHealthyPercent: 100,
      maxHealthyPercent: 200,
    });

Code Snipped: Amazon ECS service with AWS Fargate and AWS CodeDeploy

Conclusion

Using ECS-native blue/green deployments is now the recommended default for most teams. This approach provides zero-downtime cutovers, lifecycle hooks, bake time, and rollback capabilities without requiring the management of an additional service.

Choose CodeDeploy only if you need advanced traffic shifting options, such as canary or linear deployments, or if you have other dependencies with AWS CodePipeline workflows.

Bring your ECS deployments to the next level by enabling Blue/Green deployment with the strategy that best fits for your use case. For step-by-step instructions for migrating from CodeDeploy to ECS-Native refer to this migration guide.

Franco Abregu

Franco Abregu is a Sr. Delivery Consultant – DevOps at AWS Professional Services based in Argentina. Franco focuses on transforming customers DevOps culture to improve developer productivity, operations, deployments and process standardization. His expertise includes CI/CD, Infrastructure as Code, software development and organizational adoption of DevOps culture.

Chris Renzo

is a Sr. Solution Architect within the AWS Defense and Aerospace organization. Outside of work, he enjoys a balance of warm weather and traveling.

Building a scalable code modernization solution with AWS Transform custom

Post Syndicated from Dinesh Prabakaran original https://aws.amazon.com/blogs/devops/building-a-scalable-code-modernization-solution-with-aws-transform-custom/

Introduction

Software maintenance and modernization is a critical challenge for enterprises managing hundreds or thousands of repositories. Whether upgrading Java versions, migrating to new AWS SDKs, or modernizing frameworks, the scale of transformation work can be overwhelming. AWS Transform custom uses agentic AI to perform large-scale modernization of software, code, libraries, and frameworks to reduce technical debt. It handles diverse scenarios including language version upgrades, API and service migrations, framework upgrades and migrations, code refactoring, and organization-specific transformations. Through continual learning, the agent improves from every execution and developer feedback, delivering high-quality, repeatable transformations without requiring specialized automation expertise.

Organizations need to run transformations using AWS Transform custom concurrently across their entire code estate to meet aggressive modernization timelines and compliance deadlines. Running it at enterprise scale requires a solution to process repositories in parallel, in a controlled remote cloud environment, manage credentials securely, and provide visibility into transformation progress. Today, we’re introducing an open-source solution that brings production-grade scalability, reliability, and monitoring to AWS Transform custom. This infrastructure enables you to run transformations on thousands of repositories in parallel using AWS Batch and AWS Fargate, with REST API access for programmatic control and comprehensive Amazon CloudWatch monitoring.

Requirements for Enterprise-Scale Code Modernization

AWS Transform custom provides powerful AI-driven code transformation capabilities through its CLI. To effectively scale transformations across enterprise codebases, organizations need:

Scale: Ability to run transformations on 1000+ repositories concurrently rather than one-by-one
Infrastructure: Dedicated compute resources for long-running transformations beyond developers’ laptops
API Access: REST API for programmatic orchestration and seamless integration with CI/CD pipelines
Monitoring: Centralized visibility into transformation progress and status across multiple repositories
Reliability: Automatic retries, secure credential management, and built-in fault tolerance

The Solution: Batch Infrastructure with REST API

This solution provides complete, production-ready infrastructure that addresses these challenges:

Core Capabilities

  • Scalable Batch Processing Run transformations on thousands of repositories in parallel using AWS Batch with Fargate. The default configuration (256 max vCPUs, 2 vCPUs per job) supports up to 128 concurrent jobs, with automatic queuing and resource management. The compute environment scales based on your needs and Fargate service quotas.
  • REST API for Programmatic Access Seven API endpoints provide complete job lifecycle management, enabling you to submit single jobs or bulk batches of thousands in one request. The API offers real-time status tracking and progress monitoring, with Amazon Identity and access Management (IAM) authentication ensuring secure access to transformation operations.
  • Multi-Language Container The solution includes a container supporting Java (8, 11, 17, 21), Python (3.8-3.13), and Node.js (16-24) with all build tools pre-installed, including Maven, Gradle, npm, and yarn. The AWS Transform CLI and AWS CLI v2 are bundled in. The container is fully extensible for custom requirements—you can add your own libraries, languages, or tools by customizing the Dockerfile to meet their specific needs
  • Enterprise-Grade Reliability Automatic IAM credential management eliminates long-lived keys, with credentials auto-refreshing every 45 minutes for jobs up to 12 hours. The system includes automatic retries for transient failures (default: 3 attempts), with configurable timeout and retry settings to match your transformation complexity.
  • Comprehensive Monitoring A CloudWatch dashboard provides job tracking with success and failure rates, trends over time, and API and Lambda health metrics. Real-time log streaming enables you to monitor transformation progress and quickly diagnose issues.

Architecture

The solution uses a serverless architecture built on AWS managed services:

AWS Transform custom Batch solution architecture
AWS Transform custom Batch solution architecture

Key Components:

  • API Gateway: REST API with IAM authentication
  • Lambda Functions: Job orchestration, status tracking, bulk submission
  • AWS Batch: Job queue and compute environment management
  • Fargate: Serverless container execution (no EC2 to manage)
  • S3: Source code input and transformation results output
  • CloudWatch: Logs, metrics, and operational dashboard

Getting Started

Prerequisites

Before deploying, ensure you have:

  • AWS Account with appropriate IAM permissions (ECR, S3, IAM, Batch, Lambda, API Gateway, CloudWatch)
  • AWS CLI v2 configured with credentials or AWS SSO login
  • Docker installed and running
  • Git for cloning the repository
  • Node.js 18+ and AWS CDK (for CDK deployment)
  • Python3for testing the APIs

Deployment Options

Option 1: CDK Deployment (Recommended)

Step 1: Clone the Repository

git clone https://github.com/aws-samples/aws-transform-custom-samples.git

cd aws-transform-custom-samples/scaled-execution-containers

Step 2: Set Environment Variables

export AWS_ACCOUNT_ID=$(aws sts get-caller-identity --query Account --output text)
export CDK_DEFAULT_ACCOUNT=$AWS_ACCOUNT_ID
export CDK_DEFAULT_REGION=us-east-1

Step 3: Verify prerequisites

This checks that Docker is installed and running, AWS CLI v2 is configured with credentials, Git is available, and your AWS account has the required VPC and public subnets.

cd deployment
chmod +x *.sh
./check-prereqs.sh

Step 4: Set up IAM Permissions (Optional, but recommended)

Generate a least-privilege IAM policy instead of using broad permissions:

./generate-custom-policy.sh

This creates iam-custom-policy.json with minimum permissions scoped to your specific resources.

Create and attach the policy:

aws iam create-policy \
  --policy-name ATXCustomDeploymentPolicy \
  --policy-document file://iam-custom-policy.json
aws iam attach-user-policy \
  --user-name YOUR_USERNAME \
  --policy-arn arn:aws:iam::$(aws sts get-caller-identity --query Account --output text):policy/ATXCustomDeploymentPolicy

Note: If you have administrator access, you can skip this step and proceed directly to deployment.

Step 5: Deploy with CDK (One Command Does Everything!)

cd ../cdk
chmod +x *.sh
./deploy.sh

Time: 20-25 minutes (all resources)

What CDK Does Automatically:

  1. Builds Docker image from Dockerfile
  2. Pushes image to ECR
  3. Creates all AWS resources
  4. Configures everything

What Gets Deployed:

  • ECR repository with Docker image
  • S3 buckets (output, source)
  • IAM roles with least-privilege
  • AWS Batch infrastructure (Fargate)
  • 7 Lambda functions
  • API Gateway REST API
  • CloudWatch logs and dashboard

See cdk/README.md for detailed instructions and configuration options.

Step 6: Get Your API Endpoint

After deployment completes, retrieve the API endpoint URL:

export API_ENDPOINT=$(aws cloudformation describe-stacks \
  --stack-name AtxApiStack \
  --query 'Stacks[0].Outputs[?OutputKey==`ApiEndpoint`].OutputValue' \
  --output text)

echo "API Endpoint: $API_ENDPOINT"

This endpoint is used in all subsequent API calls.

Option 2: Bash Scripts (Alternative)

If you prefer manual control over each deployment step or need to customize individual components, use the bash script deployment. See deployment/README.md for the complete 3-step process with detailed explanations of what each script deploys.

Using the Solution

Single Job Submission

Quick test: Run cd ../test && ./test-apis.sh to validate all API endpoints (MCP, transformations, bulk jobs, campaigns).

Submit a Python version upgrade transformation:

cd ..
python3 utilities/invoke-api.py \
  --endpoint "$API_ENDPOINT" \
  --path "/jobs" \
  --data '{
    "source": "https://github.com/venuvasu/todoapilambda",
    "command": "atx custom def exec -n AWS/python-version-upgrade -p /source/todoapilambda -c noop --configuration \"validationCommands=pytest,additionalPlanContext=The target Python version to upgrade to is Python 3.13. Python 3.13 is already installed at /usr/bin/python3.13\" -x -t"
  }'

This API call triggers a Python version upgrade transformation on the todoapilambda public git repository. The transformation uses the AWS Managed transformation to upgrade from the current Python version to Python 3.13. The configuration parameter specifies additional validation command to be run and plan context to specifies the location of python 3.13 installation in the container and the target version. The -x flag is for non-interactive mode of the transformation , and -t flag is to trust all tools for this transformation.

API returns a job ID for tracking. Job names are auto-generated from the source repository and transformation type.

See api/README.md for complete API documentation with examples for Java, Node.js, and other transformations.

Bulk Job Submission

Transform multiple repositories in a single API call:

python3 utilities/invoke-api.py \
  --endpoint "$API_ENDPOINT" \
  --path "/jobs/batch" \
  --data '{
    "batchName": "codebase-analysis-2025",
    "jobs": [
      {"source": "https://github.com/spring-projects/spring-petclinic", "command": "atx custom def exec -n AWS/early-access-comprehensive-codebase-analysis -p /source/spring-petclinic -x -t"},
      {"source": "https://github.com/venuvasu/todoapilambda", "command": "atx custom def exec -n AWS/early-access-comprehensive-codebase-analysis -p /source/todoapilambda -x -t"},
      {"source": "https://github.com/venuvasu/toapilambdanode16", "command": "atx custom def exec -n AWS/early-access-comprehensive-codebase-analysis -p /source/toapilambdanode16 -x -t"}
    ]
  }'

This API call triggers a deep static analysis of the codebase to generate hierarchical, cross-referenced documentation for three open source repositories in parallel. The transformation uses the AWS Managed transformation to generate behavioral analysis, architectural documentation, and business intelligence extraction to create a comprehensive knowledge base organized for maximum usability and navigation.

The API submits these jobs in a async manner. i.e the API returns a batch id upon submitting these jobs to AWS Batch. Then you can monitor the progress as specified below.

See api/README.md for status checking, MCP configuration, and other API endpoints.

Monitoring Progress

Check batch status:

python3 utilities/invoke-api.py \
  --endpoint "$API_ENDPOINT" \
  --method GET \
  --path "/jobs/batch/BATCH_ID"

Response shows real-time progress:

{
  "status": "RUNNING",
  "progress": 45.5,
  "totalJobs": 1000,
  "statusCounts": {
    "RUNNING": 195,
    "SUCCEEDED": 432,
    "FAILED": 23
  }
}

Viewing Results

After a job completes, the results are stored in your S3 output bucket.

S3 Output Structure:

Results are organized by job name and conversation ID:

s3://atx-custom-output-{account-id}/
└── transformations/
    └── {job-name}/                           # e.g., guava-early-access-comprehensive-codebase-analysis
        └── {timestamp}{conversation-id}/     # e.g., 20251227_051626_8f344f5f
            ├── code/                         # Full source code + transformed changes
            └── logs/                         # Execution logs and artifacts
                └── custom/
                    └── {timestamp}{conversation-id}/
                        └── artifacts/
                            └── validation_summary.md

Validation Summary:

AWS Transform CLI generates a validation summary showing all changes made:

s3://atx-custom-output-{account-id}/transformations/{job-name}/{timestamp}{conversation-id}/logs/custom/{timestamp}{conversation-id}/artifacts/validation_summary.md

This file contains:

  • Summary of all code changes
  • Files modified, added, or deleted
  • Validation results
  • Transformation statistics

Download Results:

# Download all results for a specific job
aws s3 sync s3://atx-custom-output-{account-id}/transformations/{job-name}/{timestamp}{conversation-id}/ ./local-results/

# Download just the validation summary
aws s3 cp s3://atx-custom-output-{account-id}/transformations/{job-name}/{timestamp}{conversation-id}/logs/custom/{timestamp}{conversation-id}/artifacts/validation_summary.md ./

# Download transformed code only
aws s3 sync s3://atx-custom-output-{account-id}/transformations/{job-name}/{timestamp}{conversation-id}/code/ ./transformed-code/

Monitoring and Observability

The solution includes a CloudWatch dashboard with operational metrics:

Job Tracking:

  • Completion rate with hourly trends (completed vs failed)
  • Recent jobs table showing job name, timestamp, last message, and log stream
  • Real-time visibility into job execution

CloudWatch Dashboard screenshot for Job tracking
CloudWatch Dashboard screenshot for Job tracking

API and Lambda Health:

  • API Gateway request counts and error rates
  • Lambda invocation metrics per function
  • Performance monitoring (duration by function)

CloudWatch Dashboard screenshot for API and Lambda Health
CloudWatch Dashboard screenshot for API and Lambda Health

CloudWatch Logs:

All logs are centralized in CloudWatch Logs (/aws/batch/atx-transform) with real-time streaming.

View logs via AWS CLI:

aws logs tail /aws/batch/atx-transform --follow --region us-east-1

Or use the included utility:

python3 utilities/tail-logs.py JOB_ID --region us-east-1

View in AWS Console: CloudWatch → Log Groups → /aws/batch/atx-transform

Model Context Protocol (MCP) Integration

AWS Transform custom supports Model Context Protocol (MCP) servers to extend the AI agent with additional tools. Configure MCP servers via API:

python3 utilities/invoke-api.py \
  --endpoint "$API_ENDPOINT" \
  --path "/mcp-config" \
  --data '{
    "mcpConfig": {
      "mcpServers": {
        "github": {"command": "npx", "args": ["-y", "@modelcontextprotocol/server-github"]},
        "fetch": {"command": "uvx", "args": ["mcp-server-fetch"]}
      }
    }
  }'

The configuration is stored in S3 and automatically available to all transformations. Test with atx mcp tools to list configured servers.

See api/README.md for status checking, MCP configuration, and other API endpoints.

Customization for Private Repositories

You may need to access private repositories and artifact registries. Extend the base container to add credentials:

To access your private Git repositories or artifact registries during transformations:

Two approaches:

  1. AWS Secrets Manager (RECOMMENDED) – Credentials fetched at runtime, never stored in image
  2. Hardcode in Dockerfile (NOT RECOMMENDED) – For testing only

Steps:

  1. Uncomment placeholders in container/entrypoint.sh (Secrets Manager) or container/Dockerfile (hardcoded)
  2. Redeploy container (see below)

See container/README.md for complete setup instructions, examples, and security best practices.

Redeploying after customization:

If using CDK:

cd cdk && ./deploy.sh

CDK automatically detects Dockerfile changes and rebuilds. If changes aren’t detected, force rebuild:

cd cdk && ./deploy.sh —force

If using bash scripts:

cd deployment
./1-build-and-push.sh --rebuild
./2-deploy-infrastructure.sh

The infrastructure will use your custom container with private repository access. You can also customize the container to add support for additional language versions or entirely new languages based on their specific requirements.

See container/README.md for complete examples.

Note: For automated PR creation and pushing changes back to remote repositories after transformation, you have two options: (1) extend container/entrypoint.sh with git commands using your private credentials (see commented placeholder in the script), or (2) use a custom Transformation definition with MCP configured to connect to GitHub/GitLab for more sophisticated PR workflows.

Campaigns

Central platform teams can create campaigns through the AWS Transform web interface to manage enterprise-wide migration and modernization projects. For instance, to upgrade all repositories from Java 8 to Java 21, teams create a campaign with the Java upgrade transformation definition and target repository list. As developers execute transformations, repositories automatically register with the campaign, enabling you to track progress and monitor across your organization.

Creating a Campaign

  1. Setup Users and Login to AWS Transform web application
  2. Create a Workspace and Create a Job
  3. In the chat, specify the type of the job . For example , “I would like comprehensive code analysis on multiple repos”
  4. Based on your request, AWS Transform will display the list of transformation that matches the criteria, in this case “AWS/early-access-comprehensive-codebase-analysis (Early Access)”
  5. Once you confirm the transformation, AWS Transform will create a campaign and a command to execute for the transformation. You can just copy that command and execute via the API as described below replacing the repo details.
atx custom def exec \
--code-repository-path <path-to-repo> \
--non-interactive \
--trust-all-tools \
--campaign 0d0c7e9f-5cb2-4569-8c81-7878def8e49e \
--repo-name <repo-name> \
--add-repo

Executing the Transformation in a Campaign

python3 utilities/invoke-api.py \
  --endpoint "$API_ENDPOINT" \
  --path "/jobs" \
  --data '{
    "source": "https://github.com/spring-projects/spring-petclinic",
    "command": "atx custom def exec --code-repository-path /source/spring-petclinic --non-interactive --trust-all-tools --campaign 0d0c7e9f-5cb2-4569-8c81-7878def8e49e --repo-name spring-petclinic --add-repo"
  }'

Once this transformation Job is successful, you can view the results and dashboard in Web application as well.

Cleanup

To remove all deployed resources:

CDK Cleanup (Recommended)

cd cdk ./destroy.sh

Bash Scripts Cleanup (Alternate)

cd deployment ./cleanup.sh

This script deletes:

  • AWS Batch resources (compute environment, job queue, job definitions)
  • Lambda functions and API Gateway
  • IAM roles
  • S3 buckets (after emptying)
  • CloudWatch logs and dashboard
  • ECR repository

Conclusion

Enterprise software modernization requires infrastructure that can operate at scale with reliability and observability. This solution provides a production-ready platform for running AWS Transform custom transformations on thousands of repositories concurrently.

By combining AWS Batch’s scalability, Fargate’s serverless compute, and a REST API for programmatic access, you can:

  • Accelerate modernization initiatives
  • Reduce manual effort and human error
  • Gain visibility into transformation progress
  • Integrate with existing DevOps workflows

The code repository is open-source, fully automated, and ready for you to deploy in your AWS account today.

Get started today with AWS Transform custom

About the authors

Profile image for Venugopalan Vasudevan

Venugopalan Vasudevan

Venugopalan Vasudevan (Venu) is a Senior Specialist Solutions Architect at AWS, where he leads Generative AI initiatives focused on Amazon Q Developer, Kiro, and AWS Transform. He helps customers adopt and scale AI-powered developer and modernization solutions to accelerate innovation and business outcomes.

Profile image for Dinesh Balaaji Prabakaran

Dinesh Balaaji Prabakaran

Dinesh is a Enterprise Support Lead at AWS who specializes in supporting Independent Software Vendors (ISVs) on their cloud journey. With expertise in AWS Generative AI Services, he helps customers leverage Amazon Q Developer, Kiro, and AWS Transform to accelerate application development and modernization through AI-powered assistance.

Profile image for Brent Everman

Brent Everman

Brent Everman is a Senior Technical Account Manager with AWS, based out of Pittsburgh. He has over 17 years of experience working with enterprise and startup customers. He is passionate about improving the software development experience and specializes in the AWS Next Generation Developer Experience services.

AWS Transform custom: AI-driven Java modernization to reduce tech debt

Post Syndicated from Dinesh Prabakaran original https://aws.amazon.com/blogs/devops/aws-transform-custom-ai-driven-java-modernization-to-reduce-tech-debt/

In today’s rapidly evolving software landscape, maintaining and modernizing Java applications is a critical challenge for many organizations. As new Java versions are released and best practices evolve, the need for efficient code transformation becomes increasingly important. Organizations today face significant challenges when modernizing their Java applications. Legacy codebases often contain outdated patterns, deprecated APIs, and inefficient implementations that hinder performance and maintainability. Traditional manual refactoring approaches are time-consuming, error-prone, and difficult to scale across large codebases. In addition, as developers spend more time on new development and deployment, the volume of technical debt continues to rise, requiring transformation of legacy code at-scale.

AWS Transform custom addresses these challenges through intelligent automation, providing AWS-managed transformations – standardized transformation packages for common scenarios like Java version upgrades. These transformations enable teams to achieve quick wins through standardized, tested transformation patterns that can be executed at scale, bringing significant time and cost savings to customers. In addition, customers can create custom user defined transformations to address technical debt with code transformations across languages, frameworks, and more.

This post explores how to leverage AWS Transform custom’s out-of-the-box transformation for Java upgrades. By the end of this post, you’ll understand how to use these standardized transformations to modernize your Java applications efficiently while maintaining full control over the transformation process.

Introduction to AWS Transform custom

AWS Transform custom uses agentic AI to automate large-scale code modernization, handling language version upgrades, API migrations, framework updates, and organization-specific transformations. Through continual learning, the agent improves from every execution and developer feedback, delivering high-quality, repeatable transformations without requiring specialized automation expertise.

Prerequisites

Before starting your Java modernization journey with AWS Transform custom, ensure you have the necessary development environment, build tools, and AWS Transform custom command line interface (CLI) installed. For detailed prerequisites and setup instructions, refer to the AWS Transform custom Prerequisites Guide.

Understanding the Modernization Scenario

We’ll demonstrate AWS Transform custom using a Movie Service application – a Spring Boot REST API built on Java 8 with Gradle. This represents a typical enterprise modernization challenge with legacy dependencies, outdated patterns, and technical debt.

Leveraging AWS-Managed Transformations

AWS Transform custom focuses on leveraging AWS-managed transformations designed for common modernization tasks like Java version upgrades.

AWS-managed transformations are pre-built, AWS-vetted transformations for common use cases that are ready to use without any additional setup. These transformations provide immediate value with minimal configuration, making them ideal for standard upgrade scenarios.

Understanding AWS Transform custom CLI Capabilities

AWS Transform custom provides a comprehensive command-line interface that enables both interactive and automated transformation workflows:

atx --version                    # Display ATX version
atx --help                       # Display general help
atx custom def list              # List transformation packages
atx                              # Start interactive conversation

For detailed information on all available commands, refer to the AWS Transform custom command reference.

Screenshot of AWS Transform custom interactive mode.
Figure 1:AWS Transform custom interactive mode

Discovering Available Transformations

Use atx custom def list to view all available transformations, including AWS-managed transformations and custom-defined (user-defined) transformations created by your organization. Key AWS-managed transformations include Java/Python/Node.js version upgrades and AWS SDK migrations.

Screenshot of AWS Transform interface displaying categorized lists of AWS Managed transformations and user-defined custom
transformations.
Figure 2: AWS Transform custom lists available AWS Managed and custom-defined (user-defined) transformations

Applying AWS-Managed Transformations

Before applying any transformations, ensure your project is initialized with Git and that all build and test cases are working correctly with Java 8 (Test cases can be skipped when necessary by using the appropriate build command option and instructions to the agent). For Gradle projects, verify that ./gradlew build executes successfully.

The transformation process follows a structured approach:

  1. Ensure Clean Git State:
git status
git add .
git commit -m "Baseline before Java 21 transformation"
  1. Apply Transformation: You can apply transformations using either interactive or direct command modes. In this blog, we will use the interactive mode to walk through the process step-by-step:

Interactive Mode (used in this blog):

First, create a config.json file with your transformation configuration:

{
  "codeRepositoryPath": "/path/to/your/aws-appconfig-java-sample-gradle",
  "transformationName": "AWS/java-version-upgrade",
  "buildCommand": "./gradlew clean build",
  "validationCommands": "build and validate using \"./gradlew clean build\" after transformation to test with java 21",
  "additionalPlanContext": "This is a Java 8 to 21 transformation of a gradle app , also include all dependency migration as well. Use java path /path/to/your/java-8/bin/java and /path/to/your/java-21/bin/java when building before and after transformation. We are using gradle wrapper gradlew, update it if needed for java 21 upgrade. Check for deprecated methods and dependencies and update them."
}

Update the codeRepositoryPath in your config.json to point to your local project directory and update the Java path in additionalPlanContext to match your Java 8 and 21 installation. For more details about configuration files and their parameters, refer to Using Configuration Files.

Then execute the transformation in interactive mode (used for this blog walkthrough):

For Java version upgrade with Gradle using config.json (Interactive Mode):
atx custom def exec -t --configuration file://config.json

Screenshot of AWS Transform interface displaying categorized lists of AWS Managed transformations and user-defined custom transformations.
Figure 3: AWS Transform custom execute a gradle transformation in interactive mode with transformation configuration supplied from config.json

Direct Command Mode (alternative approach): Use this mode for automated CI/CD pipelines or when you want to execute transformations without interactive prompts.

atx custom def exec -x -t --configuration “file://config.json”

Parameter explanation: –

--configuration: Specifies the configuration file for interactive mode

– -x: Executes the transformation automatically without interactive prompts (direct mode)

– -t: Enables test mode for validation during execution (direct mode)

--configuration: Specifies the configuration file path with file://prefix (direct mode)

ATX Execution Command Executing AWS managed Java version upgrade transformation for Gradle project using ATX CLI

  1. Review Transformation Plan: AWS Transform custom analyzes your project based on the configuration provided in config.json and generates a comprehensive transformation plan. This plan details all proposed changes, including:
  • Java version updates: Migration from Java 8 to Java 21 configurations
  • API migration patterns: Automatic updates for deprecated APIs and modern alternatives
  • Framework modernization: Spring Boot version upgrades and compatibility updates
  • Dependency modifications: Updated library versions compatible with Java 21
  • Build system updates: Gradle configuration and plugin changes for Java 21 compatibility
  • Code pattern improvements: Implementation of modern Java features and best practices

We recommend doing a thorough review of the transformation plan to ensure it encompasses all expected updates. The additionalPlanContext in your config.json helps guide the transformation to include dependency migrations and Gradle wrapper updates. If adjustments are needed, provide feedback through the CLI interface.

Additionally, if you want to customize the transformation to target additional changes, for example upgrading additional legacy dependencies contained in the project, you can provide this as feedback when reviewing the transformation plan. AWS Transform custom incorporates all feedback provided to refine the transformation plan before proceeding.

  1. Apply the Transformation: After confirming the transformation plan meets your requirements, type proceed and press Enter. AWS Transform custom executes the transformation according to the approved plan.

The transformation process automatically:

– Creates a new branch and commits the transformed changes in there

– Updates Gradle configuration for Java 21

– Migrates Java EE to Jakarta EE packages (if applicable)

– Updates framework dependencies for Java 21 compatibility

– Applies all necessary code changes

– Updates test cases and testing frameworks for Java 21 compatibility

– Runs comprehensive validation builds

Results of AWS-Managed Transformations

After applying the Java version upgrade transformation, below changes are observed:

Configuration Updates: – Java version: 1.8 → 21 – Spring Boot version upgrades – Gradle plugin and configuration updates – Dependency version modernization

To validate the changes, switch to Java 21 and run ./gradlew build to ensure the transformation was successful, then test the application functionality.

Figure 4: displaying Updated Gradle Configuration Gradle build.gradle showing updated Java 21 configuration and modernized
dependencies
Figure 4: Updated Gradle Configuration Gradle build.gradle showing updated Java 21 configuration and modernized dependencies

Figure 5: Updated code where legacy pattern of raw types usage is transformed to generics
Figure 5: Updated code where legacy pattern of raw types usage is transformed to generics
Figure 6: Second example of updated code where legacy pattern of raw types usage is transformed to generics
Figure 6: Second example of updated code where legacy pattern of raw types usage is transformed to generics
Figure 7: Updated dependency from javax.security to java.security and uses CertificateFactory to get X509Certificate
Figure 7: Updated dependency from javax.security to java.security and uses CertificateFactory to get X509Certificate
Figure 8: Updated Test cases from junit 4 to junit5
Figure 8: Updated Test cases from junit 4 to junit5

Beyond AWS-Managed Transformations: Custom-Defined Transformations

While AWS-managed transformations provide excellent coverage for standard Java modernization scenarios, there are cases where the available AWS-managed transformations may not address your specific transformation requirements. In such situations, AWS Transform custom enables users to create and test their own organization specific, custom-defined transformation definitions.

When to Create Custom-Defined Transformations

Custom-defined transformations become necessary when AWS-managed transformations don’t cover your specific needs, such as proprietary frameworks, organization-specific coding standards, or complex multi-step migration scenarios.

Creating Custom-Defined Transformations

AWS Transform custom enables teams to develop custom transformations using transformation rules and configuration files. This allows organizations to define transformation logic specific to their requirements, test on sample code, and share validated transformations across teams.

AWS Transform custom’s interactive mode (atx) is particularly beneficial for creating Custom-defined transformations, enabling conversational interaction to iteratively refine requirements and get real-time feedback. Custom-defined transformations provide flexibility to extend AWS Transform custom’s capabilities when AWS-managed transformations don’t meet specific modernization needs.

Continual Learning and Knowledge Items

AWS Transform custom automatically learns from each transformation execution to improve future results. For Java upgrades specifically, the service captures patterns like successful refactoring strategies, common dependency conflicts, and framework compatibility matrices across Java versions. This knowledge feeds back into future transformations, making them more accurate at predicting successful upgrade paths and reducing manual intervention.

Knowledge items are account-specific and remain within your AWS account boundaries. Users can enable or disable continual learning, providing full control over this preference.

Conclusion

In this blog, we demonstrated how AWS Transform custom enables efficient Java application modernization using AWS managed transformations. Starting with a legacy Movie Service application running Java 8 and Spring Boot 2.x, we successfully transformed it to Java 21 with modern dependencies and patterns.

The step-by-step process showed how to establish a baseline, discover available transformations using atx custom def list, and apply transformations through AWS Transform custom’s CLI. The result was a fully modernized application with updated Java versions, Spring Boot upgrades, and modern Java features like enhanced switch expressions and local variable type inference – all achieved in minutes rather than weeks of manual refactoring.

Beyond Java Modernization

Beyond Java modernization, AWS Transform custom’s transformation capabilities extend to other programming languages and frameworks, making it a versatile solution for comprehensive application portfolio modernization across diverse technology stacks. The agent supports diverse transformation use cases including:

  • Version upgrades for Java, Python, and Node.js
  • Runtime and API migrations (AWS SDK v1→v2, Boto2→Boto3)
  • Framework transitions and upgrades
  • Language translations and architectural changes
  • Organization-specific, custom-defined transformations

Through its define once, transform everywhere approach, AWS Transform custom enables organizations to capture and amplify transformation knowledge by defining transformations once and executing repeatable tasks across the entire organization. This reduces knowledge silos and ensures consistent quality regardless of team or project scope.

Getting Started

Ready to modernize your Java applications with AWS Transform custom? Here’s how to begin:

  1. Install AWS Transform custom CLI (atx) using the installation script and verify your environment
  2. Configure AWS credentials with transform-custom:* permissions
  3. Explore available AWS-managed transformations using atx custom def list
  4. Apply transformations to your Java applications using direct execution mode (atx custom def exec) or interactive mode (atx)
  5. Validate results through comprehensive testing with ./gradlew build for Gradle projects
  6. Scale across your application portfolio for consistent modernization

Additional Resources

For detailed setup instructions and documentation, visit:

Start your modernization journey today and experience the power of AI-driven code transformation at scale.

About the authors

Profile image for Venugopalan Vasudevan

Venugopalan Vasudevan

Venugopalan Vasudevan (Venu) is a Senior Specialist Solutions Architect at AWS, where he leads Generative AI initiatives focused on Amazon Q Developer, Kiro, and AWS Transform. He helps customers adopt and scale AI-powered developer and modernization solutions to accelerate innovation and business outcomes.

Profile image for Dinesh Balaaji Prabakaran

Dinesh Balaaji Prabakaran

Dinesh is a Enterprise Support Lead at AWS who specializes in supporting Independent Software Vendors (ISVs) on their cloud journey. With expertise in AWS Generative AI Services, he helps customers leverage Amazon Q Developer, Kiro, and AWS Transform to accelerate application development and modernization through AI-powered assistance.

Profile image for Sureshkumar Natarajan

Sureshkumar Natarajan

Sureshkumar Natarajan is a Senior Technical Account Manager at AWS, where he supports Enterprise customers in their cloud journey with a focus on Generative AI initiatives. He guides organizations in leveraging Amazon Q Developer, Kiro, and AWS Transform to unlock new capabilities, streamline development workflows, and achieve transformative business results.

Profile image for Anjan Dave

Anjan Dave

Anjan Dave is a Principal Solutions Architect at AWS with over 25 years of IT experience. He specializes in generative AI application modernization, infrastructure scalability, and developer productivity initiatives.
Anjan leads GenAI and modernization strategies across global projects, influencing technology roadmaps for HCM providers through event-driven and microservices architectures. He advocates for integrating Generative AI into the software development lifecycle to automate routine tasks, enabling engineering teams to focus on high-value architectural work.

Automating AWS SDK for Java v1 to v2 Upgrades with AWS Transform

Post Syndicated from Brent Everman original https://aws.amazon.com/blogs/devops/automating-aws-sdk-for-java-v1-to-v2-upgrades-with-aws-transform/

The AWS SDK for Java v2 represents a fundamental shift in how Java applications interact with AWS services, addressing critical security requirements while delivering measurable performance improvements. For organizations still operating on v1, this transition extends beyond a routine version upgrade—it’s a strategic imperative for maintaining secure, efficient cloud operations. With v1 reaching end-of-support on December 31, 2025, organizations face a hard deadline where security vulnerabilities will no longer receive patches, potentially violating compliance frameworks that require current, supported software versions.

Security enhancements alone justify the migration, with v2 implementing advanced credential management, modernized encryption clients, and comprehensive TLS security protocols that v1’s architecture cannot accommodate. Beyond security, v2 delivers architectural improvements through non-blocking I/O operations and modular service clients that reduce application footprint while improving response times.

This blog post demonstrates how to automate AWS SDK for Java v1 to v2 upgrades using AWS Transform custom, enabling organizations to modernize their Java applications efficiently while minimizing manual intervention and potential errors.

AWS Transform custom uses agentic AI to perform large-scale modernization of software, code, libraries, and frameworks to reduce technical debt. It handles diverse scenarios including language version upgrades, API and service migrations, framework upgrades and migrations, code refactoring, and organization-specific transformations.

Prerequisites

Before beginning the transformation process, verify the following requirements:

Solution Overview

The AWS Transform CLI provides AWS-Managed Transformations that are pre-built, AWS-vetted transformations for common use cases that are ready to use without any additional setup. The AWS/java-aws-sdk-v1-to-v2 transformation enables you to upgrade the AWS SDK from v1 to v2 for Java projects. We will use this verified transformation definition to upgrade a sample Java application from AWS SDK for Java v1 to v2.

Step 1: Prepare the Sample Project

Clone the AWS Java sample repository to your local environment:

git clone https://github.com/aws-samples/aws-java-sample
cd aws-java-sample

Step 2: Execute the Transformation

The AWS Transform CLI’s def exec command provides multiple parameters for customizing transformations. View all available options using atx custom def exec --help. For this transformation, execute the following command (replace <path_to_project> with your actual project path):

atx custom def exec -n AWS/java-aws-sdk-v1-to-v2 -p <path_to_project> -t -c "mvn package"

Parameter breakdown:

  • -p: Path to the code repository to transform
  • -n: Name of the transformation definition in the registry
  • -t: Trusts all tools (no tool prompts)
  • -c: Command to run when building repository

Step 3: Provide Additional Guidance

Before AWS Transform generates the transformation plan, it asks if there is specific guidance to take into consideration when generating the plan. For example, some organizations may require or have approved the use of specific versions of libraries. If there are specific requirements like this or guidance you would like to provide, please add it here. For this sample, enter the following prompt that demonstrates how you can specify a specific version of a library that may be needed to meet organizational requirements:

Please utilize version 2.34.0 of software.amazon.awssdk

Step 4: Review the Transformation Plan

AWS Transform analyzes your project and generates a comprehensive transformation plan. This plan details all proposed changes, including:

  • Update Maven dependencies
  • API migration patterns
  • Builder pattern implementations
  • Update exception handling

The transformation plan will be outlined in a plan.json file in the specified directory in the output (Figure 1). We suggest doing a thorough review of the transformation plan to ensure it encapsulates all expected updates. If adjustments are needed, feedback can be provided through the CLI interface. AWS Transform custom incorporates all feedback provided to refine the transformation plan before proceeding.

Transformation plan output

Figure 1: Transformation plan output

Step 5: Apply the Transformation

After confirming the transformation plan meets your requirements, type proceed and press Enter. AWS Transform custom proceeds to the next step and executes the transformation according to the approved plan.

Step 6: Verify Changes

Once the transformation is complete, you can review the validation summary that was written to the validation_summary.md file in the specified directory. After reviewing the summary, we will use our IDE (VS Code in this case, you can use your preferred mechanism) to examine the transformation results.

POM.xml Updates: The AWS SDK dependency upgrades from version 1.9.6 to 2.34.0 (Figure 2), reflecting the version that was specified during the planning phase.

POM.xml Updates

Figure 2: POM.xml Updates

Code Pattern Updates: The S3Sample.java file shown in Figure 3 demonstrates v2’s builder pattern implementation.

Builder pattern updates

Figure 3: Builder pattern updates

Step 7: Build the application

Since the build command was passed as part of the -c parameter, AWS Transform custom will have already verified that the application builds as expected. We will also validate the transformation by building the application via the following command:

mvn clean package

The application should build successfully and you should see a BUILD SUCCESS message.

Step 7: Test the application

Next, we will verify that the application’s functionality is working as expected after the transformation. Configure your AWS credentials and run the application:

aws configure
mvn clean compile exec:java

The application should execute successfully (as seen in Figure 4), demonstrating that core functionality remains intact after the transformation.

Successful application execution logs

Figure 4: Successful application execution

Custom Transformation Definition

While AWS provides managed transformations for modernizing legacy projects, these standard solutions may not always meet an organization’s unique requirements. Although AWS allows customization of these managed transformations through plan context and feedback mechanisms, some scenarios demand custom solutions. This is particularly true when organizations need to:

  1. Upgrade proprietary internal frameworks
  2. Update custom libraries
  3. Manage complex SDK version upgrades
  4. Handle organization-specific code patterns

AWS Transform custom addresses these needs by enabling organizations to create and maintain their own transformation definitions. This capability offers several advantages:

  • Allows organizations to codify their specific modernization requirements
  • Creates reusable transformation patterns
  • Enables consistent application of organizational best practices
  • Facilitates scalable modernization efforts across multiple projects
  • Preserves and leverages institutional knowledge through documented transformations

By defining these custom transformations once, organizations can efficiently execute standardized modernization tasks across their entire codebase, ensuring consistency and reducing manual effort.

Conclusion

The automated transformation from AWS SDK for Java v1 to v2 using the AWS Transform CLI demonstrates how organizations can modernize their Java applications efficiently while maintaining code quality and functionality. This approach eliminates the manual effort traditionally required for SDK migrations, reducing both time investment and the risk of introducing errors during the upgrade process.

Key benefits realized through this automation:

  • Accelerated migration timeline – What typically requires weeks of manual refactoring completes in minutes
  • Consistent transformation patterns – Verified transformations ensure uniform code updates across your entire codebase
  • Reduced human error – Automated pattern recognition and replacement eliminates common migration mistakes
  • Immediate security improvements – Applications gain V2’s enhanced security features without extensive manual intervention

As AWS continues to innovate and enhance AWS SDK for Java v2 with new features and optimizations, maintaining current SDK versions becomes increasingly important. By automating this critical upgrade process, development teams can focus on delivering business value while ensuring their applications leverage the latest AWS capabilities and security enhancements. Get started with AWS Transform custom today to begin your modernization journey, or explore additional AWS-Managed Transformations to address other modernization use cases.

Building with AI-DLC using Amazon Q Developer

Post Syndicated from Will Matos original https://aws.amazon.com/blogs/devops/building-with-ai-dlc-using-amazon-q-developer/

The AI-Driven Development Life Cycle (AI-DLC) methodology marks a significant change in software development by strategically assigning routine tasks to AI while maintaining human oversight for critical decisions. Amazon Q Developer, a generative AI coding assistant, supports the entire software development lifecycle and offers the Project Rules feature, allowing users to tailor their development practices within the platform.

Recently, AWS made its AI-DLC workflow open-source, enabling developers to create software using this methodology. This workflow is implemented in Amazon Q Developer through its Project Rules customization feature. In this post, we will demonstrate how the AI-DLC workflow operates in Amazon Q Developer using an example use case.

AI-DLC Workflow Overview

The AI-DLC workflow is the practical implementation of the AI-DLC methodology for executing software development tasks. As outlined in the AI-DLC Method Definition Paper, the workflow has three phases. These phases are Inception, Construction, and Operations. Inception involves planning and architecture. Construction focuses on design and implementation. Operations cover deployment and monitoring. Each phase includes distinct stages. These stages address specific software development life cycle functions. The workflow adapts to project requirements. It analyzes requests, codebases, and complexity. This analysis determines the necessary stages. Simple bug fixes skip planning. They go directly to code generation. Complex features need requirements analysis. They also require architectural design and detailed testing.

The workflow maintains quality and control through structured milestones and transparent decision-making. At each phase, AI-DLC asks clarifying questions, creates execution plans, and waits for approval. Every decision, input, and response is logged in an audit trail for traceability. Whether building a new microservice, refactoring legacy code, or fixing a production bug, AI-DLC scales its rigor to match needs—comprehensive when complex, efficient when simple, and always in control. Figure 1 shows the phases and stages within the adaptive AI-DLC workflow. The stages shown in green boxes are mandatory, while those in yellow boxes are conditional.

AI-DLC workflow diagram showing three phases: Inception Phase (blue) with mandatory steps for Workspace Detection, Requirements Analysis, and Workflow Planning, plus conditional steps for Reverse Engineering, User Stories, Application Design, and Units Generation; Construction Phase (green) with conditional steps for Functional Design, NFR Requirements, NFR Design, and Infrastructure Design, followed by mandatory Code Generation and Build and Test steps that loop for each unit; and Operations Phase (orange) with an Operations step. The workflow flows from User Request at the top to Complete at the bottom.

Figure 1. SDLC phases and stages in AI-DLC workflow

Prerequisites

Before we begin the walk-through, we must have an AWS account or AWS Builder Id for authenticating Amazon Q Developer. If you don’t have one, sign up for AWS account or create an AWS builder id. You can use any of the Integrated Development Environments (IDEs) supported by Amazon Q Developer and install the extension as per the AWS documentation. In this post, we’ll be using the Amazon Q Developer extension in VS Code IDE. Once the plug-in is installed, you’ll need to authenticate Q Developer with the AWS cloud backend. Refer to the AWS documentation for Q Developer authentication instructions.

The AI-DLC workflow generates various Mermaid diagrams in markdown files. To view these diagrams within your IDE, you can install a Mermaid viewer plugin.

Let’s Begin Building!

Let’s construct a simple River Crossing Puzzle as a web UI app using AI-DLC. By choosing a straightforward app, we can concentrate more on learning the AI-DLC workflow and less on the project’s technical intricacies.

The sections below outline the individual steps in the AI-DLC development process using Amazon Q Developer. We’ll showcase screenshots of our IDE with the Amazon Q Developer plug-in and demonstrate how to interact with the workflow.

Although we’ve used the Amazon Q Developer IDE plug-in in this blog post, you can also use Kiro Command Line Interface (CLI) to build with AI-DLC without any additional setup. The workflow remains the same, except that you’ll interact through the command line instead of the graphical interface in the IDE.

As we progress through the workflow, your AI-DLC experience will be tailored to your specific problem statement. You’ll also notice the probabilistic nature of large language models (LLMs), as the questions and artifacts generated by them will vary from one run to another for the same problem statement. For example, if you attempt to replicate the same problem statement we used in this blog post, your experience will likely differ. This is expected and desirable. Despite these minor variations, we’ll eventually find a solution to the problem we initially set out to address.

Step 1: Clone GitHub repo containing the AI-DLC Q Developer Rules

Clone the GitHub repo containing the AI-DLC Q Developer Rules:

git clone https://github.com/awslabs/aidlc-workflows.git

Step 2: Load Q Developer Rules in your project workspace

Follow the README.md instructions in the GitHub repo to copy the rules files over to your project folder.

Step 3: Install and authenticate Amazon Q Developer Extension in IDE

Open the project folder you created in Step 2 in VS Code. Open the Amazon Q Chat Panel in the IDE and ensure that the AI-DLC workflow rules are loaded in Q Developer, as shown in Figure 2. If you don’t see what’s shown in Figure 2, please double-check the steps you performed in Step 2.

Screenshot showing four steps to access AI-DLC rules in Amazon Q: Step 1 shows opening Amazon Q Chat Panel from the left sidebar; Step 2 shows opening a chat session in Amazon Q at the top; Step 3 shows clicking on the Rules button in the chat interface; Step 4 shows ensuring AI-DLC rules are loaded in the rules panel on the right side of the screen.

Figure 2: AI-DLC rules enabling in Amazon Q Developer

Step 4: Start the AI-DLC workflow by entering a high-level problem statement

Our development environment is now set up, and we’re ready to begin application development using AI-DLC. In our Q Developer chat session, we enter the following problem statement:

Using AI-DLC let's build a web application to solve the river crossing puzzle.

Notice that we’ve prefixed our problem statement with “Using AI-DLC …” to ensure that Q Developer engages the AI-DLC workflow. Figure 3 shows what happens next. The AI-DLC workflow is triggered within Q Developer. It greets us with a welcome message and provides a brief overview of the AI-DLC methodology.

Figure 3 shows an expanded view of the AI-DLC workflow rules folder structure on the left. You’ll notice that a single aws-aidlc-rules/core-workflow.md is placed in the designated .amazonq/rules folder, while the rest of the rules files are placed in an ordinary aws-aidlc-rule-details folder. This arrangement is designed to optimize model efficiency. By placing the aws-aidlc-rules/core-workflow.md file in the .amazonq/rules folder, , it serves as additional context, ensuring that the core workflow structure is always accessible without incurring additional token consumption. Conversely, the detailed phase and stage-level behavior rules are stored in the aws-aidlc-rule-details folder and are dynamically loaded as required. This approach conserves Amazon Q’s context window and token usage by retaining only the necessary information within the context at any given time, thereby enhancing model efficiency.

The rules files under the aws-aidlc-rule-details folder are organized into three sub-folders, each representing a phase of AI-DLC. Within each phase, there are stage-specific files. A common folder houses cross-cutting rules applicable to all AI-DLC phases and stages such as the “human-in-the-loop”.

The AI-DLC workflow is self-guided and provides us with a clear understanding of what to expect next. It informs us that it will enter the AI-DLC Inception phase next, starting with the Workspace Detection stage within it.

Screenshot of Amazon Q interface showing AI-DLC workflow initialization. The left sidebar displays a file tree with various workflow stages and configuration files. The main chat area shows a problem statement input box at the top with placeholder text 'Using AI-DLC let's build a web application to solve the most pressing problem.' Below is a welcome message explaining AI-DLC (AI-Driven Development Life Cycle) and its capabilities. Three callout annotations highlight: 1) The core workflow dynamically utilizes detailed instructions for different phases and stages, loading and unloading them as required; 2) AI-DLC workflow kicks off with a welcome message and precise overview; 3) The workflow is structured to load a single Q Developer Rule file, one workflow.md, which then dynamically loads and unloads the stage definitions housed in the 'aws-aidlc-rule-details' folder as needed.

Figure 3: User enters high level problem statement in Amazon Q. AI-DLC workflow is triggered.

Step 5: Workspace Detection

We enter the Workspace Detection stage within the Inception phase. In this stage, AI-DLC analyzes the current workspace and determines whether it’s a greenfield (new) or brownfield (existing) application. Since AI-DLC is an adaptive workflow, it decides whether the next stage will be Reverse Engineering (for brownfield projects) or Requirements Analysis (for greenfield projects).

Since we’re building a greenfield application and there’s no existing code in the workspace to reverse engineer, the workflow will guide us to Requirements Analysis next. If we were working on a brownfield application, the workflow would have performed Reverse Engineering first and then moved on to Requirements Analysis. This demonstrates the adaptive nature of the workflow.

Figure 4 illustrates the process in our IDE when we enter this stage. The workflow requests our permission to create an aidlc-docs folder under the project root. This folder will serve as the repository for all the artifacts generated by AI-DLC during the workflow execution. Subsequently, the workflow generates two files within this folder: aidlc-state.md and audit.md. The purpose of these files is explained in Figure 4.

Screenshot of AI-DLC workspace detection phase showing the Amazon Q chat interface. The left sidebar displays the file tree with an 'aidlc-doc' folder highlighted. The main chat area shows the Inception Phase - Workspace Detection stage with explanatory text about analyzing the workspace. Five callout annotations explain: 1) Workflow creates aidlc-doc directory for storing AI-DLC generated artifacts; 2) The workflow tracks its progress in aidlc-metadata.json for error recovery and session continuity; 3) The audit.md file stores user's prompts; 4) Workflow highlights the AI-DLC phase and stage name with a clear heading for easy tracking; 5) Workflow loads detailed stage-level behavior files dynamically such that they don't consume the context window statically. At the bottom, a user approval prompt shows 'mkdir -p /Users/[...]/NewConsumerPortal/aidlc-docs' with the user asked to approve the 'mkdir' command.

Figure 4: Workspace Detection

The Workspace Detection will quickly finish as this is a greenfield project. The workflow will guide us into Requirements Analysis stage within the Inception phase next.

Step 6: Requirements Analysis

The workflow has progressed to the Requirements Analysis stage, where we will define the application requirements. The AI-DLC workflow presented our high-level problem statement to the Q Developer, which then responded with several requirements clarifications questions, as illustrated in Figure 4.

Several AI-DLC rules came into play at this stage. One rule instructed Amazon Q to avoid making assumptions on the user’s behalf and instead ask clarifying questions. Since LLMs tend to make assumptions and rush towards outcomes, they must be explicitly instructed to align with the engineering rigor of the AI-DLC methodology. To achieve this, the Q Developer presented several requirements clarification questions in requirement-verification-questions.md file and asked us to answer them inline in the file.

Another AI-DLC rule instructed the Q Developer to present questions in multiple-choice format and always include an open-ended option (“Other”) to enhance user convenience and provide flexibility in answering.

As shown in Figure 5, Amazon Q has asked us about the desired puzzle variant, such as the Classic Farmer, Fox, Chicken, and Grain puzzle or other popular variations. Additionally, it has asked us questions about user interaction methods, score persistence across multiple players, and the creation of a leaderboard.

These questions are essential for achieving our desired application outcome. Our responses to these questions will determine the final product. While we didn’t explicitly specify this level of detail in our high-level problem statement, AI-DLC has delegated detailed requirements elaboration to Amazon Q, but we still retain control over what gets built.

Screenshot of AI-DLC Requirements Analysis phase showing a split view. The left side displays a requirements clarification questions markdown file with multiple-choice questions about the Kuer Crossing Portal, including sections about user crossing portal variants, primary user interaction methods, and data storage preferences. The right side shows the Amazon Q chat interface with the Inception Phase - Requirements Analysis heading. Two callout annotations highlight: 1) AI-DLC asks questions in multiple choice format, with an 'Other' option that leaves an open-ended fill-in-the-blank when the answer doesn't match the predefined options; 2) AI-DLC generates config.requirements-clarification-questions.md file containing requirements clarification questions, with questions placed in an MD file where the user can respond inline in the file, using 'Answered' to indicate completion. The chat shows instructions for answering questions to clarify requirements.

Figure 5: Requirements Analysis

We answer all the questions in requirement-verification-questions.md file and enter “Done” in the chat window.

Amazon Q processes our responses. The AI-DLC workflow is designed to identify human errors. It checks if we’ve answered all the questions and identifies any contradictions or ambiguities in our answers. Any confusions, contradictions, or ambiguities will be flagged for follow-up questions. AI-DLC adheres to high standards and ensures that we don’t proceed to the next step until we’re fully in agreement on the requirements between us and Amazon Q.

Since we answered all the questions and there were no contradictions in our answers, the workflow continues and generates a comprehensive requirements.md document, as shown in figure 6.

Screenshot showing AI-DLC requirements review phase with split view. The left side displays a Requirements Document for the River Crossing Puzzle Web Application, including Intent Analysis Summary, User Request details, Request Type, and Functional Requirements with Core Puzzle Functionality items (FR-001 through FR -006) describing game features like classic farmer puzzle, timer display, move tracking, puzzle state validation, and victory messages. The right side shows the Amazon Q chat interface with 'Requirements Analysis Complete' heading, displaying project details including Puzzle Type (Classic Farmer, Fox, Chicken, and Grain river crossing puzzle), Technology (React-based modern web application), and Target Devices (web browsers only). Three callout annotations highlight: 1) Requirements Analysis phase complete; 2) Requirements document generated; 3) User may Request Changes, Add User Stories for Approval, or Approve & Continue, with a REVIEW SAFETY note warning users to review requirements and approve to continue, with options to request changes or add modifications if required.

Figure 6: Requirements Review

The workflow prompts us to review the requirements.md document and decide on the next step. If we’re not aligned on the requirements, we can prompt Amazon Q to help us achieve alignment. We can then iterate on the requirements until we’re fully aligned. Once we’re fully aligned, we prompt AI-DLC to progress to the next stage.

Given the adaptive nature of the AI-DLC workflow, Amazon Q has recommended that this application is simple enough, and we can skip the User Stories stage. If we felt otherwise, we would have overridden the model’s recommendation. In this case, we agree with Q’s recommendation and will therefore enter “Continue” in the chat window.

The workflow will enter Workflow Planning stage next.

Step 7: Workflow Planning

With our requirements established, we proceed to the Workflow Planning stage. In this phase, we leverage the requirements context and the workflow’s intelligence to plan the execution of specific stages of AI-DLC within the workflow to build our application as per the requirements specification.

Figure 7 illustrates the workflow planning stage in Q Developer. The workflow has generated an execution-plan.md file that outlines the recommended stages for execution and those that should be skipped.

The workflow planning process is highly contextual to the requirements. During requirements analysis, we decided to develop a simple river crossing puzzle application, consisting of a single HTML file, without a backend, leaderboard, or persistence. Consequently, Amazon Q recommends that we skip all the conditional stages, such as User Stories, Application Design, Units of Work Planning, and so on, and proceed directly to the Code Generation Planning stage in the Construction phase.

Figure 7 visually represents the recommended workflow graphically, indicating the stages that will be executed and those that will be skipped.

Screenshot of AI-DLC Workflow Planning phase showing an Execution Plan document on the left with Detailed Analysis Summary including user-facing changes, brownfield changes, API changes, and NFR changes, plus Risk Assessment. Below is a Workflow Visualization flowchart diagram showing the workflow stages from Inception through Construction to Operations phases. The right side shows the Amazon Q chat with 'Workflow Planning Complete' heading. Three callout annotations highlight: 1) AI -DLC workflow has analyzed requirements and based on the problem complexity has proposed a set of stages to execute in the workflow; 2) Problem is simple enough that AI-DLC is proposing to skip the detailed optional stages; 3) User may Request Changes, Add back skipped stages or Approve & Continue.

Figure 7: Workflow Planning

Since we’ve opted for a straightforward web UI app in this blog post for brevity, the workflow execution plan suggested by AI-DLC aligns seamlessly with our objectives. Should we not be aligned with the AI-DLC recommended workflow execution plan, we would request Q Developer to modify the plan to suit our preferences.

Since we’ve agreed on the workflow plan, we’ll enter “Continue” in Q’s chat session. If we weren’t aligned with the recommended workflow execution plan, we’d have prompted Q with our concerns and iterated over the revised execution plan until it aligned with our preferences. Following the recommended execution plan, the workflow will transition into the Construction phase and directly into the Code Generation Plan stage in the phase.

Step 8: Code Generation Planning

AI-DLC prioritizes planning over rushing to outcomes. This approach aligns with the concept of human-in-the-loop behavior, allowing us to detect issues early on, provide feedback on the plan, and prevent wrong assumptions from propagating further. Before we proceed with actual Code Generation, we undergo Code Generation Planning.

During Code Generation Planning, AI-DLC creates a detailed, numbered plan. It analyzes the requirements and design artifacts, breaking down the process into explicit steps for generating business logic, the API layer, the data layer, tests, documentation, and deployment files.

The plan is documented in a {unit-name}-code-generation-plan.md file, complete with check boxes. This ensures transparency, allowing users to see what will be built. It also provides control, enabling users to modify the plan. Additionally, it maintains quality by ensuring comprehensive coverage of code, tests, and documentation.

Figure 8 illustrates the AI-DLC’s code generation plan. The proposed workflow comprises eight steps, starting with creating an HTML structure and progressing to adding styling, game logic, and concluding with testing and documentation.

Screenshot of AI-DLC Code Generation Planning showing a Code Generation Plan document for River Crossing Puzzle on the left, with Unit Context listing HTML Structure, CSS Styling, and JavaScript files, followed by Unit Generation Steps including Step 1: HTML Structure Generation, Step 2: CSS Styling Generation, and Step 3 : Core Game Logic Generation with detailed checkboxes for each step. The right side shows Amazon Q chat with code generation plan details. Three callout annotations highlight: 1) The plan doc contains to-do items for AI-DLC to execute. These checkboxes get completed when the task is done; 2) This is how AI-DLC workflow persists and tracks progress state; 3) AI-DLC has proposed an 8-step code generation plan with checkboxes and review prompts, and User may Request Changes or Approve & Continue.

Figure 8: Code Generation Planning

The code generation plan appears reasonable to us. We will proceed to the Code Generation stage by entering “Continue” in Q’s chat session.

Step 9: Code Generation

The Code Generation stage executes the Code Generation Plan we approved in the previous step. It generates actual code artifacts step-by-step, including business logic, APIs, data layers, tests, and documentation. Completed steps are marked with check boxes, progress is tracked, and story traceability is ensured before presenting the generated code for user approval.

Figure 9 illustrates that the Code Generation stage has been completed. We are now reviewing a single index.html file generated with embedded styling and JavaScript consistent with our preference specified in requirements.md.

The workflow provides a summary of the activities performed during the Code Generation phase.

Screenshot of AI-DLC Code Generation phase showing generated HTML code on the left with embedded styling and JavaScript for the River Crossing Puzzle application. The right side shows Amazon Q chat with 'Code Generation Complete - river-crossing-puzzle' heading and a list of generated artifacts including HTML file, CSS interface, drag-and-drop interface, game logic, and testing services. Two callout annotations highlight: 1) The generated code is an HTML file with embedded styling and JavaScript; 2) We have specified during requirements analysis phase that we want a single-file index.html file implementation; 3) Code generation has been completed, and a summary of the generated artifacts is provided.

Figure 9: Code Generation

We’re about to test our newly created application soon. While it may be straightforward to test this simple puzzle app right now, for complex applications, we generate build and test instructions using AI-DLC.

We’ll enter “Continue” in the workflow and enter the final Build and Test stage in the Construction phase.

Step 10: Build and Test

These questions are essential for achieving our desired application.
We’ve reached the final stage of the AI-DLC Construction Phase, known as the Build and Test stage. During this stage, we create comprehensive instruction files that guide the build and packaging of the project, and document the necessary testing layers. These layers include unit tests (validating generated code), integration tests (checking unit interactions), performance tests (load/stress testing), and additional tests as required (security, contract, e2e).

The generated build instructions include dependencies and commands, test execution steps with expected results, and a summary document that provides an overview of the overall build/test status and the project’s readiness for deployment.

Figure 10 illustrates the documentation generated during this stage.

Screenshot of AI-DLC Build and Test phase showing a Build and Test Summary document on the left with Build Status (Build Tool, Build Status, Build Artifacts, Build Warnings) and Test Execution Summary including Unit Tests, Integration Tests, and Performance Tests sections with checkmarks and failure indicators. The right side shows Amazon Q chat with build and test completion status and project summary. Two callout annotations highlight: 1) Build and Test Complete! Build and Test instructions have been documented; 2) The AI-DLC workflow has concluded with a comprehensive summary of all completed stages and generated artifacts.

Figure 10: Build and Test

The AI-DLC workflow has now concluded.

Let’s Solve the Puzzle!

We open index.html in a web browser to access our newly created River Crossing Puzzle application. As shown in figure 11, we see our graphical web UI.

During requirements assessment, we chose a straightforward user interface using HTML, CSS, and JavaScript (without any frameworks), as evident in the display shown in Figure 11. Your display may vary due to the probabilistic nature of LLMs and the choices you made for requirements.

We attempt to solve the puzzle and find that it works as expected.

Side-by-side screenshots of the River Crossing Puzzle web application showing two game states. The left screenshot shows the initial state with a farmer on the left bank, and fox, chicken, and grain items listed below, with a blue river in the center and right bank on the right. The right screenshot shows a game state after moves with the farmer on the right bank and a success message 'Congratulations! You won in 7 moves!' displayed at the bottom. Both screens have a yellow 'Start Over' button and show move counts.

Figure 11: River Crossing Puzzle Web App

Conclusion

This post shows how AWS’s open-source AI-DLC workflow, guided by Amazon Q Developer’s Project Rules feature, helps developers build applications with structured oversight and transparency.

Using a River Crossing Puzzle web application as an example, the walk-through illustrates how AI-DLC methodology adapts its rigor based on project complexity, skipping unnecessary stages for simple applications while maintaining comprehensive processes for complex projects. Throughout each stage, AI-DLC enforces “human-in-the-loop” behavior, requiring user approval at critical checkpoints, asking clarifying questions, and maintaining complete audit trails for traceability.

The exercise successfully demonstrates how AI-DLC balances AI automation with human oversight, enhancing productivity without sacrificing quality or control. By following this structured, repeatable methodology, development teams can leverage generative AI’s capabilities while ensuring humans remain in charge of architectural decisions and implementation approaches. This framework provides the necessary guardrails for responsible and effective AI-assisted software development across projects of varying complexity.

Cleanup

We did not create any AWS resources in this walk-through, so no AWS cleanup is needed. You may cleanup your project workspace at your discretion.

Ready to get started? Visit our GitHub repository to download the AI-DLC workflow and join the AI-Native Builders Community to contribute to the future of software development.

About the authors:

Raja SP

Raja is a Principal Solutions Architect at AWS, where he leads Developer Transformation Programs. He has worked with more than 100 large customers, helping them design and deliver mission critical systems built on modern architectures, platform engineering practices, and Amazon inspired operating models. As generative AI reshapes the software development landscape, Raja and his team created the AI Driven Development Lifecycle (AI-DLC) — an end to end, AI native methodology that re-imagines how large teams collaboratively build production-grade software in the AI era.

Raj Jain

Raj is a Senior Solutions Architect, Developer Specialist at AWS. Prior to this role, Raj worked as a Senior Software Development Engineer at Amazon, where he helped build the security infrastructure underlying the Amazon platform. Raj is a published author in the Bell Labs Technical Journal, and has also authored IETF standards, AWS Security blogs, and holds twelve patents

Siddhesh Jog

Siddhesh is a Senior Solutions Architect at AWS. He has worked in multiple industries in a wide variety of roles and is passionate about all things technology. At AWS Siddhesh is most excited to help customers transition to the AI Driven Development Lifecycle and enable them to build applications rapidly in a secure, complaint and cost efficient cloud environment.

Will Matos

Will Matos is a Principal Specialist Solutions Architect with AWS’s Next Generation Developer Experience (NGDE) team, revolutionizing developer productivity through Generative AI, AI-powered chat interfaces, and code generation. With 27 years of technology, AI, and software development experience, he collaborates with product teams and customers to create intelligent solutions that streamline workflows and accelerate software development cycles. A thought leader engaging early adopters, Will bridges innovation and real-world needs .

Open-Sourcing Adaptive Workflows for AI-Driven Development Life Cycle (AI-DLC)

Post Syndicated from Will Matos original https://aws.amazon.com/blogs/devops/open-sourcing-adaptive-workflows-for-ai-driven-development-life-cycle-ai-dlc/

AI-Driven Development Life Cycle (AI-DLC) holds the promise of unlocking the full potential of AI in software development. By emphasizing AI-led workflows and human-centric decision-making, AI-DLC can deliver velocity and quality. However, realizing these gains hinges on how organizations effectively integrate AI into their engineering workflows.

Through our work with engineering teams across industries, we have identified three recurring challenges. These challenges consistently limit the effectiveness of AI in accelerating modern software development. The first challenge is one-size-fits-all workflows. These workflows force every project through the same rigid sequence of steps. The second challenge is the lack of flexible depth in workflow stages. This leads to over-engineering or insufficient rigor. The third challenge is tools that over-automate. These tools unintentionally divert humans away from critical validation and oversight responsibilities.

Achieving true, sustainable productivity requires the process and AI coding agents to become adaptive to context, flexible in depth, and collaborative by design. In this blog, we’ll show you how AI-DLC’s core principles address these three challenges, transforming them from productivity blockers into opportunities for adaptive, human-centered development. We’ll describe how AI-DLC enables workflows that adapt to the problem at hand by intelligently selecting stages, modulating depth, and embedding human oversight at every critical decision point.

We will also introduce our open-source Amazon Q Developer/Kiro Rules implementation, which brings AI-DLC principles to life through adaptive workflow scaffolds. This allows you to start applying these principles in your own projects and experience AI-native development that accelerates delivery without compromising engineering discipline or human judgment.

How does AI-DLC address these challenges?

Let’s explore how AI-DLC addresses these challenges.

1. The “One-Size-Fits-All” Workflow Problem

Software development has never been a linear process. In practice, different projects follow distinct pathways with their own checkpoints and deliverables. Consider these examples:

  • A simple defect fix doesn’t require elaborate requirements analysis and planning
  • A pure infrastructure porting project doesn’t warrant application design with domain modeling
  • A new feature or service addition demands different steps than applying a security patch

Yet, many modern Agentic coding tools provide hard-wired, opinionated workflows that ignore this diversity. Regardless of intent or scope, every project is forced through the same rigid sequence of steps—even when some add little or no value. This rigidity introduces friction, wastes time, and reduces productivity. The result: artificial ceremonies, unnecessary artifacts, redundant approvals, and process overhead that impede velocity.

How AI-DLC addresses this challenge:
AI-DLC addresses this challenge through the Principle 10 (No Hard-Wired, Opinionated SDLC Workflows) as defined in the AI-DLC Method Definition Paper.

“AI-DLC avoids prescribing opinionated workflows for different development pathways (such as new system development, refactoring, defect fixes, or microservice scaling). Instead, it adopts a truly AI-First approach where AI recommends the Level 1 Plan based on the given pathway intention.“

2. Lack of Flexible Depth Within Each Stage

True adaptivity must go beyond the breadth of a workflow and extend into its depth and intensity. This is how human experts intuitively plan software projects today.

Even when workflows are flexible, many tools fail to modulate the depth of engagement at each stage. For example, building a lightweight utility function doesn’t require full-scale Domain-Driven Design or detailed architectural modeling. When an AI coding agent compels teams to follow these steps regardless of need, the consequence is wasted effort and an over-engineered product. Developers spend cycles reviewing artifacts as the tools dictate rather than delivering business value.

How AI-DLC addresses this challenge:
Through the same principle 10, AI-DLC adapts both the breadth (choice of stages) and the depth of each stage to match the complexity of the intent and context. For example, the complexity of the requirements determines whether a conceptual design is sufficient or whether a full architectural deep dive is required in the Design stage.

Humans validate and adjust this AI-proposed breadth and depth, ensuring that each stage’s rigor matches the scope of the challenge. This elasticity—balancing breadth and depth—is essential for sustaining true velocity without sacrificing engineering discipline.

3. Tools that Reduce the Emphasis on Human Oversight

As AI tools automate more of the Software Development Life Cycle (SDLC), a new risk has emerged: process atrophy. Developers, excited by automation, often drift into passive execution—allowing AI to “decide everything.” The result is a loss of reflection, weakened oversight, and erosion of shared understanding. AI tools must not only automate work but also amplify the significance of human judgment. They should remind practitioners that “human in the loop” is not a checkbox—it is the cornerstone of trust, accountability, and correctness in AI-native development. Equally critical are the rituals and rhythms that sustain collaborative engineering.

How AI-DLC addresses this challenge:
AI-DLC addresses this challenge by requiring a collaborative human-in-the-loop cycle at every stage of the workflow. In this loop, AI generates a plan to execute a task, and relevant stakeholders assemble, review, and validate it.

These rituals, defined as Mob Elaboration and Mob Construction in AI-DLC, ensure that AI’s suggestions are not blindly accepted. Approved plans are executed, and stakeholders again review and validate the final artifacts. The AI-DLC workflow records every human action and approval, embedding reflection to ensure that humans remain the compass, guiding AI’s acceleration.

Circular workflow diagram showing AI-DLC collaboration cycle. Starting at top: Humans Provide Task (orange person icon) , arrow to AI Creates Plan and Seeks Clarification (blue brain icon), arrow to Humans Provide Clarification (orange person icon), arrow to AI Refines Plan (blue brain icon), arrow to Humans Approve Plan (orange person icon), arrow to AI Executes Plan (blue brain icon), arrow to Humans Verify Outcome (orange person icon), completing the cycle back to the start. The diagram illustrates iterative human-AI collaboration with humans making decisions and AI performing execution tasks.

Figure 1: AI-DLC workflow: Humans decide and validate, AI plans and executes.

Effective tooling must therefore emphasize:

  • Promoting for stakeholder collaboration: The system should explicitly call for collaborative rituals involving stakeholders
  • Auditability: Every AI-generated plan and artifact should surface rationale and invite review, recording every human oversight and interaction
  • Flow awareness: Tools should detect when automation races ahead of human validation and deliberately slow down to emphasize critical checkpoints

The goal is not to suppress automation but to embed critical human ownership.

From Principles to Practice

The ideas we outlined — adaptive workflows, flexible depth, and embedded human oversight — are compelling in theory and validated by all engineering teams we’ve engaged. The critical question is: How do we operationalize these ideas into practice without reintroducing the rigidity we seek to eliminate?

One approach is manual prompt engineering: crafting structured prompts that guide AI assistants through the AI-DLC workflow step by step. Each prompt encodes the role AI should assume, the task at hand, the governance requirements, and the audit trail expectations. This structured approach transforms a simple AI interaction into a disciplined workflow that embodies AI-DLC principles.

This approach, while promising, faces its own limitations. Crafting intricate prompts demands discipline and expertise, posing barriers to widespread adoption. Moreover, humans become responsible for maintaining workflow adaptability, selecting the appropriate prompt at the right moment, and ensuring collaborative checkpoints are honored. This places the burden of orchestration back on practitioners, diverging from our core principle of truly AI-native development, where AI itself drives adaptive decision-making.

The question arises: How can we embed AI-DLC principles directly into the execution layer, making adaptivity and collaboration inherent properties of the system rather than manual responsibilities?

Steering for Productivity

The answer lies in workflow scaffolds. These are Rules or Steering customizations for AI Coding Agents. They operationalize AI-DLC principles within the tools. This is done while maintaining transparency, audibility, and modifiability. Our implementation uses Rules/Steering Files. These serve as the foundation of this execution layer. It transforms AI from a passive assistant into an adaptive decision engine.

Rather than requiring developers to craft elaborate prompts, AI-Driven development begins with a simple statement of intent. From there, the workflow scaffolds evaluate context, assess complexity, and dynamically construct an appropriate development pathway. The core workflow definition, including a library of stages and decision heuristics for when and how to apply them, empowers AI to continuously tailor the development process to the nature of the work at hand.

Each AI-DLC phase (Inception, Construction, Operations) evaluates the depth at which it should execute, resulting in a process that adapts to the problem rather than forcing the problem to adapt to the process. This approach yields several critical outcomes:

  1. Adaptive decisioning: The workflow conforms to the problem’s shape, intelligently skipping or deepening stages based on contextual assessment rather than predetermined rules.
  2. Transparent checkpoints: Human approvals are embedded at every decision gate, preserving oversight while maintaining velocity. The system doesn’t just automate; it orchestrates collaboration.
  3. End-to-end traceability: Every artifact, decision, and conversation is logged, creating a continuous, inspectable trail of reasoning that supports both accountability and continuous improvement.

The result is a process that is context-aware, scalable, and self-correcting – capable of supporting everything from a single-line defect fix to a comprehensive system modernization, all while maintaining the rigor and human judgment that define engineering excellence.

Build, Test, and Evolve with Us

We’re open-sourcing the AI-DLC workflow, implemented as Amazon Q Rules and Kiro Steering Files, so organizations everywhere can experience AI-DLC in practice and build production-grade systems. We invite developers, architects, and engineering leaders to:

  1. Apply the steering rules in real-world projects, whether brownfield or greenfield. Refer to our companion AI-DLC workflow walkthrough blog for step-by-step instructions on how to build using AI-DLC in Amazon Q Developer.
  2. Observe how the process adapts to your project’s size, scope, and intent.
  3. Share your experience through our GitHub repository, where you can open issues, propose improvements, and contribute ideas.

Your feedback will help evolve this into a foundation for AI-native software development – one that accelerates delivery without sacrificing rigor or human judgment. Together, we can redefine what software engineering looks like in the age of AI: not scripted but steered.

Conclusion

AI-DLC addresses multiple challenges limiting AI’s effectiveness in software development such as rigid workflows, inflexible workflow depth, and tools that reduce human oversight. AI-DLC enables adaptive workflows that intelligently select stages, modulate depth, and embed human oversight at critical decision points. This approach, implemented through open-source tools like Amazon Q Developer Rules and Kiro Steering, accelerates delivery while maintaining engineering discipline and human judgment.

AI-DLC emphasizes human oversight and collaboration in AI-driven software development. Workflow scaffolds, embed AI-DLC principles into the execution layer, enabling adaptive decision-making, transparent checkpoints, and end-to-end traceability. Open-sourcing the AI-DLC workflow allows organizations to experience AI-DLC in practice and contribute to its evolution.

Ready to get started? Visit our GitHub repository to download the AI-DLC workflow and join the AI-Native Builders Community to contribute to the future of software development.

 

About the authors:

Raja SP

Raja is a Principal Solutions Architect at AWS, where he leads Developer Transformation Programs. He has worked with more than 100 large customers, helping them design and deliver mission critical systems built on modern architectures, platform engineering practices, and Amazon inspired operating models. As generative AI reshapes the software development landscape, Raja and his team created the AI Driven Development Lifecycle (AI-DLC) — an end to end, AI native methodology that re-imagines how large teams collaboratively build production-grade software in the AI era.

Raj Jain

Raj is a Senior Solutions Architect, Developer Specialist at AWS. Prior to this role, Raj worked as a Senior Software Development Engineer at Amazon, where he helped build the security infrastructure underlying the Amazon platform. Raj is a published author in the Bell Labs Technical Journal, and has also authored IETF standards, AWS Security blogs, and holds twelve patents

Siddhesh Jog

Siddhesh is a Senior Solutions Architect at AWS. He has worked in multiple industries in a wide variety of roles and is passionate about all things technology. At AWS Siddhesh is most excited to help customers transition to the AI Driven Development Lifecycle and enable them to build applications rapidly in a secure, complaint and cost efficient cloud environment.

Will Matos

Will Matos is a Principal Specialist Solutions Architect with AWS’s Next Generation Developer Experience (NGDE) team, revolutionizing developer productivity through Generative AI, AI-powered chat interfaces, and code generation. With 27 years of technology, AI, and software development experience, he collaborates with product teams and customers to create intelligent solutions that streamline workflows and accelerate software development cycles. A thought leader engaging early adopters, Will bridges innovation and real-world needs.

Introducing the AWS Infrastructure as Code MCP Server: AI-Powered CDK and CloudFormation Assistance

Post Syndicated from Idriss Laouali Abdou original https://aws.amazon.com/blogs/devops/introducing-the-aws-infrastructure-as-code-mcp-server-ai-powered-cdk-and-cloudformation-assistance/

Streamline your AWS infrastructure development with AI-powered documentation search, validation, and troubleshooting

Introduction

Today, we’re excited to introduce the AWS Infrastructure-as-Code (IaC) MCP Server, a new tool that bridges the gap between AI assistants and your AWS infrastructure development workflow. Built on the Model Context Protocol (MCP), this server enables AI assistants like Kiro CLI, Claude or Cursor to help you search AWS CloudFormation and Cloud Development Kit (CDK) documentation, validate templates, troubleshoot deployments, and follow best practices – all while maintaining the security of local execution.

Whether you’re writing AWS CloudFormation templates or AWS Cloud Development Kit (CDK) code, the IaC MCP Server acts as an intelligent companion that understands your infrastructure needs and provides contextual assistance throughout your development lifecycle.

The Model Context Protocol (MCP) is an open standard that enables AI assistants to securely connect to external data sources and tools. Think of it as a universal adapter that lets AI models interact with your development tools while keeping sensitive operations local and under your control.

The IaC MCP Server provides nine specialized tools organized into two categories:

Remote Documentation Search Tools

These tools connect to the AWS Knowledge MCP backend to retrieve relevant, up-to-date information:

  1.  search_cdk_documentation
    Search the AWS CDK knowledge base for APIs, concepts, and implementation guidance.
  2. search_cdk_samples_and_constructs
    Discover pre-built AWS CDK constructs and patterns from the AWS Construct Library.
  3. search_cloudformation_documentation
    Query CloudFormation documentation for resource types, properties, and intrinsic functions.
  4. read_cdk_documentation_page
    Retrieve and read full documentation pages returned from searches or provided URLs.

Local Validation and Troubleshooting Tools

These tools run entirely on your machine

  1. cdk_best_practices
    Access a curated collection of AWS CDK best practices and design principles.
  2. validate_cloudformation_template
    Perform syntax and schema validation using cfn-lint to catch errors before deployment.
  3. check_cloudformation_template_compliance
    Run security and compliance checks against your templates using AWS Guard rules and cfn-guard.
  4. troubleshoot_cloudformation_deployment
    Analyze CloudFormation stack deployment failures with integrated CloudTrail event analysis. This tool will use your AWS credentials to analyze your stack status.
  5. get_cloudformation_pre_deploy_validation_instructions
    Returns instructions for CloudFormation’s pre-deployment validation feature, which validates templates during change set creation.

Key Use Cases

  1. Intelligent Documentation Assistant

Instead of manually searching through documentation, ask your AI assistant natural language questions:

“How do I create an S3 bucket with encryption enabled in CDK?”

The server searches CDK best practic and samples, returning relevant code examples and explanations.

     2. Proactive Template Validation

Before deploying infrastructure changes:

User: “Validate my CloudFormation template and check for security issues”

AI Agent: [Uses validate_cloudformation_template and check_cloudformation_template_compliance]

“Found 2 issues: Missing encryption on EBS volumes,

and S3 bucket lacks public access block configuration”

 3. Rapid Deployment Troubleshooting

When a stack deployment fails:

User: “My stack ‘stack_03’ in us-east-1 failed to deploy. What happened?”

AI Agent: [Uses troubleshoot_stack_deployment with CloudTrail integration]

“The deployment failed due to insufficient IAM permissions.

CloudTrail shows AccessDenied for ec2:CreateVpc.

You need to add VPC permissions to your deployment role.”

     4. Learning and Exploration

New to AWS CDK? The server helps you discover constructs and patterns:

User: “Show me how to build a serverless API”

AI Agent: [Searches CDK constructs and samples]

“Here are three approaches using API Gateway + Lambda…”

Architecture and Security

Security Design

Local Execution: The MCP server runs entirely on your local machine using uv (the fast Python package manager). No code or templates are sent to external services except for documentation searches.

AWS Credentials: The server uses your existing AWS credentials (from ~/.aws/credentials, environment variables, or IAM roles) to access CloudFormation and CloudTrail APIs. This follows the same security model as the AWS CLI.

stdio Communication: The server communicates with AI assistants over standard input/output (stdio), with no network ports opened.

Minimal Permissions: For full functionality, the server requires read-only access to CloudFormation stacks and CloudTrail events—no write permissions needed for validation and troubleshooting workflows.

Getting Started

Prerequisites

  • Python 3.10 or later
    uv package manager
    AWS credentials configured locally
    MCP-compatible AI client (e.g., Kiro CLI, Claude Desktop)

Configuration

Configure the MCP server in your MCP client configuration. For this blog we will focus on Kiro CLI. Edit .kiro/settings/mcp.json):

{
  "mcpServers": {
    "awslabs.aws-iac-mcp-server": {
      "command": "uvx",
      "args": ["awslabs.aws-iac-mcp-server@latest"],
      "env": {
        "AWS_PROFILE": "your-named-profile",
        "FASTMCP_LOG_LEVEL": "ERROR"
      },
      "disabled": false,
      "autoApprove": []
    }
  }
}

Security Considerations

Privacy Notice: This MCP server executes AWS API calls using your credentials and shares the response data with your third-party AI model provider (e.g., Amazon Q, Claude Desktop, Cursor, VS Code). Users are responsible for understanding your AI provider’s data handling practices and ensuring compliance with your organization’s security and privacy requirements when using this tool with AWS resources.

IAM Permissions

The MCP server requires the following AWS permissions:

For Template Validation and Compliance:

  • No AWS permissions required (local validation only)

For Deployment Troubleshooting:

  • cloudformation:DescribeStacks
  • cloudformation:DescribeStackEvents
  • cloudformation:DescribeStackResources
  • cloudtrail:LookupEvents (for CloudTrail deep links)

Example IAM policy:

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": [
        "cloudformation:DescribeStacks",
        "cloudformation:DescribeStackEvents",
        "cloudformation:DescribeStackResources",
        "cloudtrail:LookupEvents"
      ],
      "Resource": "*"
    }
  ]
}

Example Use Case With Kiro CLI

IMPORTANT: Ensure you have satisfied all prerequisites before attempting these commands.

1. With the mcp.json file correctly set, try to run a sample prompt. In your terminal, run kiro-cli chat to start using Kiro-cli in the CLI.

Figure 1: Kiro-CLI with AWS IaC MCP server

Figure 1: Kiro-CLI with AWS IaC MCP server

Scenarios:

  • “What are the CDK best practices for Lambda functions?”

Figure 2 Search the CDK best practices for Lambda functions

Figure 2: Search the CDK best practices for Lambda functions

  • “Search for CDK samples that use DynamoDB with Lambda”

Figure 3: Search for CDK samples that use DynamoDB with Lambda

Figure 3: Search for CDK samples that use DynamoDB with Lambda

  • “Validate my CloudFormation template at ./template.yaml”

Figure 4: Validate my CloudFormation template with AWS IaC MCP Server

Figure 4: Validate my CloudFormation template with AWS IaC MCP Server

  • “Check if my template complies with security best practices”

Figure 5: Check if my template complies with security best practices with AWS IaC MCP Server

Figure 5: Check if my template complies with security best practices with AWS IaC MCP Server

Best Practices

  • Start with Documentation Search: Before writing code, search for existing constructs and patterns
  • Validate Early and Often: Run validation tools before attempting deployment
  • Check Compliance: Use check_template_compliance to catch security issues during development
  • Leverage CloudTrail: When troubleshooting, the CloudTrail integration provides detailed failure context
  • Follow CDK Best Practices: Use the cdk_best_practices tool to align with AWS recommendations

What’s Next?

The IAC MCP Server represents a new paradigm in the AI agentic workflow infrastructure development – one where AI assistants understand your tools, help you navigate complex documentation, and provide intelligent assistance throughout the development lifecycle.

Get Involved

The AWS IaC MCP Server is available now:

  • Documentation and GitHub Repository: aws-iac-mcp-server
  • Feedback: We welcome issues and pull requests! Or respond to our IaC survey here.

Ready to supercharge your infrastructure as code development? Install the IaC MCP Server today and experience AI-powered assistance for your AWS CDK and CloudFormation workflows.

Have questions or feedback? Reach out to the blog authors on the AWS Developer Forums.

About Authors

Idriss Laouali Abdou

Idriss is a Sr. Product Manager Technical on the AWS Infrastructure-as-Code team based in Seattle. He focuses on improving developer productivity through AWS CloudFormation and StackSets Infrastructure provisioning experiences. Outside of work, you can find him creating educational content for thousands of students, cooking, or dancing.

Brian Terry

Brian Terry, Senior WW Data & AI PSA, is an innovation leader with more than 20 years of experience in technology and engineering. Brian is pursuing a PhD in computer science at the University of North Dakota and has spearheaded generative AI projects, optimized infrastructure scalability, and driven partner integration strategies. He is passionate about leveraging technology to deliver scalable, resilient solutions that foster business growth and innovation.