Opsitron uses a branch-per-request strategy with plan and apply on the branch — changes are verified in your actual AWS environment before merging to main. This is different from the common “merge first, apply after” pattern and provides stronger safety guarantees.
The Pattern
main (always reflects deployed state)
│
├── request/14 ← AI creates branch + PR
│ ├── tofu plan (on PR open)
│ ├── tofu apply (after approval)
│ └── merge to main (after successful apply)
│
├── request/15
│ ├── tofu plan
│ ├── tofu apply
│ └── merge to main
│
└── (main always matches what's deployed)
Why Plan and Apply on the Branch
Most GitOps tools follow a merge-then-apply pattern: merge the PR to main, then apply from main. This has a problem — if the apply fails, main contains code that doesn’t match your infrastructure. You’re left with drift between your repo and your actual state.
Opsitron’s apply-then-merge pattern avoids this:
- Plan on the branch — when the PR is opened, the infrastructure workflow runs
tofu planagainst the branch code and posts the results as a PR comment - Apply on the branch — after staff reviews and approves, Opsitron triggers
tofu applyfrom the branch. The actual infrastructure is updated. - Merge after success — only after the apply succeeds does the PR merge to main. Main always reflects the real deployed state.
If the apply fails, the PR stays open. You can fix the code on the branch and try again. Main is never polluted with broken configuration.
Request Lifecycle
Each infrastructure request maps to a branch:
| Request State | Branch State | What Happens |
|---|---|---|
| Submitted | — | Request queued for AI planning |
| Planning | — | AI analyzing infrastructure |
| Plan Review | request/{number} created | AI created branch with terraform code |
| In Progress | PR opened | Infrastructure workflow runs plan |
| Plan Approved | Apply triggered | tofu apply runs on the branch |
| Apply Succeeded | PR merged | Branch merged to main, branch deleted |
| Completed | Branch cleaned up | Main reflects the deployed state |
Environment Promotion
For application infrastructure that deploys to multiple environments (dev → staging → prod), each environment has its own directory and state:
apps/web-app/
├── dev1/ ← applied first
├── stage1/ ← applied after dev1 succeeds
└── prod1/ ← applied after stage1 + client approval
A single PR can contain changes to multiple environments. The infrastructure workflow detects which directories changed and runs plan/apply for each independently. Promotion follows the configured pipeline:
- Dev — auto-approved, applies immediately
- Staging — requires staff approval before apply
- Production — requires staff + client approval, may have a deployment window
Each environment’s apply is independent — a failure in staging doesn’t affect dev, and prod won’t apply until staging succeeds.
Drift Detection
The infrastructure workflow includes drift detection during apply. Before applying, it re-runs tofu plan to verify the expected changes match what was planned on PR open. If unexpected changes appear (drift from manual changes or concurrent modifications), the apply is blocked with a warning.
This catches situations where:
- Someone made a manual change in the AWS console
- Another request modified the same resources concurrently
- AWS made automatic changes (e.g., security group rule updates)
Cost Estimation
Every plan includes a cost estimate via OpenInfraQuote, an open-source tool that calculates monthly cost impact from terraform plan output. The estimate is posted as a PR comment alongside the plan output, giving reviewers immediate visibility into cost implications before approving.
What Main Represents
The main branch is the source of truth for deployed infrastructure. At any point:
mainmatches what’s actually deployed in AWS- Feature branches (
request/*) represent pending changes - There is no “desired state” that differs from actual state
git log mainis a complete history of every infrastructure change
This means you can always tofu plan from main and expect zero changes (no drift). If you see drift, it means something changed outside of Opsitron — which the platform detects and flags.
Config Repository vs. Application Repository
This branching strategy applies to config repositories (infrastructure code) and LZA config repositories (Landing Zone Accelerator configuration). Application repositories (your app code) use standard Git flow — push to main triggers builds, and deployments are managed separately through the container/static deploy workflows.
| Repository Type | Branch Strategy | Deploy Trigger |
|---|---|---|
| Config (infra) | Branch per request, apply then merge | PR plan/apply workflow |
| LZA Config | Branch per request, apply then merge | LZA CodePipeline |
| Application | Standard Git flow (push to main) | Build workflow → auto-deploy |