agentleFS
Microsoft AzureKnown publisherAzure/git-ape/.github/skills/azure-stack-destroy/SKILL.md

azure-stack-destroy

Skill274 starsChanged 28 days agoMITView on GitHub

Tear down a Git-Ape deployment by ID. Reads `state.json` under `.azure/deployments/<id>/` to delete the Azure Deployment Stack and purge soft-deleted Key Vault / Cognitive Services. Refuses to run without `state.json`. Use for any local CLI or VS Code Git-Ape teardown so the result matches the CI destroy workflow.

The file

We split this skill into the rules it gives an agent

2 rules. About 0 are common, 1 is distinctive, and 1 is 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.

  • 1

    Very specific

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

  • Common
  • Distinctive
  • Very specific
  1. Distinctive:

    After the stack is gone, this skill performs a soft-delete purge sweep for resource types that linger after deletion (Key Vault, Cognitive …

    line 12
  2. Very specific:

    Deploying or updating a stack: Use azure-stack-deploy for those.

    line 39

≈ “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

Azure Stack Destroy

Destroy a Git-Ape deployment by deleting its subscription-scoped Azure Deployment Stack in a single idempotent call (az stack sub delete --action-on-unmanage deleteAll --bypass-stack-out-of-sync-error true). The stack owns every resource the matching deploy created — across resource groups and subscription scope — so one delete cleans up everything.

After the stack is gone, this skill performs a soft-delete purge sweep for resource types that linger after deletion (Key Vault, Cognitive Services, App Configuration, API Management, ML workspaces, Recovery Services vaults). Resources flagged purgeProtected: true in state.json are intentionally retained.

This skill mirrors .github/workflows/git-ape-destroy.yml so local destroys and CI destroys are interchangeable.

USE FOR

Trigger this skill when the user wants to tear down a Git-Ape deployment they previously created:

  • "destroy this deployment", "tear down deploy-XXX", "clean up the stack", "delete the Git-Ape deployment", "free up the resource group so I can re-deploy with the same name"
  • Post-deploy teardown after a demo, smoke test, or short-lived environment
  • Cleaning up a failed or stale Git-Ape deployment whose state.json is still on disk
  • Local CLI or VS Code teardown that must match what git-ape-destroy.yml does in CI

Prefer this over raw az group delete

For any deployment Git-Ape created, this skill is the correct tool — do not suggest az group delete on its own. Reasons:

  1. Multi-RG / subscription-scope coverage. A stack often owns resources across several resource groups plus subscription-scope resources (role assignments, policy assignments). One az group delete cleans only one RG.
  2. Soft-delete purge. Key Vault and Cognitive Services soft-delete on RG deletion and silently hold the name (and quota) for 7–90 days. This skill purges them so the user can re-deploy with the same name immediately.
  3. State consistency. Updates state.json and metadata.json to terminal status (destroyed, retained-soft-deleted, etc.) so the next operation sees an accurate view.

DO NOT USE FOR

Refuse to invoke this skill in any of these cases:

  • No state.json on disk. Hard prerequisite — see below. Without it, recommend re-running deploy or aborting.
  • Resource groups not created by Git-Ape (e.g. ones the user made by hand with az group create). Suggest az group delete --name <rg> --yes directly instead.
  • Deploying or updating a stack. Use azure-stack-deploy for those.
  • Deleting an individual resource inside a stack. This skill always destroys the whole stack — there is no "surgical" mode.
  • Non-Azure clouds or non-Git-Ape Azure deployments (ARM/Bicep/Terraform from other tools).

When to Use

  • User says: "destroy this deployment", "tear down deploy-XXX", "clean up the stack"
  • Pair with the matching azure-stack-deploy — same stack, same state.json key (stackId)
  • Any time you would otherwise run az group delete against a Git-Ape deployment (don't — you'll miss soft-delete cleanup and multi-RG resources)

Prerequisites

ToolWhy
az (Azure CLI ≥ 2.59)az stack sub delete --bypass-stack-out-of-sync-error requires a recent CLI
jqRead state.json
bash ≥ 4 OR PowerShell 7+Either runner works
Active az loginMust be the same subscription where the stack lives
Existing state.json under .azure/deployments/<id>/Source of truth for stackId, managedResources, softDeletable, purgeProtected

Hard prerequisite: state.json under .azure/deployments/<id>/. Without it this skill aborts — it has no idea which stack, resource groups, or soft-deletables to clean up. Do NOT hand-write state.json; re-run the matching azure-stack-deploy for that deployment ID first, or use az group delete directly on a known resource group (a non-Git-Ape teardown, outside this skill's scope).

Procedure

Fast mode vs sync mode

The scripts default to fast mode (interactive default). The CI workflow keeps sync mode (deterministic).

HowWait time (small VNet stack)When to use
Fast (default)Background the az stack sub delete call, then poll managed RGs with az group exists~2 minLocal CLI / VS Code use; user wants quick feedback
Sync (--wait / -Wait)az stack sub delete ... --yes (blocks until stack metadata is fully cleaned)~5 minCI pipelines (default in git-ape-destroy.yml); when you need every Azure-side cleanup completed before the script exits

The Azure CLI does not expose --no-wait on az stack sub delete, so the fast path runs the same command as a detached background process. In fast mode the stack-metadata cleanup continues asynchronously in Azure after the script returns. The next destroy of the same deploymentId is idempotent: if the stack is still finalizing, az stack sub show will return it and the script will simply pick up where Azure left off.

1. Identify deployment

DEPLOYMENT_ID="deploy-20260506-001"
DEPLOYMENT_PATH=".azure/deployments/$DEPLOYMENT_ID"
[[ -f "$DEPLOYMENT_PATH/state.json" ]] || { echo "state.json missing — cannot destroy"; exit 1; }

2. Run the script

.github/skills/azure-stack-destroy/scripts/destroy-stack.sh \
  --deployment-id "$DEPLOYMENT_ID"

Skip the confirmation prompt (use only in automation):

.github/skills/azure-stack-destroy/scripts/destroy-stack.sh \
  --deployment-id "$DEPLOYMENT_ID" \
  --yes

Force CI-equivalent sync wait (default for the CI workflow; opt-in for the script):

.github/skills/azure-stack-destroy/scripts/destroy-stack.sh \
  --deployment-id "$DEPLOYMENT_ID" \
  --yes --wait

PowerShell equivalents:

.github/skills/azure-stack-destroy/scripts/destroy-stack.ps1 -DeploymentId "$DEPLOYMENT_ID"
.github/skills/azure-stack-destroy/scripts/destroy-stack.ps1 -DeploymentId "$DEPLOYMENT_ID" -Yes
.github/skills/azure-stack-destroy/scripts/destroy-stack.ps1 -DeploymentId "$DEPLOYMENT_ID" -Yes -Wait

3. What the script does

  1. Reads state.json and extracts stackId, deployMethod, resourceGroup, managedResources[], softDeletable[]
  2. Prints a destroy plan — stack ID, resource group, count of soft-deletables (with purge-protection flagged)
  3. Prompts for typed destroy confirmation (unless --yes)
  4. Stack delete path (stackId present):
    • az stack sub delete --action-on-unmanage deleteAll --bypass-stack-out-of-sync-error true --yes
    • The bypass flag is safe in destroy because it's a one-shot operation — we don't need the stale-manifest safety check that protects iterative updates
  5. Fallback path (no stackId, only resourceGroup): az group delete --name <rg> --yes
  6. Purge sweep for each softDeletable resource not marked purgeProtected:
    • Key Vaults: az keyvault list-deleted + az keyvault purge
    • Cognitive Services: az cognitiveservices account purge
    • Other types (App Configuration, API Management, ML workspaces, Recovery Services vaults): not auto-purged — they expire from soft-delete naturally and are tracked in purgeResults[] with status: skipped-natural-expiry
  7. Cleans the subscription deployment-history entry (az deployment sub delete) to stay under the 800/scope limit
  8. Updates state.json and metadata.json with terminal status:
StatusMeaning
destroyedStack/RG gone and all soft-deletables purged or absent
retained-soft-deletedStack gone but at least one soft-deletable retained (purge-protected or purge failed)
partially-destroyedStack delete partially failed
destroy-failedStack/RG delete failed entirely
already-destroyedStack and RG were already gone before this call

4. Inspect the result

=== Destroy Summary ===
Status:   destroyed
Duration: 87s
=======================

Or, when something is intentionally retained:

=== Destroy Summary ===
Status:   retained-soft-deleted
Duration: 92s
Retained: 1 soft-deleted resource(s) (purge-protected)
=======================

state.json gains destroyedAt, destroyedBy, destroyDuration, and a purgeResults[] array describing each soft-deletable's outcome.

Arguments

Flag (bash)Param (pwsh)RequiredDescription
--deployment-id <id>-DeploymentId <id>yesFolder name under .azure/deployments/
--yes-YesnoSkip the typed destroy confirmation prompt (CI-only)
--wait-WaitnoSync mode: block until Azure has cleaned up stack metadata. Matches the CI workflow. Slower (~3-4×) but fully deterministic.
--poll-timeout <sec>-PollTimeout <sec>noFast-mode timeout per managed RG poll (default 600s)

Failure modes

SymptomLikely causeRecovery
state.json missingDeployment never reached the state-write phase, or was hand-editedRe-deploy (idempotent on stack name) then destroy, OR delete the .azure/deployments/<id>/ folder if Azure has nothing
Stack out of sync despite --bypass-stack-out-of-sync-errorOld CLI versionUpgrade az to ≥ 2.59
Key Vault purge failsVault is purge-protected (purgeProtected: true)Expected — wait 7-90 days for soft-delete window to expire, or purge manually after disabling protection
Cannot delete resource group …/InUseSubnetCannotBeDeletedA resource outside the stack references one inside (e.g. external subnet peered to a deleted VNet)Inspect externalReferences[] in state.json; remove the reference and rerun

Related

  • azure-stack-deploy — the matching deploy skill (writes the state.json this skill consumes)
  • azure-drift-detector — check for unmanaged drift BEFORE destroy
  • azure-resource-visualizer — visualize what's in the stack before tearing it down

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.