> ## Documentation Index
> Fetch the complete documentation index at: https://launchdarkly.com/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Automating the experimentation lifecycle with AWS DevOps Agent

**Developer**

**Federal docs**

**EU docs**

This guide explains how to connect AWS DevOps Agent, LaunchDarkly, GitHub Actions, and Kiro to automate experiments and guarded rollouts.

After you complete these steps, AWS DevOps Agent can:

* Read and manage LaunchDarkly feature flags, experiments, and guarded rollouts through the LaunchDarkly hosted Model Context Protocol (MCP) server
* Trigger Kiro CLI headless through GitHub Actions to implement a flagged code change and open a pull request
* Review the pull request for release readiness
* Merge the pull request and trigger deployment through GitHub Actions workflows it dispatches

## Prerequisites

To complete this guide, you must have the following:

* A LaunchDarkly account. Sign up through [AWS Marketplace](https://aws.amazon.com/marketplace/seller-profile?id=0f587861-6400-4321-b49e-eedcd4c645b8) for a 30-day free trial, or sign up at [launchdarkly.com](https://app.launchdarkly.com/signup).
* An AWS account with access to AWS DevOps Agent. Region availability applies. For more information, read [Getting started with AWS DevOps Agent](https://docs.aws.amazon.com/devopsagent/latest/userguide/getting-started-with-aws-devops-agent.html).
* A GitHub user or organization account with admin permissions and authorization to install GitHub Apps.
* A target repository that contains the application you want to experiment on.
* A Kiro subscription that permits API key generation: Pro, Pro+, Pro Max, or Power. When your Kiro account is centrally administered, ask your Kiro administrator to enable API key generation first.

> [!NOTE]
>
> **Guarded rollouts are available to customers on select plans**
>
> Guarded rollouts require an Enterprise plan with the Guardian add-on. All accounts include a limited trial. To learn more, read [Guarded rollouts](https://launchdarkly.com/docs/home/releases/guarded-rollouts).
>
> Experimentation is available on every plan. Without guarded rollouts, you can still run experiments and view reports, but you must roll out the winning variation manually.

## Concepts

This topic explains how the connected tools work together, how registration and Agent Spaces relate, and the principle that the agent follows.

### How the pieces fit together

In this guide, "the agent" means AWS DevOps Agent, including the custom agent that you create in Step 7.

The integration connects five parts:

* **AWS DevOps Agent:** Connects to LaunchDarkly and GitHub, hosts the custom agent, and reviews pull requests for release readiness.
* **LaunchDarkly hosted MCP server:** Gives the agent tools to query flag state, read targeting rules, list flags, manage experiments, and drive guarded rollouts.
* **GitHub and GitHub Actions:** Hold your repository and run the workflows that the agent dispatches to implement, merge, and deploy changes.
* **Kiro CLI:** Implements the code change inside a GitHub-hosted runner. The CLI runs headless, without an interactive session.
* **Orchestration skill:** Holds the instructions for the lifecycle. You attach the skill and the LaunchDarkly MCP tools to a custom agent, which runs the lifecycle from goal to report.

GitHub holds the state, and each workflow run is the task record. The integration needs no container and no state store.

### Account-level registration and Agent Spaces

You register LaunchDarkly and GitHub with AWS DevOps Agent once per AWS account, and all Agent Spaces in that account share each registration. An Agent Space is the workspace where the agent works with the connected tools. It's also the workspace where you start chat sessions. You attach a registration to your Agent Space because the agent requires it to use the registration.

### Experiments and guarded rollouts

The agent always runs an experiment before it starts a guarded rollout. The experiment confirms that a change works on a small slice of traffic, and the guarded rollout then expands the change gradually. Here are the details of each configuration:

* **Experiment:** Compares a treatment against a control on a primary metric, with guardrail metrics that watch for harm. The agent uses one primary metric and a fixed 50/50 split across 10% of traffic.
* **Guarded rollout:** Progressively increases traffic to the winning variation while LaunchDarkly monitors the same metrics for regressions. The agent configures each metric to roll back automatically on a regression.

To learn more, read [Experimentation](https://launchdarkly.com/docs/home/experimentation) and [Guarded rollouts](https://launchdarkly.com/docs/home/releases/guarded-rollouts).

## Step 1: Enable AWS DevOps Agent and create an Agent Space

The Agent Space is the workspace where you attach the LaunchDarkly MCP server and the GitHub repository that the agent works with. You also start the chat sessions that validate each connection there.

1. Follow the instructions in [Getting started with AWS DevOps Agent](https://docs.aws.amazon.com/devopsagent/latest/userguide/getting-started-with-aws-devops-agent.html) to enable the agent and create the space.
2. Turn on **Enable DevOps Agent Actions** in the **Agent Actions** section. The agent requires Agent Actions for write operations, such as updating a flag. With Agent Actions on, the agent asks a person to approve each write operation before it runs, including LaunchDarkly MCP write calls. Without Agent Actions, write operations fail. If you skip this when you create the space, turn it on later from the Agent Space's **Configuration** tab.
3. Under **Service role for agent actions**, choose how to set up the AWS Identity and Access Management (IAM) role that the agent uses for write actions. To have AWS DevOps Agent create the role for you, select **Auto-create a new DevOps Agent Actions role**.

## Step 2: Connect the LaunchDarkly MCP server

Register the LaunchDarkly hosted MCP server with AWS DevOps Agent and attach it to your Agent Space. This gives the agent the ability to query flag state, read targeting rules, list flags, manage experiments, and drive guarded rollouts.

### Step 2.1: Register the LaunchDarkly MCP server at the account level

You register an MCP server once per AWS account, and all Agent Spaces in that account share it. To register the LaunchDarkly MCP server with AWS DevOps Agent:

1. Sign in to the AWS DevOps Agent console.

2. In the side navigation, open **Capability Providers**.

3. Under **Available**, find **MCP Server** and click **Register**.

4. Enter the server details:

   * **Name:** `LaunchDarkly`
   * **Endpoint URL:** `https://mcp.launchdarkly.com/mcp/launchdarkly`
   * **Description:** `LaunchDarkly feature flag management MCP server`
   * Check **Enable Dynamic Client Registration**. This lets AWS DevOps Agent register itself with the LaunchDarkly authorization server using OAuth.

5. Click **Next**.

AWS DevOps Agent registers the LaunchDarkly MCP server at the account level.

> [!NOTE]
>
> **Every Agent Space acts as the member who authorized the connection**
>
> The LaunchDarkly MCP server acts with the permissions of the LaunchDarkly member who authorizes the connection. All Agent Spaces that use this registration share that one connection. We recommend that you authorize with a dedicated LaunchDarkly member for the integration instead of an individual's account. Give that member a role that grants access to the flags, metrics, experiments, and guarded rollouts in the projects the agent works with. To learn more, read [Member role concepts](https://launchdarkly.com/docs/home/account/roles/role-concepts).

### Step 2.2: Add the MCP server to your Agent Space

After you register the LaunchDarkly MCP server at the account level, attach it to your Agent Space to allow the agent to use its tools. To add the server to your Agent Space and choose which tools the agent can use:

1. In the AWS DevOps Agent console, select your Agent Space.

2. Select the **Capabilities** tab.

3. Under **MCP Servers**, click **Add**.

4. Select the LaunchDarkly MCP server that you registered.

5. Select a tool access option:

   * **Allow all tools:** Gives the agent every LaunchDarkly MCP tool.
   * **Select specific tools:** Limits the agent to the tools you select. We recommend this option for production.

6. Under **Webhook authentication type**, select **API Key**. AWS DevOps Agent expects each webhook event to include the key as a bearer token in the `Authorization` header.

7. Click **Save**. The console confirms that it created the association and shows the **Webhook URL** and **API Key** under **Webhook Configuration**.

8. Record the webhook URL and API key. AWS DevOps Agent shows the API key only once. Record it before you leave the page. We recommend that you store the API key securely and never commit it to version control. If you lose the API key, rotate the webhook from the **Capabilities** tab to generate a new one. To learn more, read [Invoking DevOps Agent through Webhook](https://docs.aws.amazon.com/devopsagent/latest/userguide/configuring-integrations-and-knowledge-invoking-devops-agent-through-webhook.html).

9. (Optional) Create a webhook in LaunchDarkly that automatically opens an AWS DevOps Agent investigation when LaunchDarkly events occur. The agent uses a separate OAuth connection to call LaunchDarkly MCP tools. To learn more, read [Webhooks](https://launchdarkly.com/docs/home/infrastructure/webhooks.md). When you create the webhook:

   * Enter the URL you recorded as the webhook URL.
   * Add the following request header:

     ```text theme={null}
     Authorization: Bearer API-KEY-FROM-AWS-DEVOPS-AGENT
     ```

### Step 2.3: Validate the LaunchDarkly connection

To confirm that your Agent Space can reach LaunchDarkly, start a new chat or investigation session in the Agent Space and ask:

> "List the feature flags in the `YOUR-PROJECT-KEY` project in the production environment."

When the agent returns flag data, the connection is live.

## Step 3: Connect GitHub to AWS DevOps Agent

Connecting GitHub gives AWS DevOps Agent access to the target repository for reading code, running release readiness review, and dispatching workflows. GitHub Actions handles execution. Kiro CLI runs headless inside a GitHub-hosted runner, and the agent dispatches the workflow that runs it through the same native GitHub integration.

Because GitHub holds the state and the workflow run is the task record, this configuration needs no container and no state store.

GitHub permissions cover every capability the lifecycle needs:

* **Implement a change behind a flag or trigger deployment:** Dispatch workflows, which requires `workflows: write`.
* **Check implementation or deployment progress:** Read workflow runs, which requires `actions: read`.

### Step 3.1: Register GitHub at the account level

You register GitHub once per AWS account, and all Agent Spaces in that account share the registration. To register GitHub at the account level and install the AWS DevOps Agent GitHub App on your target repository:

1. Sign in to the AWS DevOps Agent console.

2. Select the **Capabilities** tab.

3. Under **Pipeline**, click **Add**.

4. Select **GitHub** from the list of providers.

5. Select **User** or **Organization**, depending on the type of GitHub account you're connecting.

6. For an organization, enter the organization name exactly as it appears in GitHub. You must authorize and install the app on that same organization.

7. Under **GitHub App permissions**, select **Read & Write**.

   > [!NOTE]
   >
   > **The GitHub App requires Read & Write permissions**
   >
   > The agent must have `workflows: write` to dispatch the implementation and deployment workflows, `contents: write` to push Kiro's branch, and `pull-requests: write` to act on pull requests. With read-only access, the agent can review code but cannot trigger anything.

8. Click **Submit**. GitHub redirects you to sign in and authorize AWS DevOps Agent.

9. On the **Install & Authorize** page, select **Only select repositories**.

   > [!NOTE]
   >
   > **Install on the target repository only**
   >
   > Install the app only on a specific target repository, not on all repositories. This is the outermost boundary on what the agent can reach, and GitHub enforces it rather than your own configuration.

10. Select your target repository.

11. Click **Install & Authorize**.

### Step 3.2: Connect the repository to your Agent Space

To make the target repository available to your Agent Space:

1. In the AWS DevOps Agent console, select your Agent Space.
2. Select the **Capabilities** tab.
3. Under **Pipeline**, click **Add**.
4. Select **GitHub**.
5. Select the registration that you created in Step 3.1.
6. Select your target repository.
7. Click **Add**.

### Step 3.3: Confirm release readiness review is enabled

When you connect a repository, AWS DevOps Agent automatically adds it to the **Code Review and Automated Testing** section. This section checks each pull request before merge. To confirm that AWS DevOps Agent reviews every pull request:

1. Open **Code Review and Automated Testing** in your GitHub integration settings.
2. Confirm that **Auto trigger change review** is enabled for your repository. This setting runs a review each time a pull request is opened or updated and posts the findings as inline comments.
3. (Optional) Enable **Automated verification testing**. AWS DevOps Agent builds and tests the change in a managed environment during review.
4. Click **Save**.

> [!TIP]
>
> **Restrict reviews to specific branches**
>
> Under **Advanced settings**, you can restrict reviews to specific target branches with a regular expression. Use this when the repository also receives unrelated pull requests.

## Step 4: Prepare GitHub for headless Kiro runs

The implementation workflow runs Kiro CLI headless inside a GitHub-hosted runner, with no one present to sign in or approve actions. To prepare GitHub for these unattended runs, you allow GitHub Actions to open pull requests, generate a Kiro API key to replace the interactive browser login, and store the key as a repository secret that the workflow can use.

### Step 4.1: Allow GitHub Actions to create pull requests

By default, GitHub blocks Actions from opening pull requests. You must enable the **Allow GitHub Actions to create and approve pull requests** setting to allow the implementation workflow to open a pull request. Until you enable it, the workflow fails at its final step with the error "GitHub Actions is not permitted to create or approve pull requests."

This setting is separate from the `pull-requests: write` permission in the workflow file, and the workflow needs both.

To enable the setting:

1. In your repository, click **Settings**.

2. Select **Actions** > **General**.

3. Under **Workflow permissions**, select **Allow GitHub Actions to create and approve pull requests**.

   > [!NOTE]
   >
   > **An organization policy can disable this setting**
   >
   > When the checkbox is off, your organization enforces this setting. Enable it under **Organization Settings** > **Actions** > **General**.

4. Click **Save**.

### Step 4.2: Generate a Kiro API key

Kiro CLI needs an API key to authenticate when the implementation workflow runs it. Headless mode uses the key instead of the interactive browser login. When you set the `KIRO_API_KEY` environment variable, Kiro CLI skips interactive authentication entirely.

To create the API key that Kiro CLI uses to authenticate:

1. Log in to the [Kiro portal](https://app.kiro.dev).
2. Open your account settings.
3. Generate an API key.
4. Record the API key. You store it as a repository secret in Step 4.3.

> [!NOTE]
>
> **Administrator governance rules apply to headless sessions**
>
> Governance rules that your Kiro administrator sets, such as MCP server restrictions, model access policies, and web fetch permissions, apply to headless sessions exactly as they apply to interactive sessions.

### Step 4.3: Store the API key as a repository secret

Storing the API key as a repository secret makes it available to the workflow while keeping it separate from your workflow files. To store the key as a repository secret:

1. Navigate to **Settings** in your GitHub repository.
2. Select **Secrets and variables** > **Actions**.
3. Click **New repository secret**.
4. Name the secret `KIRO_API_KEY`.
5. Enter the API key you recorded in Step 4.2 as the secret value.
6. Click **Add secret**.

> [!WARNING]
>
> **Keep the API key out of workflow files and version control**
>
> Never put the key in a workflow file or commit it to version control. Rotate the key periodically. Revoke unused keys from the Kiro portal.

## Step 5: Add the Kiro agent and workflows

AWS DevOps Agent implements, merges, and deploys changes by dispatching workflows in your target repository. You commit the Kiro agent definition and the implementation and merge workflows, and you confirm that your deploy workflow can be dispatched. These files keep the agent's behavior under version control and code review.

### Step 5.1: Define the Kiro implementation agent

A Kiro custom agent defines a persona with a specific job, tools, and behavior rules. Committing the definition to your repository puts the agent's instructions and tool permissions under version control and code review, instead of a prompt assembled at runtime.

To define the agent, create a file named `.kiro/agents/flag-implementer.json` and add the following:

```json title="flag-implementer.json" theme={null}
{
  "name": "flag-implementer",
  "description": "Implements a single change gated behind a LaunchDarkly feature flag.",
  "prompt": "You implement one narrowly scoped change at a time, always gated behind the LaunchDarkly feature flag key supplied in the task. Requirements: (1) Evaluate the flag using the LaunchDarkly SDK already present in the repository; do not add a new SDK or a new client instance. (2) The control path must remain the default behavior when the flag is off or when flag evaluation fails. (3) Do not change flag configuration in LaunchDarkly — the flag already exists and is managed elsewhere. (4) Touch only the files required for this change. (5) Do not create commits, branches, or pull requests; the surrounding workflow handles version control. (6) If the task is ambiguous or would require a change outside the application code, stop and explain rather than guessing.",
  "tools": ["fs_read", "fs_write", "execute_bash"],
  "allowedTools": ["fs_read", "fs_write"],
  "permissions": {
    "rules": [
      { "capability": "fs_read", "match": ["./**"], "effect": "allow" },
      { "capability": "fs_write", "match": ["./**"], "effect": "allow" },
      {
        "capability": "fs_write",
        "match": [".git", ".git/**", ".github/**", ".kiro/**", "**/.gitattributes"],
        "effect": "deny"
      }
    ]
  }
}

```

The agent definition has three fields that control tool use:

* The `tools` field lists everything the agent can use.
* The `allowedTools` field lists the subset of tools that the agent can use without approval.
* The `permissions` field limits where the agent can read and write. It lets the agent read and write files in the repository, and it blocks writes to `.git`, `.github`, `.kiro`, and `.gitattributes` files. These paths control Git, the workflows, and the agent definition itself.

The run is unattended, with no one present to approve tool calls. For that reason, `allowedTools` pre-approves `fs_read` and `fs_write`, which lets the agent read and change files. `execute_bash` is not pre-approved, which means the agent cannot run a shell command without approval.

### Step 5.2: Add the implementation workflow

The agent dispatches this workflow instead of making a direct "implement code" tool call. The `workflow_dispatch` inputs are the contract between the agent and Kiro.

To add the workflow, create a file named `.github/workflows/kiro-implement.yml` and add the following:

```yaml title="kiro-implement.yml" theme={null}
name: Kiro Implement Behind Flag

on:
  workflow_dispatch:
    inputs:
      task_description:
        description: "What to implement"
        required: true
      flag_key:
        description: "LaunchDarkly flag key gating the change"
        required: true
      variation_details:
        description: "Behavior of the treatment variation"
        required: true

permissions:
  contents: write
  pull-requests: write

jobs:
  implement:
    runs-on: ubuntu-24.04
    timeout-minutes: 30
    steps:
      - uses: actions/checkout@v4
        with:
          persist-credentials: false

      - name: Install Kiro CLI
        run: curl -fsSL https://cli.kiro.dev/install | bash

      - name: Create working branch
        env:
          FLAG_KEY: ${{ inputs.flag_key }}
        run: |
          if [[ ! "$FLAG_KEY" =~ ^[A-Za-z0-9._-]+$ ]]; then
            echo "::error::Invalid flag key"
            exit 1
          fi
          BRANCH="experiment/${FLAG_KEY}-${GITHUB_RUN_ID}"
          echo "BRANCH=$BRANCH" >> "$GITHUB_ENV"
          git checkout -b "$BRANCH"
          git config user.email "kiro-agent@users.noreply.github.com"
          git config user.name "Kiro Agent"

      - name: Snapshot .git state
        run: |
          find .git -type f -print0 | sort -z \
            | xargs -0 sha256sum > "$RUNNER_TEMP/git-snapshot.sha256"

      - name: Implement the change
        env:
          KIRO_API_KEY: ${{ secrets.KIRO_API_KEY }}
          TASK_DESCRIPTION: ${{ inputs.task_description }}
          FLAG_KEY: ${{ inputs.flag_key }}
          VARIATION_DETAILS: ${{ inputs.variation_details }}
        run: |
          set -o pipefail
          kiro-cli chat \
            --agent flag-implementer \
            --no-interactive \
            "Task: ${TASK_DESCRIPTION}
             LaunchDarkly flag key: ${FLAG_KEY}
             Treatment variation: ${VARIATION_DETAILS}" \
            | tee "$RUNNER_TEMP/kiro-run.jsonl"

      - name: Commit and push
        env:
          GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
          TASK_DESCRIPTION: ${{ inputs.task_description }}
          FLAG_KEY: ${{ inputs.flag_key }}
        run: |
          # Refuse to proceed if Kiro wrote anywhere under .git/ — a tampered
          # .git/config (core.fsmonitor, core.hooksPath, remote URL, etc.)
          # could make the git commands below execute attacker-controlled code
          # with GH_TOKEN in the environment.
          find .git -type f -print0 | sort -z \
            | xargs -0 sha256sum > "$RUNNER_TEMP/git-snapshot-after.sha256"
          if ! diff -q "$RUNNER_TEMP/git-snapshot.sha256" "$RUNNER_TEMP/git-snapshot-after.sha256" >/dev/null; then
            echo "::error::.git contents changed during Kiro run — refusing to commit"
            diff "$RUNNER_TEMP/git-snapshot.sha256" "$RUNNER_TEMP/git-snapshot-after.sha256" || true
            exit 1
          fi
          GIT="git -c core.fsmonitor=false -c core.hooksPath=/dev/null"
          $GIT add -A
          if $GIT diff --staged --quiet; then
            echo "::error::Kiro produced no changes"
            exit 1
          fi
          $GIT commit -m "feat: ${TASK_DESCRIPTION} (flag: ${FLAG_KEY})"
          $GIT push "https://x-access-token:${GH_TOKEN}@github.com/${GITHUB_REPOSITORY}.git" "$BRANCH"

      - name: Open pull request
        env:
          GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
          TASK_DESCRIPTION: ${{ inputs.task_description }}
          FLAG_KEY: ${{ inputs.flag_key }}
        run: |
          gh pr create \
            --base main \
            --head "$BRANCH" \
            --title "feat: ${TASK_DESCRIPTION}" \
            --body "Implemented by Kiro CLI in headless mode.
            Gated behind LaunchDarkly flag ${FLAG_KEY}."

      - name: Upload run log
        if: always()
        uses: actions/upload-artifact@v4
        with:
          name: kiro-run-log
          path: ${{ runner.temp }}/kiro-run.jsonl


```

The workflow passes each input to the shell through an environment variable instead of writing `${{ inputs.* }}` directly into a `run:` script. GitHub Actions substitutes an expression into the script text before the shell runs. Written directly, quotes, backticks, or `$(...)` in an input run as commands. This matters because the agent writes the inputs from content it reads, and some of that content can come from untrusted sources. The workflow also rejects a flag key that contains anything other than letters, numbers, periods, underscores, or hyphens, because the flag key becomes part of the branch name.

The checkout step sets `persist-credentials: false`. Without it, `actions/checkout` stores the GitHub token in the repository's Git configuration, where Kiro could read it during its run. The workflow supplies the token only to the steps that push the branch and open the pull request.

The `--no-interactive` option makes the run headless. It prints the response to standard output and exits instead of opening a chat session. It requires a prompt argument.

> [!TIP]
>
> **Capture machine-readable run events**
>
> Add `--output-format stream-json` together with `--agent-engine v2` to capture machine-readable run events. Use the spelling `--agent-engine`. Streaming output requires the v2 or v3 engine and fails on v1.

The workflow also relies on two details that fail without producing an error.

> [!WARNING]
>
> **Two details prevent silent failures**
>
> * Keep `set -o pipefail`. Without it, the pipeline reports the exit status of `tee` instead of Kiro, which means a failed implementation does not stop the job and the job commits anyway.
> * Write the log to `$RUNNER_TEMP` instead of the working tree. `git add -A` picks up a log file inside the repository, which means the "no changes" check passes and the job commits the log instead of your code change.

### Step 5.3: Add the merge workflow and confirm the deploy workflow can be dispatched

The agent merges a pull request only after release readiness review passes. Routing the merge through its own workflow keeps the merge conditions, such as the base branch, merge method, and required checks, in version-controlled configuration instead of a one-off API call.

To add the merge workflow, create a file named `.github/workflows/merge-pr.yml` and add the following:

```yaml title="merge-pr.yml" theme={null}
name: Merge Experiment Pull Request

on:
  workflow_dispatch:
    inputs:
      pr_number:
        description: "Pull request number to merge"
        required: true

permissions:
  contents: write
  pull-requests: write

jobs:
  merge:
    runs-on: ubuntu-24.04
    steps:
      - name: Merge the pull request
        env:
          GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
          PR_NUMBER: ${{ inputs.pr_number }}
        run: |
          if [[ ! "$PR_NUMBER" =~ ^[0-9]+$ ]]; then
            echo "::error::Invalid pull request number"
            exit 1
          fi
          # Only merge PRs opened by the Kiro experiment workflow, which pushes
          # from branches named experiment/<flag>-<run-id>.
          HEAD_REF=$(gh pr view "$PR_NUMBER" \
            --repo "$GITHUB_REPOSITORY" \
            --json headRefName --jq .headRefName)
          if [[ ! "$HEAD_REF" =~ ^experiment/ ]]; then
            echo "::error::PR #$PR_NUMBER head branch '$HEAD_REF' is not an experiment/* branch"
            exit 1
          fi
          gh pr merge "$PR_NUMBER" \
            --repo "$GITHUB_REPOSITORY" \
            --squash --delete-branch

```

Next, confirm that your existing deployment workflow declares `workflow_dispatch` as a trigger because the agent needs it to start the workflow directly. The deployment workflow needs no other changes.

> [!NOTE]
>
> **Deployment does not start automatically on merge**
>
> A deployment workflow that uses only the `workflow_dispatch` trigger does not run automatically on merge. This is expected. The agent triggers deployment as its own explicit lifecycle step.

## Step 6: Protect and validate the repository

The workflow files and the agent definition set the limits on what the agent can do. You protect the `main` branch to keep those files under pull request review, then confirm that each connection works before the agent runs the full lifecycle.

### Step 6.1: Enable branch protection

The workflow files fix which branch the agent targets and which commands run, and the agent definition fixes which tools Kiro can use. Branch protection makes those files trustworthy.

> [!WARNING]
>
> **Branch protection secures the agent's configuration**
>
> Anyone who can push directly to `main` can silently change the agent definition or the workflows that run it, which changes what the autonomous agent can do. Branch protection is the security boundary for the agent's entire configuration.

To require pull requests and passing status checks on `main` and restrict direct pushes:

1. In your repository, click **Settings**.
2. Select **Branches**.
3. Add a branch protection rule for `main`.
4. Require a pull request before merging.
5. Require status checks to pass.
6. Restrict who can push directly to the branch.

### Step 6.2: Validate the GitHub configuration

The lifecycle depends on the GitHub integration and headless Kiro runs. Testing each of these on its own, before the agent runs the full lifecycle, isolates any problem to a single part.

To verify that AWS DevOps Agent can read your repository:

1. In the AWS DevOps Agent console, start a chat session in your Agent Space.
2. Ask the agent to list the open pull requests in your repository.

When the agent returns them, the GitHub integration is active.

To verify that the implementation workflow runs Kiro CLI headless and opens a pull request:

1. Navigate to your GitHub repository and click the **Actions** tab.

2. Select **Kiro Implement Behind Flag**, then click **Run workflow**.

   > [!NOTE]
   >
   > **Start a fresh run after you edit a workflow**
   >
   > When you edit a workflow between test attempts, start a fresh run with **Run workflow** instead of **Re-run jobs**. Re-running replays the original run's workflow file and commit. It ignores your edits, and the run fails the same way, which makes it look like the fix didn't work. You can recognize a re-run because its run ID matches the previous attempt.

3. Enter the following values for a small test task:

   * **What to implement:** "add a clarifying code comment to the flag evaluation helper"
   * **LaunchDarkly flag key gating the change:** Any existing flag key
   * **Behavior of the treatment variation:** "no behavior change"

4. Confirm that the job completes and opens a pull request.

5. Download the `kiro-run-log` artifact to see what Kiro did.

Finally, to remove the test resources:

1. Close the test pull request.
2. Delete its branch.

## Step 7: Create the custom agent with the orchestration skill

The orchestration skill tells the agent how to run the experimentation lifecycle, and the custom agent runs it end to end. With LaunchDarkly connected in Step 2 and GitHub and Kiro connected in Steps 3 to 6, you now create the skill and the custom agent.

### Step 7.1: Create the experiment-orchestration skill

The skill holds the instructions for the experimentation lifecycle. Its own steps are numbered separately from the steps in this guide. To create the skill:

1. In the AWS DevOps Agent console, create a new skill named `experiment-orchestration`. For instructions, read [Create a skill using the AWS DevOps Agent console](https://docs.aws.amazon.com/devopsagent/latest/userguide/about-aws-devops-agent-devops-agent-skills.html#creating-skills).
2. Paste the following skill text into the **Instructions** field.
3. Select which agents have access to the skill.

> **Orchestration skill text**
>
> ````text theme={null}
> ---
> 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).
>
> **Approvals:** if the LaunchDarkly environment requires approval for a change (for example, to turn a flag on or off, start or stop an experiment, or start a guarded rollout), create an approval request instead of the direct change. Tell the person who must review it. Continue only after `list-approval-requests` shows it approved, then apply it with `apply-approval-request` and go to the next step. If a reviewer rejects it, stop and report.
>
> **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, with `defaults` of `{"onVariation": 1, "offVariation": 1}` so that it serves false even when it is on, and `clientSideAvailability` of `{"usingEnvironmentId": true, "usingMobileKey": true}` so that every SDK can read it. Name it with a clear pattern like `exp-<metric>-<short-description>` (e.g. `exp-checkout-conversion-cta-color`), lowercase with hyphens, ~50 chars max. If the project has its own flag naming conventions (for example, a required prefix or case), follow them instead.
> 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 with control as the winner, then move to Phase 2. Stopping serves the winner to everyone, so a treatment winner would skip the guarded rollout.
> - **Significant + negative lift** → declare a loser, stop the iteration with control as the winner, turn the flag off (do not archive it while the code still evaluates it), skip Phase 2, go straight to the Step 8 report.
> - **No significance after a reasonable ceiling (e.g. 4 weeks)** → report "inconclusive, need more traffic", stop the iteration with control as the winner, 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, turn the flag off (do not archive it while the code still evaluates 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 from Experiment Report to Next Steps:
>
> ```markdown
> ## 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.
> ````

> [!NOTE]
>
> **Remove guarded rollout actions when your plan does not include guarded rollouts**
>
> When your LaunchDarkly plan does not include guarded rollouts, edit the skill to remove the guarded rollout actions. The workflow still runs experiments and produces reports, but rollout past the experiment phase becomes a manual decision.

### Step 7.2: Create the custom agent

The custom agent runs the lifecycle end to end. To create it and give it the LaunchDarkly MCP tools and the orchestration skill:

1. Create a custom agent in AWS DevOps Agent. For instructions, read [Custom Agent in AWS DevOps Agent](https://docs.aws.amazon.com/devopsagent/latest/userguide/custom-agents-creating-a-custom-agent.html#creating-a-custom-agent-using-the-form).

2. Enter the following system prompt for the agent:

   ```text theme={null}
   You are an experimentation agent that moves a product goal through a LaunchDarkly experiment and, if the experiment wins, a rollout. Load the experiment-orchestration skill and follow it as the source of truth for the procedure, using the LaunchDarkly MCP tools for every flag, metric, experiment, approval request, and rollout action. Never start a goal that a person did not ask for. At each step, give the output the skill specifies, and on every terminal outcome, deliver the report defined by the skill’s final step.
   ```

3. Attach the LaunchDarkly MCP tools to the agent.

4. Attach the `experiment-orchestration` skill to the agent.

### Step 7.3: Start an experiment

To start an experiment, state a goal in chat, for example "increase add-to-cart rate by 10%". The agent asks for the success metric and the target improvement when you don't provide them. The agent then:

* Generates and presents a hypothesis
* Creates a flag
* Dispatches the implementation workflow
* Merges the pull request after a clean review
* Triggers deployment
* Runs the experiment
* Starts a guarded rollout of the winning variation, with automatic rollback on a regression, when your plan includes guarded rollouts
* Produces a structured report on every final outcome

After you confirm the goal, the agent runs these stages in sequence. Before each write operation, such as creating a flag or starting an experiment, the agent asks you to approve it through Agent Actions. Otherwise, the agent stops and asks you a question only when it cannot recover from repeated failed release reviews, a deployment failure, or an inconclusive or losing experiment result.

When your LaunchDarkly environment requires approvals, the agent creates an approval request instead of making the change directly. This applies to changes such as turning a flag on, starting an experiment, or starting a guarded rollout. The agent continues after a reviewer approves the request, and stops and reports when a reviewer rejects it. To learn more, read [Approvals](https://launchdarkly.com/docs/home/releases/approvals).

## Conclusion

In this guide, you connected AWS DevOps Agent to LaunchDarkly and GitHub, and created a custom agent that runs the experimentation lifecycle. To learn more, read [Experimentation](https://launchdarkly.com/docs/home/experimentation) and [Guarded rollouts](https://launchdarkly.com/docs/home/releases/guarded-rollouts).

**Developer**

> [!NOTE]
>
> **Want to know more? Start a trial.**
>
> Your trial begins as soon as you sign up. Get started in minutes using the in-app Quickstart. You'll discover how easy it is to release, monitor, and optimize your software.\
> \\
>
> Want to try it out? [Start a trial](https://app.launchdarkly.com/signup).

**Federal docs**

**EU docs**
