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

# bolt-ci-healer

When a **Turbo CI** check fails on a pull request, Paradime's Self-Healing feature can automatically trigger a DinoAI programmable agent against the failure. This guide walks you through wiring up a `bolt-ci-healer` agent that runs on the back of Turbo CI and autofixes the two things that break CI most often — **pre-commit / lint failures** and **dbt errors on the build step** — by pushing a fix commit straight to the PR's branch.

Crucially, it does more than blindly re-fix every red check. It **deduplicates** against prior healing attempts on the same branch, so it pushes a fix when one is genuinely needed and **escalates to a human instead of looping** when it has already tried.

<Info>
  **Before You Start**

  **Integrations**

  The following must already be connected in Paradime:

  * **Slack** — Self-Healing posts and the agent's progress run in the configured `slack_channel`
  * A connected **Git provider** (GitHub / GitLab / Azure DevOps) so the agent can push a commit to the PR branch
</Info>

#### What You'll Build

By the end of this guide you'll have:

* A `bolt-ci-healer` DinoAI agent YAML committed under `.dinoai/agents/`
* A Turbo CI schedule with `self_healing.enabled = true` pointing at this agent
* A safe-by-default autopilot that classifies the failure (pre-commit vs dbt), **pushes a fix commit to the PR's own branch**, and **stops after one attempt per distinct error** instead of opening a new PR or looping forever

**What Happens When a CI Check Fails**

Once Self-Healing is enabled on a Turbo CI schedule:

```
Turbo CI runs on PR #482 ("fix: rename stg_orders columns") — a step fails
    └─ Paradime posts the standard CI failure notification to #data-alerts and #agent-demo
    └─ In #agent-demo (the configured self_healing.slack_channel):
        └─ "🦖 CI healing enabled — starting healing session..."
        └─ DinoAI agent `bolt-ci-healer` is triggered with:
              prompt   = "Review the CI run log and fix the failing checks on PR #482 (ci run_id 90412)"
              context  = Prior CI-healing attempts for this PR / branch (recent sessions)
        └─ Agent runs the recover-or-escalate flow:
              1. Get the CI run logs            (get_bolt_run_logs)
              2. Classify the failure           pre-commit/lint  ─or─  dbt build error
              3. Resolve the target branch      (list_pull_requests / read_pull_request)
              4. Inspect prior healing attempts on this branch (sessions + recent commits)
              5. If same error already fixed by a prior healing commit ─► STOP, escalate, exit
              6. Otherwise ─► apply fix, commit to the PR branch, push, post link
```

The dedup / loop-guard in steps 4–5 is the heart of this agent. Without it, a fix that re-triggers CI could fail again, heal again, and loop — burying the PR in commits and never reaching a human.

#### Architecture Overview

```mermaid theme={"system"}
flowchart TD
    CI([Turbo CI check fails on a PR])
    CI --> SH{self_healing.enabled?}
    SH -- no --> END([Standard CI failure notification only])
    SH -- yes --> S1[#agent-demo: '🦖 CI healing enabled...']
    S1 --> AG([bolt-ci-healer\nagent session])

    AG --> T1[get_bolt_run_logs\nfetch CI error]
    T1 --> CLS{Classify failure}
    CLS -- pre-commit/lint --> T2[read_pull_request\nresolve target branch]
    CLS -- dbt error --> T2

    T2 --> T3[Prior sessions context\n+ recent commits on branch]
    T3 --> DEDUP{Same error +\nfix already pushed?}

    DEDUP -- yes --> NOFIX([Escalate in #agent-demo\nStop — do not loop])
    DEDUP -- no --> FIX[Apply fix on PR branch]
    FIX --> PUSH([Commit + push to PR branch\npost link in #agent-demo])
    PUSH --> RERUN([Turbo CI re-runs automatically])
```

