AgentStack
Browse Sign in
Browse Why AgentStack Sell Docs
Sign in
SKILL unreviewed MIT Self-run

Azd Patterns

skill-aiappsgbb-awesome-gbb-azd-patterns · by aiappsgbb

>

No reviews yet
0 installs
31 views
0.0% view→install

Install

$ agentstack add skill-aiappsgbb-awesome-gbb-azd-patterns

Open-source listing, not yet scanned by AgentStack. Follow the source repository for install instructions.

Security review

⚠ Flagged

1 finding(s); flagged for manual review. · v0.1.0 How review works →

  • Prompt-injection patterns
  • Secret / credential exfiltration
  • Dangerous shell & filesystem operations
  • Untrusted network calls
  • Known-malicious package signatures
  • high Dangerous shell/eval execution.

What it can access

  • Network access Used
  • Filesystem access Used
  • Shell / process execution Used
  • Environment & secrets Used
  • Dynamic code execution No

From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.

View the full security report →

Reliability & compatibility

Not yet reviewed
0 installs to date
no reviews yet
2mo ago

Declared compatibility

Claude CodeClaude Desktop

Compatibility is declared by the source manifest. End-to-end runtime verification is coming, see below.

Preview Execution monitoring

We're building live execution health for every listing: tool-call success rate, median latency, uptime, and last-checked timestamps, measured, not self-reported. It isn't live yet, so we don't show numbers we can't stand behind.

How agent discovery & health will work →
Are you the author of Azd Patterns? Claim this listing to set pricing, connect Stripe payouts, and keep 70% of every sale.
Sign up to claim

About

AZD Tips & Patterns

Conventions and best practices for azd workflows, hooks, and ACA job deployments gathered from real repos.


ACA Job Deployment

azd does not natively deploy Container Apps Jobs — only Container Apps. Jobs need a separate deployment step.

Recommended: Python + postdeploy hook (cross-platform)

Used in newer repos. The pattern:

  1. azure.yaml — wire a postdeploy hook that runs after azd deploy:

``yaml hooks: postdeploy: shell: pwsh run: 'cd infra/scripts && uv sync --frozen && uv run deploy_job.py' interactive: false continueOnError: false ``

  1. infra/scripts/deploy_job.py — update the job image via Azure SDK:

```python import asyncio, os, sys, logging from utils import loadazdenv from azure.identity.aio import AzureCliCredential from azure.mgmt.appcontainers.aio import ContainerAppsAPIClient

async def main(): loadazdenv() imagename = os.getenv("SERVICEAGENTSIMAGENAME") jobname = os.getenv("JOBNAME") resourcegroup = os.getenv("RESOURCEGROUP") subscriptionid = os.getenv("SUBSCRIPTIONID") tenantid = os.getenv("AZURETENANT_ID")

async with AzureCliCredential(tenantid=tenantid) as credential: async with ContainerAppsAPIClient(credential, subscriptionid) as client: job = await client.jobs.get(resourcegroup, jobname) job.template.containers[0].image = imagename # Remove stale sidecars — they cause "Failed" status if they exit non-zero job.template.containers = [job.template.containers[0]] poller = await client.jobs.begincreateorupdate(resourcegroup, job_name, job) await poller.result()

if __name__ == "__main__": try: asyncio.run(main()) except Exception as e: logging.critical("Error deploying job: %s", e) sys.exit(1) ```

  1. infra/scripts/utils.py — load azd environment variables:

```python import json, os, subprocess from pathlib import Path from dotenv import load_dotenv

def ensureazdconfigdir(): """Walk up from script dir to find repo-root .azure directory. Needed when azd hooks run from a temp directory.""" if os.environ.get("AZDCONFIGDIR"): return search = Path(__file__).resolve().parent for in range(10): candidate = search / ".azure" if candidate.isdir() and any( (candidate / d / ".env").exists() for d in os.listdir(candidate) if (candidate / d).isdir() ): os.environ["AZDCONFIG_DIR"] = str(candidate) return if search.parent == search: break search = search.parent

def loadazdenv(): """Load the default azd environment's .env file.""" ensureazdconfigdir() result = subprocess.run("azd env list -o json", shell=True, captureoutput=True, text=True) if result.returncode != 0: raise Exception("Error loading azd env") envjson = json.loads(result.stdout) for entry in envjson: if entry["IsDefault"]: loaddotenv(entry["DotEnvPath"], override=True) return raise Exception("No default azd env file found") ```

  1. infra/scripts/pyproject.toml — managed by uv:

