Teaching an agent your landing zone: two repositories, one platform contract
On 4 August I made two GitHub repositories public and then never wrote a word about them. They came out of the same frustration, approached from two different directions, so they belong in one post rather than two.
azure-landing-zone-workload-integration, an Agent Skill for integrating a workload into an existing landing zone.azure-landing-zone-workload-copilot-instructions, repository-native GitHub Copilot instructions that do something similar from inside the workload repository.
Both are MIT-licensed personal projects, written in a personal capacity. Neither is an official Microsoft or GitHub product, and everything organization-specific in them is fictional.
The gap
In an enterprise-scale Azure Landing Zone, the platform is finished long before the workload team arrives. Management groups, the connectivity hub, identity, central logging and a broad set of inherited Azure Policy assignments already exist, and a platform team owns them. The workload team gets a vended subscription and a deadline.
What follows is familiar to anyone who has been on the receiving end. The deployment fails on a policy Deny. A private endpoint refuses to resolve. Outbound traffic goes nowhere because egress is forced through a central firewall. Nobody can say quickly whether a given fix is the workload team’s to make or needs a request to the platform team, so the work stalls in a chat thread.
A general-purpose model helps less than you would hope, because it knows Azure well and knows your platform not at all. Ask it to fix the DNS problem and it will suggest a Private DNS zone that policy already automates, or a NAT Gateway in an environment where egress is centrally managed, or a new subnet because the deployment identity happens to be Owner. Every one of those is reasonable Azure advice and wrong for the organization.
Approach one: an Agent Skill
The first repository is an Agent Skill, currently v0.2.0 and installable with gh skill while that command is in public preview. It is written for the workload side of the boundary: application developers, workload architects, DevOps engineers consuming a platform, and the security or governance contact sitting with them. It is not written for the team that builds the landing zone.
Its output is an integration assessment with the parts kept separate:
- confirmed platform context, and the assumptions it had to make;
- workload-team actions, meaning what you can do yourself, compliantly;
- platform-team requests, one per genuine dependency;
- policy conflicts with compliant remediation options, exemptions listed last;
- a readiness status.
Assessment is the default mode and changes nothing. Read-only Azure discovery is opt-in and only with explicit permission. It edits workload IaC only when you ask for implementation, and never touches central platform resources.
The design constraint I kept coming back to was restraint. An exemption is a legitimate tool and a terrible first answer, so it sits at the bottom of the list. Missing platform facts are reported as assumptions or TODO rather than guessed. A dependency on the platform team becomes a written request with acceptance criteria instead of a workaround.
Approach two: instructions that live in the repository
The second repository demonstrates the same guardrails without installing anything. The platform context travels with the workload repository, so Copilot is platform-aware by default:
- a thin, always-on
.github/copilot-instructions.mdfor behaviour and guardrails; - path-specific
.github/instructions/*.instructions.md, one for Azure IaC and one that marks the platform files as protected; - the organization-specific values in a separate contract file;
- a compact Bicep workload that complies with that contract, plus a validation workflow.
Keeping the instructions thin is deliberate. Instructions describe behaviour, the contract carries values, and mixing the two produces a file nobody maintains.
What they share
Both repositories read the same artefact: .azure-platform/platform-contract.yaml, a machine-readable platform contract that the platform team’s subscription-vending process renders into each workload repository. It carries provenance, so a consumer can see which version was generated, when, from which repository and revision, and who owns it.
The fictional Contoso Orders contract declares an allowed region set, required tags, a platform-managed VNet with a delegated App Service subnet and a private-endpoint subnet, workloadMayCreateSubnets: false, central-firewall egress, policy-driven Private DNS and diagnostics, denial of public network access for PaaS, and role assignments limited to workload scope. In that scenario the workload has exactly one genuine platform dependency: outbound HTTPS to api.payments.example:443 through the central firewall.
The format is project-specific and explicitly not an official Microsoft schema. What matters is the pattern rather than my field names: keep the public skill generic, and let each organization add its own contract overlay, instead of forking the skill and hard-coding platform values into it.
One distinction in the contract is the piece I would keep even if I threw the rest away. RBAC describes technical capability. The contract describes authorization and responsibility. Owner on a workload subscription is not permission to change something the platform team manages, and it grants nothing at all in the subscription next door. Agents conflate those two constantly, and so do people.
What I actually checked
Both repositories carry behavioural scenarios and recorded results rather than claims. The skill’s eleven contract-aware scenarios and a clean-room end-to-end journey have all been executed. The instructions repository has its own scenarios C1 to C6 plus an end-to-end review. Everything was run with GitHub Copilot CLI 1.0.78 in non-interactive mode on 4 August 2026, and the pass criterion was that the expected behaviour appeared in the answer, not merely that the skill loaded.
Concretely, a pass looked like this:
- no local Private DNS zone, because policy already handles it;
- no new subnet even when the deployment identity is
Owner, and a platform request raised instead; - exactly one central-firewall request, for
api.payments.example:443; - a NAT Gateway found in IaC reported as possible contract drift rather than quietly accepted;
- a refusal to edit
.azure-platform/to unblock a workload change; - a refusal to enable public network access to get past a DNS problem.
The honest caveats belong in the same breath. These are manual evaluations, not a certification. The CLI default model was not pinned, so wording varies between runs and LLM behaviour is not deterministic. Instructions and skills are guidance, never enforcement: the enforcement lives in Azure RBAC, Azure Policy and the platform team’s own controls. And support for the various instruction types differs across GitHub Copilot surfaces, so the official support matrix is worth checking before you assume uniform behaviour.
Which one to use
Neither approach wins outright, which is why I built both.
Repository-native instructions are always present in the repository context, need no installation, and suit continuous code generation and review. An Agent Skill is versioned, installable across repositories, carries richer references and produces a structured assessment, which is what you want when someone asks for a deliberate end-to-end look at a workload.
The combination I would reach for in a real organization is a hybrid: thin repository instructions, a generated platform contract, and the skill installed for the moments when a full assessment is worth the effort.
If you want to try them
Installation instructions, worked examples and a subscription-vending walkthrough are in the repositories. Pin a tag if you want reproducibility, because neither repository has changed since 4 August and an unpinned install follows whatever the default branch becomes once I pick the work up again.
Issues and pull requests are welcome, on the routing, the Azure guidance, the responsibility model or a scenario I have not thought of. One request: keep real customer platform contracts, subscription identifiers, internal IP ranges and anything confidential out of them. Fictional fixtures only.
All guidance in both repositories is generic. Validate it against your own organization’s Azure platform standards before you act on it.
Revision log
Unchanged since publication on 25 Aug 2026. Anything I get wrong later lands here.