> For the complete documentation index, see [llms.txt](https://developer.harness.io/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://developer.harness.io/ai-sre/ai-sre-for-administrators/set-up-change-management/sources/circleci.md).

# Configure CircleCI for Deploy Change Investigator

Send build and deployment data from CircleCI workflows to the [Deploy Change Investigator](/ai-sre/ai-sre-for-administrators/set-up-change-management/deploy-change-investigator.md) using webhook steps.

### Before you begin <a href="#before-you-begin" id="before-you-begin"></a>

* **Deploy Change Investigator setup:** Build and deploy webhook integrations created in AI SRE. Go to [Deploy Change Investigator](/ai-sre/ai-sre-for-administrators/set-up-change-management/deploy-change-investigator.md) to create webhook endpoints.
* **CircleCI project access:** Permission to edit `.circleci/config.yml` and manage environment variables.
* **Webhook URLs:** Build and deploy webhook URLs from the AI SRE integrations page.

***

### Store webhook URLs as environment variables <a href="#store-webhook-urls-as-environment-variables" id="store-webhook-urls-as-environment-variables"></a>

Store webhook URLs securely in CircleCI project settings:

1. Navigate to your project in the CircleCI dashboard
2. Click **Project Settings**
3. Select **Environment Variables**
4. Click **Add Environment Variable**
5. Create build webhook variable:
   * **Name:** `AISRE_BUILD_WEBHOOK_URL`
   * **Value:** Build webhook URL from AI SRE
6. Click **Add Environment Variable**
7. Create deploy webhook variable:
   * **Name:** `AISRE_DEPLOY_WEBHOOK_URL`
   * **Value:** Deploy webhook URL from AI SRE

***

### Configure build webhooks <a href="#configure-build-webhooks" id="configure-build-webhooks"></a>

Add a webhook step to your build job after artifacts are published.

#### Docker build workflow <a href="#docker-build-workflow" id="docker-build-workflow"></a>

```yaml
version: 2.1

orbs:
  docker: circleci/docker@2.4.0

jobs:
  build:
    docker:
      - image: cimg/base:stable
    steps:
      - checkout
      - setup_remote_docker:
          docker_layer_caching: true
      
      - run:
          name: Build Docker image
          command: |
            docker build -t registry.example.com/myapp:$CIRCLE_SHA1 .
      
      - run:
          name: Push Docker image
          command: |
            echo $DOCKER_PASSWORD | docker login -u $DOCKER_USERNAME --password-stdin registry.example.com
            docker push registry.example.com/myapp:$CIRCLE_SHA1
      
      - run:
          name: Send build webhook to AI SRE
          when: on_success
          command: |
            curl -X POST "$AISRE_BUILD_WEBHOOK_URL" \
              -H "Content-Type: application/json" \
              -d '{
                "artifact": {
                  "name": "registry.example.com/myapp",
                  "version": "'"$CIRCLE_SHA1"'"
                },
                "source": {
                  "commitSha": "'"$CIRCLE_SHA1"'",
                  "kind": "branch",
                  "value": "'"$CIRCLE_BRANCH"'",
                  "repository_url": "'"$CIRCLE_REPOSITORY_URL"'"
                },
                "service": {
                  "name": "'"$CIRCLE_PROJECT_REPONAME"'",
                  "version": "'"$CIRCLE_SHA1"'"
                },
                "buildId": "'"$CIRCLE_WORKFLOW_ID"'"
              }'

workflows:
  version: 2
  build-and-deploy:
    jobs:
      - build:
          filters:
            branches:
              only:
                - main
                - develop
```

***

### CircleCI environment variables <a href="#circleci-environment-variables" id="circleci-environment-variables"></a>

CircleCI provides these environment variables automatically:

| Variable                  | Description                  | Example                                    |
| ------------------------- | ---------------------------- | ------------------------------------------ |
| `CIRCLE_SHA1`             | Full commit SHA              | `ffac537e6cbbf934b08745a378932722df287a53` |
| `CIRCLE_BRANCH`           | Branch name                  | `main`                                     |
| `CIRCLE_PROJECT_REPONAME` | Repository name              | `myapp`                                    |
| `CIRCLE_PROJECT_USERNAME` | GitHub or Bitbucket username | `myorg`                                    |
| `CIRCLE_REPOSITORY_URL`   | Git repository URL           | `https://github.com/myorg/myapp`           |
| `CIRCLE_WORKFLOW_ID`      | Unique workflow identifier   | `abc123-def456-ghi789`                     |
| `CIRCLE_BUILD_NUM`        | Build number                 | `1234`                                     |
| `CIRCLE_USERNAME`         | User who triggered build     | `username`                                 |

Access variables using shell syntax: `$CIRCLE_SHA1`

***

### Configure deploy webhooks <a href="#configure-deploy-webhooks" id="configure-deploy-webhooks"></a>

Add webhook steps to deployment jobs after deployment completes.

#### Kubernetes deployment workflow <a href="#kubernetes-deployment-workflow" id="kubernetes-deployment-workflow"></a>

```yaml
version: 2.1

orbs:
  kubernetes: circleci/kubernetes@1.3.1

jobs:
  deploy:
    docker:
      - image: cimg/base:stable
    parameters:
      environment:
        type: string
        default: production
    steps:
      - checkout
      
      - kubernetes/install-kubectl
      
      - run:
          name: Configure kubectl
          command: |
            echo $KUBE_CONFIG | base64 -d > kubeconfig.yaml
            export KUBECONFIG=kubeconfig.yaml
      
      - run:
          name: Deploy to Kubernetes
          command: |
            kubectl set image deployment/$CIRCLE_PROJECT_REPONAME \
              $CIRCLE_PROJECT_REPONAME=registry.example.com/$CIRCLE_PROJECT_REPONAME:$CIRCLE_SHA1 \
              -n << parameters.environment >>
            kubectl rollout status deployment/$CIRCLE_PROJECT_REPONAME \
              -n << parameters.environment >> \
              --timeout=5m
      
      - run:
          name: Send deploy webhook to AI SRE
          when: on_success
          command: |
            curl -X POST "$AISRE_DEPLOY_WEBHOOK_URL" \
              -H "Content-Type: application/json" \
              -d '{
                "services": [{
                  "service": "'"$CIRCLE_PROJECT_REPONAME"'",
                  "version": "'"$CIRCLE_SHA1"'"
                }],
                "environments": ["<< parameters.environment >>"],
                "changeId": "'"$CIRCLE_WORKFLOW_ID"'",
                "status": "SUCCESS",
                "deployedBy": "'"$CIRCLE_USERNAME"'",
                "deployTimestamp": "'$(date -u +%Y-%m-%dT%H:%M:%SZ)'"
              }'
      
      - run:
          name: Send failure webhook to AI SRE
          when: on_fail
          command: |
            curl -X POST "$AISRE_DEPLOY_WEBHOOK_URL" \
              -H "Content-Type: application/json" \
              -d '{
                "services": [{
                  "service": "'"$CIRCLE_PROJECT_REPONAME"'",
                  "version": "'"$CIRCLE_SHA1"'"
                }],
                "environments": ["<< parameters.environment >>"],
                "changeId": "'"$CIRCLE_WORKFLOW_ID"'",
                "status": "FAILURE",
                "deployedBy": "'"$CIRCLE_USERNAME"'",
                "deployTimestamp": "'$(date -u +%Y-%m-%dT%H:%M:%SZ)'"
              }'
```

{% hint style="info" %}
**DEPLOY STATUS IS RECORDED AS SUCCESS**

The stock Harness Deployment template records every deploy activity as `success`. Sending a `FAILURE` status is accepted but does not create a failed-deployment record. Keep the failure webhook if you want the deploy event captured, but do not rely on the status value to distinguish failed deploys.
{% endhint %}

```yaml
workflows:
  version: 2
  build-and-deploy:
    jobs:
      - build:
          filters:
            branches:
              only: main
      - deploy:
          environment: production
          requires:
            - build
          filters:
            branches:
              only: main
```

***

### Step execution conditions <a href="#step-execution-conditions" id="step-execution-conditions"></a>

Control when steps execute using `when` attribute:

| Condition          | When it runs              |
| ------------------ | ------------------------- |
| `when: on_success` | Previous steps succeeded  |
| `when: on_fail`    | Previous steps failed     |
| `when: always`     | Runs regardless of status |

Example with conditions:

```yaml
- run:
    name: Notify always
    when: always
    command: echo "Job finished"

- run:
    name: Notify on success
    when: on_success
    command: curl -X POST $WEBHOOK_URL -d '{"status": "SUCCESS"}'

- run:
    name: Notify on failure
    when: on_fail
    command: curl -X POST $WEBHOOK_URL -d '{"status": "FAILURE"}'
```

***

### Multi-service deployments <a href="#multi-service-deployments" id="multi-service-deployments"></a>

For workflows that deploy multiple services, send all services in one webhook:

```yaml
- run:
    name: Send deploy webhook to AI SRE
    when: on_success
    command: |
      curl -X POST "$AISRE_DEPLOY_WEBHOOK_URL" \
        -H "Content-Type: application/json" \
        -d '{
          "services": [
            {"service": "frontend", "version": "'"$FRONTEND_VERSION"'"},
            {"service": "backend", "version": "'"$BACKEND_VERSION"'"},
            {"service": "worker", "version": "'"$WORKER_VERSION"'"}
          ],
          "environments": ["production"],
          "changeId": "'"$CIRCLE_WORKFLOW_ID"'",
          "status": "SUCCESS",
          "deployedBy": "'"$CIRCLE_USERNAME"'",
          "deployTimestamp": "'$(date -u +%Y-%m-%dT%H:%M:%SZ)'"
        }'
```

***

### Reusable commands <a href="#reusable-commands" id="reusable-commands"></a>

Create reusable commands to standardize webhook notifications:

```yaml
version: 2.1

commands:
  notify-build:
    parameters:
      service:
        type: string
      version:
        type: string
    steps:
      - run:
          name: Send build webhook to AI SRE
          command: |
            curl -X POST "$AISRE_BUILD_WEBHOOK_URL" \
              -H "Content-Type: application/json" \
              -d '{
                "artifact": {
                  "name": "registry.example.com/<< parameters.service >>",
                  "version": "<< parameters.version >>"
                },
                "source": {
                  "commitSha": "'"$CIRCLE_SHA1"'",
                  "kind": "branch",
                  "value": "'"$CIRCLE_BRANCH"'",
                  "repository_url": "'"$CIRCLE_REPOSITORY_URL"'"
                },
                "service": {
                  "name": "<< parameters.service >>",
                  "version": "<< parameters.version >>"
                },
                "buildId": "'"$CIRCLE_WORKFLOW_ID"'"
              }'

  notify-deploy:
    parameters:
      service:
        type: string
      version:
        type: string
      environment:
        type: string
    steps:
      - run:
          name: Send deploy webhook to AI SRE
          when: on_success
          command: |
            curl -X POST "$AISRE_DEPLOY_WEBHOOK_URL" \
              -H "Content-Type: application/json" \
              -d '{
                "services": [{
                  "service": "<< parameters.service >>",
                  "version": "<< parameters.version >>"
                }],
                "environments": ["<< parameters.environment >>"],
                "changeId": "'"$CIRCLE_WORKFLOW_ID"'",
                "status": "SUCCESS",
                "deployedBy": "'"$CIRCLE_USERNAME"'",
                "deployTimestamp": "'$(date -u +%Y-%m-%dT%H:%M:%SZ)'"
              }'

jobs:
  build:
    docker:
      - image: cimg/base:stable
    steps:
      - checkout
      - run: docker build -t registry.example.com/myapp:$CIRCLE_SHA1 .
      - run: docker push registry.example.com/myapp:$CIRCLE_SHA1
      - notify-build:
          service: myapp
          version: $CIRCLE_SHA1

  deploy:
    docker:
      - image: cimg/base:stable
    steps:
      - checkout
      # Deployment steps here
      - notify-deploy:
          service: myapp
          version: $CIRCLE_SHA1
          environment: production
```

***

### Workflow filters <a href="#workflow-filters" id="workflow-filters"></a>

Control which branches trigger jobs using filters:

```yaml
workflows:
  version: 2
  build-and-deploy:
    jobs:
      - build:
          filters:
            branches:
              only:
                - main
                - develop
      
      - deploy-staging:
          requires:
            - build
          filters:
            branches:
              only: develop
      
      - deploy-production:
          requires:
            - build
          filters:
            branches:
              only: main
```

***

### Map services and versions <a href="#map-services-and-versions" id="map-services-and-versions"></a>

The Deploy Change Investigator requires exact matches between build and deploy webhooks:

| Build webhook                           | Deploy webhook       | Must match |
| --------------------------------------- | -------------------- | ---------- |
| `service.name`                          | `services[].service` | ✅ Required |
| `artifact.version` or `service.version` | `services[].version` | ✅ Required |

Use the same variable (`$CIRCLE_SHA1`) in both build and deploy webhooks to ensure versions match.

***

### Testing webhooks <a href="#testing-webhooks" id="testing-webhooks"></a>

#### Test build webhook <a href="#test-build-webhook" id="test-build-webhook"></a>

Trigger a build and confirm the build webhook reaches AI SRE:

1. Push a commit to trigger a build
2. Check build logs for the webhook step
3. Verify the curl command executed successfully
4. Navigate to **AI SRE**, then select **Integrations**
5. Click the **More** icon on the BUILD integration
6. Select **Debug**
7. Verify the webhook appears with the correct payload

#### Test deploy webhook <a href="#test-deploy-webhook" id="test-deploy-webhook"></a>

Run a deployment and confirm the deploy webhook reaches AI SRE:

1. Trigger the deployment workflow
2. Check the deployment job logs
3. Navigate to **AI SRE**, then select **Integrations**
4. Click the **More** icon on the DEPLOY integration
5. Select **Debug**
6. Verify the webhook appears

#### Verify correlation <a href="#verify-correlation" id="verify-correlation"></a>

After sending both webhooks:

1. Navigate to **AI SRE**, then select **Change Management**
2. Deployments should appear linked to builds
3. Click a deployment to see artifact versions and commit information

***

### Troubleshooting <a href="#troubleshooting" id="troubleshooting"></a>

<details>

<summary>CircleCI webhook not received in AI SRE</summary>

Confirm the environment variable AISRE\_BUILD\_WEBHOOK\_URL or AISRE\_DEPLOY\_WEBHOOK\_URL is configured, verify the curl command runs in the job logs, ensure CircleCI executors allow outbound HTTPS, and check the JSON payload for syntax errors. Test manually with curl -v -X POST against the webhook URL.

</details>

<details>

<summary>CircleCI deployments not linked to builds in AI SRE</summary>

Ensure services\[].service in the deploy webhook exactly matches service.name in the build webhook, and services\[].version exactly matches the build webhook version. Confirm both webhooks were sent successfully by checking the Debug view.

</details>

<details>

<summary>CircleCI shell variable interpolation issues in webhook JSON</summary>

Shell variables may not expand in JSON. Use the quote pattern \\"'\\"$VARIABLE\\"'\\" for proper JSON escaping, for example \\"service\\": \\"'\\"$CIRCLE\_PROJECT\_REPONAME\\"'\\".

</details>

***

### Next steps <a href="#next-steps" id="next-steps"></a>

* Go to [Deploy Change Investigator](/ai-sre/ai-sre-for-administrators/set-up-change-management/deploy-change-investigator.md) to complete the setup.
* Go to [AI Agent RCA](/ai-sre/ai-sre-for-incident-responders/use-ai-agents/rca-change-agent.md) to understand how the AI agent uses change detection during incidents.
* Go to [Configure Jenkins](/ai-sre/ai-sre-for-administrators/set-up-change-management/sources/jenkins.md) to set up webhooks in Jenkins pipelines.
