Expert Bicep Implement
All-in-one agent covering azure, bicep, infrastructure, code. Includes structured workflows, validation checks, and reusable patterns for devops infrastructure.
Expert Bicep Implement
An Azure Bicep Infrastructure as Code specialist that writes production-grade Bicep templates following Azure best practices, covering module design, parameter validation, conditional deployments, and CI/CD integration.
When to Use This Agent
Choose Expert Bicep Implement when:
- Writing new Bicep templates for Azure resource deployments
- Refactoring ARM JSON templates into clean Bicep code
- Creating reusable Bicep modules for team-wide use
- Implementing conditional and looped resource deployments
- Setting up Bicep CI/CD pipelines with validation and what-if
Consider alternatives when:
- Using Azure Verified Modules (use Azure Verified Modules Guru)
- Exporting existing resources to IaC (use Azure IaC Exporter)
- Writing Terraform instead of Bicep (use a Terraform specialist)
Quick Start
# .claude/agents/expert-bicep-implement.yml name: Expert Bicep Implement description: Write production-grade Azure Bicep templates model: claude-sonnet tools: - Read - Write - Edit - Bash - Glob - Grep
Example invocation:
claude "Create a Bicep module for deploying an Azure App Service with staging slots, managed identity, custom domain, and diagnostic settings"
Core Concepts
Bicep Template Structure
| File | Purpose | Example |
|---|---|---|
main.bicep | Orchestration, module composition | Deploys all modules |
modules/*.bicep | Reusable resource modules | appService.bicep |
parameters/*.json | Environment-specific values | dev.parameters.json |
bicepconfig.json | Linter and registry config | Module aliases |
Bicep Module Pattern
// modules/appService.bicep @description('Name of the App Service') param appName string @description('Azure region') param location string = resourceGroup().location @description('App Service Plan SKU') @allowed(['B1', 'S1', 'P1v3', 'P2v3']) param skuName string = 'S1' @description('Enable staging deployment slot') param enableStagingSlot bool = true @description('Log Analytics workspace ID for diagnostics') param logAnalyticsWorkspaceId string @description('Tags to apply to all resources') param tags object = {} // App Service Plan resource appServicePlan 'Microsoft.Web/serverfarms@2023-01-01' = { name: '${appName}-plan' location: location tags: tags sku: { name: skuName } properties: { reserved: true } } // Web App resource webApp 'Microsoft.Web/sites@2023-01-01' = { name: appName location: location tags: tags identity: { type: 'SystemAssigned' } properties: { serverFarmId: appServicePlan.id httpsOnly: true siteConfig: { linuxFxVersion: 'NODE|20-lts' alwaysOn: true ftpsState: 'Disabled' minTlsVersion: '1.2' http20Enabled: true } } } // Staging slot (conditional) resource stagingSlot 'Microsoft.Web/sites/slots@2023-01-01' = if (enableStagingSlot) { parent: webApp name: 'staging' location: location tags: tags identity: { type: 'SystemAssigned' } properties: { serverFarmId: appServicePlan.id siteConfig: webApp.properties.siteConfig } } // Diagnostic settings resource diagnostics 'Microsoft.Insights/diagnosticSettings@2021-05-01-preview' = { scope: webApp name: '${appName}-diag' properties: { workspaceId: logAnalyticsWorkspaceId logs: [ { category: 'AppServiceHTTPLogs', enabled: true } { category: 'AppServiceConsoleLogs', enabled: true } { category: 'AppServiceAppLogs', enabled: true } ] metrics: [ { category: 'AllMetrics', enabled: true } ] } } // Outputs output appServiceId string = webApp.id output defaultHostname string = webApp.properties.defaultHostName output principalId string = webApp.identity.principalId
CI/CD Pipeline
# .github/workflows/deploy-infra.yml name: Deploy Infrastructure on: push: paths: ['infra/**'] branches: [main] pull_request: paths: ['infra/**'] jobs: validate: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - uses: azure/login@v2 with: client-id: ${{ secrets.AZURE_CLIENT_ID }} tenant-id: ${{ secrets.AZURE_TENANT_ID }} subscription-id: ${{ secrets.AZURE_SUBSCRIPTION_ID }} - run: az bicep build --file infra/main.bicep - run: | az deployment group validate \ --resource-group myapp-rg \ --template-file infra/main.bicep \ --parameters infra/parameters/prod.json what-if: needs: validate if: github.event_name == 'pull_request' runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - uses: azure/login@v2 with: { client-id: '${{ secrets.AZURE_CLIENT_ID }}', tenant-id: '${{ secrets.AZURE_TENANT_ID }}', subscription-id: '${{ secrets.AZURE_SUBSCRIPTION_ID }}' } - run: | az deployment group what-if \ --resource-group myapp-rg \ --template-file infra/main.bicep \ --parameters infra/parameters/prod.json deploy: needs: validate if: github.ref == 'refs/heads/main' runs-on: ubuntu-latest environment: production steps: - uses: actions/checkout@v4 - uses: azure/login@v2 with: { client-id: '${{ secrets.AZURE_CLIENT_ID }}', tenant-id: '${{ secrets.AZURE_TENANT_ID }}', subscription-id: '${{ secrets.AZURE_SUBSCRIPTION_ID }}' } - run: | az deployment group create \ --resource-group myapp-rg \ --template-file infra/main.bicep \ --parameters infra/parameters/prod.json
Configuration
| Parameter | Description | Default |
|---|---|---|
bicep_version | Bicep CLI version | latest |
target_scope | Deployment scope (resourceGroup, subscription) | resourceGroup |
module_registry | Bicep module registry (public, private ACR) | br/public |
linter_rules | Bicep linter configuration | Default rules |
naming_convention | Resource naming pattern | Azure CAF |
parameter_format | Parameter file format (json, bicepparam) | json |
Best Practices
-
Use parameter decorators for validation instead of runtime checks. Bicep's
@allowed,@minLength,@maxLength,@minValue, and@maxValuedecorators catch invalid parameters at deployment time, before any resources are created. Add@descriptionto every parameter for self-documenting templates. Validation at the template level prevents failed deployments that partially create resources. -
Create modules for every reusable resource pattern. If an App Service with diagnostic settings and managed identity is deployed in 3 environments, create one module and call it 3 times with different parameters. Modules enforce consistency — every App Service gets the same security baseline, logging configuration, and identity setup. Changes to the module propagate to all deployments automatically.
-
Use
existingkeyword to reference resources without redeploying them. When a module needs to reference a Key Vault, VNet, or Log Analytics workspace that is managed by another template, useresource kv 'Microsoft.KeyVault/vaults@2023-07-01' existing = { name: kvName }. This reads the resource's properties without attempting to modify it, avoiding permission conflicts and unintended changes. -
Run
what-ifon every pull request before merging infrastructure changes. Theaz deployment group what-ifcommand shows exactly what resources will be created, modified, or deleted without actually making changes. Include the what-if output as a PR comment so reviewers can see the infrastructure impact. This is the Bicep equivalent of a terraform plan, and it prevents surprise changes. -
Separate concerns between main.bicep and modules. Main.bicep should only orchestrate module calls and pass parameters. All resource definitions belong in modules. This keeps main.bicep short and readable (under 100 lines), makes modules independently testable, and allows different teams to own different modules while sharing the same deployment orchestration.
Common Issues
Deployment fails with "resource already exists" when renaming resources. Azure does not rename resources — changing a name creates a new resource and orphans the old one, which may conflict. To rename, deploy the new resource alongside the old one, migrate data/configuration, then remove the old resource in a subsequent deployment. Never rename resources that contain stateful data (databases, storage accounts) without a migration plan.
Circular dependency between two resources that reference each other. Resource A's property references Resource B, and Resource B's property references Resource A, creating a deployment deadlock. Break the cycle by deploying one resource without the cross-reference, then updating it in a second deployment step. Alternatively, use dependsOn to establish ordering and set one reference using a resource block with the existing keyword after both resources exist.
Parameters file grows unwieldy with dozens of parameters. As templates add more resources and configuration options, the parameters file becomes difficult to manage. Group related parameters into objects: networking: { vnetPrefix, subnetPrefix, nsgRules } instead of vnetPrefix, subnetPrefix, nsgRules as separate top-level parameters. Use parameter files per environment and per module, not one monolithic file.
Reviews
No reviews yet. Be the first to review this template!
Similar Templates
API Endpoint Builder
Agent that scaffolds complete REST API endpoints with controller, service, route, types, and tests. Supports Express, Fastify, and NestJS.
Documentation Auto-Generator
Agent that reads your codebase and generates comprehensive documentation including API docs, architecture guides, and setup instructions.
Ai Ethics Advisor Partner
All-in-one agent covering ethics, responsible, development, specialist. Includes structured workflows, validation checks, and reusable patterns for ai specialists.