``toml [project] name = "infra-scripts" requires-python = ">=3.11" dependencies = [ "azure-identity", "azure-mgmt-appcontainers", "python-dotenv", ] ``

Benefits over the old PowerShell approach

| Old (publish_aca.ps1) | New (deploy_job.py) | |---|---| | Shells out to az acr build + az containerapp job update | Uses Azure SDK directly | | Windows-only (or requires PS Core) | Cross-platform (Python) | | Depends on az CLI subscription state | Uses AzureCliCredential (respects AZURE_CONFIG_DIR) | | No sidecar cleanup | Removes stale sidecars that cause false "Failed" status | | Manual image tagging | Reads image name from azd env vars (SERVICE_*_IMAGE_NAME) |

Legacy: PowerShell script (publish_aca.ps1)

Older repos (e.g. acme-demo-form) use a postprovision hook with a PowerShell script:

# azure.yaml
hooks:
  postprovision:
    shell: pwsh
    run: |
      $RG = azd env get-value AZURE_RESOURCE_GROUP
      $APP_NAME = azd env get-value AZURE_CAJOB_NAME
      .\infra\scripts\publish_aca.ps1 -RG $RG -APP_SOURCE_FOLDER .\src\ca-job -APP_NAME $APP_NAME -TYPE job
    interactive: true
    continueOnError: false

The script does az acr build + az containerapp job update. This works but is not cross-platform and depends on az CLI subscription state.

> ⚠️ Gotcha: postprovision runs only on azd provision/azd up, NOT on azd deploy. If the job needs updating on every deploy, use postdeploy instead.


Fetch-Latest-Image Pattern (Bicep + ACR)

When Bicep provisions a Container App (or Job), it needs an image reference. On first deploy the real image hasn't been built yet, so Bicep uses a placeholder. On subsequent deploys, azd deploy builds the real image into ACR and patches the running container. This is the expected lifecycle — the placeholder in Bicep is intentional, not a bug.

Why the placeholder exists

// infra/main.bicep — first-deploy bootstrap
resource mcpApp 'Microsoft.App/containerApps@2024-10-02-preview' = {
  ...
  tags: {
    'azd-service-name': 'mcp'  // REQUIRED — azd deploy uses this tag to find the resource
  }
  properties: {
    template: {
      containers: [
        {
          name: 'mcp'
          // Placeholder: azd deploy will swap this to the real ACR image
          image: 'mcr.microsoft.com/azuredocs/containerapps-helloworld:latest'
        }
      ]
    }
  }
}

> ⚠️ The azd-service-name tag is MANDATORY. azd deploy locates the > Container App to patch by searching for a resource tagged with > azd-service-name: matching the service name in azure.yaml. > Without this tag, azd deploy fails with "resource not found: unable to > find a resource tagged with 'azd-service-name: mcp'". This is not > documented prominently in the azd docs — add it to every ACA Bicep.

On azd up:

  1. azd provision runs Bicep → Container App created with placeholder image
  2. azd deploy builds src/mcp/ → pushes to ACR → patches the Container App with the real image
  3. Subsequent azd deploy calls repeat step 2 only

Pattern A — azure.yaml service binding (recommended)

Let azd manage the image lifecycle. Declare each container as a service:

# azure.yaml
services:
  mcp:
    host: containerapp
    project: src/mcp
    docker:
      path: src/mcp/Dockerfile
      context: src/mcp

azd deploy will:

  • Build the Dockerfile into ACR (tag = azd-deploy-{timestamp})
  • Set env var SERVICE_MCP_IMAGE_NAME = full ACR image ref
  • Patch the Container App to use the new image

azure.yaml field traps

> ⚠️ language: html and language: static are NOT valid azure.yaml > values. They look plausible for static or front-end services but silently > break azd build detection. For custom-Dockerfile services, omit > language entirely and declare only project + docker.

When the Dockerfile is not in the service root, set docker.context to the actual build-context directory:

services:
  web:
    host: containerapp
    project: .
    docker:
      path: ./src/Dockerfile
      context: ./src

