Skip to main content
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:
# .cloudeval/config.yaml
version: 1

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

resolve:
  linked_templates: true
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 a complete public repository using this contract, see ganakailabs/cloudeval-azure-arm-review-example. Its .cloudeval/config.yaml is safe to copy into a nested ARM workspace and then adjust for your own entry file, thresholds, and budget.

Supported keys

KeyRequiredPurpose
versionYesConfig schema version. Current supported value is 1.
stacks[].idYesStable stack id used in status and generated bundle paths.
stacks[].nameNoHuman-readable stack label shown in config examples and future UI surfaces.
stacks[].entryYesVisualization source file, relative to the project root.
stacks[].parametersNoARM parameters file, relative to the project root.
resolve.linked_templatesNoFollows relative ARM templateLink files and merges them into the analysis bundle. Defaults to true.
analysis.auto_resolve_on_importNoResolves the stack immediately after import. Defaults to false.
analysis.auto_refresh_on_resolveNoRefreshes diagram and reports after resolve. Defaults to true.
ci.gates.enforcementNoblock_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_scoreNoMinimum 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_scoreNoDefault 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>NoPer-pillar score override. Supported public pillar keys include security, reliability, operational_excellence, performance_efficiency, and cost_optimization.
ci.gates.fail_when_high_risk_findings_existNoFails 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_failsNoFails 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_usdNoOptional maximum monthly cost in USD. Existing max_monthly_cost is still accepted. Omit it if cost should not gate merges.
ci.review.outputs.pdf.enabledNoWrites 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_typeNoPDF scope. Supported values: all, architecture, cost, and unit_tests. Defaults to all.
ci.review.outputs.pdf.verbosityNoPDF depth. Supported values: brief, detailed, and evidence. Defaults to evidence for review artifacts.
ci.review.outputs.pdf.fail_on_errorNoWhen 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:
🟢 **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.
.cloudeval
config.yaml
azuredeploy.json
nested
network.json
README.md
If your repository contains a real folder named repo, CloudEval treats it as a normal folder:
repo/
  azuredeploy.json
That means the config entry must include the folder:
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.
.cloudeval
config.yaml
azuredeploy.json
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.

GitHub repository sync

When a project is created from a GitHub repository, CloudEval stores source provenance on the project:
{
  "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:
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:
cloudeval review \
  --project "$PROJECT_ID" \
  --format json \
  --non-interactive
The review command stops before calling CloudEval when the local working tree is dirty:
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:
.cloudeval/
  config.yaml
azuredeploy.json
azuredeploy.parameters.json
nested/
  network.json
  storage.json
README.md
# .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
{
  "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 itemWhy
Unknown YAML keysForward-compatible; CloudEval v1 reads only the documented schema.
Commented examplesYAML 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

MistakeFix
Using .cloudeval/cloudeval.yamlRename it to .cloudeval/config.yaml.
Setting entry to a generated bundlePoint entry at the source template, not .cloudeval/bundles/**.
Uploading generated report/share folders as sourceKeep .cloudeval/reports/**, .cloudeval/share/**, and .cloudeval/shares/** as CloudEval-managed outputs.
Expecting repo/ to be strippedUse root-relative paths exactly as they exist in your repository.
Last modified on July 2, 2026