Modernize your Azure Infrastructure with AI. A production-ready template for building Well-Architected environments using custom Copilot agents, Dev Containers, and the Model Context Protocol (MCP).
This accelerator provides the scaffolding and governance to move from requirements to deployed infrastructure using an orchestrated multi-agent workflow. It leverages domain-specific AI agents to ensure every deployment is Well-Architected, governed, and documented.
What you get: Specialized agents, skills, validation scripts, a full dev container with all tools pre-installed, and an optional weekly sync workflow that keeps your agents and skills up to date with the upstream APEX project.
| Requirement | Details |
|---|---|
| VS Code | Latest stable release |
| GitHub Copilot | Active license (Individual, Business, or Enterprise) |
| Docker Desktop | Validated on x86-64 and ARM64, including Windows with WSL 2; Linux hosts are supported (GitHub Codespaces is not separately validated) |
| Azure subscription | Required (Owner or Contributor on the target subscription) |
This repository is a GitHub Template — not a fork.
- Click "Use this template" → "Create a new repository" at the top of this page
- Choose an owner and name (e.g.,
my-infraops-project) - Select Private (do not use Public)
- Click Create repository
Your new repo has the same directory structure and files but a clean commit history and no fork relationship. It is entirely yours.
git clone https://github.com/YOUR-USERNAME/my-infraops-project.git
cd my-infraops-projectIf you are a Microsoft employee, use the Microsoft launcher below instead of code ..
Run it on your host, immediately after cloning, not inside a container or a VS Code integrated terminal.
Connect to your approved corporate network/VPN as required, and fully exit all VS Code windows first:
opening another window can reuse an existing process that does not have the feed settings.
On Windows, run from PowerShell:
.\.devcontainer\open-microsoft.ps1On Linux, macOS, or WSL, run from your host shell:
bash .devcontainer/open-microsoft.shThe launcher opens this repository in VS Code with Microsoft's CFS package feeds for npm, Python, and PowerShell. The npm/Python settings apply to image and Feature builds as well as the running container. It needs no administrator access, Node.js, or Python on the host; the Windows launcher also works with Windows PowerShell 5.1. It does not install packages, edit global settings or shell profiles, change credentials, disable TLS checks, or fall back to public registries. Do not bypass a corporate execution policy if it blocks the script; use your organization's approved execution method.
Use the launcher again whenever opening a fresh VS Code process for this project. No feed settings are persisted to your host. Other organizations can supply their own approved feeds using the opt-ins documented in Package Sources. Microsoft maintainers must also follow the publication-age and approved-source policy in AGENTS.md; choosing a feed alone does not prove every package meets that policy.
Not a Microsoft employee? Skip the Microsoft launchers. The default public registries are unchanged; apply your own organization's package-source requirements if applicable.
code .When prompted by VS Code, click "Reopen in Container" (or run Dev Containers: Reopen in Container
from the Command Palette). Build time depends on downloads and host resources. The container pre-installs:
- Azure CLI with Bicep extension
- Terraform CLI with TFLint
- GitHub CLI (
gh) - Node.js + npm (validation scripts)
- Python 3 + pip (diagram generation, apex-recall CLI)
If setup fails, inspect Dev Containers: Show Container Log. A HandshakeFailure while fetching pip from
files.pythonhosted.org means that build attempted public PyPI: check that you launched a fresh VS Code process
through the Microsoft script, then rebuild. If the approved feed itself is unavailable or lacks a required
package, stop and resolve that with your package-feed administrator; do not switch to public downloads.
After the dev container starts, run the initialization commands:
npm install
npm run init
npm run sync:workflowsWhat these do:
| Command | Purpose |
|---|---|
npm install |
Install Node.js dependencies (validation scripts, linting) |
npm run init |
One-time setup — replaces all references to the accelerator template repo with your repo's URL (auto-detected from git remote). Run npm run init -- --dry-run first to preview changes. |
npm run sync:workflows |
Fetches the latest GitHub Actions workflows from the upstream APEX project into your .github/workflows/ directory |
Note: Python dependencies (diagrams and apex-recall) are installed automatically by the dev container's
post-create.shscript. No manualpip installis needed.
After running, review and commit:
git --no-pager diff
git add -A && git commit -m "chore: initialize from template"
git pushExpected diff: You will see changes to
AGENTS.md,CONTRIBUTING.md, and one or more.github/workflows/files. You may also see formatting-only changes to.mcp.json(the dev container normalizes its JSON arrays to multi-line format on first start) — this is expected and safe to commit.Tip: Use
git --no-pager diffinstead of plaingit diffto avoid thelesspager. If you do usegit diffand see a:prompt, pressqto exit orSpaceto scroll.
Run the setup wizard to configure Azure OIDC authentication, RBAC roles, and GitHub secrets/variables — all in one command:
az login
npm run setupThe wizard creates an Entra ID app registration, OIDC federated credentials (for main branch + dev/staging/prod environments), assigns Reader at your Management Group and Contributor at your subscription, and configures all GitHub secrets and variables. It is idempotent — safe to re-run.
See the Azure Setup documentation for headless mode, manual setup steps, and troubleshooting.
The maintenance workflows (step 6) open pull requests automatically when they detect drift. This requires one permission change in your repository settings.
- Go to your repository on GitHub
- Click Settings → Actions → General
- Scroll to Workflow permissions
- Check Allow GitHub Actions to create and approve pull requests
- Click Save
Why: GitHub disables this by default on all new repositories. Without it, any workflow that opens a PR will fail with:
GitHub Actions is not permitted to create or approve pull requests
After Azure setup completes, trigger the two scheduled maintenance workflows once so your repository has a fresh baseline before you start working. Both run weekly on Mondays after this initial seed.
gh workflow run "Weekly Maintenance"
gh workflow run "Governance Policy Baseline"| Workflow | Purpose | Schedule |
|---|---|---|
| Weekly Maintenance | Refreshes the AVM module index, tracks Azure service deprecations, runs the quarterly docs/orphan audit, and link-checks docs. | Mondays 06:00 UTC |
| Governance Policy Baseline | Collects effective Azure Policy assignments (including management-group inheritance) from your subscription into agent-output/_baseline/ so the IaC planner consumes real governance constraints. Requires step 4 to be complete. |
Mondays 05:00 UTC |
Verify both runs succeeded before continuing:
gh run list --workflow "Weekly Maintenance" --limit 1
gh run list --workflow "Governance Policy Baseline" --limit 1Each run may open a pull request when it detects drift (new AVM module versions, policy changes, deprecated services). Review and merge those PRs as they appear — they are never auto-merged.
Once you are working in your repo, here is what lives where:
.github/
agents/ # Agent definitions (*.agent.md)
_subagents/ # Subagent definitions (non-user-invocable)
skills/ # Reusable domain knowledge (SKILL.md per skill)
instructions/ # File-type rules with glob-based auto-application
copilot-instructions.md # VS Code Copilot-specific orchestration instructions
workflows/ # GitHub Actions (sync, CI, validation)
agent-output/ # Generated artifacts organized by project
{project}/ # 01-requirements.md through 07-*.md
infra/
bicep/{project}/ # Bicep templates (main.bicep + modules/)
terraform/{project}/ # Terraform configurations (main.tf + modules/)
tools/
apex-recall/ # Progressive session recall CLI
scripts/ # Validation and maintenance scripts
| Your files (safe to edit, never overwritten by sync) | Upstream-managed files (overwritten by sync) |
|---|---|
agent-output/ — generated project artifacts |
.github/agents/ — agent definitions |
infra/bicep/ — your Bicep templates |
.github/skills/ — agent skills |
.github/workflows/ — your CI/CD workflows |
.github/instructions/ — coding rules |
README.md — your documentation |
.github/copilot-instructions.md |
tools/, package.json |
|
AGENTS.md, .devcontainer/, .vscode/ |
Note: If you disable the sync workflow, everything becomes yours to edit freely. See Customization below.
When you create from this template, every file is yours. The question is which approach gives you the best experience over time.
Strategy A: Edit directly (simplest)
Edit the file you need — for example, change swedencentral to westeurope in
.github/skills/apex-azure-defaults/SKILL.md. If you don't plan to pull upstream
improvements, disable the sync workflow entirely (repo Settings → Actions → disable
Upstream Sync) and manage the repo as your own.
If you want upstream updates later, re-enable the workflow. The sync PR will overwrite your edited files with the upstream version (it is not a merge), so you'll need to re-apply your changes after merging. Keep a record of what you changed.
Strategy B: Keep sync enabled, layer your overrides (recommended for teams that want continuous upstream improvements)
The sync workflow overwrites all upstream-managed files but never touches the four excluded paths. To safely store overrides that survive sync:
-
Edit the sync exclusion list — the sync workflow file itself is user-owned (
.github/workflows/is excluded from sync). Open.github/workflows/weekly-upstream-sync.ymland add paths toEXCLUDE_PATHS. The mirror and preservation check both consume this list:EXCLUDE_PATHS: | .github/workflows/ agent-output/ infra/bicep/ infra/terraform/ README.md AGENTS.md
Then add your overrides to root
AGENTS.md— it will survive all future syncs. -
Use project-local guidance — place organization defaults in
infra/bicep/{project}/AGENTS.mdorinfra/terraform/{project}/AGENTS.md. Project folders are preserved. The shared track-levelAGENTS.mdfiles are upstream-owned exceptions so security and workflow corrections reach both tracks. To own a shared file instead, remove its entry fromSYNC_EXCEPTIONS. -
VS Code user-profile instructions — place a
.instructions.mdfile in your VS Code profile'sprompts/folder. This lives outside the repo entirely and applies to all your workspaces.
Which strategy to pick?
| Approach | Best for |
|---|---|
| A: Edit directly, skip sync | Solo users, teams that self-manage updates |
| B: Layer overrides, keep sync | Teams that want automatic upstream improvements |
Agents are defined in .github/agents/*.agent.md and skills in
.github/skills/*/SKILL.md. You can add new ones alongside the existing set.
If you keep sync enabled, add your custom paths to EXCLUDE_PATHS.
Distinctive names alone do not protect files: the mirror removes upstream-absent paths.
Manual Upstream Sync runs default to dry_run=true: they mirror into the runner,
validate contracts, and summarize changes without pushing or changing pull requests.
Set upstream_ref to an existing upstream feature branch to preview unmerged changes.
Non-main branches cannot publish.
Scheduled runs use upstream main. A manual main run can set dry_run=false
to propose a sync PR. Every run records the exact upstream commit; review remains manual.
The stabilization and publication checks run before publishing. These checks are not
native agent acceptance or permission to deploy Azure resources.
Private governance baselines, project outputs, generated infrastructure, repository
workflows, local logs and scratch remain preserved. AVM indexes, the module cache and deprecation
data are seeded only when absent, then owned by consumer maintenance. The public governance
fixture and shared track-level guidance continue to follow upstream via SYNC_EXCEPTIONS.
The accelerator distributes governance, IaC and weekly maintenance workflows from APEX's
.github/consumer-workflows/ templates. Operational jobs are disabled in APEX, this accelerator
and template repositories. Repositories created from this template run IaC checks and maintenance
automatically when Actions is enabled. Governance additionally requires
GOVERNANCE_BASELINE_ENABLED=true, a Management Group ID and configured Azure OIDC credentials.
Preview template updates with npm run sync:workflows -- --dry-run, then apply a reviewed
commit using npm run sync:workflows -- --apply --ref <commit-sha>.
Modified workflows block the update; retired files are reported for review, never deleted automatically.
The updater provenance is preserved by content sync. See
consumer workflow ownership.
Both IaC tracks are fully supported. The Requirements agent (Step 1) captures your
iac_tool preference, and the Orchestrator routes Steps 4-6 to the correct track.
| Factor | Bicep | Terraform |
|---|---|---|
| Azure-only | Native DSL, first-class support | Multi-cloud via AzureRM provider |
| State | No state file (ARM-managed) | State file (Azure Storage backend) |
| AVM modules | br/public:avm/res/ |
registry.terraform.io/Azure/avm-res-*/ |
| CI/CD | az deployment group create |
terraform plan + terraform apply |
The accelerator is designed for one repo containing multiple projects. Each project gets its own folders:
agent-output/{project}/— artifacts (requirements, architecture, plans, docs)infra/bicep/{project}/orinfra/terraform/{project}/— IaC templates
Agents, skills, instructions, and the dev container are shared across all projects.
One repo per project is also valid when teams need separate governance or isolation. Each repo is created independently from the template.
- Edit the sync exclusion list in each repo to protect
AGENTS.md, then maintain a standard overrides section that you copy into each repo - VS Code user-profile instructions — personal preferences that follow you across repos without any per-repo setup
- Canonical overrides in a shared location — maintain a standard overrides snippet in a team wiki or internal repo and copy it when creating new instances
| What | How | Frequency |
|---|---|---|
| Agents, skills, instructions, docs, scripts | Automated weekly PR (upstream sync workflow) | Weekly |
| GitHub Actions workflows | npm run sync:workflows (manual) |
As needed |
| All validations | npm run validate:all |
Before each PR |
The sync workflow opens a PR for human review — it never auto-merges. You can disable it entirely if you prefer to manage updates manually.
# Run all code and documentation validations
npm run validate:all
# Fix markdown formatting
npm run lint:md:fix
# Bicep validation (replace {project})
bicep build infra/bicep/{project}/main.bicep
bicep lint infra/bicep/{project}/main.bicep
# Terraform validation
terraform fmt -check -recursive infra/terraform/
cd infra/terraform/{project} && terraform init -backend=false && terraform validate