> For the complete documentation index, see [llms.txt](https://docs.paradime.io/app-help/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.paradime.io/app-help/guides-new/programmable-agents/bolt-ci-healer.md).

# 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.

{% hint style="info" icon="compass" %}
**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
  {% endhint %}

#### 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
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])
```

{% stepper %}
{% step %}
**Create the Agent YAML**

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

{% code title=".dinoai/agents/bolt-ci-healer.yml" lineNumbers="true" %}

```yaml
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
```

{% endcode %}

{% hint style="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.
{% endhint %}
{% endstep %}

{% 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.
{% endstep %}

{% 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:

{% code title="paradime:schedules.yml" lineNumbers="true" %}

```yaml
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
```

{% endcode %}

{% hint style="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.
{% endhint %}

See the full schema at Schedules as Code → Configuration Reference → Self-Healing.
{% endstep %}

{% 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.
   {% endstep %}
   {% endstepper %}

#### 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.

{% hint style="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.
{% endhint %}

#### 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](/app-help/products/dino-ai/bolt-pipeline-agent/self-healing.md)
* [**Bolt Pipeline Healer** — the scheduled-run sibling of this agent](/app-help/guides-new/programmable-agents/bolt-pipeline-healer.md)
* [**Programmable Agents — Quick Start**](/app-help/products/dino-ai/programmable-agents/quick-start.md)
* [**Programmable Agents — YAML Configuration**](/app-help/products/dino-ai/programmable-agents/yaml-configuration.md)
* [**Programmable Agents — Tools Reference**](/app-help/products/dino-ai/programmable-agents/tools-reference.md)
* [**Schedules as Code — Configuration Reference**](/app-help/products/bolt/creating-schedules/schedules-as-code.md)


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://docs.paradime.io/app-help/guides-new/programmable-agents/bolt-ci-healer.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
