Sdaf Orientation And Surface
Azure/sap-automation
Orient a newcomer to the SAP Deployment Automation Framework (SDAF): explain the spine (control plane → workload zone → SAP system → software → install → operate/remove), summarise the three…
Sets up a Power Platform Pipeline for automated Power Pages deployments.
$ npx skills add microsoft/power-platform-skills --skill setup-pipeline -a claude-codeProject install by default; add -g for ~/.claude/skills/.
$ gh skill install microsoft/power-platform-skills setup-pipeline --agent claude-codeProject scope by default; add --scope user for a personal install. Needs GitHub CLI 2.90.0 or later (public preview).
$ git clone --depth 1 https://github.com/microsoft/power-platform-skills.git skills-src && mkdir -p .claude/skills && cp -r skills-src/plugins/power-pages/skills/setup-pipeline .claude/skills/setup-pipeline && rm -rf skills-srcUse ~/.claude/skills/ instead of .claude/skills for a personal install. The folder must contain SKILL.md.
Claude Code skills documentation · loads skills from .claude/skills/
Install the "setup-pipeline" agent skill from https://github.com/microsoft/power-platform-skills/tree/main/plugins/power-pages/skills/setup-pipeline into .claude/skills/setup-pipeline/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "setup-pipeline", then confirm the skill loads.Claude Code copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$skill-installer install https://github.com/microsoft/power-platform-skills/tree/main/plugins/power-pages/skills/setup-pipelineType this inside Codex. $skill-installer <name> installs a curated skill from openai/skills. The installer writes to $CODEX_HOME/skills (default ~/.codex/skills). Restart Codex if the skill does not show up.
$ npx skills add microsoft/power-platform-skills --skill setup-pipeline -a codexProject install goes to .agents/skills/; add -g for ~/.codex/skills/.
$ gh skill install microsoft/power-platform-skills setup-pipeline --agent codexProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/microsoft/power-platform-skills.git skills-src && mkdir -p .agents/skills && cp -r skills-src/plugins/power-pages/skills/setup-pipeline .agents/skills/setup-pipeline && rm -rf skills-srcUse ~/.agents/skills/ instead of .agents/skills for a personal install.
Codex skills documentation · loads skills from .agents/skills/
Install the "setup-pipeline" agent skill from https://github.com/microsoft/power-platform-skills/tree/main/plugins/power-pages/skills/setup-pipeline into .agents/skills/setup-pipeline/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "setup-pipeline", then confirm the skill loads.Codex copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ npx skills add microsoft/power-platform-skills --skill setup-pipeline -a cursorProject install goes to .agents/skills/; add -g for ~/.cursor/skills/.
$ gh skill install microsoft/power-platform-skills setup-pipeline --agent cursorProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/microsoft/power-platform-skills.git skills-src && mkdir -p .cursor/skills && cp -r skills-src/plugins/power-pages/skills/setup-pipeline .cursor/skills/setup-pipeline && rm -rf skills-srcUse ~/.cursor/skills/ instead of .cursor/skills for a personal install.
Cursor skills documentation · loads skills from .cursor/skills/, .agents/skills/, .claude/skills/, .codex/skills/
Install the "setup-pipeline" agent skill from https://github.com/microsoft/power-platform-skills/tree/main/plugins/power-pages/skills/setup-pipeline into .cursor/skills/setup-pipeline/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "setup-pipeline", then confirm the skill loads.Cursor copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ gemini skills install https://github.com/microsoft/power-platform-skills.git --path plugins/power-pages/skills/setup-pipeline--scope user (default) or --scope workspace; --path is the subfolder of the repo that holds the skill; --consent skips the security confirmation prompt.
$ npx skills add microsoft/power-platform-skills --skill setup-pipeline -a gemini-cliProject install goes to .agents/skills/; add -g for ~/.gemini/skills/.
$ gh skill install microsoft/power-platform-skills setup-pipeline --agent gemini-cliProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/microsoft/power-platform-skills.git skills-src && mkdir -p .gemini/skills && cp -r skills-src/plugins/power-pages/skills/setup-pipeline .gemini/skills/setup-pipeline && rm -rf skills-srcUse ~/.gemini/skills/ instead of .gemini/skills for a personal install, then run /skills reload.
Gemini CLI skills documentation · loads skills from .gemini/skills/, .agents/skills/
Install the "setup-pipeline" agent skill from https://github.com/microsoft/power-platform-skills/tree/main/plugins/power-pages/skills/setup-pipeline into .gemini/skills/setup-pipeline/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "setup-pipeline", then confirm the skill loads.Gemini CLI copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ gh skill install microsoft/power-platform-skills setup-pipelineInstalls for Copilot at project scope by default; add --scope user for a personal install. Preview a skill first with gh skill preview. Needs GitHub CLI 2.90.0 or later (public preview).
$ npx skills add microsoft/power-platform-skills --skill setup-pipeline -a github-copilotProject install goes to .agents/skills/; add -g for ~/.copilot/skills/.
$ git clone --depth 1 https://github.com/microsoft/power-platform-skills.git skills-src && mkdir -p .github/skills && cp -r skills-src/plugins/power-pages/skills/setup-pipeline .github/skills/setup-pipeline && rm -rf skills-srcUse ~/.copilot/skills/ instead of .github/skills for a personal install. Commit .github/skills so cloud agent and code review can use it.
GitHub Copilot skills documentation · loads skills from .github/skills/, .claude/skills/, .agents/skills/
Install the "setup-pipeline" agent skill from https://github.com/microsoft/power-platform-skills/tree/main/plugins/power-pages/skills/setup-pipeline into .github/skills/setup-pipeline/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "setup-pipeline", then confirm the skill loads.GitHub Copilot copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ npx skills add microsoft/power-platform-skills --skill setup-pipeline -a opencodeOpenCode documents no install command of its own. Project install goes to .agents/skills/; add -g for ~/.config/opencode/skills/.
$ gh skill install microsoft/power-platform-skills setup-pipeline --agent opencodeProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/microsoft/power-platform-skills.git skills-src && mkdir -p .opencode/skills && cp -r skills-src/plugins/power-pages/skills/setup-pipeline .opencode/skills/setup-pipeline && rm -rf skills-srcUse ~/.config/opencode/skills/ instead of .opencode/skills for a personal install.
OpenCode skills documentation · loads skills from .opencode/skills/, .claude/skills/, .agents/skills/
Install the "setup-pipeline" agent skill from https://github.com/microsoft/power-platform-skills/tree/main/plugins/power-pages/skills/setup-pipeline into .opencode/skills/setup-pipeline/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "setup-pipeline", then confirm the skill loads.OpenCode copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
setup-pipelineSets up a Power Platform Pipeline for automated Power Pages deployments.
Setup Pipeline is an agent skill from microsoft/power-platform-skills, published by the product's own GitHub organization. Sets up a Power Platform Pipeline for automated Power Pages deployments. Power Platform Pipelines is Microsoft's native CI/CD tool built into the Power Platform — no external infrastructure required. Use when asked to: "set up ci/cd", "create pipeline", "setup pipeline", "set up power platform pipelines", "create power pipelines", "automate deployments", "set up automated deployment", "create deployment pipeline", "use power pipelines". Also handles: "set up github actions" or "set up azure devops pipeline"…
Its SKILL.md is about 11k tokens, which your agent loads only when the skill is triggered. The skill folder holds 2 other files, including scripts (for example `scripts/validate-pipeline.js`).
It sits in DevOps & Cloud, covering CI/CD and Deployment. It works with Power Automate, Azure DevOps, GitHub Actions and Microsoft Azure. The repository describes itself as: A plugin marketplace for GitHub Copilot and other AI agents that provides Power Platform development plugins, including reusable skills, agents, and commands for building and… The licence is MIT.
9 steps, taken from the step headings in SKILL.md.
Read from SKILL.md and the folder at commit 0d044b8. It shows what the files ask for, not the result of running them.
Pre-approves these tools, so the agent can use them without asking each time:
ReadWriteEditBashGlobGrepTaskCreateTaskUpdateTaskListAskUserQuestion…and 2 more on the same allowed-tools line.
From allowed-tools in the SKILL.md frontmatter.
Ships 1 file in scripts/ (JavaScript), which the agent can run.
Shell commands in SKILL.md call:
nodeazgitFrom the folder's file list and the shell code blocks in SKILL.md.
Hosts in commands or code, which the agent is likely to contact:
learn.microsoft.comservice.powerapps.comstaging.crm.dynamics.comFrom URLs in SKILL.md, links to its own repository left out.
Names these keys or tokens, usually read from environment variables:
HOST_TOKENDEV_TOKENBAP_TOKENFrom names ending in _API_KEY, _TOKEN, _SECRET, _KEY or _PASSWORD in SKILL.md.
Setup Pipeline loads about 11k tokens when it runs. Until then it costs about 144 tokens; SKILL.md has 4,637 words of instructions outside code blocks.
Estimates: characters ÷ 4, the usual rule of thumb; real counts depend on the model's tokenizer. Scripts and assets cost tokens only if the agent reads them.
The automated check noted patterns worth knowing about, such as sudo or a known installer.
allowed-tools: Read, Write, Edit, Bash, Glob, Grep, TaskCreate, TaskUpdate, TaskList, AskUserQuestion, mcp__plugin_Automated static check — not a guarantee. Review scripts before installing. It scans the text of SKILL.md for risky patterns (piping downloads into a shell, reading credential files, hidden Unicode, destructive commands); the scripts in this folder are not scanned.
The full file from microsoft/power-platform-skills at commit 0d044b8, republished under its MIT licence (© microsoft). 4,637 words, ~10,735 tokens.
.claude/skills/setup-pipeline/SKILL.md (or your agent's skills folder). This skill also uses 1 other file; get the full folder from GitHub.Plugin check: Run
node "${PLUGIN_ROOT}/scripts/check-version.js"— if it outputs a message, show it to the user before proceeding.
Sets up a Power Platform Pipeline for automated Power Pages solution deployments. Creates the pipeline configuration directly in Dataverse using the PP Pipelines OData API — no YAML files, no external CI/CD infrastructure needed.
GitHub Actions and Azure DevOps Pipeline options are shown in the platform menu as coming soon.
Refer to
${PLUGIN_ROOT}/references/cicd-pipeline-patterns.mdfor all HAR-confirmed API patterns used in this skill.
powerpages.config.json exists in the project root.solution-manifest.json exists (solution must be created first via setup-solution)az account show succeeds)pac env who succeeds)
plan-almis the front door. When the user expresses an ALM intent (promote / ship / deploy / set up CI-CD / move to staging / push to prod), the orchestrator (/power-pages:plan-alm) should run first. This Phase 0 enforces that and is meant to fail closed when there's no plan, not to be a one-time check the user can dismiss forever.
Skip rule. If this skill was invoked as part of an active plan-alm orchestration, skip Phase 0 entirely and proceed to Phase 1. The gate helper exposes this via its inExecution block — pass through silently to Phase 1 when:
inExecution.status === "active"The helper computes this from docs/.alm-plan-data.json — PLAN_STATUS === "In Execution" AND LAST_INVOCATION_AT within the last 60 minutes. check-alm-plan.js refreshes LAST_INVOCATION_AT automatically on every invocation that finds the plan in execution, so each in-chain skill keeps the chain alive for the next one — even multi-hour deploys (deploy-pipeline alone can take 60 min per stage) survive the window without the chain incorrectly de-classifying. Stalled chains (no heartbeat for > 60 min) reclassify as stale-heartbeat and Phase 0 gates fire normally so an abandoned plan doesn't silently bypass user confirmation.
When inExecution.status is anything other than "active" ("not-running", "stale-heartbeat", "no-plan"), run the Phase 0 gate flow below. Branch on the remaining helper fields:
Step 1 — Run the gate helper.
node "${PLUGIN_ROOT}/scripts/lib/check-alm-plan.js" \
--projectRoot "." \
--envUrl "{devEnvUrl}" \
--token "{token}" \
--solutionId "{solutionId from .solution-manifest.json, if available}"The helper returns JSON with { exists, stale, staleness: { reason, detail }, generatedAt, planStatus, ... }. The freshness check requires env credentials + solutionId; without those the helper does an existence-only check.
Step 2 — Branch on the result.
| Result | Behavior |
|---|---|
deferred: true | The user has explicitly deferred ALM for this project (.alm-deferred marker present). Pass through silently to Phase 1 — do not nag. |
exists: false | The user hasn't run plan-alm yet. See Step 3. |
exists: true, stale: false | Plan is current. Pass through silently to Phase 1. |
exists: true, stale: true (reason: solution-modified) | The solution changed after the plan was generated. See Step 4. |
Step 3 — No plan. Tell the user:
"No ALM plan exists for this project.
/power-pages:plan-almbuilds one — it detects the project state, asks about your promotion strategy (PP Pipelines vs Manual export/import), and orchestrates the right skills (including this one) in the right order. Want me to run plan-alm now?"
<!-- gate: setup-pipeline:0.no-plan | category=intent | cancel-leaves=nothing -->
🚦 Gate (intent · setup-pipeline:0.no-plan): Fail-closed entry gate when
check-alm-plan.jsreturnsexists:false. Helper-script-backed.
AskUserQuestion:
| Question | Header | Options |
|---|---|---|
Run /power-pages:plan-alm first? | ALM plan gate | Yes — run /power-pages:plan-alm now (Recommended), Continue without a plan (advanced — I know what I'm doing), Cancel |
/power-pages:plan-alm. It builds the plan and returns — plan-alm is a planner and does not deploy. This skill then re-runs the Phase 0 check (now exists:true) and proceeds to Phase 1.BYPASSED_PLAN_GATE = true and proceed to Phase 1.Step 4 — Stale plan. Tell the user:
"ALM plan exists from
{generatedAt}but the source solution has been modified since (at{solution.modifiedon}). Components may have changed. Re-runningplan-almwill refresh the analysis and the rendered HTML."
<!-- gate: setup-pipeline:0.stale-plan | category=intent | cancel-leaves=nothing -->
🚦 Gate (intent · setup-pipeline:0.stale-plan): Fail-closed entry gate when
check-alm-plan.jsreturnsstale:true. Helper-script-backed.
AskUserQuestion:
| Question | Header | Options |
|---|---|---|
| Refresh the plan first? | ALM plan freshness | Refresh — re-run /power-pages:plan-alm (Recommended), Continue with the existing plan, Cancel |
/power-pages:plan-alm. After completion, re-run the Phase 0 helper once to confirm freshness; if still stale, surface the detail and proceed to Phase 1 anyway (don't infinite-loop).STALE_PLAN_ACK = true and proceed to Phase 1.Why this gate exists. Direct invocation of this skill bypasses the orchestrator's pre-deploy completeness check, host-resolution decision, deployment-strategy selection, and rendered HTML plan. Users who run setup-pipeline directly often miss components that should have been added to the solution, miss the asset advisory for large web files, or build a pipeline against the wrong host environment. The gate ensures plan-alm either ran (so all of those decisions are surfaced and recorded) or the user explicitly chose to bypass it.
Create all tasks upfront at the start of this phase.
Tasks to create:
Steps:
Read project context using detect-project-context.js:
node "${PLUGIN_ROOT}/scripts/lib/detect-project-context.js"Capture output as JSON; extract .siteName (store as siteName), .websiteRecordId, .environmentUrl (store as devEnvUrl), and .solutionManifest (store as solutionManifest). devEnvUrl is null for declarative / data-model (EDM) sites — detect-project-context.js reads the env URL only from powerpages.config.json, which those sites don't have. Do not treat a null devEnvUrl as an error here; Step 2 resolves the authoritative dev env URL from pac env who. If siteName is absent, stop and advise running /power-pages:create-site first — a downloaded/deployed site (code or declarative) always resolves a siteName (from powerpages.config.json or .powerpages-site/website.yml), so a missing siteName means there is no site checked out here, not merely "no powerpages.config.json". If solutionManifest is null (no .solution-manifest.json), stop and advise running /power-pages:setup-solution first.
Manifest version check:
solutionManifest.schemaVersion === 2 (multi-solution layout), set MULTI_SOLUTION_MODE = true and store solutionManifest.solutions[] as SOLUTIONS_LIST. See Phase 6b — a SINGLE pipeline ships all solutions through per-solution stage runs (the pre-v1.3.x "one pipeline per solution" layout was reverted because it cluttered the Pipelines UI).schemaVersion is absent or 1 (single solution), read solutionManifest.solution.uniqueName and solutionManifest.solution.solutionId. One pipeline will be created (existing flow).Run verify-alm-prerequisites.js to confirm PAC CLI auth, acquire a token, and verify API access. Pass --envUrl only when devEnvUrl is non-null (code sites). When devEnvUrl is null (declarative / data-model sites from Step 1), omit --envUrl entirely — do not pass --envUrl "null" or an empty value:
# Code sites — devEnvUrl resolved from powerpages.config.json in Step 1:
node "${PLUGIN_ROOT}/scripts/lib/verify-alm-prerequisites.js" --envUrl "{devEnvUrl}"
# Declarative / data-model (EDM) sites — devEnvUrl is null, omit the flag:
node "${PLUGIN_ROOT}/scripts/lib/verify-alm-prerequisites.js"verify-alm-prerequisites.js treats --envUrl as optional and resolves the environment from pac env who when it's omitted (the flag only overrides the PAC CLI env). Capture output as JSON; extract .envUrl and .token (store as DEV_TOKEN), then set devEnvUrl = .envUrl — this verified value (from pac env who) is the authoritative dev env URL for every later step: it backfills the null for declarative sites and confirms it for code sites. If .envUrl is still empty after this, stop and advise the user to run pac auth create / select an environment (pac org select) before retrying.
Run silently:
node "${PLUGIN_ROOT}/scripts/lib/list-environments.js"Store the JSON array as ENV_LIST (entries: { displayName, environmentId, environmentUrl, uniqueName, active }). This helper parses pac env list — the old pac env list --output json is invalid on current PAC CLI (pac env list only accepts --filter). It prints [] and exits 0 when PAC is unauthenticated, so this step degrades gracefully.
Resolve the Pipelines host via ensure-pipelines-host-detect.js (the same flow /power-pages:ensure-pipelines-host runs internally — it reads any cached docs/alm/last-host-check.json, then walks the resolution order: org-setting binding → BAP env GET → tenant default custom host → tenant-wide enumeration. Read-only; never prompts the user):
BAP_TOKEN=$(az account get-access-token --resource "https://service.powerapps.com/" --query accessToken -o tsv)
node "${PLUGIN_ROOT}/scripts/lib/ensure-pipelines-host-detect.js" \
--envUrl "{devEnvUrl}" \
--token "{DEV_TOKEN}" \
--userId "{userId}" \
--bapToken "{BAP_TOKEN}" \
--projectRoot "."Capture stdout as JSON: const hostResult = JSON.parse(output). Read hostResult.resolutionStatus, hostResult.finalHostEnvUrl, hostResult.ready.
Branch on resolutionStatus:
AvailableUsingPlatformHost / AvailableUsingCustomHost / AvailableUsingCustomHostByAdminDefault — host is already established and ready: true. Store HOST_ENV_URL = hostResult.finalHostEnvUrl and continue. Phase 3 confirms with the user.AvailableUnboundCustomHost / MultipleUnboundCustomHosts / PlatformHostExistsUnbound / NoHost — no host bound to the dev env. Delegate to /power-pages:ensure-pipelines-host so the user can reuse an existing host or provision a new Custom Host (D365_ProjectHost template). Tell the user: "No Pipelines host bound to {devEnvUrl}. Invoking /power-pages:ensure-pipelines-host to set one up — it will run a tenant-wide search for existing hosts and offer to provision a new Custom Host if none are found." After the sub-skill completes, re-read docs/alm/last-host-check.json; capture HOST_ENV_URL = finalHostEnvUrl only if the new marker has ready: true. If the user cancelled the sub-skill, stop this skill — no pipeline can be created without a host.CannotRedirect — stop with the specific tenant-misconfiguration error from hostResult.warnings[0]. Tell the user: "This tenant's DefaultCustomPipelinesHostEnvForTenant setting and the source env's ProjectHostEnvironmentId org setting disagree — only a Power Platform admin can resolve."OrgSettingStale — stop and surface the warning: "ProjectHostEnvironmentId on {devEnvUrl} points at a host env that is no longer visible (deleted, disabled, or you lack access). Clear the org setting via PPAC or contact the env owner."PermissionDenied — stop and surface the warning: "Caller lacks BAP read access on the env {devEnvUrl} is bound to. Contact the host env owner for at least Deployment Pipeline User access."Why this replaces the old
discover-pipelines-host.jscall: that helper only checked the tenant-levelDefaultCustomPipelinesHostEnvForTenantsetting (one of four resolution signals).ensure-pipelines-host-detect.jswalks the full resolution order the Power Apps UI uses (mirrorsProjectHostProvider.tsx), so we agree with the UI in every case — including the previously-undetectedAvailableUnboundCustomHostcase where a Custom Host exists in the tenant but the source env hasn't been bound yet. Seereferences/cicd-pipeline-patterns.mdfor the full state matrix.
Check for existing docs/alm/last-pipeline.json. If found, read its contents.
Report findings: "Project: {siteName}. Solution: {uniqueName}. Dev env: {devEnvUrl}. Host env: {HOST_ENV_URL ?? 'pending — will be ensured next'} ({hostResult.resolutionStatus}). Existing pipeline: found/not found."
<!-- gate: setup-pipeline:1.existing-pipeline | category=plan | cancel-leaves=nothing -->
🚦 Gate (plan · setup-pipeline:1.existing-pipeline): Existing
docs/alm/last-pipeline.jsonfound — overwrite, review first, or cancel. No Dataverse write yet.
If an existing docs/alm/last-pipeline.json is found, ask via AskUserQuestion:
"A pipeline configuration already exists for
{pipelineName}(created {createdAt}). How would you like to proceed?
- Overwrite — create a new pipeline, replacing the marker
- Review existing setup first, then decide
- Cancel"
docs/alm/last-pipeline.json contents, then ask again with the same 3 options.Reference:
${PLUGIN_ROOT}/references/alm-docs-grounding.md
Cap this step at ~30 seconds. If MCP search / fetch errors out, log a one-line note and continue — this skill must remain runnable offline.
microsoft_docs_search with the query: Power Platform Pipelines setup OData API host environment deploymentenvironments.https://learn.microsoft.com/en-us/power-platform/alm/pipelines (and at most one sister page on host setup or pipeline creation) in parallel via microsoft_docs_fetch.deploymentenvironments / deploymentpipelines / deploymentstages schema, and pipeline lifecycle. Compare against ${PLUGIN_ROOT}/references/cicd-pipeline-patterns.md and flag any divergence (new fields, deprecated APIs, changed validation status codes).<!-- gate: setup-pipeline:2.platform | category=plan | cancel-leaves=nothing -->
🚦 Gate (plan · setup-pipeline:2.platform): Pick CI/CD platform — PP Pipelines (full) vs GitHub Actions / ADO (coming soon stubs).
Ask user via AskUserQuestion:
"Which CI/CD platform do you want to use?
- Power Platform Pipelines — Microsoft's native deployment pipeline. No external infrastructure needed. (Recommended)
- GitHub Actions — Coming soon
- Azure DevOps Pipeline — Coming soon"
If the user passed power-platform, github, or ado as an argument, skip this question and use the provided value.
Store the selection as PLATFORM.
If github or ado selected → display the Coming Soon path and stop.
Before asking any questions, assemble what was auto-detected:
| Setting | Auto-detected value |
|---|---|
| Site name | {siteName} from powerpages.config.json |
| Solution unique name | {uniqueName} from .solution-manifest.json |
| Dev environment URL | {devEnvUrl} from pac env who |
| Host environment URL | {HOST_ENV_URL} from ensure-pipelines-host-detect.js (resolved in Phase 1 step 4) |
| BAP environment ID (dev) | From pac env list |
<!-- gate: setup-pipeline:3.config | category=plan | cancel-leaves=nothing -->
🚦 Gate (plan · setup-pipeline:3.config): Confirm auto-detected pipeline configuration — pipeline name, host env, target envs. Cancel exits before any Dataverse write to the host.
Ask user via AskUserQuestion with pre-filled values:
"I've gathered the following pipeline configuration. Please confirm or correct:
- Pipeline name:
{siteName} Pipeline(can change)- Source (Dev) environment:
{devEnvUrl}- Host environment (where Pipelines is installed):
{HOST_ENV_URL}(resolved in Phase 1 — should always be present at this point;ensure-pipelines-hostwould have stopped the skill otherwise)- Solution to deploy:
{uniqueName}- Target environments: How many? (Dev → Staging / Dev → Staging → Production)"
Collect from user:
PIPELINE_NAME (default: {siteName} Pipeline)HOST_ENV_URL (confirm — already resolved in Phase 1; user can override only if they want to point at a different host they administer, in which case re-run /power-pages:ensure-pipelines-host first to validate it)STAGING_ENV_URL, PROD_ENV_URL if applicable)pac env list — pre-fill if found, otherwise ask)Store HOST_TOKEN by running:
az account get-access-token --resource "{hostEnvOrigin}" --query accessToken -o tsvPresent a final confirmation summary and ask user to approve before proceeding.
Use Node.js https module for all Dataverse calls (curl has encoding issues on Windows).
4.1 Verify host environment has Pipelines installed:
GET {hostEnvUrl}/api/data/v9.1/deploymentpipelines?$top=0
Authorization: Bearer {HOST_TOKEN}If response is 404 or returns an "unknown entity" error, stop and inform the user: "The selected host environment does not have Power Platform Pipelines installed. Please select a different environment or install the Pipelines package."
4.2 Verify solution exists in dev environment using verify-solution-exists.js:
node "${PLUGIN_ROOT}/scripts/lib/verify-solution-exists.js" \
--envUrl "{devEnvUrl}" \
--uniqueName "{uniqueName}" \
--token "{DEV_TOKEN}"Capture output as JSON; check .found. If false: warn the user — the solution must be exported from dev before it can be deployed.
4.3 Check for existing pipeline with same name:
GET {hostEnvUrl}/api/data/v9.1/deploymentpipelines?$filter=name eq '{PIPELINE_NAME}'&$select=deploymentpipelineid&$top=1
Authorization: Bearer {HOST_TOKEN}<!-- gate: setup-pipeline:4.3.name-conflict | category=plan | cancel-leaves=nothing -->
🚦 Gate (plan · setup-pipeline:4.3.name-conflict): A pipeline with the same name already exists in the host env. Pick: reuse the existing pipeline ID, or create a new one with a different name. Auto-reusing risks attaching to a pipeline owned by someone else; auto-overwriting loses their stage history.
Trigger: Phase 4.3 query returned a hit. Why we ask: Either a foreign pipeline gets its stages overwritten, or a duplicate pipeline gets created that pollutes the host env's pipeline list. Cancel leaves: Nothing — no Dataverse write yet.
If found: ask via AskUserQuestion whether to use the existing pipeline ID or create a new one with a different name.
4.4 Check blockedattachments on source + all target envs:
Power Pages code sites include .js files in their compiled output. If .js is in the env's blockedattachments setting, pac pages upload-code-site (on the source) and deploy-pipeline (on targets) will both fail with AttachmentBlocked. Run this on the source env and on every target env:
node "${PLUGIN_ROOT}/scripts/lib/fix-blocked-attachments.js" \
--envUrl "{envUrl}" \
--extensions js \
--dry-runIf wasBlocked is non-empty for any env, inform the user:
"
.jsfiles are blocked in{envUrl}. This will cause upload/deployment failures for Power Pages code sites. Remove the block? This modifies an environment-level security setting."
<!-- gate: setup-pipeline:4.4.blocked-attachments | category=consent | cancel-leaves=attachment-block-modified -->
🚦 Gate (consent · setup-pipeline:4.4.blocked-attachments): Modify env-level
blockedattachmentssecurity setting (tenant-wide impact). Affects all users of the env, not just this skill. Reversible from PPAC. Fires PER ENV that has blocks. Phase 4.4 checks source + every target env; if M envs out of N have.js(or other media extensions) on the blocklist, the gate fires M times — once per env. Each env has its own security setting and its own group of affected makers. Yes for source does NOT cover staging; yes for staging does NOT cover production. Do NOT batch consent across envs.
Ask via AskUserQuestion: 1. Yes, remove block (recommended) / 2. Skip (I'll fix manually).
If approved, re-run without --dry-run to apply the change. If the user declines, record it as a warning — they'll need to fix it manually before deployment succeeds.
Report preflight results. If any critical check failed, stop with clear instructions. If warnings only, ask user to confirm before proceeding.
Register each environment (source + targets) with the Pipelines host by creating a deploymentenvironments row in the host's Dataverse. This is a metadata-only registration — the row is a pointer to an existing BAP environment, not a provisioning call. The environments themselves must already exist in BAP. The host validates that the referenced env is reachable and the caller has the right access (validationstatus flips Pending → Succeeded). Process source env first, then targets.
Use create-deployment-environment.js for each environment (dev source + each target):
node "${PLUGIN_ROOT}/scripts/lib/create-deployment-environment.js" \
--hostEnvUrl "{HOST_ENV_URL}" \
--token "{HOST_TOKEN}" \
--name "{siteName} {label}" \
--bapEnvId "{BAP_ENV_GUID}" \
--environmentType 200000000 \
[--environmentUrl "{environmentUrl}"]Required args (per scripts/lib/create-deployment-environment.js):
--bapEnvId — the BAP environment GUID for the env being added. Resolve via pac env list (column Environment ID) or pac env who for the current source env. NOT the org/Dataverse URL.--environmentType — 200000000 for the dev/source env, 200000001 for each target env.--environmentUrl is optional and only echoed back into the output marker; it is not posted to Dataverse.Capture stdout as JSON: const envResult = JSON.parse(output).
Store envResult.deploymentEnvironmentId as SOURCE_DEPLOYMENT_ENV_ID (for the dev source env) or append to TARGET_DEPLOYMENT_ENV_IDs (for each target). Also retain the bapEnvId value used for each call — Phase 5a's force-link auto-fix needs it if creation lands in a Failed state.
Note: The script POSTs to
deploymentenvironmentswith unprefixed fields (name,environmentid,environmenttype), extracts thedeploymentenvironmentidGUID from theOData-EntityIdheader, then pollsvalidationstatusevery 3 seconds (max 20 attempts) until status200000001(Succeeded) or200000002(Failed). On failure the script writes the error details to stderr and exits 1 — stop and report the error to the user. (The earliermsdyn_-prefixed field shape and192350001/192350002status codes were from an early-preview HAR; the shipped Pipelines schema rejectsmsdyn_-prefixed properties and uses the2000000XXcodes.)
On failure: stop with the error — deployment environment creation is mandatory.
If the script's stderr (case-insensitively) contains any of these substrings, the BAP env is currently stamped to a different Pipelines host:
already associated with another pipelines hostassociated with another pipelines hostenvironment is already linked to a different hostenvironment is already bound tolinked to another hostclaimed by another hostMatch all of these case-insensitively (String.prototype.toLowerCase() before .includes()) so backend wording drift between Pipelines package versions doesn't silently break detection. If none match but the script exited with the underlying Dataverse error code 0x80048d18 (or a wrapped errormessage containing that hex code), treat it as the same pattern — that's the stable signal even when the message wording shifts.
<!-- gate: setup-pipeline:5a.pattern-15 | category=consent | cancel-leaves=nothing -->
🚦 Gate (consent · setup-pipeline:5a.pattern-15): Target env stamped to a different Pipelines host. Offer force-link as documented auto-fix — DESTRUCTIVE: previous host loses pipeline access for this env. Cancel here exits setup-pipeline cleanly. Fires PER ENV that triggers Pattern 15. Phase 5 loops over source + each target env when registering with the host; if two target envs both turn out to be stamped to different hosts, this gate fires twice — once per env. Do NOT batch the consent across envs; the destructive blast radius is per-env (each env carries its own previous-host stamp and its own group of makers losing access).
This is Pattern 15 in ${PLUGIN_ROOT}/references/deployment-error-catalog.md. Do NOT silently retry. Surface the raw errormessage to the user verbatim and offer the documented auto-fix via AskUserQuestion:
question: "<envLabel> is already linked to a different Pipelines host. The /power-pages:force-link-environment skill can take over the association (DESTRUCTIVE to the previous host — makers there lose pipeline access for this env). Run it now?"
header: "Force Link?"
options:
- "Run /power-pages:force-link-environment now (Recommended)" — auto-fix per the deployment error catalog
- "Cancel setup-pipeline" — investigate the previous host firstImportant guardrails:
/power-pages:force-link-environment without explicit user consent through this prompt — the action is reversible only by performing Force Link again from the previous host./power-pages:force-link-environment with --host <HOST_ENV_URL> and --dev-env <bapEnvId> (the BAP env GUID captured for this env in Phase 5 — see the "Also retain the bapEnvId value" note above) so the sub-skill skips its own host/env prompts.create-deployment-environment.js with the same args — do NOT restart Phase 5 wholesale. The create script is idempotent: it short-circuits via findExistingByBapId for envs already created (they return reused: true), and the previously-failing env will now resolve to Succeeded because the host stamp has moved./power-pages:ensure-pipelines-host detect-only to inspect the current host bindings before retrying.For any other create-deployment-environment failure, fall through to the generic "stop with the error" path above.
Report progress for each environment as validation completes.
Use create-deployment-pipeline.js to create the pipeline, associate the source environment, and create all stage records in one call:
node "${PLUGIN_ROOT}/scripts/lib/create-deployment-pipeline.js" \
--hostEnvUrl "{HOST_ENV_URL}" \
--token "{HOST_TOKEN}" \
--pipelineName "{PIPELINE_NAME}" \
--description "Power Pages deployment pipeline for {siteName}" \
--sourceDeploymentEnvironmentId "{SOURCE_DEPLOYMENT_ENV_ID}" \
--stagesJson '[{"name":"Deploy to {targetLabel}","targetDeploymentEnvironmentId":"{TARGET_DEPLOYMENT_ENV_ID}","order":1}]'Capture stdout as JSON: const pipelineResult = JSON.parse(output).
Extract:
pipelineResult.pipelineId → store as PIPELINE_IDpipelineResult.stages → array of { stageId, name, targetDeploymentEnvironmentId }What the script does internally (uses the unprefixed field schema — the earlier
msdyn_-prefixed body was rejected by the shipped Pipelines schema; see the comment block at the top ofcreate-deployment-pipeline.jsfor the full migration map):
- POSTs
{ name, description }todeploymentpipelines(v9.1) — extractsdeploymentpipelineidfromOData-EntityIdheader- POSTs a relative-path
@odata.idbody todeploymentpipelines({pipelineId})/deploymentpipeline_deploymentenvironment/$refto associate the source environment (HAR-confirmed — no leading/or full URL)- For each stage: POSTs
{ name, deploymentpipelineid@odata.bind, targetdeploymentenvironmentid@odata.bind }todeploymentstages— extractsdeploymentstagesidfromOData-EntityIdheader
On failure: the script writes the error to stderr and exits 1 — stop and report the error to the user.
MULTI_SOLUTION_MODE = true)Design note (updated v1.3.x): A single Power Platform Pipeline can deploy multiple solutions through separate stage runs — each run just specifies a different
artifactname+solutionidon the samedeploymentstagesrecord. Creating one pipeline per solution was wasteful and cluttered the Pipelines UI. We now create ONE pipeline + one stage per target env, and record the per-solution deployment order indocs/alm/last-pipeline.json.deploy-pipelinethen loops over the order, creating a stage run per solution against the same stage.
When the manifest is schemaVersion: 2, do not call create-deployment-pipeline.js multiple times. Instead:
create-deployment-pipeline.js once with:pipelineName = "{siteName}-Pipeline" (e.g. IdeaSphere-Pipeline).description listing the solutions that will deploy through it (e.g. "Deploys IdeaSphere_Core → IdeaSphere_WebAssets → IdeaSphere_Future in order").deploymentstages record per target environment (not per solution).deploymentOrder array from SOLUTIONS_LIST sorted by order. Each entry has { solutionUniqueName, solutionId, order }. Skip entries where isFutureBuffer: true AND components.length === 0 — an empty Future solution has nothing to deploy; it's created by setup-solution but does not participate in the deployment loop until it has content. Keep it in the order array with status: "SkippedEmpty" so the renderer can show the intent.pipelineId and its stages[]. Persist deploymentOrder to docs/alm/last-pipeline.json (see Phase 7).7.1 Verify pipeline was created:
GET {hostEnvUrl}/api/data/v9.1/deploymentpipelines({PIPELINE_ID})?$select=name,statecode
Authorization: Bearer {HOST_TOKEN}Confirm statecode = 0 (Active). If the query fails, report as "verification inconclusive — pipeline may still be valid".
7.2 Write docs/alm/last-pipeline.json (create the docs/alm/ directory first if missing — node -e "require('fs').mkdirSync('docs/alm',{recursive:true})"):
{
"pipelineId": "{PIPELINE_ID}",
"pipelineName": "{PIPELINE_NAME}",
"hostEnvUrl": "{HOST_ENV_URL}",
"sourceDeploymentEnvironmentId": "{SOURCE_DEPLOYMENT_ENV_ID}",
"sourceEnvironmentUrl": "{devEnvUrl}",
"solutionName": "{uniqueName}",
"createdAt": "{ISO timestamp}",
"stages": [
{
"stageId": "{deploymentstagesid}",
"name": "Deploy to {targetLabel}",
"rank": 1,
"targetDeploymentEnvironmentId": "{TARGET_DEPLOYMENT_ENV_ID}",
"targetEnvironmentUrl": "{targetEnvUrl}"
}
]
}Multi-solution marker (manifest v2): When MULTI_SOLUTION_MODE = true, docs/alm/last-pipeline.json uses schemaVersion: 3 with a single pipeline and a deploymentOrder[] describing which solutions deploy through it, in what order:
{
"schemaVersion": 3,
"pipelineId": "...",
"pipelineName": "IdeaSphere-Pipeline",
"hostEnvUrl": "{HOST_ENV_URL}",
"sourceDeploymentEnvironmentId": "{SOURCE_DEPLOYMENT_ENV_ID}",
"sourceEnvironmentUrl": "{devEnvUrl}",
"createdAt": "{ISO timestamp}",
"stages": [
{
"stageId": "...",
"name": "Deploy to Staging",
"rank": 1,
"targetDeploymentEnvironmentId": "...",
"targetEnvironmentUrl": "https://staging.crm.dynamics.com"
}
],
"deploymentOrder": [
{ "solutionUniqueName": "IdeaSphere_Core", "solutionId": "...", "order": 1 },
{ "solutionUniqueName": "IdeaSphere_WebAssets", "solutionId": "...", "order": 2 },
{ "solutionUniqueName": "IdeaSphere_Future", "solutionId": "...", "order": 3, "status": "SkippedEmpty", "isFutureBuffer": true }
]
}<!-- gate: setup-pipeline:6b.v2-migration | category=plan | cancel-leaves=nothing -->
🚦 Gate (plan · setup-pipeline:6b.v2-migration): v2
pipelines[]manifest detected on re-run. Pick: migrate to v3 (delete the N-1 extra pipelines and collapse to one) or keep the legacy layout.Trigger: Re-running setup-pipeline on a project whose
docs/alm/last-pipeline.jsonisschemaVersion: 2. Why we ask: Auto-migrating deletes Dataverse pipeline records — destructive against host env state, irreversible without re-running setup-pipeline. Cancel leaves: Nothing — no pipeline records deleted yet.
Migration note: Earlier versions of this skill used
schemaVersion: 2with apipelines[]array (one Dataverse pipeline record per solution). Projects pinned to v2 continue to work with the olddeploy-pipelineMULTI_PIPELINE_MODE path; the v3 format should be used for all new setups. When re-runningsetup-pipelineon a v2 project, ask viaAskUserQuestionwhether to migrate (delete the N-1 extra pipelines and collapse to a single one) or keep the legacy layout.
7.3 Write (or re-render) docs/pipeline-setup.md (create docs/ directory if needed).
Contents:
solutionManifest.solutions[], list {uniqueName, version, componentCount}. Read componentCount from each entry's components.length if the manifest tracks it, otherwise from a live Dataverse query (solutioncomponents?$filter=_solutionid_value eq '{solutionId}' and componenttype ne 380&$count=true) — DO NOT hard-code or carry forward a stale count from a prior invocation./power-pages:deploy-pipeline or open Power Platform make.powerapps.com → Solutions → PipelinesSync-mode re-render: when
setup-pipelineis invoked on a project wheredocs/alm/last-pipeline.jsonALREADY exists (re-run afterconfigure-env-variables,setup-solutionsync, or a follow-up env-var addition that bumped component counts), regenerate this file in full from current Dataverse state — do not patch in place. Validated failure: a Citizens portalpipeline-setup.mdshowed Foundation = 13 components while Dataverse had 15 afterconfigure-env-variablesadded 2 env var definitions to that solution; the markdown never updated. The simplest safe behavior is "always re-render in Phase 7.3", because the operation reads current state directly and the file has no user-editable sections worth preserving.
7.4 Commit:
git add docs/alm/last-pipeline.json docs/pipeline-setup.md
git commit -m "Add Power Platform Pipeline configuration for {siteName}"7.5 Record skill usage:
Reference:
${PLUGIN_ROOT}/references/skill-tracking-reference.md
Follow the skill tracking instructions in the reference to record this skill's usage. Use --skillName "SetupPipeline".
7.5b Refresh the ALM plan (if one exists):
node "${PLUGIN_ROOT}/scripts/lib/refresh-alm-plan-data.js" \
--projectRoot "." \
--phase setup-pipeline \
--renderThe helper reads docs/alm/last-host-check.json + docs/alm/last-pipeline.json, refreshes planData.hostResolution and planData.pipelineMeta, drops pre-setup "no host detected" risks, and re-renders docs/alm-plan.html. When docs/.alm-plan-data.json is absent (standalone invocation, not part of an ALM plan), the helper returns ok:false as a soft no-op — safe to run unconditionally.
Point the user at the next step (user-driven sequencing). The helper's stdout JSON includes nextStep: { name, skill: string | null } | null. When non-null, branch on skill: when skill is non-null, tell the user "Plan updated. Next in your plan: {nextStep.name} → run {nextStep.skill} when you're ready."; when skill is null (an internal step such as Finalize, no user command), name the step only — *"Plan updated. Next in your plan: {nextStep.name}."* — and never print run null. When null (all steps done) or the helper returned ok:false (no plan), say nothing about a next step. Never auto-invoke the next skill — the user drives execution.
7.6 Present summary:
| Resource | ID / URL |
|---|---|
| Pipeline | {PIPELINE_NAME} ({PIPELINE_ID}) |
| Host environment | {HOST_ENV_URL} |
| Source deployment env | {SOURCE_DEPLOYMENT_ENV_ID} |
| Stage: {name} | {stageId} → {targetEnvUrl} |
Files written:
docs/alm/last-pipeline.json — pipeline configuration markerdocs/pipeline-setup.md — setup documentationNext step:
Run
/power-pages:deploy-pipelineto trigger your first deployment run.
If GitHub Actions or Azure DevOps was selected:
Inform the user:
"GitHub Actions and Azure DevOps Pipeline support are coming soon for this skill.
For now, you have two options:
- Use Power Platform Pipelines — select option 1 to set up Microsoft's native deployment pipeline (recommended)
- Exit — I'll set up GitHub Actions / Azure DevOps manually using the documentation"
<!-- gate: setup-pipeline:coming-soon.exit | category=plan | cancel-leaves=nothing -->
🚦 Gate (plan · setup-pipeline:coming-soon.exit): User selected GitHub/ADO (coming-soon stubs) — offer to switch back to PP Pipelines or exit cleanly.
Ask via AskUserQuestion:
If GitHub/ADO passed as argument: display above message and exit gracefully.
docs/alm/last-pipeline.json found)powerpages.config.json: stop, advise /power-pages:create-site.solution-manifest.json: stop, advise /power-pages:setup-solutionRetrieveSetting returns empty: ask user for host environment URL manuallystatecode = 1 with non-null errormessage (validation failed): stop with error details$ref call fails: stop — this association is required before stages can be created| Task subject | activeForm | Description |
|---|---|---|
| Detect project context | Detecting project context | Read powerpages.config.json and .solution-manifest.json; run pac env who and pac env list; call RetrieveSetting to find host env; check for existing docs/alm/last-pipeline.json |
| Select CI/CD platform | Selecting CI/CD platform | Ask user: Power Platform Pipelines (full) or GitHub/ADO (coming soon) |
| Confirm pipeline configuration | Confirming pipeline configuration | Pre-fill pipeline name, source env, host env, solution name from auto-detected values; ask for target environments; get user confirmation |
| Run preflight checks | Running preflight checks | Verify host env has Pipelines installed; verify solution exists in dev env; check for pipeline name conflict |
| Create deployment environments | Creating deployment environments | POST deploymentenvironments for source + each target; poll validationstatus for each until Succeeded |
| Create pipeline and stages | Creating pipeline and stages | POST deploymentpipelines; $ref associate source env; POST deploymentstages for each target (linked via previousdeploymentstageid) |
| Verify and write artifacts | Verifying and writing artifacts | Query pipeline to confirm active; write docs/alm/last-pipeline.json; write docs/pipeline-setup.md; commit; present summary with next steps |
© microsoft, MIT. Rendered from Markdown: HTML in the file is shown as text, images as links, and headings moved down two levels. Raw file
SKILL.md and 1 other file (scripts) in plugins/power-pages/skills/setup-pipeline of microsoft/power-platform-skills.
Open the folder on GitHubat commit 0d044b8
Setup Pipeline next to the 5 skills that share the most tags, products or categories with it. Stars are the repository's; “used in” counts other GitHub owners with a copy.
| Skill | Stars | Used in | Tokens | Auto-check | Licence | Repo updated |
|---|---|---|---|---|---|---|
| Setup Pipeline this skillmicrosoft/power-platform-skills | 972 | — | ~11k | Automated safety check: Notes | MIT | |
| Sdaf Orientation And SurfaceAzure/sap-automation | 145 | — | ~1.6k | Automated safety check: Pass | MIT | |
| Adf MasterKilo-Org/kilo-marketplace | 190 | — | ~3.2k | Automated safety check: Pass | MIT | |
| Azure Bicep Skilltimothywarner-org/claude-code | 224 | — | ~2.9k | Automated safety check: Pass | MIT | |
| APIOps Deployment for Azure APIMthomast1906/github-copilot-agent-skills | 202 | — | ~3.6k | Automated safety check: Pass | MIT | |
| Azure Devopssickn33/agentic-awesome-skills | 47k | 1 repos | ~2.3k | Automated safety check: Notes | MIT |
Azure/sap-automation
Orient a newcomer to the SAP Deployment Automation Framework (SDAF): explain the spine (control plane → workload zone → SAP system → software → install → operate/remove), summarise the three…
Kilo-Org/kilo-marketplace
Azure Data Factory (ADF) CI/CD, deployment, and pipeline development.
timothywarner-org/claude-code
A skill your agent uses when authoring, reviewing, or refactoring Azure Bicep code.
thomast1906/github-copilot-agent-skills
Supplies Bicep and Terraform templates, CI/CD pipeline patterns and phased promotion plans for deploying Azure API Management with APIOps workflows.
sickn33/agentic-awesome-skills
Set up Azure Pipelines for CI/CD, configure build and release pipelines, manage Azure DevOps projects, and integrate with Azure services.
BagelHole/DevOps-Security-Agent-Skills
Set up Azure Pipelines for CI/CD, configure build and release pipelines, manage Azure DevOps projects, and integrate with Azure services.
microsoft/power-platform-skills
Inspects and configures the web application firewall (WAF) in front of a Power Pages production site.
microsoft/power-platform-skills
Inspects and configures the security headers a Power Pages site sends to browsers — Content Security Policy, frame and clickjacking protection, cross-origin sharing, cookie behavior, and related…
microsoft/power-platform-skills
Scans a Power Pages site project for security issues in source code and dependencies.
microsoft/power-platform-skills
Runs a security scan on a deployed Power Pages site, fetches the latest scan report, and produces a plain-language summary.
microsoft/power-platform-skills
Creates Dataverse tables, columns, and relationships for a Power Pages site based on a data model proposal.
microsoft/power-platform-skills
Creates, edits, and manages Power Pages Server Logic files — server-side JavaScript that runs securely on the Power Pages runtime.
Categories
Sets up a Power Platform Pipeline for automated Power Pages deployments. Setup Pipeline is an agent skill from microsoft/power-platform-skills, published by the product's own GitHub organization. Sets up a Power Platform Pipeline for automated Power Pages deployments.
Setup Pipeline fits situations like: asked to: set up ci/cd; create pipeline; set up power platform pipelines; create power pipelines.
Run `npx skills add microsoft/power-platform-skills --skill setup-pipeline -a claude-code`. Or copy the skill folder (plugins/power-pages/skills/setup-pipeline in microsoft/power-platform-skills) into .claude/skills/setup-pipeline in your project. Claude Code loads it when a task matches its description.
Run `npx skills add microsoft/power-platform-skills --skill setup-pipeline -a codex`. Or copy the skill folder (plugins/power-pages/skills/setup-pipeline in microsoft/power-platform-skills) into .agents/skills/setup-pipeline in your project. Codex loads it when a task matches its description.
Cursor, Gemini CLI, GitHub Copilot and OpenCode also load SKILL.md folders. With the skills CLI, run `npx skills add microsoft/power-platform-skills --skill setup-pipeline -a cursor` (or -a gemini-cli, github-copilot or opencode for the others). To copy it by hand, put the folder in .cursor/skills/setup-pipeline, .gemini/skills/setup-pipeline, .github/skills/setup-pipeline and .opencode/skills/setup-pipeline in your project.
Going by SKILL.md and its folder, Setup Pipeline needs JavaScript for the scripts in its folder, the command-line tools its instructions call (node, az and git) and credentials named HOST_TOKEN, DEV_TOKEN and BAP_TOKEN. Our summary lists: Node.js; A credential in DEV_TOKEN; A credential in BAP_TOKEN. Its frontmatter pre-approves these tools: Read, Write, Edit, Bash, Glob, Grep, TaskCreate, TaskUpdate, TaskList, AskUserQuestion, mcp__plugin_power-pages_microsoft-learn__microsoft_docs_search, mcp__plugin_power-pages_microsoft-learn__microsoft_docs_fetch.
SKILL.md names 3 domains. In commands or code: learn.microsoft.com, service.powerapps.com and staging.crm.dynamics.com; the agent is likely to contact these when it follows the instructions. This is read from the text; nothing was executed.
Our automated static check of SKILL.md found notes only (pre-approves every shell command (allowed-tools: bash)), nothing it rates as a warning. It is not a guarantee. The check reads SKILL.md only: the scripts in the folder are not scanned, so read them before running anything.
Setup Pipeline is published under the MIT licence (the repository's licence). It allows redistribution, so the full SKILL.md is shown on this page.
About 11k tokens (SKILL.md is roughly 43k characters). Agents keep only the skill's name and description in context until a task matches; then they load SKILL.md in full.
Skills that share tags, products or a category with Setup Pipeline: Sdaf Orientation And Surface (Azure/sap-automation, 145 stars), Adf Master (Kilo-Org/kilo-marketplace, 190 stars), Azure Bicep Skill (timothywarner-org/claude-code, 224 stars) and APIOps Deployment for Azure APIM (thomast1906/github-copilot-agent-skills, 202 stars). The comparison table on this page puts their stars, adoption, token cost, safety result and licence side by side.
microsoft (a GitHub organization, an official publisher) maintains it in microsoft/power-platform-skills, which has 972 GitHub stars. The repository holds 87 skills in this directory. The repository was last updated on October 7, 2026.
Source: microsoft/power-platform-skills on GitHub. Facts on this page come from the repository at the commit we read; the author's words are quoted as theirs.