Without docker.context, azd deploy builds from the service root and the Dockerfile's COPY lines fail because the expected files are outside the build context.

Pattern B — postdeploy hook with SERVICE_*_IMAGE_NAME

For Container Apps Jobs (not managed by azd deploy), use a postdeploy hook that reads the azd-generated image name:

hooks:
  postdeploy:
    shell: pwsh
    run: 'cd infra/scripts && uv sync --frozen && uv run deploy_job.py'
# infra/scripts/deploy_job.py
image_name = os.getenv("SERVICE_MCP_IMAGE_NAME")  # set by azd deploy
# ... patch the Container App Job with this image

Pattern C — Bicep containerImage parameter with default

For repos where the image is pre-built (e.g., shared ACR across teams):

param containerImage string = 'mcr.microsoft.com/azuredocs/containerapps-helloworld:latest'

resource app 'Microsoft.App/containerApps@2024-10-02-preview' = {
  ...
  properties: {
    template: {
      containers: [{ name: 'app', image: containerImage }]
    }
  }
}

Override at deploy time: azd provision --parameter containerImage=myacr.azurecr.io/app:v2

The SERVICE_*_IMAGE_NAME convention

azd auto-generates env vars for each service declared in azure.yaml:

| azure.yaml service name | Env var | Example value | |---|---|---| | mcp | SERVICE_MCP_IMAGE_NAME | acrfoo.azurecr.io/mcp:azd-deploy-1716300000 | | agent | SERVICE_AGENT_IMAGE_NAME | acrfoo.azurecr.io/agent:azd-deploy-1716300000 |

These are available in postdeploy hooks and in .azure/{env}/.env.

> ⚠️ Don't treat the Bicep placeholder as a bug. When reviewing Bicep > that uses containerapps-helloworld:latest, check whether azure.yaml > declares the corresponding service. If it does, azd deploy handles the > image swap automatically. The placeholder is a bootstrap artifact, not a > deployment gap.


ACA Job: silent-failure debug playbook

Symptom we keep hitting. ACA Job execution flips to Failed within 60s of the deploy completing, but zero console + system logs reach Log Analytics Workspace even though sibling ACA apps (MCP server, agent) in the same env route logs cleanly. az containerapp job logs show hangs indefinitely. This has bitten deadline-watcher cron jobs after in-process refactors and is often the biggest end-of-session blocker.

The diagnostic ladder below goes cheap → expensive. Stop at the first rung that surfaces actionable signal.

Rung 1 — Verify the basics aren't lying

$RG  = 'rg--poc'
$JOB = 'aca-job-deadline-watcher'

# Confirm the job exists and what image it's actually running
az containerapp job show --resource-group $RG --name $JOB `
  --query "{state:properties.runningState, image:properties.template.containers[0].image, env:properties.environmentId}" -o table

# Confirm last execution(s)
az containerapp job execution list --resource-group $RG --name $JOB `
  --query "[].{name:name, status:properties.status, start:properties.startTime, end:properties.endTime}" `
  --output table | Select-Object -First 10

Common findings:

  • Image is mcr.microsoft.com/azuredocs/containerapps-helloworld — `azd

provision ran but azd deploy / publish_aca didn't (placeholder leak — threadlight-safe-check` Step 3.5 (image-probe) catches this; check separately).

  • Image hash matches latest ACR push but jobs still Failed → real

runtime crash, advance to Rung 2.

Rung 2 — Probe LAW for ANY signal at all (including system events)

