# PR bot configuration

> How the optional .levelfour/config.yml file tunes the PR bot per repository, where it lives, every field with its default, and what it does not control.

Source: https://docs.levelfour.ai/guides/pr-bot-configuration


Once you [install LevelFour on a GitHub organization](/integrations/github), the PR bot is **on by default** for every repository you granted access to. On every pull request, LevelFour reads the Terraform and CloudFormation changes in the diff, computes cost impact, and posts a single check-run comment with the cost breakdown. When LevelFour has concrete patch suggestions, they appear as inline "Suggested change" boxes on the diff itself. The main comment does not list them.

You tune the bot per repo with a `.levelfour/config.yml` file at the root of the default branch. The file is optional. With no file, the bot uses the defaults documented below.

> **Note**
>
> A dashboard-driven org and per-repo toggle is on the roadmap, so you will be able to silence the bot across thousands of repos at once, or roll it out in stages, without committing a YAML file to every repo. The toggle will take precedence over `.levelfour/config.yml`. Until then, every per-repo override lives in this file.

## Where the file lives

Path: `.levelfour/config.yml` at the repository root, on the **default branch**.

The bot reads this file at the start of every pull request analysis. Changes take effect on the next PR or push, never on an analysis that has already run.

To check a file before it matters, copy one of the examples below into your repo and open a draft PR. [Validation behavior](#validation-behavior) covers what comes back.

## Quick examples

### Disable the bot on a single repository

```yaml title=".levelfour/config.yml"
enabled: false
```

> **Success**
>
> The next pull request on this repo gets no comment and no check run.

This does not stop LevelFour reading the repo. See [what this file does not control](#what-this-file-does-not-control).

### Drop inline patch suggestions, keep the cost comment

```yaml title=".levelfour/config.yml"
code_suggestions_enabled: false
```

The bot still posts the cost summary on each PR, but does not propose inline "Suggested change" boxes on the diff.

### Exclude test fixtures and a noisy resource type

```yaml title=".levelfour/config.yml"
excluded_paths:
  - tests/fixtures/**
  - examples/**
excluded_resource_types:
  - aws_iam_role_policy_attachment
  - AWS::Logs::*
```

Write each type the way its own language does: `aws_*` for Terraform, `AWS::Service::Resource` for CloudFormation.

### Price a CloudFormation template with its production parameters

```yaml title=".levelfour/config.yml"
cloudformation:
  samconfig_env: prod
  parameter_files:
    stacks/app.yaml: stacks/params/prod.json
```

The bot prices `stacks/app.yaml` with the values in `stacks/params/prod.json`, and reads the `prod` environment from any `samconfig` file beside a template. [CloudFormation](#cloudformation) has the order the bot reads them in.

### Pin all cost estimates to a specific region

```yaml title=".levelfour/config.yml"
region_override: us-east-1
```

Reach for this when your Terraform omits `provider "aws" { region = ... }` and the bot would otherwise default to the global price. For CloudFormation it also wins over the region in `samconfig`.

## Schema

| Field                                   | Type           | Default   | What it does                                                                                                                                                                                                                                                                   |
| --------------------------------------- | -------------- | --------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `enabled`                               | bool           | `true`    | Master switch. When `false`, the bot skips this repo. No comments, no check runs.                                                                                                                                                                                              |
| `code_suggestions_enabled`              | bool           | `true`    | When `false`, the bot still posts the cost comment but does not propose inline patch suggestions.                                                                                                                                                                              |
| `max_code_suggestions`                  | int (0 to 25)  | `25`      | Cap on inline suggestion comments per PR. A suggestion that needs a second setting changed with it, such as gp3 with its IOPS, posts as one comment per line and counts each one. The bot never posts part of such a pair. Lower it if the bot is too chatty on large changes. |
| `excluded_resource_types`               | string\[]      | `[]`      | Resource type globs to skip, in each language's own type names. Example: `aws_iam_*` matches every Terraform IAM resource, `AWS::IAM::*` every CloudFormation one.                                                                                                             |
| `excluded_paths`                        | string\[]      | `[]`      | File path globs to skip, for Terraform files and CloudFormation templates alike. Example: `tests/fixtures/**`.                                                                                                                                                                 |
| `region_override`                       | string or null | `null`    | Pin all cost estimates to one AWS region.                                                                                                                                                                                                                                      |
| `cloudformation.enabled`                | bool           | `true`    | When `false`, the bot skips CloudFormation templates and prices Terraform only.                                                                                                                                                                                                |
| `cloudformation.paths`                  | string\[]      | `[]`      | Path globs that pick which templates the bot prices. Empty picks every template in the repository. A template outside them is still read when a picked template nests it.                                                                                                      |
| `cloudformation.samconfig_env`          | string         | `default` | The `samconfig` environment whose `parameter_overrides` and region apply.                                                                                                                                                                                                      |
| `cloudformation.parameter_files`        | map            | `{}`      | A parameters file for each template, both as paths from the repository root.                                                                                                                                                                                                   |
| `graviton_for_managed_services_enabled` | bool           | `false`   | Opt in to Graviton-vs-Intel suggestions for AWS managed services (RDS, ElastiCache, OpenSearch). Off by default while the rule is being tuned.                                                                                                                                 |
| `comment_sections.summary`              | bool           | `true`    | Show the top-of-comment summary block.                                                                                                                                                                                                                                         |
| `comment_sections.cost_breakdown`       | bool           | `true`    | Show the per-resource cost diff table.                                                                                                                                                                                                                                         |
| `comment_sections.monthly_spend`        | bool           | `true`    | Show the monthly spend total.                                                                                                                                                                                                                                                  |
| `comment_sections.optimization_tips`    | bool           | `true`    | Accepted so older files raise no unknown-field warning. It changes nothing: suggestions appear only inline on the diff, and `code_suggestions_enabled` turns those off.                                                                                                        |

## Limits

`excluded_paths`, `excluded_resource_types` and `cloudformation.paths` each take at most 100 globs of up to 256 characters. `cloudformation.parameter_files` takes at most 400 entries. The bot drops the rest and warns on the PR comment.

## Glob syntax for `excluded_paths`, `excluded_resource_types` and `cloudformation.paths`

A `*` matches any run of characters, slashes included:

* `tests/fixtures/**` matches every path under `tests/fixtures/`.
* `aws_iam_*` matches every Terraform resource type starting with `aws_iam_`.
* `AWS::Lambda::*` matches every CloudFormation Lambda type.
* `examples/*.tf` matches every Terraform file under `examples/`, in subdirectories too.

Without `*`, the bot matches the string exactly.

## CloudFormation

A parameter takes the first value the bot finds:

1. The file `cloudformation.parameter_files` maps to the template
2. `parameter_overrides` in the `samconfig.toml`, `samconfig.yaml` or `samconfig.yml` in the template's directory, under the `cloudformation.samconfig_env` environment. A `samconfig` applies to the template its `template_file` names. With no `template_file`, it applies to `template.yaml`, `template.yml` or `template.json` in its directory
3. The `Default` the template declares

A parameters file is JSON in the AWS CLI format or the CodePipeline template configuration format:

**AWS CLI**

```json title="stacks/params/prod.json"
[
  { "ParameterKey": "InstanceType", "ParameterValue": "m7g.large" },
  { "ParameterKey": "Environment", "ParameterValue": "prod" }
]
```

**CodePipeline**

```json title="stacks/params/prod.json"
{
  "Parameters": {
    "InstanceType": "m7g.large",
    "Environment": "prod"
  }
}
```

The region comes from `region_override`, then from the `samconfig` environment, then defaults to `us-east-1`. A nested stack takes the parameters its parent passes down and the parent's region.

The cost comment lists the values the bot had to assume under **Assumptions**. [Pull request bot](/integrations/pull-request-bot#how-it-prices-a-cloudformation-template) covers what the bot reads and what it cannot price.

## Validation behavior

The bot validates `.levelfour/config.yml` on every PR.

| Situation                                                      | What the bot does                                                                                      |
| -------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------ |
| An unknown field, at the top level or under `comment_sections` | Strips it silently from the parsed config, and reports it as a warning at the bottom of the PR comment |
| A type mismatch, for example a number where a bool is expected | Falls back to defaults for that field, and warns on the PR                                             |
| No file                                                        | Uses all defaults. This is the expected state for most repos                                           |

> **Warning**
>
> A misspelled key is stripped, so `enabld: false` leaves the bot enabled and commenting. Read the unknown-field warning on the PR comment before you assume a repo is silent.

## What this file does not control

* **Whether LevelFour can read the repo.** The GitHub App's repository access, set in your GitHub org settings, decides that. Even with `enabled: false`, LevelFour still reads the Infrastructure-as-Code for the savings recommendations engine. To stop LevelFour reading a repo at all, remove it from the GitHub App installation. See [GitHub onboarding](/integrations/github).
* **PR creation by LevelFour.** This file affects PRs your team opens. The savings PRs LevelFour opens come from the recommendation engine and ignore `enabled`.
* **Check runs the dashboard executes.** Cost recommendation runs from the dashboard ignore this file.

## Next

* [GitHub onboarding](/integrations/github) is how the app gets installed, and where you change which repos it can see
* [GitHub Actions](/guides/github-actions) is a separate feature: calling the LevelFour API from your own CI workflows
