agentleFS
MicrosoftKnown publishermicrosoft/entra-agentid-samples/.claude/skills/deploy-agent-aca-dev/SKILL.md

deploy-agent-aca-dev

Skill12 starsChanged 7 months agoMITView on GitHub

AI-led deployment of the local-LLM sample agent (Ollama + Microsoft Entra Agent ID sidecar) to Azure Container Apps. Use when the user wants to deploy sidecar/dev to ACA, run the agent on Azure without AWS/GCP, host Ollama on Container Apps, promote the docker-compose local-dev stack from ClientSecret to SignedAssertionFromManagedIdentity (secretless), or debug AADSTS65001/AADSTS50011/ImagePullBackOff/Ollama OOM errors in this specific deployment. NOT for AWS Bedrock (use deploy-agent-aca-aws) and NOT for local docker-compose on a laptop (use sidecar/dev directly). Chains to entra-agent-id-setup for the Blueprint + Agent Identity + Client SPA objects.

The file

We split this skill into the rules it gives an agent

5 rules. About 0 are common, 1 is distinctive, and 4 are very specific to this project.

  • ≈0

    Common · estimate

    Many files like this have a rule of this kind.

  • ≈1

    Distinctive · estimate

    This author's own choices. Worth a look.

  • 4

    Very specific

    Tied to their project's names, files or tools. Probably skip.

  • Common
  • Distinctive
  • Very specific
  1. Very specific:

    Before running any az command that provisions resources, confirm each SKU choice with the user.

    line 44
  2. Very specific:

    Ask the user to confirm: tenant ID, subscription ID, resource group name, location, SKU choices (including OLLAMA_CPU / OLLAMA_MEMORY — …

    line 62
  3. Very specific:

    No Docker Desktop needed. Works for llm-agent and weather-api only.

    line 112
  4. Very specific:

    If OLLAMA_IMAGE_STRATEGY=baked (Option A only):

    line 125
  5. Distinctive:

    If all prerequisites are in place and SKU variables are confirmed:

    line 169

≈ “Common” is an estimate: at least 1 in 5 of the 350,495 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.

Keep what fits and drop the rest. Your version, ready for your agents.
Files
SKILL.md

Deploy Local-LLM Agent to Azure Container Apps (AI-Led)

End-to-end, secretless deployment of sidecar/dev (Ollama + Entra Agent ID sidecar) to Azure Container Apps. One federation chain (MI → Entra Blueprint), no second cloud.

Canonical tutorial: sidecar/dev/deploy-local-llm-agent-sidecar-container-apps.md. This skill is the automated, fast-path counterpart.

When to Use

  • User says: "deploy dev to ACA", "deploy the local LLM agent to Azure", "Ollama on Container Apps", "ship sidecar/dev to Azure"
  • User wants a self-contained demo in a tenant where AWS/GCP aren't options (airgapped, regulated, customer-owned)
  • User hits AADSTS65001 on OBO sign-in — see references/post-deploy-manual-steps.md
  • User hits AADSTS50011: redirect URI mismatch — same reference
  • User hits Ollama out of memory or ImagePullBackOff — see references/ollama-on-aca.md
  • User asks "can I run this without Bedrock / Vertex?"

Do NOT Use When

  • AWS Bedrock deployment — use deploy-agent-aca-aws
  • GCP Vertex AI deployment — pending skill deploy-agent-aca-gcp
  • Local laptop docker-compose — use sidecar/dev/ directly with docker compose up, no federation needed

Prerequisites (verify BEFORE running anything)

  1. Entra role on signing-in user — one of: Global Administrator, Agent ID Administrator, Agent ID Developer. See entra-agent-id-setup.
  2. Tooling: az ≥ 2.60, pwsh 7.4+, Microsoft.Graph.* 2.35+ (install: Install-Module Microsoft.Graph.Authentication, Microsoft.Graph.Beta.Applications -Scope CurrentUser), and one of: docker buildx for linux/amd64 OR az acr build (no local Docker needed — see Step 4).
  3. Tenant-confirmed preflight — ALWAYS confirm tenant ID + subscription ID with the user before any az command that mutates resources.
  4. Entra Agent ID base objects exist — Blueprint, Agent Identity, Client SPA. If not, run the entra-agent-id-setup skill first.

[!NOTE] Windows / PowerShell users: This skill's scripts and orchestrator are bash. If running from PowerShell without WSL or Git Bash:

  • source file → . file or set $env:VAR individually
  • envsubst → PowerShell -replace operators or (Get-Content template) -replace '\$\{VAR\}', $value
  • bash script.sh → translate each az / pwsh command into the PowerShell session directly
  • docker buildx build --push → az acr build for llm-agent and weather-api (but not for baked Ollama — see Step 4)
  • az ad app update --set spa='{...}' may fail with JSON escaping — use az rest --method PATCH instead (see Step 6)

SKU decisions — ask the user first

Before running any az command that provisions resources, confirm each SKU choice with the user. Do not silently default to the cheapest tier. The orchestrator requires each SKU variable to be set and fails hard if any is missing. Full tradeoff matrix: references/sku-sizing.md.

VariableAskDemo defaultSilent-failure mode if chosen wrong
ACR_SKUBasic / Standard / PremiumBasicOllama image ~1 GB; Basic fills up with 10 variants
ACA_WORKLOAD_PROFILEConsumption / Dedicated-D4 / GPUConsumption1.5B model on Consumption CPU = 5–20 s per answer
LOGS_DESTINATIONnone / log-analyticslog-analyticsnone hides Ollama OOM crashes and sidecar auth errors
MIN_REPLICAS / MAX_REPLICAScounts1 / 1min=0 = model reloads into RAM on every cold start
OLLAMA_MODELqwen2.5:1.5b / qwen2.5:7b / llama3.2:1bqwen2.5:1.5b7B model on Consumption times out ACA ingress
OLLAMA_IMAGE_STRATEGYbaked / runtime-pullbakedruntime-pull = 30 s first-request delay
OLLAMA_CPU / OLLAMA_MEMORYsee model-to-sizing table0.75 / 1.5GiUndersized memory → Ollama OOM. qwen2.5:3b needs 2.5 Gi (requires Dedicated-D4+). See sku-sizing.md §7.

When invoking this skill, explicitly state the defaults to the user and ask them to confirm or override — do not assume.

Procedure

Step 0 — Confirm account and populate variables

Ask the user to confirm: tenant ID, subscription ID, resource group name, location, SKU choices (including OLLAMA_CPU / OLLAMA_MEMORY — match to model), Ollama model. Then:

cp .claude/skills/deploy-agent-aca-dev/scripts/deploy-vars.sh.template /tmp/deploy-vars.sh
# edit /tmp/deploy-vars.sh with confirmed values
source /tmp/deploy-vars.sh
az login --tenant "$TENANT_ID" && az account set --subscription "$SUBSCRIPTION_ID"

Step 1 — Create Entra objects (Blueprint, Agent, Client SPA)

Delegate to entra-agent-id-setup. Capture BLUEPRINT_APP_ID, AGENT_CLIENT_ID, CLIENT_SPA_APP_ID into /tmp/deploy-vars.sh.

[!WARNING] Run Connect-MgGraph in an interactive pwsh session, not via pwsh -Command "Connect-MgGraph ..." subshell. The WAM authentication popup hides behind other windows in a subshell and silently times out.

Configure the Blueprint for OBO using the ACA-compatible PowerShell script:

pwsh -NoProfile -File .claude/skills/deploy-agent-aca-dev/scripts/setup-obo-blueprint-for-aca.ps1 \
  -BlueprintAppId "$BLUEPRINT_APP_ID" \
  -ClientSpaAppId "$CLIENT_SPA_APP_ID" \
  -AgentAppId "$AGENT_CLIENT_ID" \
  -TenantId "$TENANT_ID"

Step 2 — Azure infrastructure (RG, ACR, env, container app skeleton)

See tutorial §6. Uses SKU variables. Capture MI_OBJECT_ID and APP_FQDN, append to /tmp/deploy-vars.sh. Grant AcrPull to the MI.

[!NOTE] Adding a Dedicated-D4 workload profile can take 20+ minutes to provision. This is normal — do not cancel. If Azure Policy enforces tags on resource groups (e.g., Owner, MonthlyCost), add them during az group create or use a pre-existing RG.

Step 3 — Federate MI to Blueprint (only federation chain)

Single Graph call — see tutorial §7. Subject = $MI_OBJECT_ID, audience = api://AzureADTokenExchange.

Unlike the AWS skill, there is no Step 4 (AWS federation). The local LLM needs no external cloud.

Step 4 — Build and push images

Tutorial §8. Three images: llm-agent, weather-api, ollama (baked) — or two if using runtime-pull.

Option A — Local Docker (docker buildx):

Requires Docker Desktop running. Works for all images including baked Ollama.

Option B — Remote build (az acr build):

No Docker Desktop needed. Works for llm-agent and weather-api only.

az acr build --registry "$ACR_NAME" --image agent-id-dev/llm-agent:1.0.0 --platform linux/amd64 sidecar/dev/
az acr build --registry "$ACR_NAME" --image agent-id-dev/weather-api:1.0.0 --platform linux/amd64 sidecar/weather-api/

[!NOTE] UnicodeEncodeError: 'charmap' codec can't encode characters from az acr build on Windows is cosmetic (colorama/cp1252 encoding). The build succeeds — ignore the error.

[!IMPORTANT] Baked Ollama images cannot be built via az acr build — the RUN ollama serve & ollama pull ... step requires a running Docker daemon that ACR Build does not provide. The image silently fails to appear in ACR. If Docker Desktop is unavailable, switch to OLLAMA_IMAGE_STRATEGY=runtime-pull.

If OLLAMA_IMAGE_STRATEGY=baked (Option A only):

bash .claude/skills/deploy-agent-aca-dev/scripts/build-ollama-image.sh

Step 5 — Deploy the multi-container app

envsubst < .claude/skills/deploy-agent-aca-dev/scripts/containerapp.yaml.template > /tmp/containerapp.yaml
az containerapp update -g "$RG" -n "$APP_NAME" --yaml /tmp/containerapp.yaml

Step 6 — Post-deploy wiring (REQUIRED — execute immediately after Step 5)

[!IMPORTANT] The AI agent MUST execute both sub-steps below. Do NOT skip or leave for the user. These are automatable — APP_FQDN is known from Step 2, and all app IDs are known from Step 1.

Two things that cannot be done before deploy:

  1. Add deployed SPA redirect URI — bash .claude/skills/deploy-agent-aca-dev/scripts/add-spa-redirect-uri.sh

    [!WARNING] On PowerShell, az ad app update --set spa='{...}' fails with Property spa in payload has a value that does not match schema due to JSON escaping. Use this workaround instead:

    $body = @{ spa = @{ redirectUris = @("http://localhost:3003", "https://$env:APP_FQDN/") } } | ConvertTo-Json -Depth 3
    az rest --method PATCH --url "https://graph.microsoft.com/v1.0/applications(appId='$env:CLIENT_SPA_APP_ID')" --body $body --headers "Content-Type=application/json"
  2. Grant Agent → Graph delegated User.Read (fixes AADSTS65001):

    pwsh -NoProfile -File .claude/skills/deploy-agent-aca-dev/scripts/grant-agent-obo-consent.ps1 \
      -AgentAppId "$AGENT_CLIENT_ID" -TenantId "$TENANT_ID"

Full rationale: references/post-deploy-manual-steps.md.

Step 7 — Verify

Tutorial §11. ollama_available: true in status; autonomous flow returns Qwen-generated answer; OBO works via MSAL popup.

One-Shot Orchestrator

If all prerequisites are in place and SKU variables are confirmed:

bash .claude/skills/deploy-agent-aca-dev/scripts/deploy-aca-dev.sh

Idempotent. Invokes steps 2–5 in order. Steps 0, 1, 6 require human decisions and remain manual.

Key Artifacts

Persisted in /tmp/deploy-vars.sh:

VariableSource
TENANT_ID, SUBSCRIPTION_IDUser
ACR_SKU, ACA_WORKLOAD_PROFILE, LOGS_DESTINATION, MIN_REPLICAS, MAX_REPLICASUser (SKU decisions)
OLLAMA_MODEL, OLLAMA_IMAGE_STRATEGYUser
OLLAMA_CPU, OLLAMA_MEMORYUser (match to model — see sku-sizing.md §7)
BLUEPRINT_APP_ID, AGENT_CLIENT_ID, CLIENT_SPA_APP_IDStep 1
MI_OBJECT_ID, APP_FQDNStep 2

No client secrets, no external-cloud credentials anywhere.

References

  • Architecture summary
  • SKU and sizing decisions
  • Ollama on Azure Container Apps
  • Post-deploy manual steps (SPA URI + OBO consent)
  • Troubleshooting matrix
  • Full tutorial

Download now (ZIP)

Does it work?

Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.

No reviews yet

People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.

  • It worked
  • Partly
  • It didn't
What did you use it for? e.g. Reviewing pull requests in a Rails app

Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.

Your trail

Files you open will collect here, so you can find them again.

Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.

Now do this for your own.

Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.