<Steps>
  <Step>
    **Create the Agent YAML**

    Commit this file at `.dinoai/agents/bolt-ci-healer.yml`:

    ```yaml title=".dinoai/agents/bolt-ci-healer.yml" lineNumbers theme={"system"}
    name: bolt-ci-healer
    version: 1

    role: >
      Turbo CI Recovery Specialist focused on getting failing CI checks on open
      pull requests back to green — pre-commit / lint failures and dbt build errors.

    goal: >
      When a Turbo CI check fails, get the PR back to green with the smallest
      possible change pushed directly to the PR's own branch.

      Follow this recover-or-escalate flow:
      1. Fetch the logs of the failed CI run and extract the exact error message.
      2. Classify the failure:
           - PRE-COMMIT / LINT  → a pre-commit hook failed (e.g. sqlfluff, formatting,
             yaml-lint, trailing whitespace).
           - DBT ERROR          → the dbt build/compile step failed (compilation error,
             failing test, missing ref, broken model SQL).
      3. Resolve the pull request and branch this CI run belongs to.
      4. Inspect prior CI-healing attempts for this branch (from the initial context
         block) and the recent commits already on the branch.
      5. If the SAME error was already addressed by a prior healing commit AND the
         check is still failing the same way, STOP — do NOT push again. Pushing a
         second time would re-trigger CI and risk an endless heal loop. Instead, post
         a Slack message explaining the fix attempt did not resolve it, link the
         commit, and ask a human to take a look.
      6. Otherwise, apply the fix:
           - PRE-COMMIT / LINT  → run the project's autofixers (e.g. `pre-commit run
             --all-files`, `sqlfluff fix`), then stage the resulting changes.
           - DBT ERROR          → make a surgical edit to the offending model / macro /
             schema yml that resolves the specific error in the log.
         Commit the change to the PR's branch with a clear message referencing the
         CI run, push, and post the commit link. Turbo CI re-runs automatically.

    backstory: >
      You know dbt and pre-commit tooling deeply, prefer surgical edits over
      rewrites, and always cite the failing command's error message in your
      reasoning. You commit ON TOP of the existing branch — you never force-push and
      never rewrite a contributor's history. You are disciplined about loops: you
      make at most one fix attempt per distinct error, and if that attempt doesn't
      clear the check you hand it to a human rather than pushing again. You never
      open a new PR — the PR already exists, so the fix belongs on its branch.

    tools:
      mode: allowlist
      list:
        - read_file
        - search_files_and_directories
        - ripgrep_search
        - run_sql_query
        - list_pull_requests
        - read_pull_request
        - get_bolt_run_logs
        - run_terminal_command
    ```

    <Info>
      **Tool allowlist is deliberately narrow — and deliberately excludes PR creation.** The agent has read access (`read_file`, `ripgrep_search`, `run_sql_query`), CI observability (`get_bolt_run_logs`), PR awareness (`list_pull_requests`, `read_pull_request`), and a terminal (`run_terminal_command`) to run the autofixers and `git commit` / `git push` to the PR branch. There is **no** `create_pull_request` — unlike the scheduled Pipeline Healer, a CI failure already has a PR, so the fix is committed to that branch, not a new one. No `post_slack_message` is needed either — Self-Healing already threads the agent into a Slack channel and the agent's stdout shows up there automatically.
    </Info>
  </Step>

  <Step>
    **Enable Self-Healing on the Turbo CI schedule (UI)**

    In the schedule editor for your Turbo CI schedule:

    1. Open the **Self-Healing** section.
    2. Toggle **Enable Self-Healing**.
    3. Pick the **Slack channel** the agent should run in — e.g. `#agent-demo`. It must already be configured under Notification Settings on this schedule.
    4. From the **Agent Name** dropdown, pick `bolt-ci-healer`. The list is populated from `.dinoai/agents/*.yml` on the schedule's git branch — so make sure the YAML from Step 1 has been merged into the base branch before configuring this.
    5. Save the schedule.

    See Turbo CI for how CI runs are triggered, and Bolt → Self-Healing for the full UI walkthrough.
  </Step>

  <Step>
    **Or: enable Self-Healing via YAML (schedules-as-code)**

    If you manage your Turbo CI schedule as code, add the `self_healing` block to the CI schedule entry:

    ```yaml title="paradime:schedules.yml" lineNumbers theme={"system"}
    schedules:
      - name: turbo ci
        description: Turbo CI checks on pull requests
        environment: production
        git_branch: main            # base branch CI builds against
        trigger_on:
          pull_request: true
        commands:
          - pre-commit run --all-files
          - dbt build --select state:modified+
        turbo_ci:
          enabled: true

        notifications:
          slack_channels:
            - channel: '#data-alerts'
              events:
                - failed
            - channel: '#agent-demo'
              events:
                - failed

        self_healing:
          enabled: true
          slack_channel: '#agent-demo'
          agent_name: bolt-ci-healer
    ```

    <Warning>
      `self_healing.slack_channel` **must also appear** in this schedule's `notifications.slack_channels`. The deployer rejects the schedule otherwise — the agent threads into the existing CI failure notification, so the notification has to exist for the agent to find it.
    </Warning>

    See the full schema at Schedules as Code → Configuration Reference → Self-Healing.
  </Step>

  <Step>
    **Watch the first heal in action**

    Open a PR that deliberately breaks CI — e.g. an unformatted model (pre-commit) or a model with a bad `ref()` (dbt). The next time Turbo CI runs and fails:

    1. Open `#agent-demo` in Slack and find the CI failure notification for the run.
    2. Inside that thread you'll see:
       * `🦖 CI healing enabled — starting healing session...`
       * A series of agent messages showing the flow in action (CI logs → failure class → target branch → prior attempts)
       * Either:
         * A **commit link** pushed to the PR's branch (`fix(ci): sqlfluff lint on stg_orders` / `fix(ci): correct ref in fct_orders`), which re-triggers Turbo CI automatically, or
         * An **"already tried this — needs a human"** escalation post (when the loop-guard trips)
    3. Watch Turbo CI re-run on the new commit. If it goes green, review and merge the PR as normal.
  </Step>