$WS = az monitor log-analytics workspace list --resource-group $RG `
        --query "[0].customerId" -o tsv
$JOB = 'aca-job-deadline-watcher'

# Console logs — what stdout/stderr emitted (this is the "no logs" thing if empty)
az monitor log-analytics query --workspace $WS --analytics-query @"
ContainerAppConsoleLogs_CL
| where ContainerJobName_s == '$JOB'
| order by TimeGenerated desc
| project TimeGenerated, RevisionName_s, Log_s
| take 50
"@ -o table

# System logs — ACA control plane events (start/stop/pull/probe failures)
az monitor log-analytics query --workspace $WS --analytics-query @"
ContainerAppSystemLogs_CL
| where ContainerAppName_s == '$JOB'
| order by TimeGenerated desc
| project TimeGenerated, Type_s, Reason_s, Log_s
| take 50
"@ -o table

What each empty/non-empty combo means:

| ConsoleLogs | SystemLogs | Likely cause | |---|---|---| | Empty | Empty | LAW routing not wired to this job (env-level diag setting missing or job created before diag setting), OR ACA Job log-pipeline lag (try again 2-3 min after execution) | | Empty | Non-empty | Image pulls / starts but exits before any print() / logging.info() reaches LAW. Usually an import-time crash — the process exits before logging.basicConfig() fires. Move to Rung 3. | | Non-empty | Non-empty | You have signal — read it. |

Rung 3 — Force first-line logging in the entrypoint

When the ConsoleLogs pipe is empty but SystemLogs show the container started + exited, the crash is import-side. Tactic: emit a synchronous write to stderr before any other import so even an ImportError produces a visible breadcrumb.

# main.py — top of file, BEFORE any project imports
import sys
sys.stderr.write("BOOT: entrypoint reached\n"); sys.stderr.flush()
try:
    import azure.identity     # the usual suspects first
    sys.stderr.write("BOOT: azure.identity OK\n"); sys.stderr.flush()
    import azure.cosmos
    sys.stderr.write("BOOT: azure.cosmos OK\n"); sys.stderr.flush()
    # ... your imports ...
except Exception as e:
    sys.stderr.write(f"BOOT: import failed: {type(e).__name__}: {e}\n")
    sys.stderr.flush()
    raise

Push, redeploy, kick off a manual execution (az containerapp job start --resource-group $RG --name $JOB), wait ~90s, re-run the ConsoleLogs query at Rung 2. The breadcrumbs reveal which import exploded.

Rung 4 — Activity log probe (orthogonal channel — bypasses LAW entirely)

$RG = 'rg--poc'
$JOB = 'aca-job-deadline-watcher'
$JOB_ID = az containerapp job show --resource-group $RG --name $JOB --query id -o tsv

# Last 4 hours of activity log entries for the job resource
az monitor activity-log list `
  --resource-id $JOB_ID `
  --start-time (Get-Date).AddHours(-4).ToString('o') `
  --query "[].{time:eventTimestamp, level:level, op:operationName.value, status:status.value, msg:properties.statusMessage}" `
  -o table | Select-Object -First 20

Catches: image pull failures (ACR auth / RBAC missing on the env's UAMI), execution-create failures (quota), control-plane denials.

Rung 5 — Portal Container Apps blade (job execution detail)

The most painful diagnostic to automate, but it has signal that is NOT exposed via CLI. Path:

  1. Azure Portal → Resource group → the ACA Job resource
  2. Left nav → Execution history
  3. Click the failed execution name
  4. The right pane shows per-replica logs including init-container

output and any pre-logging.basicConfig stderr — the same data that LAW would show if the routing were healthy.

Use this rung when Rungs 1–4 give you nothing actionable. Do not skip the earlier rungs — they're 1-line probes; the portal click is several minutes of navigation.

Rung 6 — Detectors API (preview — sometimes 404s)

$RG = 'rg--poc'
$JOB = 'aca-job-deadline-watcher'
$exec = (az containerapp job execution list --resource-group $RG --name $JOB `
          --query "[0].name" -o tsv)
az rest --method get `
  --uri "https://management.azure.com/subscriptions/$(az account show --query id -o tsv)/resourceGroups/$RG/providers/Microsoft.App/jobs/$JOB/executions/$exec/detectors?api-version=2024-03-01"

Returns 404 on many regions / SKU combos as of May 2026 — try api-version=2024-08-02-preview or 2025-01-01 if 404. When it works, surfaces structured root-cause diagnostics (e.g. "OutOfMemoryException", "ImagePullBackOff", "MaxReplicasExceeded").

Common root causes — the "if I ran out of time, what's it most likely?" table

| Symptom in logs | Likely cause | Fix | |---|---|---| | ConsoleLogs empty + SystemLogs Type=Pull, Reason=ImagePullError | ACR pull RBAC missing on the UAMI bound to that specific ACA app (identity.userAssignedIdentities), or image tag doesn't exist in ACR. Common trap: in a multi-service pi

Source & license

This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.

Install and usage instructions live in the source repository linked above.

Reviews

No reviews yet, be the first.

Versions

  • v0.1.0 Imported from the upstream source.