Integrate a generated health model Bicep project into existing infrastructure-as-code. Detects IaC type (Bicep/Terraform/none), proposes integration level (NONE/SOME/FULL), generates integration snippets, verifies offline, and asks the user to deploy. WHEN: 'integrate health model into my infra', 'add health model to my bicep', 'connect health model to existing IaC', 'integrate health model bicep'. DO NOT USE FOR: designing entities (use healthmodel-design), deploying standalone health models (use healthmodel-deploy), discovering resources (use healthmodel-discovery), or Terraform module generation.
How this skill is triggered — by the user, by Claude, or both
Slash command
/azure-healthmodel-skills:healthmodel-integrateThe summary Claude sees in its skill listing — used to decide when to auto-load this skill
Integrate a generated health model Bicep project (`.healthmodel/05-bicep/`) into the user's existing infrastructure-as-code. The skill detects the IaC type, proposes an integration level, generates integration artifacts as **snippets the user applies manually**, verifies everything offline, and asks the user to test deployment themselves.
Integrate a generated health model Bicep project (.healthmodel/05-bicep/) into the user's existing infrastructure-as-code. The skill detects the IaC type, proposes an integration level, generates integration artifacts as snippets the user applies manually, verifies everything offline, and asks the user to test deployment themselves.
| Level | What it does | When to use |
|---|---|---|
| NONE | Health model Bicep stays standalone. Deploy separately via az deployment group create. | No Bicep IaC, Terraform projects, Azure Export Bicep, or user preference. |
| SOME | Parameterizes all resource references. Generates a .bicepparam file and a module-reference snippet for the user's entrypoint. | User has Bicep IaC and wants the health model to deploy alongside it with correct resource names. |
| FULL | Regenerates health model as an inline Bicep module with feature flags, object parameters, and conditional entity creation. | User wants deep integration where IaC feature flags control which health model entities exist. Matches the azure-search-openai-demo pattern. |
.bicepparam files for the user to apply. The user owns their IaC — the skill produces integration artifacts, not mutations.az bicep build. Ask the user to deploy and report results..healthmodel/05-bicep/ must exist before this skill runs. If missing, tell the user to run healthmodel-design first.loadJsonContent() for fields that need parameterization. Generate inline Bicep resource declarations instead. loadJsonContent() requires compile-time literal paths and cannot accept parameters.az bicep build..healthmodel/06-integrate/. Never write to user IaC directories.dependsOn — use output references instead. Referencing a resource's output property (e.g. parentEntity.id) creates an implicit dependency that Bicep enforces at compile time. Explicit dependsOn is fragile, redundant, and hides the actual data flow.# Health model Bicep project must exist
ls .healthmodel/05-bicep/main.bicep
# Azure CLI with Bicep (for offline verification)
az bicep version
# jq for JSON processing
command -v jq && echo "jq: ok"
Check that .healthmodel/05-bicep/main.bicep exists and compiles:
az bicep build --file .healthmodel/05-bicep/main.bicep --stdout > /dev/null && echo "✓ health model Bicep compiles"
If it doesn't exist, stop and tell the user:
"No health model Bicep found. Run the design skill first:
design entities and signals"
Scan the project directory (and common infra subdirectories) for IaC files:
# Detect Bicep
BICEP_FILES=$(find . -name '*.bicep' -not -path './.healthmodel/*' -not -path './node_modules/*' | head -20)
# Detect Terraform
TF_FILES=$(find . -name '*.tf' -not -path './.healthmodel/*' -not -path './node_modules/*' | head -20)
# Detect Azure Export markers (look for export-generated comments)
EXPORT_MARKERS=$(grep -rl 'Generated by Azure Bicep\|az bicep export\|exported from Azure' . --include='*.bicep' 2>/dev/null | head -5)
Classify the IaC type:
| Detection | IaC Type | Default Level |
|---|---|---|
*.tf files found | Terraform | NONE |
Export markers found in *.bicep | Azure Export Bicep | NONE |
*.bicep files found (no export markers) | Bicep (hand-written) | SOME |
| Neither found | No IaC | NONE |
If Bicep is detected, analyze the entrypoint:
main.bicep files, or the single .bicep file at the repo root or in common dirs (infra/, deploy/, iac/, bicep/)targetScope: Check if it's subscription, resourceGroup (default), managementGroup, or tenant.bicepparam files, parameters.json, or inline params?modules/, core/, or similar subdirectories with reusable modules?Record all findings in .healthmodel/06-integrate/iac-detection.json:
{
"iacType": "bicep",
"entrypoint": "infra/main.bicep",
"targetScope": "subscription",
"parameterStyle": "bicepparam",
"moduleConventions": "infra/core/<category>/<resource>.bicep",
"exportBicep": false,
"resourceTypes": ["Microsoft.Web/sites", "Microsoft.CognitiveServices/accounts", ...],
"overlapWithDesign": ["Microsoft.Web/sites", "Microsoft.CognitiveServices/accounts"]
}
Present the detection results to the user and let them choose the integration level.
Use the ask_user tool:
{
"message": "I've analyzed your infrastructure-as-code. Here's what I found:\n\n**IaC Type**: <detected type>\n**Entrypoint**: <detected file or 'none found'>\n**Target Scope**: <scope>\n**Resource overlap with health model**: <count> resources\n\nBased on this, I recommend **<LEVEL>** integration.\n\nChoose your integration level:",
"requestedSchema": {
"properties": {
"integrationLevel": {
"type": "string",
"title": "Integration level",
"description": "NONE = standalone health model, deploy separately. SOME = parameterized module, deploys with your IaC with correct resource references. FULL = deep integration with feature flags and conditional entities (requires Bicep restructuring).",
"oneOf": [
{"const": "NONE", "title": "NONE — Standalone (deploy health model separately)"},
{"const": "SOME", "title": "SOME — Parameterized module (resource IDs as params)"},
{"const": "FULL", "title": "FULL — Deep integration (feature flags + conditional entities)"}
],
"default": "<detected recommendation>"
}
},
"required": ["integrationLevel"]
}
}
If the user chose a level higher than recommended (e.g., FULL when detection suggests SOME), warn them about the complexity and confirm. If they insist, proceed.
When level is NONE:
.healthmodel/06-integrate/deploy-standalone.md:# Standalone Health Model Deployment
The health model Bicep is self-contained and deploys independently from your IaC.
## Deploy command
```bash
az deployment group create \
--resource-group <YOUR_RG> \
--template-file .healthmodel/05-bicep/main.bicep \
--parameters healthModelName=<NAME> location=<LOCATION>
```
## Why standalone?
<reason — Terraform detected / Azure Export Bicep / user preference / no IaC found>
az deployment group create."Skip to Step 7 (verification).
When level is SOME:
Scan all design JSON files in .healthmodel/03-design/ to find ARM resource IDs:
# Find all resource IDs in signal definitions
jq -r '.. | .resourceId? // empty' .healthmodel/03-design/signals/*.json 2>/dev/null | sort -u
# Find resource IDs in entities
jq -r '.. | .resourceId? // empty' .healthmodel/03-design/entities/*.json 2>/dev/null | sort -u
Collect all unique resource IDs and the parameters they map to (healthModelName, location, resource group).
Create .healthmodel/06-integrate/health-model-module.bicep — a wrapper that takes resource IDs as parameters and calls the health model:
// GENERATED FILE — edit .healthmodel/03-design instead, then re-run integration
// Integration level: SOME — parameterized module wrapper
@description('Name of the health model resource.')
param healthModelName string
@description('Azure region for the health model.')
param location string
@description('Resource ID of <resource 1>.')
param <resource1>ResourceId string
@description('Resource ID of <resource 2>.')
param <resource2>ResourceId string
// ... one param per unique resource reference
module healthModel '../05-bicep/main.bicep' = {
name: 'healthModel'
params: {
healthModelName: healthModelName
location: location
}
}
For SOME level, the inner main.bicep keeps loadJsonContent() — resource IDs are baked into the JSON from the discovery phase. The resource ID params on the wrapper are documentation-only — they make the module's dependencies explicit in the .bicepparam file so the deployment operator knows which resources must exist. They are NOT passed to the inner module.
.bicepparam fileCreate .healthmodel/06-integrate/health-model.bicepparam:
using './health-model-module.bicep'
param healthModelName = '<from discovery>'
param location = '<from discovery>'
param <resource1>ResourceId = '<extracted ID>'
// ...
Generate .healthmodel/06-integrate/snippet-for-main.bicep — the module reference the user should add to their entrypoint:
// ── Health Model ──
// Add this module reference to your entrypoint (e.g., infra/main.bicep)
module healthModel '<relative-path-to-health-model-module>' = {
name: 'healthModel'
scope: resourceGroup // adjust to match your targetScope
params: {
healthModelName: 'hm-${environmentName}'
location: location
<resource1>ResourceId: <module-output-or-resource-id>
// Map each param to your existing module outputs or resource IDs
}
}
Show the user:
.healthmodel/06-integrate/Use ask_user to confirm they understand and will apply the snippet:
{
"message": "I've generated the integration artifacts. Here's what to do:\n\n1. Review the generated files in `.healthmodel/06-integrate/`\n2. Copy the module reference from `snippet-for-main.bicep` into your `<entrypoint>`\n3. Map the resource ID parameters to your existing module outputs\n\nDo you want me to explain the parameter mapping in detail?",
"requestedSchema": {
"properties": {
"understood": {
"type": "boolean",
"title": "I understand the integration steps",
"default": true
},
"needsHelp": {
"type": "boolean",
"title": "I need help mapping parameters to my existing resources",
"default": false
}
},
"required": ["understood"]
}
}
If needsHelp is true, walk through each parameter and suggest which existing module output or resource reference to use, based on the IaC detection in Step 2.
When level is FULL:
Read the health model design to identify:
Cross-reference with the IaC detection (Step 2) to determine which resources have feature flags or conditional deployment in the user's existing Bicep.
Following the azure-search-openai-demo pattern:
deployAzureOpenAi, useApplicationInsights= '' default) for conditional onesDocument the parameter design in .healthmodel/06-integrate/param-design.json:
{
"featureFlags": [
{"name": "deployOpenAi", "type": "bool", "default": true, "controls": ["ai-inference-entity", "openai-signals"]},
{"name": "useAppInsights", "type": "bool", "default": false, "controls": ["app-perf-entity", "appinsights-signals"]}
],
"resourceIdParams": [
{"name": "appServiceResourceId", "type": "string", "required": true, "mapsTo": "backend-app entity"},
{"name": "cognitiveServicesResourceId", "type": "string", "required": false, "conditionedOn": "deployOpenAi"}
]
}
Create .healthmodel/06-integrate/health-model-full.bicep — a single-file module with:
@description decoratorsif guards based on feature flagsloadJsonContent()) for signals whose resource references come from parametersdependsOnFollow the reference pattern from azure-search-openai-demo/infra/core/monitor/health-model.bicep:
// GENERATED FILE — edit .healthmodel/03-design instead, then re-run integration
// Integration level: FULL — inline module with conditional entities
@description('Name of the health model resource.')
param name string
@description('Azure region.')
param location string
@description('Resource tags.')
param tags object = {}
// Feature flags
@description('Whether Azure OpenAI is deployed.')
param deployAzureOpenAi bool = true
// Resource IDs
@description('Resource ID of the App Service.')
param appServiceResourceId string
@description('Resource ID of Azure OpenAI. Required when deployAzureOpenAi is true.')
param cognitiveServicesResourceId string = ''
// Canvas layout — conditional child counts
var aiGroupChildCount = 1 + (deployAzureOpenAi ? 1 : 0)
var xAiGroup = 0
var xNextGroup = xAiGroup + aiGroupChildCount * 250
// Health model root
resource identity 'Microsoft.ManagedIdentity/userAssignedIdentities@2023-01-31' = {
name: '${name}-identity'
location: location
tags: tags
}
resource healthModel 'Microsoft.CloudHealth/healthModels@2026-01-01-preview' = {
name: name
location: location
tags: tags
identity: { type: 'UserAssigned', userAssignedIdentities: { '${identity.id}': {} } }
properties: {}
}
// Conditional entity — only created when feature flag is true
resource aiInferenceEntity 'Microsoft.CloudHealth/healthModels/entities@2026-01-01-preview' = if (deployAzureOpenAi) {
parent: healthModel
name: 'ai-inference'
properties: {
displayName: 'AI Inference'
resourceId: cognitiveServicesResourceId
// ... inline properties from design JSON
}
}
Same as Step 5d but with the FULL module and richer parameters:
module healthModel '<path>/health-model-full.bicep' = {
name: 'healthModel'
params: {
name: 'hm-${environmentName}'
location: location
tags: tags
deployAzureOpenAi: deployAzureOpenAi // from your existing feature flags
appServiceResourceId: backend.outputs.id
cognitiveServicesResourceId: deployAzureOpenAi ? openAi.outputs.resourceId : ''
}
}
Show the user the full module, the snippet, and how to map feature flags and resource IDs from their existing IaC. Use the same ask_user pattern as Step 5e.
Run az bicep build to verify all generated Bicep compiles:
# 1. Verify health model Bicep (always)
az bicep build --file .healthmodel/05-bicep/main.bicep --stdout > /dev/null \
&& echo "✓ health model Bicep compiles"
# 2. Verify integration module (SOME/FULL only)
if [ -f .healthmodel/06-integrate/health-model-module.bicep ]; then
az bicep build --file .healthmodel/06-integrate/health-model-module.bicep --stdout > /dev/null \
&& echo "✓ integration module compiles"
fi
if [ -f .healthmodel/06-integrate/health-model-full.bicep ]; then
az bicep build --file .healthmodel/06-integrate/health-model-full.bicep --stdout > /dev/null \
&& echo "✓ full integration module compiles"
fi
# 3. Verify user's entrypoint (if they've applied the snippet)
# Ask the user to run: az bicep build --file <their-entrypoint>
If verification fails, show the error and fix the generated Bicep. Re-verify after every fix.
⛔ Do NOT run the user's full deployment. Verification is offline only.
Tell the user what to do next and collect their results.
Use the ask_user tool:
{
"message": "Integration is ready! Here's what to do:\n\n1. Apply the snippet from `.healthmodel/06-integrate/` to your IaC entrypoint\n2. Run `az bicep build --file <your-entrypoint>` to verify it compiles\n3. Deploy using your normal deployment pipeline\n4. Come back and tell me how it went\n\nI won't run your deployment — that's your call.",
"requestedSchema": {
"properties": {
"deploymentStatus": {
"type": "string",
"title": "How did the deployment go?",
"oneOf": [
{"const": "success", "title": "Success — everything deployed correctly"},
{"const": "partial", "title": "Partial — some resources deployed, some failed"},
{"const": "failed", "title": "Failed — deployment did not succeed"},
{"const": "not_yet", "title": "Haven't deployed yet — I'll come back later"}
]
},
"details": {
"type": "string",
"title": "Details (error messages, what worked, what didn't)",
"description": "Paste any error messages or describe what happened. Leave blank if everything worked."
}
},
"required": ["deploymentStatus"]
}
}
Based on the response:
healthmodel-deploy's smoke testWrite the integration outcome to .healthmodel/06-integrate/integration-state.json:
{
"integrationLevel": "SOME",
"iacType": "bicep",
"entrypoint": "infra/main.bicep",
"generatedFiles": [
".healthmodel/06-integrate/health-model-module.bicep",
".healthmodel/06-integrate/health-model.bicepparam",
".healthmodel/06-integrate/snippet-for-main.bicep"
],
"verificationPassed": true,
"userDeploymentStatus": "success",
"integratedAt": "2026-05-24T10:00:00Z"
}
If .healthmodel/06-integrate/integration-state.json already exists:
npx claudepluginhub abossard/azure-healthmodel-skills --plugin azure-healthmodel-skillsCreates bite-sized, testable implementation plans from specs or requirements, with file structure and task decomposition. Activates before coding multi-step tasks.