[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"skill-azure-azure-arg-external-evaluation-policy-author":3,"mdc--e1mz04-key":35,"related-org-azure-azure-arg-external-evaluation-policy-author":1382,"related-repo-azure-azure-arg-external-evaluation-policy-author":1551},{"slug":4,"name":4,"fn":5,"description":6,"org":7,"tags":12,"stars":24,"repoUrl":25,"updatedAt":26,"license":27,"forks":28,"topics":29,"repo":30,"sourceUrl":33,"mdContent":34},"azure-arg-external-evaluation-policy-author","author and test Azure Resource Graph policies","Use when the user wants to author, design, or test an Azure Policy that queries Azure Resource Graph (ARG) at request-time — i.e. a policy whose deny\u002Faudit decision depends on data from elsewhere in the subscription (sibling\u002Fparent resource state, RG-wide invariants, multi-hop relationships, etc.). Formally called Azure Policy External Evaluation; sometimes referred to colloquially as \"Invoke\". Drives an iterative KQL co-design loop against the user's real subscription via `az graph query`, then emits a policy definition, assignment, `.http` test flow, and an `EXPLANATION.md` companion. Read-only; never provisions anything.",{"slug":8,"name":9,"logoUrl":10,"githubOrg":11},"azure","Azure (Microsoft)","https:\u002F\u002Fpexgzepcugksgbtrxkhf.supabase.co\u002Fstorage\u002Fv1\u002Fobject\u002Fpublic\u002Forg-logos\u002Fazure.png","Azure",[13,15,18,21],{"name":11,"slug":8,"type":14},"tag",{"name":16,"slug":17,"type":14},"Compliance","compliance",{"name":19,"slug":20,"type":14},"Governance","governance",{"name":22,"slug":23,"type":14},"Policy","policy",1686,"https:\u002F\u002Fgithub.com\u002FAzure\u002Fazure-policy","2026-07-12T08:17:48.378432",null,1153,[8,23],{"repoUrl":25,"stars":24,"forks":28,"topics":31,"description":32},[8,23],"Repository for Azure Resource Policy built-in definitions and samples","https:\u002F\u002Fgithub.com\u002FAzure\u002Fazure-policy\u002Ftree\u002FHEAD\u002FExternalEvaluationPolicies\u002Fagent-skills\u002Fazure-arg-external-evaluation-policy-author","---\nname: azure-arg-external-evaluation-policy-author\ndescription: Use when the user wants to author, design, or test an Azure Policy that queries Azure Resource Graph (ARG) at request-time — i.e. a policy whose deny\u002Faudit decision depends on data from elsewhere in the subscription (sibling\u002Fparent resource state, RG-wide invariants, multi-hop relationships, etc.). Formally called Azure Policy External Evaluation; sometimes referred to colloquially as \"Invoke\". Drives an iterative KQL co-design loop against the user's real subscription via `az graph query`, then emits a policy definition, assignment, `.http` test flow, and an `EXPLANATION.md` companion. Read-only; never provisions anything.\n---\n\n# Azure Policy External Evaluation (ARG) authoring\n\nProcedure for authoring and testing an **enforcement Azure Policy that queries Azure Resource Graph (ARG)**, utilizing the new **External Evaluation** features. Follow the workflow below when the user asks for a policy whose decision depends on ARG data.\n\nThe output of the procedure is a folder containing: a `policy-definition.json`, a `test-flow.http`, and an `EXPLANATION.md`. The policy assignment body lives inline in the `.http` file (see step 4 below). A secondary goal of this procedure is to help users learn about the new External Evaluation feature.\n\nThe procedure never provisions anything in the user's subscription; the only Azure side-effects are read-only ARG queries via `az graph query`.\n\nKnowledge files referenced throughout — read them **as needed**:\n\n- [`knowledge\u002F01-overview.md`](.\u002Fknowledge\u002F01-overview.md) — what External Evaluation + ARG is and known feature limits\n- [`knowledge\u002F02-policy-artifacts-shape.md`](.\u002Fknowledge\u002F02-policy-artifacts-shape.md) — canonical JSON for definition + assignment, field by field, with locks and leeway\n- [`knowledge\u002F03-rest-flow.md`](.\u002Fknowledge\u002F03-rest-flow.md) — Token API REST contracts, response shapes, the 403 to expect\n\nAlso available: [`templates\u002F`](.\u002Ftemplates\u002F) (canonical skeletons) and [`examples\u002F`](.\u002Fexamples\u002F) (worked end-to-end scenarios).\n\n---\n\n## Rules\n\n- **Never modify, create, or delete anything in the user's subscription.** ARG queries via `az graph query` are read-only and are the only Azure side-effects you produce.\n- **Stay within External Evaluation + ARG's limits.** If the user ask can't be achieved with the existing capabilities, say so plainly, explain why and stop.\n   - If the user asks for a policy that doesn't need an ARG call but they want to use it anyway, let them know and continue with creating the policy if they're ok with it.\n- **Your generated artifacts should strictly follow the pattern described in the knowledge base**.\n- **Work with the user to create and test the ARG query**. Always run the co-design process.\n- **Cite a knowledge file or official docs** every time you justify a non-obvious choice (e.g. \"queryWithUserIdentity: true — see the shape doc\"). No bare hand-waving. Goal is to ensure that you are accountable to the accuracy of your decisions as well as educating the user.\n\n---\n\n## Workflow\n\n### Step 0 - Read the overview doc\n\n[`knowledge\u002F01-overview.md`](.\u002Fknowledge\u002F01-overview.md)\nExternal Evaluation is new and not yet covered by public documentation. Prior context and official docs will not fill in the gaps — read the overview first.\n\n### Step 1 — Intake & feasibility\n\nGoal is to reach a mutual agreement with the user about what the policy is doing and whether it's feasible to utilize the External Evaluation feature.\n\n1. **Restate the free-text policy intent in one sentence. Reiterate based on user feedback until they approve**:\n   - Name which resource operations are targeted: operation type (write\u002Fdelete, could be implicit), resource type and any other constraints on the resource payload.\n   - Loosely describe what the ARG query returns and which returned values will result in denial.\n   - Example: \"Deny the association of an NSG to a subnet if an ARG query that counts other subnets using the NSG returns a number greater than 3\"\n2. **Feasibility check.** Walk through these reasons-to-reject:\n   - Is the invariant **within one subscription**? Cross-sub \u002F cross-tenant \u002F MG-scoped → reject.\n   - The ARG query must return a result that has a single column and 0 or 1 rows. Can the invariant collapse to **one boolean or scalar**?\n      - This means that parts of the policy logic will have to be shifted to the ARG query side. e.g. instead of an `allOf: [ claims().a == 1, claims().b == 2]` in the policy condition, the ARG query will have a `| project a == 1 and b == 2` statement.\n      - Common ways to return a single result is to have the query filter by a specific resource id, or use `summarize`\n      - Try hard - ARG language is more capable than the policy language and it's most likely doable. Only reject if you genuinely cannot.\n   - Is the desired effect in `{audit, deny, auditAction, denyAction}`?\n   When rejecting, state the reason plainly, point at the relevant knowledge file section, and suggest the closest standard-policy alternative if one exists. Then stop.\n\n### Step 2 — KQL co-design with the user\n\nGoal is to work with the user to compose and test a draft of the query that will be used in the policy.\n\nThe main challenge with the new kind of policies is that any meaningful use case will require formatting the ARG query at evaluation time, plugging in details from the evaluated resource or policy parameter values. This means that the policy definition you'll author will likely have ugly `[format()]` expressions that construct the query, with the necessary runtime details plugged in via expressions like `[field()]` and `[parameters()]`, as well as escaping any quotes. This expression is not very human readable and extremely hard to manually convert to and from a runnable ARG query for testing. You are to shield the user from this complexity. Help them author and test a \"regular\" ARG query against a real environment, being mindful (and helping the user understand) about the parts of the query that will need to be parameterized at runtime vs parts of the query that are meant to perform the desired logic.\n\n1. Get the initial query that captures the intent.\n   - Ask the user if they have a working sample query that they want to use as a starting point. The query doesn't have to conform to the added rules and limitations of the policy. It should express the general idea.\n   - If they don't have a query, suggest a starting query for them and ask for feedback. Your query should focus on the core logic. Don't add any collapsing logic yet.\n   - For example, for the NSG oversharing example (see [`examples\u002F01-deny-nsg-overshared\u002F`](.\u002Fexamples\u002F01-deny-nsg-overshared\u002F)), the starting query can return all pairs of associated subnet-nsgs:\n      - `resources | where type =~ \"microsoft.network\u002Fnetworksecuritygroups\" | mv-expand subnet = properties[\"subnets\"] | project nsgId = id, subnetId = subnet[\"id\"]`\n2. Sanity check query run:\n   - Ask the user for permission to run the query, as well as against which subscriptions to run it — we want a test subscription where the query will return results.\n   - Run the query, analyze the results and present them to the user, raising any potential issues with the query or the quality of the test data set, as well as asking if it makes sense to them.\n   - Loop with the user until they have confidence that the query returns the right data to drive the requested policy.\n3. Re-write the query in a policy-friendly form:\n   - Add additional filters if the initial query is too broad — the policy query needs to only return results that are relevant to the evaluated resource.\n   - Try to separate between conditions that will require parameterization and any conditions that act only on the properties of the queried resources.\n   - Your filters should use hard coded values that you know will yield results from the test set.\n   - Apply the necessary consolidation.\n   - Going with the NSG oversharing example above, the revised query will be: `resources | where type =~ \"microsoft.network\u002Fnetworksecuritygroups\" | where id == '\u003Chard coded NSG Id that will be populated in runtime in the policy>' | mv-expand subnet = properties[\"subnets\"] | where isnotnull(subnet[\"id\"]) | where subnet[\"id\"] !~ '\u003Chard coded subnet Id that will be populated in runtime in the policy>' | summarize otherSubnetsCount = count()`\n      - In this revised query, we imagine that the policy will target subnets, and that we'll have 2 dynamic values in the ARG query: which NSG we're about to add to the subnet (so that we can find who else uses it) as well as the id of the evaluated subnet, so that we can exclude it from the count if it's already attached to this NSG. We also consolidate the results by using a `summarize count()` aggregation.\n   - Share this query with the user, explain what you did and why, run it and ensure the results make sense. You may need to produce multiple versions of the query with different placeholder values hard-coded into it for different test cases. Iterate with the user until reaching an acceptable result.\n   - These queries and details will also be added to EXPLANATION.md\n\n### Step 3 - Design the policy definition\n\nNow that you have a working ARG query, work with the user to create a Policy Definition utilizing the external evaluation feature.\nNote that this skill is meant to help utilizing the new external evaluation feature, it's not a generic policy authoring skill. Also remember that the external evaluation feature is not publicly documented yet. This means that:\n- You must follow the canonical policy definition shape in `knowledge\u002F02-policy-artifacts-shape.md` to ensure proper use of the new primitives and maximize your chances to create a working policy.\n- When it comes to the core evaluation logic, you should rely heavily on the user's input. If the user seems to be well versed in Azure Policy, your role should become helping them plug in the external evaluation endpoint definition and claims usage.\n\n1. Start with crafting the policy rule's `if` condition based on the input you received so far. The condition should capture both the applicability of the policy (e.g. `type == vm && tags[env] == prod`) as well as claims assertions (e.g. `coalesce(claims().otherSubnetsCount, null()) > 0`). Follow the shape described in `knowledge\u002F02-policy-artifacts-shape.md`.\n2. Share the `if` condition with the user. Explain in words what the condition is doing. The verbal description of the condition should loosely match the policy intent one-liner you came up with in step 1. Answer any questions the user has about the claims() usage. Remember to anchor your responses with references to your knowledge base. Iterate with the user until reaching an acceptable result.\n3. Craft the `then` block. `effect` is always `[parameters('effect')]`. **If the effect family is action-time (`auditAction` \u002F `denyAction`), also include `then.details.actionNames`** — the engine rejects the assignment otherwise. See `knowledge\u002F02-policy-artifacts-shape.md` → `policyRule.then.details` for the exact shape.\n4. Craft the `externalEvaluationEnforcementSettings` section based on the canonical definition shape and the query you constructed in the previous stage. Take the query with the hard-coded values and replace it with an ARM template expression that formats the query at runtime, using `field()` \u002F `parameters()` calls for the dynamic values. Escape every quote in the inner KQL.\n\n    Before (literal query, hard-coded NSG and subnet ids):\n\n    ```kusto\n    resources\n    | where type =~ \"microsoft.network\u002Fnetworksecuritygroups\"\n    | where id == \"\u003CNSG id being attached>\"\n    | mv-expand subnet = properties[\"subnets\"]\n    | where isnotnull(subnet[\"id\"])\n    | where subnet[\"id\"] !~ \"\u003Csubnet id being modified>\"\n    | summarize otherSubnetsCount = count()\n    ```\n\n    After (ARM template expression, single-line, all inner quotes escaped):\n\n    ```jsonc\n    \"query\": \"[format('resources | where type =~ \\\"microsoft.network\u002Fnetworksecuritygroups\\\" | where id == \\\"{0}\\\" | mv-expand subnet = properties[\\\"subnets\\\"] | where isnotnull(subnet[\\\"id\\\"]) | where subnet[\\\"id\\\"] !~ \\\"{1}\\\" | summarize otherSubnetsCount = count()', field('Microsoft.Network\u002FvirtualNetworks\u002Fsubnets\u002FnetworkSecurityGroup.id'), field('id'))]\"\n    ```\n\n5. Share this section with the user. Explain what each part is doing and how you transformed the query and why. Iterate with the user until reaching an acceptable result.\n\n### Step 4 — Emit artifacts\n\nBefore writing anything, tell the user — in one short line each — which files you're about to create and what each is for. Then write them.\n\nCreate a new folder named after the policy (kebab-case, prefixed with `audit-` \u002F `deny-` \u002F `auditaction-` \u002F `denyaction-`) and write three files:\n\n- `policy-definition.json` — model the canonical shape in `knowledge\u002F02-policy-artifacts-shape.md` and the worked examples under `examples\u002F`. Fill in the effect family from step 1, the target resource type, the claim name, and the `[format(...)]` KQL from step 2. The shape doc is authoritative for every field.\n- `test-flow.http` — start from `templates\u002Ftest-flow.template.http`. Substitute the concrete RP path, API version, location, and request body. Keep the `### Expected:` lines. The policy assignment body is inlined inside this file rather than living in its own JSON — the REST Client extension does not expand `@`-variables inside files included via `\u003C .\u002Ffile.json`, so an external assignment file would emit a broken request.\n  - **Before each `acquirePolicyToken` POST, include a direct ARG query that mirrors what the policy will run for that case.** Build it from the same materialized KQL with the same inputs the policy will substitute (resource id, parameter values). Lets the user — and the agent, on a failing case — distinguish a wrong query from a policy\u002Ftoken\u002Fwiring problem in one extra send. See `examples\u002F03-denyaction-actiongroup-in-use\u002Ftest-flow.http` for the pattern.\n- `EXPLANATION.md` — three sections:\n  1. **What this policy does** — intent, target operation, bad-state condition, what gets denied vs allowed.\n  2. **Test queries used during co-design** — for each iteration of the KQL loop: the materialized query, the inputs, the actual ARG result, the conclusion.\n  3. **How to test this** — concrete steps for Portal, Azure CLI, and the `.http` file.\n\nAuthoring rules for these files:\n\n- **No real environment values.** Subscription ids, resource group names, tenant ids, and specific resource names from the user's environment must be replaced with placeholders like `\u003CsubId>`, `\u003CrgName>`, `\u003CnsgName>` (or a generic-looking default like `nsg-immutable-test`) in *every* file you emit, including KQL examples quoted inside `EXPLANATION.md`. These bundles are shared publicly.\n- **Cross-references stay inside the bundle.** When `EXPLANATION.md` links to a knowledge file or another example, use a relative path inside this bundle (e.g. `..\u002F..\u002Fknowledge\u002F01-overview.md`). Do not invent absolute paths under `.copilot\u002Fskills\u002F...` or any other deploy-time location — those won't resolve for the reader.\n\nOnce the files are written, respond with a short message: list the files you created, point the user at `EXPLANATION.md` for the design walkthrough and at `test-flow.http` for the end-to-end create-and-test flow, and invite follow-ups. Do **not** re-explain what the policy does or restate each design decision — that's what `EXPLANATION.md` is for.\n\n---\n\n## When asked \"why X?\"\n\nCite the relevant knowledge file and answer in one or two sentences. If the answer involves a trade-off (`missingTokenAction`, `mode: Indexed` vs `All`, `queryWithUserIdentity`), state the trade, the default, and offer to change it. If you don't have a citation, say so — don't invent one.\n\n---\n\n## When to stop\n\nIf you discover mid-flow that the ask hits a limit you missed in step 1 — cross-sub query, request-mutation effect, data not in ARG, an invariant that won't collapse to one claim, or an unsupported endpoint kind — stop and explain. Don't write artifacts you know won't work. Suggest the nearest workable alternative (classic policy, DeployIfNotExists, a pipeline check) if one exists.\n\nPush back, but proceed after re-confirmation, when the user picks an effect from the wrong family for their operation kind (e.g. `denyAction` on a PUT, `deny` on a DELETE). The wrong family silently no-ops at runtime — the test loop appears to succeed and the customer thinks they have protection.\n\n---\n\n## Output style\n\n- Lead with the punchline. Use matter-of-fact and neutral tone. Be concise. Use plain language.\n- Show the materialized KQL (literal values substituted) — not the `[format(...)]` wrapper. That's the form that matters for debugging.\n- After each emitted artifact, a short `_why:_` callout listing the 3–6 most surprising choices with a pointer to the relevant knowledge file.\n- One concrete suggestion, not a list of options.\n",{"data":36,"body":37},{"name":4,"description":6},{"type":38,"children":39},"root",[40,49,70,108,121,133,184,213,217,224,291,294,300,307,320,326,331,453,459,464,493,631,637,642,662,920,926,931,965,1121,1126,1218,1251,1254,1260,1295,1298,1304,1309,1329,1332,1338,1376],{"type":41,"tag":42,"props":43,"children":45},"element","h1",{"id":44},"azure-policy-external-evaluation-arg-authoring",[46],{"type":47,"value":48},"text","Azure Policy External Evaluation (ARG) authoring",{"type":41,"tag":50,"props":51,"children":52},"p",{},[53,55,61,63,68],{"type":47,"value":54},"Procedure for authoring and testing an ",{"type":41,"tag":56,"props":57,"children":58},"strong",{},[59],{"type":47,"value":60},"enforcement Azure Policy that queries Azure Resource Graph (ARG)",{"type":47,"value":62},", utilizing the new ",{"type":41,"tag":56,"props":64,"children":65},{},[66],{"type":47,"value":67},"External Evaluation",{"type":47,"value":69}," features. Follow the workflow below when the user asks for a policy whose decision depends on ARG data.",{"type":41,"tag":50,"props":71,"children":72},{},[73,75,82,84,90,92,98,100,106],{"type":47,"value":74},"The output of the procedure is a folder containing: a ",{"type":41,"tag":76,"props":77,"children":79},"code",{"className":78},[],[80],{"type":47,"value":81},"policy-definition.json",{"type":47,"value":83},", a ",{"type":41,"tag":76,"props":85,"children":87},{"className":86},[],[88],{"type":47,"value":89},"test-flow.http",{"type":47,"value":91},", and an ",{"type":41,"tag":76,"props":93,"children":95},{"className":94},[],[96],{"type":47,"value":97},"EXPLANATION.md",{"type":47,"value":99},". The policy assignment body lives inline in the ",{"type":41,"tag":76,"props":101,"children":103},{"className":102},[],[104],{"type":47,"value":105},".http",{"type":47,"value":107}," file (see step 4 below). A secondary goal of this procedure is to help users learn about the new External Evaluation feature.",{"type":41,"tag":50,"props":109,"children":110},{},[111,113,119],{"type":47,"value":112},"The procedure never provisions anything in the user's subscription; the only Azure side-effects are read-only ARG queries via ",{"type":41,"tag":76,"props":114,"children":116},{"className":115},[],[117],{"type":47,"value":118},"az graph query",{"type":47,"value":120},".",{"type":41,"tag":50,"props":122,"children":123},{},[124,126,131],{"type":47,"value":125},"Knowledge files referenced throughout — read them ",{"type":41,"tag":56,"props":127,"children":128},{},[129],{"type":47,"value":130},"as needed",{"type":47,"value":132},":",{"type":41,"tag":134,"props":135,"children":136},"ul",{},[137,154,169],{"type":41,"tag":138,"props":139,"children":140},"li",{},[141,152],{"type":41,"tag":142,"props":143,"children":145},"a",{"href":144},".\u002Fknowledge\u002F01-overview.md",[146],{"type":41,"tag":76,"props":147,"children":149},{"className":148},[],[150],{"type":47,"value":151},"knowledge\u002F01-overview.md",{"type":47,"value":153}," — what External Evaluation + ARG is and known feature limits",{"type":41,"tag":138,"props":155,"children":156},{},[157,167],{"type":41,"tag":142,"props":158,"children":160},{"href":159},".\u002Fknowledge\u002F02-policy-artifacts-shape.md",[161],{"type":41,"tag":76,"props":162,"children":164},{"className":163},[],[165],{"type":47,"value":166},"knowledge\u002F02-policy-artifacts-shape.md",{"type":47,"value":168}," — canonical JSON for definition + assignment, field by field, with locks and leeway",{"type":41,"tag":138,"props":170,"children":171},{},[172,182],{"type":41,"tag":142,"props":173,"children":175},{"href":174},".\u002Fknowledge\u002F03-rest-flow.md",[176],{"type":41,"tag":76,"props":177,"children":179},{"className":178},[],[180],{"type":47,"value":181},"knowledge\u002F03-rest-flow.md",{"type":47,"value":183}," — Token API REST contracts, response shapes, the 403 to expect",{"type":41,"tag":50,"props":185,"children":186},{},[187,189,199,201,211],{"type":47,"value":188},"Also available: ",{"type":41,"tag":142,"props":190,"children":192},{"href":191},".\u002Ftemplates\u002F",[193],{"type":41,"tag":76,"props":194,"children":196},{"className":195},[],[197],{"type":47,"value":198},"templates\u002F",{"type":47,"value":200}," (canonical skeletons) and ",{"type":41,"tag":142,"props":202,"children":204},{"href":203},".\u002Fexamples\u002F",[205],{"type":41,"tag":76,"props":206,"children":208},{"className":207},[],[209],{"type":47,"value":210},"examples\u002F",{"type":47,"value":212}," (worked end-to-end scenarios).",{"type":41,"tag":214,"props":215,"children":216},"hr",{},[],{"type":41,"tag":218,"props":219,"children":221},"h2",{"id":220},"rules",[222],{"type":47,"value":223},"Rules",{"type":41,"tag":134,"props":225,"children":226},{},[227,244,262,271,281],{"type":41,"tag":138,"props":228,"children":229},{},[230,235,237,242],{"type":41,"tag":56,"props":231,"children":232},{},[233],{"type":47,"value":234},"Never modify, create, or delete anything in the user's subscription.",{"type":47,"value":236}," ARG queries via ",{"type":41,"tag":76,"props":238,"children":240},{"className":239},[],[241],{"type":47,"value":118},{"type":47,"value":243}," are read-only and are the only Azure side-effects you produce.",{"type":41,"tag":138,"props":245,"children":246},{},[247,252,254],{"type":41,"tag":56,"props":248,"children":249},{},[250],{"type":47,"value":251},"Stay within External Evaluation + ARG's limits.",{"type":47,"value":253}," If the user ask can't be achieved with the existing capabilities, say so plainly, explain why and stop.\n",{"type":41,"tag":134,"props":255,"children":256},{},[257],{"type":41,"tag":138,"props":258,"children":259},{},[260],{"type":47,"value":261},"If the user asks for a policy that doesn't need an ARG call but they want to use it anyway, let them know and continue with creating the policy if they're ok with it.",{"type":41,"tag":138,"props":263,"children":264},{},[265,270],{"type":41,"tag":56,"props":266,"children":267},{},[268],{"type":47,"value":269},"Your generated artifacts should strictly follow the pattern described in the knowledge base",{"type":47,"value":120},{"type":41,"tag":138,"props":272,"children":273},{},[274,279],{"type":41,"tag":56,"props":275,"children":276},{},[277],{"type":47,"value":278},"Work with the user to create and test the ARG query",{"type":47,"value":280},". Always run the co-design process.",{"type":41,"tag":138,"props":282,"children":283},{},[284,289],{"type":41,"tag":56,"props":285,"children":286},{},[287],{"type":47,"value":288},"Cite a knowledge file or official docs",{"type":47,"value":290}," every time you justify a non-obvious choice (e.g. \"queryWithUserIdentity: true — see the shape doc\"). No bare hand-waving. Goal is to ensure that you are accountable to the accuracy of your decisions as well as educating the user.",{"type":41,"tag":214,"props":292,"children":293},{},[],{"type":41,"tag":218,"props":295,"children":297},{"id":296},"workflow",[298],{"type":47,"value":299},"Workflow",{"type":41,"tag":301,"props":302,"children":304},"h3",{"id":303},"step-0-read-the-overview-doc",[305],{"type":47,"value":306},"Step 0 - Read the overview doc",{"type":41,"tag":50,"props":308,"children":309},{},[310,318],{"type":41,"tag":142,"props":311,"children":312},{"href":144},[313],{"type":41,"tag":76,"props":314,"children":316},{"className":315},[],[317],{"type":47,"value":151},{"type":47,"value":319},"\nExternal Evaluation is new and not yet covered by public documentation. Prior context and official docs will not fill in the gaps — read the overview first.",{"type":41,"tag":301,"props":321,"children":323},{"id":322},"step-1-intake-feasibility",[324],{"type":47,"value":325},"Step 1 — Intake & feasibility",{"type":41,"tag":50,"props":327,"children":328},{},[329],{"type":47,"value":330},"Goal is to reach a mutual agreement with the user about what the policy is doing and whether it's feasible to utilize the External Evaluation feature.",{"type":41,"tag":332,"props":333,"children":334},"ol",{},[335,363],{"type":41,"tag":138,"props":336,"children":337},{},[338,343,345],{"type":41,"tag":56,"props":339,"children":340},{},[341],{"type":47,"value":342},"Restate the free-text policy intent in one sentence. Reiterate based on user feedback until they approve",{"type":47,"value":344},":\n",{"type":41,"tag":134,"props":346,"children":347},{},[348,353,358],{"type":41,"tag":138,"props":349,"children":350},{},[351],{"type":47,"value":352},"Name which resource operations are targeted: operation type (write\u002Fdelete, could be implicit), resource type and any other constraints on the resource payload.",{"type":41,"tag":138,"props":354,"children":355},{},[356],{"type":47,"value":357},"Loosely describe what the ARG query returns and which returned values will result in denial.",{"type":41,"tag":138,"props":359,"children":360},{},[361],{"type":47,"value":362},"Example: \"Deny the association of an NSG to a subnet if an ARG query that counts other subnets using the NSG returns a number greater than 3\"",{"type":41,"tag":138,"props":364,"children":365},{},[366,371,373],{"type":41,"tag":56,"props":367,"children":368},{},[369],{"type":47,"value":370},"Feasibility check.",{"type":47,"value":372}," Walk through these reasons-to-reject:\n",{"type":41,"tag":134,"props":374,"children":375},{},[376,388,440],{"type":41,"tag":138,"props":377,"children":378},{},[379,381,386],{"type":47,"value":380},"Is the invariant ",{"type":41,"tag":56,"props":382,"children":383},{},[384],{"type":47,"value":385},"within one subscription",{"type":47,"value":387},"? Cross-sub \u002F cross-tenant \u002F MG-scoped → reject.",{"type":41,"tag":138,"props":389,"children":390},{},[391,393,398,400],{"type":47,"value":392},"The ARG query must return a result that has a single column and 0 or 1 rows. Can the invariant collapse to ",{"type":41,"tag":56,"props":394,"children":395},{},[396],{"type":47,"value":397},"one boolean or scalar",{"type":47,"value":399},"?\n",{"type":41,"tag":134,"props":401,"children":402},{},[403,424,435],{"type":41,"tag":138,"props":404,"children":405},{},[406,408,414,416,422],{"type":47,"value":407},"This means that parts of the policy logic will have to be shifted to the ARG query side. e.g. instead of an ",{"type":41,"tag":76,"props":409,"children":411},{"className":410},[],[412],{"type":47,"value":413},"allOf: [ claims().a == 1, claims().b == 2]",{"type":47,"value":415}," in the policy condition, the ARG query will have a ",{"type":41,"tag":76,"props":417,"children":419},{"className":418},[],[420],{"type":47,"value":421},"| project a == 1 and b == 2",{"type":47,"value":423}," statement.",{"type":41,"tag":138,"props":425,"children":426},{},[427,429],{"type":47,"value":428},"Common ways to return a single result is to have the query filter by a specific resource id, or use ",{"type":41,"tag":76,"props":430,"children":432},{"className":431},[],[433],{"type":47,"value":434},"summarize",{"type":41,"tag":138,"props":436,"children":437},{},[438],{"type":47,"value":439},"Try hard - ARG language is more capable than the policy language and it's most likely doable. Only reject if you genuinely cannot.",{"type":41,"tag":138,"props":441,"children":442},{},[443,445,451],{"type":47,"value":444},"Is the desired effect in ",{"type":41,"tag":76,"props":446,"children":448},{"className":447},[],[449],{"type":47,"value":450},"{audit, deny, auditAction, denyAction}",{"type":47,"value":452},"?\nWhen rejecting, state the reason plainly, point at the relevant knowledge file section, and suggest the closest standard-policy alternative if one exists. Then stop.",{"type":41,"tag":301,"props":454,"children":456},{"id":455},"step-2-kql-co-design-with-the-user",[457],{"type":47,"value":458},"Step 2 — KQL co-design with the user",{"type":41,"tag":50,"props":460,"children":461},{},[462],{"type":47,"value":463},"Goal is to work with the user to compose and test a draft of the query that will be used in the policy.",{"type":41,"tag":50,"props":465,"children":466},{},[467,469,475,477,483,485,491],{"type":47,"value":468},"The main challenge with the new kind of policies is that any meaningful use case will require formatting the ARG query at evaluation time, plugging in details from the evaluated resource or policy parameter values. This means that the policy definition you'll author will likely have ugly ",{"type":41,"tag":76,"props":470,"children":472},{"className":471},[],[473],{"type":47,"value":474},"[format()]",{"type":47,"value":476}," expressions that construct the query, with the necessary runtime details plugged in via expressions like ",{"type":41,"tag":76,"props":478,"children":480},{"className":479},[],[481],{"type":47,"value":482},"[field()]",{"type":47,"value":484}," and ",{"type":41,"tag":76,"props":486,"children":488},{"className":487},[],[489],{"type":47,"value":490},"[parameters()]",{"type":47,"value":492},", as well as escaping any quotes. This expression is not very human readable and extremely hard to manually convert to and from a runnable ARG query for testing. You are to shield the user from this complexity. Help them author and test a \"regular\" ARG query against a real environment, being mindful (and helping the user understand) about the parts of the query that will need to be parameterized at runtime vs parts of the query that are meant to perform the desired logic.",{"type":41,"tag":332,"props":494,"children":495},{},[496,543,566],{"type":41,"tag":138,"props":497,"children":498},{},[499,501],{"type":47,"value":500},"Get the initial query that captures the intent.\n",{"type":41,"tag":134,"props":502,"children":503},{},[504,509,514],{"type":41,"tag":138,"props":505,"children":506},{},[507],{"type":47,"value":508},"Ask the user if they have a working sample query that they want to use as a starting point. The query doesn't have to conform to the added rules and limitations of the policy. It should express the general idea.",{"type":41,"tag":138,"props":510,"children":511},{},[512],{"type":47,"value":513},"If they don't have a query, suggest a starting query for them and ask for feedback. Your query should focus on the core logic. Don't add any collapsing logic yet.",{"type":41,"tag":138,"props":515,"children":516},{},[517,519,529,531],{"type":47,"value":518},"For example, for the NSG oversharing example (see ",{"type":41,"tag":142,"props":520,"children":522},{"href":521},".\u002Fexamples\u002F01-deny-nsg-overshared\u002F",[523],{"type":41,"tag":76,"props":524,"children":526},{"className":525},[],[527],{"type":47,"value":528},"examples\u002F01-deny-nsg-overshared\u002F",{"type":47,"value":530},"), the starting query can return all pairs of associated subnet-nsgs:\n",{"type":41,"tag":134,"props":532,"children":533},{},[534],{"type":41,"tag":138,"props":535,"children":536},{},[537],{"type":41,"tag":76,"props":538,"children":540},{"className":539},[],[541],{"type":47,"value":542},"resources | where type =~ \"microsoft.network\u002Fnetworksecuritygroups\" | mv-expand subnet = properties[\"subnets\"] | project nsgId = id, subnetId = subnet[\"id\"]",{"type":41,"tag":138,"props":544,"children":545},{},[546,548],{"type":47,"value":547},"Sanity check query run:\n",{"type":41,"tag":134,"props":549,"children":550},{},[551,556,561],{"type":41,"tag":138,"props":552,"children":553},{},[554],{"type":47,"value":555},"Ask the user for permission to run the query, as well as against which subscriptions to run it — we want a test subscription where the query will return results.",{"type":41,"tag":138,"props":557,"children":558},{},[559],{"type":47,"value":560},"Run the query, analyze the results and present them to the user, raising any potential issues with the query or the quality of the test data set, as well as asking if it makes sense to them.",{"type":41,"tag":138,"props":562,"children":563},{},[564],{"type":47,"value":565},"Loop with the user until they have confidence that the query returns the right data to drive the requested policy.",{"type":41,"tag":138,"props":567,"children":568},{},[569,571],{"type":47,"value":570},"Re-write the query in a policy-friendly form:\n",{"type":41,"tag":134,"props":572,"children":573},{},[574,579,584,589,594,621,626],{"type":41,"tag":138,"props":575,"children":576},{},[577],{"type":47,"value":578},"Add additional filters if the initial query is too broad — the policy query needs to only return results that are relevant to the evaluated resource.",{"type":41,"tag":138,"props":580,"children":581},{},[582],{"type":47,"value":583},"Try to separate between conditions that will require parameterization and any conditions that act only on the properties of the queried resources.",{"type":41,"tag":138,"props":585,"children":586},{},[587],{"type":47,"value":588},"Your filters should use hard coded values that you know will yield results from the test set.",{"type":41,"tag":138,"props":590,"children":591},{},[592],{"type":47,"value":593},"Apply the necessary consolidation.",{"type":41,"tag":138,"props":595,"children":596},{},[597,599,605],{"type":47,"value":598},"Going with the NSG oversharing example above, the revised query will be: ",{"type":41,"tag":76,"props":600,"children":602},{"className":601},[],[603],{"type":47,"value":604},"resources | where type =~ \"microsoft.network\u002Fnetworksecuritygroups\" | where id == '\u003Chard coded NSG Id that will be populated in runtime in the policy>' | mv-expand subnet = properties[\"subnets\"] | where isnotnull(subnet[\"id\"]) | where subnet[\"id\"] !~ '\u003Chard coded subnet Id that will be populated in runtime in the policy>' | summarize otherSubnetsCount = count()",{"type":41,"tag":134,"props":606,"children":607},{},[608],{"type":41,"tag":138,"props":609,"children":610},{},[611,613,619],{"type":47,"value":612},"In this revised query, we imagine that the policy will target subnets, and that we'll have 2 dynamic values in the ARG query: which NSG we're about to add to the subnet (so that we can find who else uses it) as well as the id of the evaluated subnet, so that we can exclude it from the count if it's already attached to this NSG. We also consolidate the results by using a ",{"type":41,"tag":76,"props":614,"children":616},{"className":615},[],[617],{"type":47,"value":618},"summarize count()",{"type":47,"value":620}," aggregation.",{"type":41,"tag":138,"props":622,"children":623},{},[624],{"type":47,"value":625},"Share this query with the user, explain what you did and why, run it and ensure the results make sense. You may need to produce multiple versions of the query with different placeholder values hard-coded into it for different test cases. Iterate with the user until reaching an acceptable result.",{"type":41,"tag":138,"props":627,"children":628},{},[629],{"type":47,"value":630},"These queries and details will also be added to EXPLANATION.md",{"type":41,"tag":301,"props":632,"children":634},{"id":633},"step-3-design-the-policy-definition",[635],{"type":47,"value":636},"Step 3 - Design the policy definition",{"type":41,"tag":50,"props":638,"children":639},{},[640],{"type":47,"value":641},"Now that you have a working ARG query, work with the user to create a Policy Definition utilizing the external evaluation feature.\nNote that this skill is meant to help utilizing the new external evaluation feature, it's not a generic policy authoring skill. Also remember that the external evaluation feature is not publicly documented yet. This means that:",{"type":41,"tag":134,"props":643,"children":644},{},[645,657],{"type":41,"tag":138,"props":646,"children":647},{},[648,650,655],{"type":47,"value":649},"You must follow the canonical policy definition shape in ",{"type":41,"tag":76,"props":651,"children":653},{"className":652},[],[654],{"type":47,"value":166},{"type":47,"value":656}," to ensure proper use of the new primitives and maximize your chances to create a working policy.",{"type":41,"tag":138,"props":658,"children":659},{},[660],{"type":47,"value":661},"When it comes to the core evaluation logic, you should rely heavily on the user's input. If the user seems to be well versed in Azure Policy, your role should become helping them plug in the external evaluation endpoint definition and claims usage.",{"type":41,"tag":332,"props":663,"children":664},{},[665,700,712,785,915],{"type":41,"tag":138,"props":666,"children":667},{},[668,670,676,678,684,686,692,694,699],{"type":47,"value":669},"Start with crafting the policy rule's ",{"type":41,"tag":76,"props":671,"children":673},{"className":672},[],[674],{"type":47,"value":675},"if",{"type":47,"value":677}," condition based on the input you received so far. The condition should capture both the applicability of the policy (e.g. ",{"type":41,"tag":76,"props":679,"children":681},{"className":680},[],[682],{"type":47,"value":683},"type == vm && tags[env] == prod",{"type":47,"value":685},") as well as claims assertions (e.g. ",{"type":41,"tag":76,"props":687,"children":689},{"className":688},[],[690],{"type":47,"value":691},"coalesce(claims().otherSubnetsCount, null()) > 0",{"type":47,"value":693},"). Follow the shape described in ",{"type":41,"tag":76,"props":695,"children":697},{"className":696},[],[698],{"type":47,"value":166},{"type":47,"value":120},{"type":41,"tag":138,"props":701,"children":702},{},[703,705,710],{"type":47,"value":704},"Share the ",{"type":41,"tag":76,"props":706,"children":708},{"className":707},[],[709],{"type":47,"value":675},{"type":47,"value":711}," condition with the user. Explain in words what the condition is doing. The verbal description of the condition should loosely match the policy intent one-liner you came up with in step 1. Answer any questions the user has about the claims() usage. Remember to anchor your responses with references to your knowledge base. Iterate with the user until reaching an acceptable result.",{"type":41,"tag":138,"props":713,"children":714},{},[715,717,723,725,731,733,739,741,768,770,775,777,783],{"type":47,"value":716},"Craft the ",{"type":41,"tag":76,"props":718,"children":720},{"className":719},[],[721],{"type":47,"value":722},"then",{"type":47,"value":724}," block. ",{"type":41,"tag":76,"props":726,"children":728},{"className":727},[],[729],{"type":47,"value":730},"effect",{"type":47,"value":732}," is always ",{"type":41,"tag":76,"props":734,"children":736},{"className":735},[],[737],{"type":47,"value":738},"[parameters('effect')]",{"type":47,"value":740},". ",{"type":41,"tag":56,"props":742,"children":743},{},[744,746,752,754,760,762],{"type":47,"value":745},"If the effect family is action-time (",{"type":41,"tag":76,"props":747,"children":749},{"className":748},[],[750],{"type":47,"value":751},"auditAction",{"type":47,"value":753}," \u002F ",{"type":41,"tag":76,"props":755,"children":757},{"className":756},[],[758],{"type":47,"value":759},"denyAction",{"type":47,"value":761},"), also include ",{"type":41,"tag":76,"props":763,"children":765},{"className":764},[],[766],{"type":47,"value":767},"then.details.actionNames",{"type":47,"value":769}," — the engine rejects the assignment otherwise. See ",{"type":41,"tag":76,"props":771,"children":773},{"className":772},[],[774],{"type":47,"value":166},{"type":47,"value":776}," → ",{"type":41,"tag":76,"props":778,"children":780},{"className":779},[],[781],{"type":47,"value":782},"policyRule.then.details",{"type":47,"value":784}," for the exact shape.",{"type":41,"tag":138,"props":786,"children":787},{},[788,789,795,797,803,804,810,812,816,818,894,897,899],{"type":47,"value":716},{"type":41,"tag":76,"props":790,"children":792},{"className":791},[],[793],{"type":47,"value":794},"externalEvaluationEnforcementSettings",{"type":47,"value":796}," section based on the canonical definition shape and the query you constructed in the previous stage. Take the query with the hard-coded values and replace it with an ARM template expression that formats the query at runtime, using ",{"type":41,"tag":76,"props":798,"children":800},{"className":799},[],[801],{"type":47,"value":802},"field()",{"type":47,"value":753},{"type":41,"tag":76,"props":805,"children":807},{"className":806},[],[808],{"type":47,"value":809},"parameters()",{"type":47,"value":811}," calls for the dynamic values. Escape every quote in the inner KQL.",{"type":41,"tag":813,"props":814,"children":815},"br",{},[],{"type":47,"value":817},"Before (literal query, hard-coded NSG and subnet ids):",{"type":41,"tag":819,"props":820,"children":825},"pre",{"className":821,"code":822,"language":823,"meta":824,"style":824},"language-kusto shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","resources\n| where type =~ \"microsoft.network\u002Fnetworksecuritygroups\"\n| where id == \"\u003CNSG id being attached>\"\n| mv-expand subnet = properties[\"subnets\"]\n| where isnotnull(subnet[\"id\"])\n| where subnet[\"id\"] !~ \"\u003Csubnet id being modified>\"\n| summarize otherSubnetsCount = count()\n","kusto","",[826],{"type":41,"tag":76,"props":827,"children":828},{"__ignoreMap":824},[829,840,849,858,867,876,885],{"type":41,"tag":830,"props":831,"children":834},"span",{"class":832,"line":833},"line",1,[835],{"type":41,"tag":830,"props":836,"children":837},{},[838],{"type":47,"value":839},"resources\n",{"type":41,"tag":830,"props":841,"children":843},{"class":832,"line":842},2,[844],{"type":41,"tag":830,"props":845,"children":846},{},[847],{"type":47,"value":848},"| where type =~ \"microsoft.network\u002Fnetworksecuritygroups\"\n",{"type":41,"tag":830,"props":850,"children":852},{"class":832,"line":851},3,[853],{"type":41,"tag":830,"props":854,"children":855},{},[856],{"type":47,"value":857},"| where id == \"\u003CNSG id being attached>\"\n",{"type":41,"tag":830,"props":859,"children":861},{"class":832,"line":860},4,[862],{"type":41,"tag":830,"props":863,"children":864},{},[865],{"type":47,"value":866},"| mv-expand subnet = properties[\"subnets\"]\n",{"type":41,"tag":830,"props":868,"children":870},{"class":832,"line":869},5,[871],{"type":41,"tag":830,"props":872,"children":873},{},[874],{"type":47,"value":875},"| where isnotnull(subnet[\"id\"])\n",{"type":41,"tag":830,"props":877,"children":879},{"class":832,"line":878},6,[880],{"type":41,"tag":830,"props":881,"children":882},{},[883],{"type":47,"value":884},"| where subnet[\"id\"] !~ \"\u003Csubnet id being modified>\"\n",{"type":41,"tag":830,"props":886,"children":888},{"class":832,"line":887},7,[889],{"type":41,"tag":830,"props":890,"children":891},{},[892],{"type":47,"value":893},"| summarize otherSubnetsCount = count()\n",{"type":41,"tag":813,"props":895,"children":896},{},[],{"type":47,"value":898},"After (ARM template expression, single-line, all inner quotes escaped):",{"type":41,"tag":819,"props":900,"children":904},{"className":901,"code":902,"language":903,"meta":824,"style":824},"language-jsonc shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","\"query\": \"[format('resources | where type =~ \\\"microsoft.network\u002Fnetworksecuritygroups\\\" | where id == \\\"{0}\\\" | mv-expand subnet = properties[\\\"subnets\\\"] | where isnotnull(subnet[\\\"id\\\"]) | where subnet[\\\"id\\\"] !~ \\\"{1}\\\" | summarize otherSubnetsCount = count()', field('Microsoft.Network\u002FvirtualNetworks\u002Fsubnets\u002FnetworkSecurityGroup.id'), field('id'))]\"\n","jsonc",[905],{"type":41,"tag":76,"props":906,"children":907},{"__ignoreMap":824},[908],{"type":41,"tag":830,"props":909,"children":910},{"class":832,"line":833},[911],{"type":41,"tag":830,"props":912,"children":913},{},[914],{"type":47,"value":902},{"type":41,"tag":138,"props":916,"children":917},{},[918],{"type":47,"value":919},"Share this section with the user. Explain what each part is doing and how you transformed the query and why. Iterate with the user until reaching an acceptable result.",{"type":41,"tag":301,"props":921,"children":923},{"id":922},"step-4-emit-artifacts",[924],{"type":47,"value":925},"Step 4 — Emit artifacts",{"type":41,"tag":50,"props":927,"children":928},{},[929],{"type":47,"value":930},"Before writing anything, tell the user — in one short line each — which files you're about to create and what each is for. Then write them.",{"type":41,"tag":50,"props":932,"children":933},{},[934,936,942,943,949,950,956,957,963],{"type":47,"value":935},"Create a new folder named after the policy (kebab-case, prefixed with ",{"type":41,"tag":76,"props":937,"children":939},{"className":938},[],[940],{"type":47,"value":941},"audit-",{"type":47,"value":753},{"type":41,"tag":76,"props":944,"children":946},{"className":945},[],[947],{"type":47,"value":948},"deny-",{"type":47,"value":753},{"type":41,"tag":76,"props":951,"children":953},{"className":952},[],[954],{"type":47,"value":955},"auditaction-",{"type":47,"value":753},{"type":41,"tag":76,"props":958,"children":960},{"className":959},[],[961],{"type":47,"value":962},"denyaction-",{"type":47,"value":964},") and write three files:",{"type":41,"tag":134,"props":966,"children":967},{},[968,1000,1071],{"type":41,"tag":138,"props":969,"children":970},{},[971,976,978,983,985,990,992,998],{"type":41,"tag":76,"props":972,"children":974},{"className":973},[],[975],{"type":47,"value":81},{"type":47,"value":977}," — model the canonical shape in ",{"type":41,"tag":76,"props":979,"children":981},{"className":980},[],[982],{"type":47,"value":166},{"type":47,"value":984}," and the worked examples under ",{"type":41,"tag":76,"props":986,"children":988},{"className":987},[],[989],{"type":47,"value":210},{"type":47,"value":991},". Fill in the effect family from step 1, the target resource type, the claim name, and the ",{"type":41,"tag":76,"props":993,"children":995},{"className":994},[],[996],{"type":47,"value":997},"[format(...)]",{"type":47,"value":999}," KQL from step 2. The shape doc is authoritative for every field.",{"type":41,"tag":138,"props":1001,"children":1002},{},[1003,1008,1010,1016,1018,1024,1026,1032,1034,1040,1042],{"type":41,"tag":76,"props":1004,"children":1006},{"className":1005},[],[1007],{"type":47,"value":89},{"type":47,"value":1009}," — start from ",{"type":41,"tag":76,"props":1011,"children":1013},{"className":1012},[],[1014],{"type":47,"value":1015},"templates\u002Ftest-flow.template.http",{"type":47,"value":1017},". Substitute the concrete RP path, API version, location, and request body. Keep the ",{"type":41,"tag":76,"props":1019,"children":1021},{"className":1020},[],[1022],{"type":47,"value":1023},"### Expected:",{"type":47,"value":1025}," lines. The policy assignment body is inlined inside this file rather than living in its own JSON — the REST Client extension does not expand ",{"type":41,"tag":76,"props":1027,"children":1029},{"className":1028},[],[1030],{"type":47,"value":1031},"@",{"type":47,"value":1033},"-variables inside files included via ",{"type":41,"tag":76,"props":1035,"children":1037},{"className":1036},[],[1038],{"type":47,"value":1039},"\u003C .\u002Ffile.json",{"type":47,"value":1041},", so an external assignment file would emit a broken request.\n",{"type":41,"tag":134,"props":1043,"children":1044},{},[1045],{"type":41,"tag":138,"props":1046,"children":1047},{},[1048,1061,1063,1069],{"type":41,"tag":56,"props":1049,"children":1050},{},[1051,1053,1059],{"type":47,"value":1052},"Before each ",{"type":41,"tag":76,"props":1054,"children":1056},{"className":1055},[],[1057],{"type":47,"value":1058},"acquirePolicyToken",{"type":47,"value":1060}," POST, include a direct ARG query that mirrors what the policy will run for that case.",{"type":47,"value":1062}," Build it from the same materialized KQL with the same inputs the policy will substitute (resource id, parameter values). Lets the user — and the agent, on a failing case — distinguish a wrong query from a policy\u002Ftoken\u002Fwiring problem in one extra send. See ",{"type":41,"tag":76,"props":1064,"children":1066},{"className":1065},[],[1067],{"type":47,"value":1068},"examples\u002F03-denyaction-actiongroup-in-use\u002Ftest-flow.http",{"type":47,"value":1070}," for the pattern.",{"type":41,"tag":138,"props":1072,"children":1073},{},[1074,1079,1081],{"type":41,"tag":76,"props":1075,"children":1077},{"className":1076},[],[1078],{"type":47,"value":97},{"type":47,"value":1080}," — three sections:\n",{"type":41,"tag":332,"props":1082,"children":1083},{},[1084,1094,1104],{"type":41,"tag":138,"props":1085,"children":1086},{},[1087,1092],{"type":41,"tag":56,"props":1088,"children":1089},{},[1090],{"type":47,"value":1091},"What this policy does",{"type":47,"value":1093}," — intent, target operation, bad-state condition, what gets denied vs allowed.",{"type":41,"tag":138,"props":1095,"children":1096},{},[1097,1102],{"type":41,"tag":56,"props":1098,"children":1099},{},[1100],{"type":47,"value":1101},"Test queries used during co-design",{"type":47,"value":1103}," — for each iteration of the KQL loop: the materialized query, the inputs, the actual ARG result, the conclusion.",{"type":41,"tag":138,"props":1105,"children":1106},{},[1107,1112,1114,1119],{"type":41,"tag":56,"props":1108,"children":1109},{},[1110],{"type":47,"value":1111},"How to test this",{"type":47,"value":1113}," — concrete steps for Portal, Azure CLI, and the ",{"type":41,"tag":76,"props":1115,"children":1117},{"className":1116},[],[1118],{"type":47,"value":105},{"type":47,"value":1120}," file.",{"type":41,"tag":50,"props":1122,"children":1123},{},[1124],{"type":47,"value":1125},"Authoring rules for these files:",{"type":41,"tag":134,"props":1127,"children":1128},{},[1129,1185],{"type":41,"tag":138,"props":1130,"children":1131},{},[1132,1137,1139,1145,1147,1153,1154,1160,1162,1168,1170,1176,1178,1183],{"type":41,"tag":56,"props":1133,"children":1134},{},[1135],{"type":47,"value":1136},"No real environment values.",{"type":47,"value":1138}," Subscription ids, resource group names, tenant ids, and specific resource names from the user's environment must be replaced with placeholders like ",{"type":41,"tag":76,"props":1140,"children":1142},{"className":1141},[],[1143],{"type":47,"value":1144},"\u003CsubId>",{"type":47,"value":1146},", ",{"type":41,"tag":76,"props":1148,"children":1150},{"className":1149},[],[1151],{"type":47,"value":1152},"\u003CrgName>",{"type":47,"value":1146},{"type":41,"tag":76,"props":1155,"children":1157},{"className":1156},[],[1158],{"type":47,"value":1159},"\u003CnsgName>",{"type":47,"value":1161}," (or a generic-looking default like ",{"type":41,"tag":76,"props":1163,"children":1165},{"className":1164},[],[1166],{"type":47,"value":1167},"nsg-immutable-test",{"type":47,"value":1169},") in ",{"type":41,"tag":1171,"props":1172,"children":1173},"em",{},[1174],{"type":47,"value":1175},"every",{"type":47,"value":1177}," file you emit, including KQL examples quoted inside ",{"type":41,"tag":76,"props":1179,"children":1181},{"className":1180},[],[1182],{"type":47,"value":97},{"type":47,"value":1184},". These bundles are shared publicly.",{"type":41,"tag":138,"props":1186,"children":1187},{},[1188,1193,1195,1200,1202,1208,1210,1216],{"type":41,"tag":56,"props":1189,"children":1190},{},[1191],{"type":47,"value":1192},"Cross-references stay inside the bundle.",{"type":47,"value":1194}," When ",{"type":41,"tag":76,"props":1196,"children":1198},{"className":1197},[],[1199],{"type":47,"value":97},{"type":47,"value":1201}," links to a knowledge file or another example, use a relative path inside this bundle (e.g. ",{"type":41,"tag":76,"props":1203,"children":1205},{"className":1204},[],[1206],{"type":47,"value":1207},"..\u002F..\u002Fknowledge\u002F01-overview.md",{"type":47,"value":1209},"). Do not invent absolute paths under ",{"type":41,"tag":76,"props":1211,"children":1213},{"className":1212},[],[1214],{"type":47,"value":1215},".copilot\u002Fskills\u002F...",{"type":47,"value":1217}," or any other deploy-time location — those won't resolve for the reader.",{"type":41,"tag":50,"props":1219,"children":1220},{},[1221,1223,1228,1230,1235,1237,1242,1244,1249],{"type":47,"value":1222},"Once the files are written, respond with a short message: list the files you created, point the user at ",{"type":41,"tag":76,"props":1224,"children":1226},{"className":1225},[],[1227],{"type":47,"value":97},{"type":47,"value":1229}," for the design walkthrough and at ",{"type":41,"tag":76,"props":1231,"children":1233},{"className":1232},[],[1234],{"type":47,"value":89},{"type":47,"value":1236}," for the end-to-end create-and-test flow, and invite follow-ups. Do ",{"type":41,"tag":56,"props":1238,"children":1239},{},[1240],{"type":47,"value":1241},"not",{"type":47,"value":1243}," re-explain what the policy does or restate each design decision — that's what ",{"type":41,"tag":76,"props":1245,"children":1247},{"className":1246},[],[1248],{"type":47,"value":97},{"type":47,"value":1250}," is for.",{"type":41,"tag":214,"props":1252,"children":1253},{},[],{"type":41,"tag":218,"props":1255,"children":1257},{"id":1256},"when-asked-why-x",[1258],{"type":47,"value":1259},"When asked \"why X?\"",{"type":41,"tag":50,"props":1261,"children":1262},{},[1263,1265,1271,1272,1278,1280,1286,1287,1293],{"type":47,"value":1264},"Cite the relevant knowledge file and answer in one or two sentences. If the answer involves a trade-off (",{"type":41,"tag":76,"props":1266,"children":1268},{"className":1267},[],[1269],{"type":47,"value":1270},"missingTokenAction",{"type":47,"value":1146},{"type":41,"tag":76,"props":1273,"children":1275},{"className":1274},[],[1276],{"type":47,"value":1277},"mode: Indexed",{"type":47,"value":1279}," vs ",{"type":41,"tag":76,"props":1281,"children":1283},{"className":1282},[],[1284],{"type":47,"value":1285},"All",{"type":47,"value":1146},{"type":41,"tag":76,"props":1288,"children":1290},{"className":1289},[],[1291],{"type":47,"value":1292},"queryWithUserIdentity",{"type":47,"value":1294},"), state the trade, the default, and offer to change it. If you don't have a citation, say so — don't invent one.",{"type":41,"tag":214,"props":1296,"children":1297},{},[],{"type":41,"tag":218,"props":1299,"children":1301},{"id":1300},"when-to-stop",[1302],{"type":47,"value":1303},"When to stop",{"type":41,"tag":50,"props":1305,"children":1306},{},[1307],{"type":47,"value":1308},"If you discover mid-flow that the ask hits a limit you missed in step 1 — cross-sub query, request-mutation effect, data not in ARG, an invariant that won't collapse to one claim, or an unsupported endpoint kind — stop and explain. Don't write artifacts you know won't work. Suggest the nearest workable alternative (classic policy, DeployIfNotExists, a pipeline check) if one exists.",{"type":41,"tag":50,"props":1310,"children":1311},{},[1312,1314,1319,1321,1327],{"type":47,"value":1313},"Push back, but proceed after re-confirmation, when the user picks an effect from the wrong family for their operation kind (e.g. ",{"type":41,"tag":76,"props":1315,"children":1317},{"className":1316},[],[1318],{"type":47,"value":759},{"type":47,"value":1320}," on a PUT, ",{"type":41,"tag":76,"props":1322,"children":1324},{"className":1323},[],[1325],{"type":47,"value":1326},"deny",{"type":47,"value":1328}," on a DELETE). The wrong family silently no-ops at runtime — the test loop appears to succeed and the customer thinks they have protection.",{"type":41,"tag":214,"props":1330,"children":1331},{},[],{"type":41,"tag":218,"props":1333,"children":1335},{"id":1334},"output-style",[1336],{"type":47,"value":1337},"Output style",{"type":41,"tag":134,"props":1339,"children":1340},{},[1341,1346,1358,1371],{"type":41,"tag":138,"props":1342,"children":1343},{},[1344],{"type":47,"value":1345},"Lead with the punchline. Use matter-of-fact and neutral tone. Be concise. Use plain language.",{"type":41,"tag":138,"props":1347,"children":1348},{},[1349,1351,1356],{"type":47,"value":1350},"Show the materialized KQL (literal values substituted) — not the ",{"type":41,"tag":76,"props":1352,"children":1354},{"className":1353},[],[1355],{"type":47,"value":997},{"type":47,"value":1357}," wrapper. That's the form that matters for debugging.",{"type":41,"tag":138,"props":1359,"children":1360},{},[1361,1363,1369],{"type":47,"value":1362},"After each emitted artifact, a short ",{"type":41,"tag":76,"props":1364,"children":1366},{"className":1365},[],[1367],{"type":47,"value":1368},"_why:_",{"type":47,"value":1370}," callout listing the 3–6 most surprising choices with a pointer to the relevant knowledge file.",{"type":41,"tag":138,"props":1372,"children":1373},{},[1374],{"type":47,"value":1375},"One concrete suggestion, not a list of options.",{"type":41,"tag":1377,"props":1378,"children":1379},"style",{},[1380],{"type":47,"value":1381},"html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}",{"items":1383,"total":1550},[1384,1391,1410,1429,1444,1459,1472,1487,1498,1512,1525,1538],{"slug":4,"name":4,"fn":5,"description":6,"org":1385,"tags":1386,"stars":24,"repoUrl":25,"updatedAt":26},{"slug":8,"name":9,"logoUrl":10,"githubOrg":11},[1387,1388,1389,1390],{"name":11,"slug":8,"type":14},{"name":16,"slug":17,"type":14},{"name":19,"slug":20,"type":14},{"name":22,"slug":23,"type":14},{"slug":1392,"name":1392,"fn":1393,"description":1394,"org":1395,"tags":1396,"stars":1407,"repoUrl":1408,"updatedAt":1409},"azure-blueprints-migration","migrate Azure Blueprints to Template Specs","Use when a user needs to migrate off Azure Blueprints (definitions and\u002For assignments) to Template Specs and Deployment Stacks before the January 31, 2027 retirement. Covers inventory, export, conversion to Bicep, policy decoupling, Template Spec publishing, Deployment Stack deployment with deny-settings, validation, and cutover.",{"slug":8,"name":9,"logoUrl":10,"githubOrg":11},[1397,1398,1401,1404],{"name":11,"slug":8,"type":14},{"name":1399,"slug":1400,"type":14},"Deployment","deployment",{"name":1402,"slug":1403,"type":14},"Infrastructure as Code","infrastructure-as-code",{"name":1405,"slug":1406,"type":14},"Migration","migration",260,"https:\u002F\u002Fgithub.com\u002FAzure\u002Fazure-blueprints","2026-07-12T08:17:49.646405",{"slug":1411,"name":1411,"fn":1412,"description":1413,"org":1414,"tags":1415,"stars":1426,"repoUrl":1427,"updatedAt":1428},"apiview-feedback-resolution","resolve APIView feedback on Azure SDKs","Analyze and resolve APIView review feedback on Azure SDK PRs. **UTILITY SKILL**. USE FOR: APIView comments, API review feedback, SDK API surface changes. DO NOT USE FOR: general code review, non-APIView feedback. INVOKES: azure-sdk-mcp:azsdk_apiview_get_comments, azure-sdk-mcp:azsdk_typespec_customized_code_update.",{"slug":8,"name":9,"logoUrl":10,"githubOrg":11},[1416,1419,1420,1423],{"name":1417,"slug":1418,"type":14},"API Development","api-development",{"name":11,"slug":8,"type":14},{"name":1421,"slug":1422,"type":14},"Code Review","code-review",{"name":1424,"slug":1425,"type":14},"Documentation","documentation",133,"https:\u002F\u002Fgithub.com\u002FAzure\u002Fazure-sdk-tools","2026-07-12T08:17:43.350876",{"slug":1430,"name":1430,"fn":1431,"description":1432,"org":1433,"tags":1434,"stars":1426,"repoUrl":1427,"updatedAt":1443},"azsdk-common-live-and-recorded-tests","deploy resources and run Azure SDK tests","Deploy test resources and run Azure SDK tests in live, record, or playback mode. WHEN: \"run live tests\", \"run recorded tests\", \"deploy test resources\", \"record tests\", \"run tests in record mode\", \"clean up test resources\", \"run tests against live resources\". DO NOT USE FOR: writing new tests, authoring Bicep templates, playback-only test runs without resource deployment. INVOKES: azure-sdk-mcp:azsdk_package_run_tests.",{"slug":8,"name":9,"logoUrl":10,"githubOrg":11},[1435,1436,1437,1440],{"name":11,"slug":8,"type":14},{"name":1399,"slug":1400,"type":14},{"name":1438,"slug":1439,"type":14},"SDK","sdk",{"name":1441,"slug":1442,"type":14},"Testing","testing","2026-07-12T08:17:44.718943",{"slug":1445,"name":1445,"fn":1446,"description":1447,"org":1448,"tags":1449,"stars":1426,"repoUrl":1427,"updatedAt":1458},"azsdk-common-prepare-release-plan","manage Azure SDK release plan work items","Create, get, update, abandon, and link SDK PRs to release plan work items for Azure SDK releases. **UTILITY SKILL**. USE FOR: \"create release plan\", \"get release plan\", \"update release plan\", \"update API spec in release plan\", \"update SDK details in release plan\", \"abandon release plan\", \"link SDK PR to plan\", \"namespace approval\", \"check release plan status\". DO NOT USE FOR: SDK code generation, pipeline troubleshooting, API review feedback. INVOKES: azure-sdk-mcp:azsdk_create_release_plan, azure-sdk-mcp:azsdk_get_release_plan, azure-sdk-mcp:azsdk_get_release_plan_for_spec_pr, azure-sdk-mcp:azsdk_update_release_plan, azure-sdk-mcp:azsdk_update_api_spec_pull_request_in_release_plan, azure-sdk-mcp:azsdk_update_sdk_details_in_release_plan, azure-sdk-mcp:azsdk_abandon_release_plan, azure-sdk-mcp:azsdk_link_sdk_pull_request_to_release_plan, azure-sdk-mcp:azsdk_link_namespace_approval_issue.",{"slug":8,"name":9,"logoUrl":10,"githubOrg":11},[1450,1451,1454,1457],{"name":11,"slug":8,"type":14},{"name":1452,"slug":1453,"type":14},"GitHub","github",{"name":1455,"slug":1456,"type":14},"Project Management","project-management",{"name":1438,"slug":1439,"type":14},"2026-07-12T08:17:38.345387",{"slug":1460,"name":1460,"fn":1461,"description":1462,"org":1463,"tags":1464,"stars":1426,"repoUrl":1427,"updatedAt":1471},"azsdk-common-sdk-release","release Azure SDK packages","Check release readiness and trigger the release pipeline for Azure SDK packages. **UTILITY SKILL**. USE FOR: \"release SDK\", \"trigger release\", \"check release readiness\", \"release pipeline\", \"publish package\", \"ship SDK\". DO NOT USE FOR: SDK development, code generation, pipeline debugging, release plan creation. INVOKES: azure-sdk-mcp:azsdk_release_sdk.",{"slug":8,"name":9,"logoUrl":10,"githubOrg":11},[1465,1466,1469,1470],{"name":11,"slug":8,"type":14},{"name":1467,"slug":1468,"type":14},"CI\u002FCD","ci-cd",{"name":1399,"slug":1400,"type":14},{"name":1438,"slug":1439,"type":14},"2026-07-12T08:17:34.27607",{"slug":1473,"name":1473,"fn":1474,"description":1475,"org":1476,"tags":1477,"stars":1426,"repoUrl":1427,"updatedAt":1486},"azure-typespec-author","author and modify Azure TypeSpec API specifications","Authors and modifies Azure TypeSpec (.tsp) API specifications. USE FOR: any TypeSpec\u002Ftsp change — api versions (add, bump, preview, stable, promote), resources, operations, models, properties, decorators, visibility, constraints, breaking changes, LRO, suppressions, operationId, spread model. Covers ARM resource-manager and data-plane services. DO NOT USE FOR: SDK generation, releasing SDK packages, or single MCP tool calls. INVOKES: azure-sdk-mcp:azsdk_typespec_generate_authoring_plan, azure-sdk-mcp:azsdk_run_typespec_validation.",{"slug":8,"name":9,"logoUrl":10,"githubOrg":11},[1478,1479,1480,1483],{"name":1417,"slug":1418,"type":14},{"name":11,"slug":8,"type":14},{"name":1481,"slug":1482,"type":14},"OpenAPI","openapi",{"name":1484,"slug":1485,"type":14},"Technical Writing","technical-writing","2026-07-12T08:17:39.603232",{"slug":1488,"name":1488,"fn":1489,"description":1490,"org":1491,"tags":1492,"stars":1426,"repoUrl":1427,"updatedAt":1497},"generate-sdk-locally","generate and test Azure SDKs locally","Generate, build, and test Azure SDKs locally from TypeSpec with automatic customization. WHEN: \"generate SDK locally\", \"build SDK\", \"run SDK tests\", \"run CI checks\", \"validate package\", \"run checks\", \"update changelog\", \"fix SDK build errors\", \"fix breaking changes\", \"resolve SDK generation errors\", \"customize TypeSpec\", \"rename SDK client\", \"rename SDK model\", \"hide operation from SDK\", \"fix analyzer errors\", \"resolve customization drift\", \"create subclient\", \"update metadata\", \"update version\". DO NOT USE FOR: publishing to package registries, CI pipeline configuration, API design review. INVOKES: azsdk_verify_setup, azsdk_package_generate_code, azsdk_package_build_code, azsdk_package_run_check, azsdk_package_run_tests, azsdk_customized_code_update, azsdk_package_update_changelog_content, azsdk_package_update_metadata, azsdk_package_update_version.",{"slug":8,"name":9,"logoUrl":10,"githubOrg":11},[1493,1494,1495,1496],{"name":11,"slug":8,"type":14},{"name":1467,"slug":1468,"type":14},{"name":1438,"slug":1439,"type":14},{"name":1441,"slug":1442,"type":14},"2026-07-12T08:17:37.08523",{"slug":1499,"name":1499,"fn":1500,"description":1501,"org":1502,"tags":1503,"stars":1426,"repoUrl":1427,"updatedAt":1511},"markdown-token-optimizer","optimize markdown files for token efficiency","Analyze markdown files for token efficiency and reduce context-window bloat. **UTILITY SKILL**. DO NOT USE FOR: code optimization, general file editing, non-markdown files. TRIGGERS: optimize markdown, reduce tokens, token count, token bloat, too many tokens, make concise, shrink file, file too large, optimize for AI, token efficiency, verbose markdown, reduce file size. INVOKES: waza CLI.",{"slug":8,"name":9,"logoUrl":10,"githubOrg":11},[1504,1507,1510],{"name":1505,"slug":1506,"type":14},"LLM","llm",{"name":1508,"slug":1509,"type":14},"Performance","performance",{"name":1484,"slug":1485,"type":14},"2026-07-12T08:17:42.080413",{"slug":1513,"name":1513,"fn":1514,"description":1515,"org":1516,"tags":1517,"stars":1426,"repoUrl":1427,"updatedAt":1524},"pipeline-troubleshooting","troubleshoot Azure SDK CI pipelines","Diagnose and resolve failures in Azure SDK CI and generation pipelines. **UTILITY SKILL**. USE FOR: \"pipeline failed\", \"build failure\", \"CI check failing\", \"SDK generation error\", \"reproduce pipeline locally\", \"debug SDK pipeline\". DO NOT USE FOR: local build issues without pipeline context, API design review, SDK publishing. INVOKES: azure-sdk-mcp:azsdk_analyze_pipeline, azure-sdk-mcp:azsdk_package_build_code, azure-sdk-mcp:azsdk_package_run_check.",{"slug":8,"name":9,"logoUrl":10,"githubOrg":11},[1518,1519,1520,1523],{"name":11,"slug":8,"type":14},{"name":1467,"slug":1468,"type":14},{"name":1521,"slug":1522,"type":14},"Debugging","debugging",{"name":1438,"slug":1439,"type":14},"2026-07-12T08:17:40.821512",{"slug":1526,"name":1526,"fn":1527,"description":1528,"org":1529,"tags":1530,"stars":1426,"repoUrl":1427,"updatedAt":1537},"sensei","improve skill frontmatter compliance","**WORKFLOW SKILL** — Iteratively improve skill frontmatter compliance using the Ralph loop pattern. WHEN: \"run sensei\", \"sensei help\", \"improve skill\", \"fix frontmatter\", \"skill compliance\", \"frontmatter audit\", \"score skill\", \"check skill tokens\". INVOKES: token counting tools, test runners, git commands. FOR SINGLE OPERATIONS: use token CLI directly for counts\u002Fchecks.",{"slug":8,"name":9,"logoUrl":10,"githubOrg":11},[1531,1532,1533,1536],{"name":11,"slug":8,"type":14},{"name":16,"slug":17,"type":14},{"name":1534,"slug":1535,"type":14},"Process Optimization","process-optimization",{"name":1484,"slug":1485,"type":14},"2026-07-12T08:17:32.970921",{"slug":1539,"name":1539,"fn":1540,"description":1541,"org":1542,"tags":1543,"stars":1426,"repoUrl":1427,"updatedAt":1549},"skill-authoring","author agent skills for agentskills.io","Write Agent Skills that comply with the agentskills.io specification. WHEN: \"create a skill\", \"new skill\", \"write a skill\", \"skill template\", \"skill structure\", \"review skill\", \"skill PR\", \"skill compliance\", \"SKILL.md format\", \"skill frontmatter\", \"skill best practices\". DO NOT USE FOR: improving existing skills (use sensei), general documentation. INVOKES: waza CLI.",{"slug":8,"name":9,"logoUrl":10,"githubOrg":11},[1544,1545,1548],{"name":1424,"slug":1425,"type":14},{"name":1546,"slug":1547,"type":14},"Plugin Development","plugin-development",{"name":1484,"slug":1485,"type":14},"2026-07-12T08:17:35.873862",109,{"items":1552,"total":833},[1553],{"slug":4,"name":4,"fn":5,"description":6,"org":1554,"tags":1555,"stars":24,"repoUrl":25,"updatedAt":26},{"slug":8,"name":9,"logoUrl":10,"githubOrg":11},[1556,1557,1558,1559],{"name":11,"slug":8,"type":14},{"name":16,"slug":17,"type":14},{"name":19,"slug":20,"type":14},{"name":22,"slug":23,"type":14}]