</Steps>

#### How the loop-guard works

The loop-guard is what makes this agent safe to leave running unattended on every PR. Because a CI fix is itself re-tested by CI, a naive healer could push → fail → heal → push forever. The guard caps the agent at **one fix attempt per distinct error** and is driven by three pieces of context the agent reasons over:

| Input                         | Source                                                                                                                                                    | Used to answer                                                   |
| ----------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------- |
| **Current CI error**          | `get_bolt_run_logs(run_id=<failed CI run>)`                                                                                                               | What's failing right now — pre-commit/lint or a dbt error?       |
| **Target PR / branch**        | `list_pull_requests` / `read_pull_request`                                                                                                                | Which branch do I commit the fix to?                             |
| **Prior CI-healing attempts** | Initial context block prepended automatically by Paradime when this PR / branch has prior healing sessions, plus the recent commits already on the branch | Have I already pushed a fix for this exact error on this branch? |

The agent stops and escalates instead of pushing another commit if **both** conditions hold:

1. The current error matches an error from a prior CI-healing attempt on the same branch.
2. A healing commit addressing that error already exists on the branch and CI is still failing the same way.

If either condition fails — the error is genuinely new, or the prior attempt cleared and a *different* check is now red — the agent proceeds with the fix.

<Info>
  **Why the initial context matters.** Paradime injects a "Prior CI-healing attempts for this PR / branch" block into the agent's prompt automatically when prior sessions exist for the same branch. This is what gives the agent recall across CI re-runs without needing its own memory tool — and it's exactly what the loop-guard reads to decide whether it has already tried.
</Info>

#### File Structure

Your repository should look like this after completing the setup:

```
your-repo/
├── dbt_project.yml
├── .pre-commit-config.yaml      ← drives the pre-commit/lint checks CI runs
├── .dinoai/
│   └── agents/
│       └── bolt-ci-healer.yml
└── models/
    └── ...
```

#### Related Docs

* **Turbo CI** — slim, state-aware CI on every pull request
* [**Bolt → Self-Healing** — enabling the feature on a schedule](/products/dino-ai/bolt-pipeline-agent/self-healing)
* [**Bolt Pipeline Healer** — the scheduled-run sibling of this agent](/guides/programmable-agents/bolt-pipeline-healer)
* [**Programmable Agents — Quick Start**](/products/dino-ai/programmable-agents/quick-start)
* [**Programmable Agents — YAML Configuration**](/products/dino-ai/programmable-agents/yaml-configuration)
* [**Programmable Agents — Tools Reference**](/products/dino-ai/programmable-agents/tools-reference)
* [**Schedules as Code — Configuration Reference**](/products/bolt/creating-schedules/schedules-as-code/index)


## Related topics

- [Bolt Pipeline Healer](/guides/programmable-agents/bolt-pipeline-healer.md)
- [CI/CD](/products/bolt/ci-cd/index.md)
- [GitHub](/products/bolt/ci-cd/turbo-ci/github.md)
- [BitBucket](/products/bolt/ci-cd/turbo-ci/bitbucket.md)
- [GitLab](/products/bolt/ci-cd/turbo-ci/gitlab.md)
