Pipeline Rules — Reference
Cross-cutting rules enforced across all workflow steps. Referenced from SKILL.md ## Pipeline Rules.
Approval gates
⛔ Two separate approval gates are required — never merge them.
- Scaffold gate (Step 6): "✅ Ready to proceed with scaffolding? (Yes / Edit plan / Cancel)" — approves IaC generation only. ⛔ When the plan includes PostgreSQL/MySQL, add
Private accessas a selectable choice — see approval-gates.md for the exact variant. - Deploy gate (Step 8): "🚀 Ready to deploy? (Yes / Run manually / Edit plan / Cancel)" — approves resource provisioning.
The scaffold gate does NOT grant deploy permission. After scaffold completes, you MUST present the deploy gate as a SEPARATE response. Never go from scaffold approval directly to az group create or az deployment.
⛔ BOTH gates MUST show Subscription (name + ID), Resource Group, and Region as standalone lines above the service table — users must see WHERE resources will be created before approving.
⛔ NEVER create, write, or modify infrastructure files before the user explicitly says "Yes" to the scaffold gate. No exceptions — not for simple apps, trivial plans, free-tier deployments, or single-component repos.
⛔ Modifying existing IaC files (not AppOnboard-generated) requires explicit user approval. Present: "I need to modify {file}: {change description}. Approve? (Yes / Edit / Cancel)". This applies to repos with existing Bicep/Terraform where AppOnboard adjusts SKUs, regions, or settings.
Each gate is the LAST content in its response — do NOT continue past a gate in the same turn.
❌ BAD: Writes Bicep without approval · scaffolds and deploys in same response · skips deploy gate after scaffold approval ✅ GOOD: Shows plan → user says Yes → scaffold → show validation summary → deploy gate → user says Yes → deploy
Phase lifecycle
Update context.json at phase boundaries — combine completedPhases update with currentPhase for the next phase in a single write. Write the phase artifact before marking complete. The orchestrator SKILL.md specifies exact write points (after prereq, after scaffold, after deploy).
currentPhase must NEVER appear in completedPhases — if invariant violated, halt and report.
context.json is NOT write-once — each phase boundary MUST update it on completion:
- Write
intentafter Step 2 componentsafter Step 3azure.resourceGroupafter Step 7 (also written todeploy-result.json.resourceGroupName)- Push to
completedPhasesat phase boundaries - Update
statusSummaryat every phase exit — 1-line description. Templates:- prereq:
"{N} components, stack: {detectedStack}, health: {overallHealth}" - prepare:
"{N} services, ~${monthlyUsd}/mo, region: {region}"(ifquotaValidation.checkedRegions>1, append fallback reason:"region: westus2 (eastus quota full)") - scaffold:
"{N} files, self-review: {VERIFIED|FLAGGED count}" - deploy:
"{healthStatus}, RG: {resourceGroupName}" - cancel:
"Paused at {phase} — {reason}"
- prereq:
Session artifacts
Session file writes: New-Item -ItemType Directory for directories, create tool for file content. Create session directory via New-Item -ItemType Directory -Path ".copilot-azure/sessions/{uuid}" -Force, then create tool for all JSON/md content. Never use Out-File, Set-Content, or shell commands for file content.
Phase transition rule
⛔ Before executing the FIRST command of any new phase, re-read that phase's sub-SKILL.md. After prereq → read
prepare/SKILL.md. After prepare →scaffold/SKILL.md. After scaffold gate →deploy/SKILL.md. This applies at EVERY transition.
Post-compaction recovery
⛔ After ANY compaction, re-read current phase SKILL.md + this file. Check
scaffold-manifest.jsonandcompletedPhasesexist if mid-scaffold/deploy.
Begin responses with: "Started session at .copilot-azure/sessions/{uuid}/" or "Resuming session from [date] — {statusSummary}".
⛔ Session immutability: NEVER write to any session folder other than the active session (the one .copilot-azure/sessions/active-session.json points to). Old sessions are read-only — no updates, no backfills, no status changes.
Session TTL: 7 days. Non-active sessions where context.json.lastModifiedUtc is >7 days ago are deleted on next invocation. The active session is never pruned.
fastTrackEligible
Set by prereq: (1) auto-approves readiness gate, (2) simplifies prepare Step 3 alternatives. Does NOT skip phases, reads, gates, self-review, validation, or preflight.
Deploy as-is
⛔ Do NOT refactor or upgrade working application code. Deploy what works. Fixing broken code IS allowed (build errors, missing deps) through the approval gate. Upgrade suggestions → prepare-plan.json.postDeployRecommendations[]. Infrastructure changes = allowed; code rewrites = forbidden; Azure compatibility changes (TLS, SSL, port) = allowed when detected by prereq AND approved. Never prompt for passwords — auto-generate into Key Vault.
Known Platform Bugs
See pipeline-rules-runtime.md § Known Platform Bugs for the full bug table and workarounds.
No top-level skill invocation
⛔ NEVER call external skills (azure-validate, azure-deploy, azure-prepare, etc.) during the AppOnboard pipeline. Only azure-app-onboard-prereq and azure-app-onboard orchestrator are allowed. Use direct CLI commands for validation and deployment.
Structured sub-agent delegation
⛔ Use ONLY subagent-*.md templates — no ad-hoc prompts. Pass template content verbatim. Destructive commands (az deployment, az webapp deploy, az acr build) execute in main thread only.
Security baseline
See iac-generation-rules.md § Security Patterns and bicep-patterns-security.md. Flag AllowAzureServices firewall rule as a security warning.
azure.yaml prohibition
⛔ NEVER generate azure.yaml. NEVER use azd up/azd provision/azd deploy. AppOnboard deploys via az deployment sub create (Bicep) or terraform apply (Terraform). Repos with existing azure.yaml → route per azd-template-routing.md.