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

# Configure an IaC project

> Configure the visualization source, linked templates, and Cloudeval-managed folders for template-backed projects.

Use `.cloudeval/config.yaml` when a template-backed project has more than one file or when you want Cloudeval to use a specific entry template.

## Why it matters

Cloudeval needs one explicit visualization source. In a repository with parameters, linked templates, modules, and generated outputs, the config file tells Cloudeval which file starts the graph and report pipeline.

The same config file is used for local uploads, CLI workspace uploads, and
GitHub repository sync. For GitHub-linked projects, Cloudeval reads source files
from the selected repository branch/root and keeps them read-only in the app.

## Quick example

Create this file at the root of your IaC workspace:

<CodeGroup>
  ```yaml minimal.yml theme={null}
  # .cloudeval/config.yaml
  version: 1

  stacks:
    - id: primary-architecture
      name: Primary architecture
      entry: azuredeploy.json
      parameters: azuredeploy.parameters.json

  resolve:
    linked_templates: true
  ```

  ```yaml with-gates.yml theme={null}
  # .cloudeval/config.yaml
  # Cloudeval config v1. Paths are relative to this workspace root.
  version: 1

  # Visualization source for diagrams and reports.
  stacks:
    - id: primary-architecture
      name: Primary architecture
      entry: azuredeploy.json
      parameters: azuredeploy.parameters.json

  resolve:
    # Follow relative ARM templateLink files when building the analysis bundle.
    linked_templates: true

  analysis:
    # Import/resolution behavior for UI, CLI workspace upload, and GitHub sync.
    auto_resolve_on_import: false
    auto_refresh_on_resolve: true

  # Optional CI gates for `cloudeval review` and GitHub Actions.
  ci:
    gates:
      # block_pull_request fails CI on gate failures; comment_only only reports them.
      enforcement: block_pull_request

      # Minimum Well-Architected score out of 100.
      minimum_well_architected_score: 85

      # Fail on high-risk architecture findings.
      fail_when_high_risk_findings_exist: true

      # Optional monthly budget gate. Omit if cost should be reported but not gated.
      max_monthly_cost_usd: 500

    review:
      diff:
        # Compare local/PR changes against this ref when collecting review evidence.
        base_ref: origin/main
        # Bound patch text stored in review.json.
        max_patch_bytes: 40000
      github:
        checks:
          # Post a Cloudeval GitHub App Check Run with inline annotations.
          enabled: true
          name: Cloudeval
          # Keep annotations scoped to files changed in the branch/PR.
          changed_files_only: true
          annotation_limit: 50
          include_notices: false
        sarif:
          # Write review.sarif.json for GitHub code scanning upload.
          enabled: true
          category: cloudeval-iac
      outputs:
        pdf:
          # Write review.pdf when `cloudeval review --output <dir>` runs.
          # GitHub Actions uploads it when `upload_artifacts: true`.
          enabled: true
          report_type: all
          verbosity: evidence
          fail_on_error: false
  ```
</CodeGroup>

Expected result:

* Cloudeval reads `azuredeploy.json` as the visualization source.
* Relative `templateLink` files are resolved when `resolve.linked_templates` is `true`.
* Generated bundles, connection mirrors, reports, and share assets are not treated as source files.
* `cloudeval review --output <dir>` writes `review.pdf` when `ci.review.outputs.pdf.enabled` is `true`.

For complete public repositories using this contract, start with:

* [ganakailabs/cloudeval-azure-arm-review-example](https://github.com/ganakailabs/cloudeval-azure-arm-review-example) for nested ARM templates, linked-template resolution, and long-lived demo PRs.
* [ganakailabs/cloudeval-aws-cloudformation-review-example](https://github.com/ganakailabs/cloudeval-aws-cloudformation-review-example) for AWS CloudFormation JSON/YAML beta projects and scanner-backed PR review setup.

Copy the closest `.cloudeval/config.yaml`, then adjust entry files, thresholds, and budget for your repository. Keep AWS scoring expectations explicit: AWS CloudFormation beta can surface scanner findings and reviewed mappings where available, while unsupported AWS scoring areas should stay `Not assessed`.

## Supported keys

| Key                                           | Required | Purpose                                                                                                                                                                                                                         |
| --------------------------------------------- | -------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `version`                                     | Yes      | Config schema version. Current supported value is `1`.                                                                                                                                                                          |
| `stacks[].id`                                 | Yes      | Stable stack id used in status and generated bundle paths.                                                                                                                                                                      |
| `stacks[].name`                               | No       | Human-readable stack label shown in config examples and future UI surfaces.                                                                                                                                                     |
| `stacks[].entry`                              | Yes      | Visualization source file, relative to the project root.                                                                                                                                                                        |
| `stacks[].parameters`                         | No       | ARM parameters file, relative to the project root.                                                                                                                                                                              |
| `resolve.linked_templates`                    | No       | Follows relative ARM `templateLink` files and merges them into the analysis bundle. Defaults to `true`.                                                                                                                         |
| `analysis.auto_resolve_on_import`             | No       | Resolves the stack immediately after import. Defaults to `false`.                                                                                                                                                               |
| `analysis.auto_refresh_on_resolve`            | No       | Refreshes diagram and reports after resolve. Defaults to `true`.                                                                                                                                                                |
| `ci.gates.enforcement`                        | No       | `block_pull_request` fails `cloudeval review` on gate failures. `comment_only` reports failures without failing the job. Existing `required` and `warn` values are still accepted. Defaults to blocking when `ci.gates` exists. |
| `ci.gates.minimum_well_architected_score`     | No       | Minimum Well-Architected overall score for `cloudeval review` and GitHub Action `mode: review`. Existing `overall_score_min` is still accepted. Defaults to `80` when `ci.gates` exists.                                        |
| `ci.gates.minimum_pillar_score`               | No       | Default minimum for every Well-Architected pillar score. Existing `pillar_score_min` is still accepted. Omit it if only the overall score should gate.                                                                          |
| `ci.gates.pillars.<pillar>`                   | No       | Per-pillar score override. Supported public pillar keys include `security`, `reliability`, `operational_excellence`, `performance_efficiency`, and `cost_optimization`.                                                         |
| `ci.gates.fail_when_high_risk_findings_exist` | No       | Fails review when high-risk architecture findings exist. Existing `fail_on_high_risk` is still accepted. Defaults to `true` when `ci.gates` exists.                                                                             |
| `ci.gates.fail_when_validation_fails`         | No       | Fails review when policy checks or unit tests have failures. Existing `fail_on_validation_errors` is still accepted. Defaults to `true` when `ci.gates` exists.                                                                 |
| `ci.gates.max_monthly_cost_usd`               | No       | Optional maximum monthly cost in USD. Existing `max_monthly_cost` is still accepted. Omit it if cost should not gate merges.                                                                                                    |
| `ci.review.diff.base_ref`                     | No       | Git ref used as the base when `cloudeval review` collects changed-file evidence. Defaults to `origin/<GitHub base branch>` in Actions, then `origin/main`.                                                                      |
| `ci.review.diff.max_files`                    | No       | Maximum changed files recorded in `review.json`. Defaults to `100`.                                                                                                                                                             |
| `ci.review.diff.max_patch_bytes`              | No       | Maximum patch text stored in `review.json`. Defaults to `40000`.                                                                                                                                                                |
| `ci.review.github.checks.enabled`             | No       | Emits GitHub Check Run annotation payload in `review.json`; the official action posts it through the Cloudeval GitHub App when `github_checks` is enabled. Defaults to `false`.                                                 |
| `ci.review.github.checks.name`                | No       | GitHub Check Run display name. Defaults to `CloudEval`.                                                                                                                                                                         |
| `ci.review.github.checks.changed_files_only`  | No       | Limits annotations to files changed in the branch or PR. Defaults to `true`.                                                                                                                                                    |
| `ci.review.github.checks.annotation_limit`    | No       | Maximum annotations emitted for the check run. Defaults to `50`.                                                                                                                                                                |
| `ci.review.github.checks.include_notices`     | No       | Includes informational findings as annotations. Defaults to `false`; failures and warnings are usually enough for PR review.                                                                                                    |
| `ci.review.github.sarif.enabled`              | No       | Writes `review.sarif.json` when `cloudeval review --output <dir>` runs. Defaults to `false`.                                                                                                                                    |
| `ci.review.github.sarif.category`             | No       | SARIF automation category used by GitHub code scanning. Defaults to `cloudeval-iac`.                                                                                                                                            |
| `ci.review.github.sarif.upload`               | No       | Documents intent to upload SARIF from CI. The official action generates the file and exposes `sarif_path`; upload is done with GitHub's SARIF upload action. Defaults to `false`.                                               |
| `ci.review.github.sarif.fail_on_upload_error` | No       | Reserved for workflows that enforce SARIF upload failures. Defaults to `false`.                                                                                                                                                 |
| `ci.review.outputs.pdf.enabled`               | No       | Writes `review.pdf` into the `cloudeval review --output` directory. Defaults to `false`. In GitHub Actions, combine this with `upload_artifacts: true` to attach the PDF to the workflow artifact.                              |
| `ci.review.outputs.pdf.report_type`           | No       | PDF scope. Supported values: `all`, `architecture`, `cost`, and `unit_tests`. Defaults to `all`.                                                                                                                                |
| `ci.review.outputs.pdf.verbosity`             | No       | PDF depth. Supported values: `brief`, `detailed`, and `evidence`. Defaults to `evidence` for review artifacts.                                                                                                                  |
| `ci.review.outputs.pdf.fail_on_error`         | No       | When `true`, a PDF export failure fails `cloudeval review`. Defaults to `false`, so review gates and comments can still complete if PDF export is temporarily unavailable.                                                      |

If `ci.gates` is not defined, review automation reports a warning and does not fail by default. Add the section only when the repository is ready for explicit CI enforcement. Use `enforcement: comment_only` first when you want PR comments and review artifacts without blocking merges.

Use `ci.review.outputs.pdf` when reviewers need a durable evidence packet from the exact CI run. The PR comment keeps the Cloudeval-hosted `PDF` badge for the latest hosted download; the GitHub artifact captures the generated `review/review.pdf` next to `review/review.md` and `review/review.json`, including runs where the configured review gate fails.

Review comments distinguish the configured gate from observed posture:

```md theme={null}
🟢 **Overall** : PASS
🔴 Well-Architected Posture: 23.1/100 (CRITICAL)
🔴 Validation: 3 unit tests failed
🟢 Policy checks: GOOD
🟢 Cost: 143.81 USD/mo (under 100K budget)

#### Source

- **Cloudeval project**: [GitHub Nested E2E](https://cloudeval.ai/app/projects/...)
- **Repository**: `owner/repo`
- **Ref**: `feature/infra-change`
- **Commit**: `abc123def456`
- **Workflow run**: https://github.com/owner/repo/actions/runs/123456789
```

`Overall` is the gate result from `ci.gates`. Score labels such as `CRITICAL`, `POOR`, `FAIR`, `GOOD`, and `EXCELLENT` describe posture. They block merges only when your thresholds require them to block.

The same config drives local `cloudeval review` and GitHub Action review comments. Review Markdown can include Cloudeval report links, a resource-cost pie chart, a projected-versus-optimized cost chart, validation failure details, and architecture signals when those reports are available. When PDF output is enabled, the CLI also records `data.outputs.pdf` in `review.json`.

## Folder behavior

Cloudeval treats the project root like a repository root. It does not add or strip a synthetic `repo/` folder.

<Tree>
  <Tree.Folder name=".cloudeval" defaultOpen>
    <Tree.File name="config.yaml" />
  </Tree.Folder>

  <Tree.File name="azuredeploy.json" />

  <Tree.Folder name="nested" defaultOpen>
    <Tree.File name="network.json" />
  </Tree.Folder>

  <Tree.File name="README.md" />
</Tree>

If your repository contains a real folder named `repo`, Cloudeval treats it as a normal folder:

```text theme={null}
repo/
  azuredeploy.json
```

That means the config entry must include the folder:

```yaml theme={null}
stacks:
  - id: primary-architecture
    name: Primary architecture
    entry: repo/azuredeploy.json
```

Cloudeval-managed files live under `.cloudeval/**`, but only
`.cloudeval/config.yaml` is source input. Generated bundles, connection mirrors,
snapshots, reports, and share assets are derived outputs.

<Tree>
  <Tree.Folder name=".cloudeval" defaultOpen>
    <Tree.File name="config.yaml" />

    <Tree.Folder name="bundles">
      <Tree.File name="primary-architecture.resolved.json" />
    </Tree.Folder>

    <Tree.Folder name="connections">
      <Tree.File name="github-source.json" />
    </Tree.Folder>

    <Tree.Folder name="reports">
      <Tree.File name="architecture.latest.json" />

      <Tree.File name="cost.latest.json" />
    </Tree.Folder>

    <Tree.Folder name="snapshots">
      <Tree.File name="latest-sync.json" />
    </Tree.Folder>

    <Tree.Folder name="template-cache">
      <Tree.File name="linked-template-index.json" />
    </Tree.Folder>
  </Tree.Folder>

  <Tree.File name="azuredeploy.json" />

  <Tree.Folder name="nested">
    <Tree.File name="network.json" />
  </Tree.Folder>
</Tree>

<Warning>
  Do not set `stacks[].entry` to a file under `.cloudeval/bundles/**`,
  `.cloudeval/reports/**`, or `.cloudeval/snapshots/**`. Point it at the source
  template that lives in your repository.
</Warning>

## GitHub repository sync

When a project is created from a GitHub repository, Cloudeval stores source
provenance on the project:

```json theme={null}
{
  "type": "github",
  "installation_id": 123456,
  "repo_full_name": "org/repo",
  "ref": "main",
  "commit_sha": "abc123",
  "source_root": "infra",
  "display_label": "org/repo main"
}
```

The source root is stripped before files are written into the Cloudeval
workspace. For example, `source_root: infra` maps
`infra/azuredeploy.json` to `azuredeploy.json`.

Cloudeval excludes noisy or unsafe repository paths during V1 sync:

* `.git/**`
* `.github/**`
* `node_modules/**`
* `.terraform/**`
* `*.tfstate` and `*.tfstate.*`
* `.env` and `.env.*`
* Cloudeval-generated `.cloudeval/bundles/**`, `.cloudeval/connections/**`,
  `.cloudeval/template-cache/**`, and `.cloudeval/snapshots/**`

Push webhooks refresh GitHub-linked projects for the selected branch. You can
also use **Sync from GitHub** from the project page.

## CLI and API contract

The public import contract is path based:

* `.cloudeval/config.yaml` is read from the workspace root.
* `stacks[].entry` is the visualization source, relative to that same root.
* Linked templates and parameters are uploaded as individual files and keep
  their relative paths.
* Cloudeval writes derived analysis artifacts under managed `.cloudeval/`
  subfolders; those artifacts are not source inputs.

The CLI follows the same contract when you use `--workspace-dir`:

```bash theme={null}
cloudeval projects create \
  --workspace-dir ./infra \
  --workspace-entry azuredeploy.json \
  --name "Nested ARM workspace" \
  --provider azure \
  --format json \
  --output ./cloudeval-project.json
```

Run a local review from a GitHub-backed checkout:

```bash theme={null}
cloudeval review \
  --project "$PROJECT_ID" \
  --format json \
  --non-interactive
```

The review command stops before calling Cloudeval when the local working tree is dirty:

```text theme={null}
Reviews pushed commits only. Add --ignore-dirty to review HEAD anyway.
```

Use `--ignore-dirty` only for deliberate local generated-file workflows. Normal PR checks should review a pushed commit.

If `.cloudeval/config.yaml` is missing, the CLI creates a minimal config using
the selected entry file and the detected parameters file, then sends that config
with the workspace upload. Passing `--workspace-entry` is recommended for
repositories with more than one deployable template.

## Nested ARM example

Use this structure when a parent ARM template deploys child templates by
relative path:

```text theme={null}
.cloudeval/
  config.yaml
azuredeploy.json
azuredeploy.parameters.json
nested/
  network.json
  storage.json
README.md
```

```yaml theme={null}
# .cloudeval/config.yaml
version: 1
stacks:
  - id: primary-architecture
    name: Primary architecture
    entry: azuredeploy.json
    parameters: azuredeploy.parameters.json
resolve:
  linked_templates: true
analysis:
  auto_resolve_on_import: true
  auto_refresh_on_resolve: true
```

```json theme={null}
{
  "resources": [
    {
      "type": "Microsoft.Resources/deployments",
      "apiVersion": "2022-09-01",
      "name": "network",
      "properties": {
        "mode": "Incremental",
        "templateLink": {
          "uri": "nested/network.json"
        }
      }
    }
  ]
}
```

Expected result: the code view still shows individual source files, while the
diagram and reports use the resolved stack.

## Ignored config and managed paths

Cloudeval ignores unknown YAML keys so future fields can be added without breaking existing repositories. Comments are guidance only.

| Ignored item                                                 | Why                                                                |
| ------------------------------------------------------------ | ------------------------------------------------------------------ |
| Unknown YAML keys                                            | Forward-compatible; Cloudeval v1 reads only the documented schema. |
| Commented examples                                           | YAML comments are never parsed.                                    |
| `.cloudeval/bundles/**`                                      | Derived resolved templates written by Cloudeval.                   |
| `.cloudeval/connections/**`                                  | Derived connection mirrors written by Cloudeval.                   |
| `.cloudeval/reports/**`                                      | User-visible report outputs written by Cloudeval.                  |
| `.cloudeval/share/**` and `.cloudeval/shares/**`             | User-visible share assets and metadata written by Cloudeval.       |
| `.cloudeval/snapshots/**` and `.cloudeval/template-cache/**` | Internal caches and snapshots written by Cloudeval.                |

## Common mistakes

| Mistake                                            | Fix                                                                                                           |
| -------------------------------------------------- | ------------------------------------------------------------------------------------------------------------- |
| Using `.cloudeval/cloudeval.yaml`                  | Rename it to `.cloudeval/config.yaml`.                                                                        |
| Setting `entry` to a generated bundle              | Point `entry` at the source template, not `.cloudeval/bundles/**`.                                            |
| Uploading generated report/share folders as source | Keep `.cloudeval/reports/**`, `.cloudeval/share/**`, and `.cloudeval/shares/**` as Cloudeval-managed outputs. |
| Expecting `repo/` to be stripped                   | Use root-relative paths exactly as they exist in your repository.                                             |

## Related pages

* [Import an ARM or Bicep template](/guides/connect/arm-bicep)
* [Review IaC before deployment](/guides/review/iac-before-deployment)
* [Platform model](/reference/platform-objects)
