<!-- alm-lint-ignore: SKILL-must-read-manifest — this skill manages the Pipelines host environment (deploymentenvironments / deploymentpipelines tables on the host), not the source-env solution. The site's .solution-manifest.json is irrelevant to host lifecycle: a host can be provisioned before any solution exists, and a single host is shared across many solutions. ALM-aware-by-default does not apply. -->Plugin check: Run
node "${CLAUDE_PLUGIN_ROOT}/scripts/check-version.js"— if it outputs a message, show it to the user before proceeding.
ensure-pipelines-host
Scope: When no host is bound to the source env, this skill detects any existing host (Custom or PE) for reuse, or — in
NoHoststate — offers three provisioning paths: a new Platform Host (recommended; idempotent, ~3–5 min); a new Custom Host (admin-only, ~5–10 min); or PPAC manual provisioning (fallback). Implementation details — endpoint names, template names, BAP audience — live in Phase 4.0 / 4.A / 4.C below; user-facing prose stays focused on outcomes.
Power Platform Pipelines need a host environment — a Dataverse environment with the Power Platform Pipelines managed solution installed, where pipelines, stages, run history, and artifacts live. The existing setup-pipeline and deploy-pipeline skills assume a host is already configured. This skill closes that gap.
What we know (sources of truth)
This plan is grounded in three primary sources, in priority order:
useGetOrCreatePlatformEnvironment.v4.ts(Microsoft-internal client source —power-platform-ux/packages/powerapps-appdeployment-ux/src/hooks/v4/). Defines the exact HTTP contract for Platform Environment provisioning: endpoint, body, headers, polling.ProjectHostProvider.tsx(same repo,src/components/ProjectHostProvider/). Defines the exact resolution order the Power Apps UI uses to determine which environment is the project host for a source environment. We mirror that order so this skill agrees with the UI.- eng.ms
createcustompipelineshost(Microsoft-internal). Documents the Custom Host fast-path: aD365_ProjectHostorg template that ships the Pipelines app pre-installed, callable through the standard environment-creation API.
Public Microsoft Learn (learn.microsoft.com/power-platform/alm/{platform-host-pipelines, custom-host-pipelines, set-a-default-pipelines-host}) is the user-facing description of the same flows; we cite it for behaviors users will recognize. HARs in PipelinesDeployScenario.har and Pipelines.har confirm the read-side calls.
Three host shapes the tenant can be in
| Shape | How it got there | Where it lives | Org template |
|---|---|---|---|
| Platform Host (PE) | Auto-provisioned by getOrCreate BAP call (or as a side-effect of first navigation to the Pipelines page in make.powerapps.com). Hidden from the env picker. One per tenant. | Microsoft-managed Dataverse env in tenant's home geo | D365_1stPartyAdminApps |
| Custom Host | Created by an admin via PPAC Deployments → New custom host, or via the standard env-create API with the D365_ProjectHost template, or by installing the Power Platform Pipelines app on an existing Dataverse env. | A regular Dataverse env in the tenant | D365_ProjectHost (or app-installed-onto-existing-env) |
| No host bound to source env | Tenant has not used Pipelines from this env. | — | — |
The current discover-pipelines-host.js only checks the tenant-level DefaultCustomPipelinesHostEnvForTenant setting. That's one signal of many. This skill implements the full resolution order.
Resolution order (mirrors ProjectHostProvider.tsx)
This is the load-bearing decision tree. It is what the Power Apps UI does. We replicate it so the skill agrees with the UI.
┌─────────────────────────────────────────────────────────────────────┐
│ 1. GetOrgDbOrgSetting('ProjectHostEnvironmentId') on source env │
└──────────────────────────┬──────────────────────────────────────────┘
│
┌──────────────┴───────────────┐
│ value present │ value empty
▼ ▼
┌───────────────────────┐ ┌────────────────────────────┐
│ 2. Resolve env via │ │ 5a. Tenant-wide search: │
│ BAP GET │ │ list envs + per-env │
│ /environments/{id} │ │ /deploymentpipelines │
└───────┬───────────────┘ │ probe. │
│ │ │
environmentSku? │ - 1 Custom Host found → │
│ │ AvailableUnboundCustom │
┌────┴────────────┐ │ (3.C-pre) │
│ Platform │ │ - >1 Custom Hosts → │
│ │ │ MultipleUnboundCustom │
│ │ │ (3.C-pre') │
│ │ │ - PE only → │
│ │ │ PlatformHostExists- │
│ │ │ Unbound (3.C-pre'') │
│ │ │ - none → NoHost (3.C) │
│ │ │ │
│ │ │ 5b. Decision tree paths │
│ │ │ for create-new (3.C): │
│ │ │ - Platform getOrCreate │
│ │ │ (fast-path, no admin) │
│ │ │ - Custom D365_ProjectHost│
│ │ │ (fast-path, admin) │
│ │ │ - Manual app install │
│ │ │ - Manual PPAC create │
│ │ └────────────────────────────┘
▼ │
┌──────────────┐ │
│ 3. Check │ │ environmentSku ≠ Platform (Custom Host)
│ Default- │ ▼
│ Custom- │ ┌──────────────────────────────┐
│ Pipelines- │ │ 4. Use the Custom Host │
│ HostEnv- │ │ directly. Skip default- │
│ ForTenant │ │ custom check. │
└──────┬───────┘ └──────────────────────────────┘
│
┌───┴────────────────────────┐
│ admin set a custom default │
│ │
▼ ▼
┌─────────────────┐ ┌─────────────────────────┐
│ default == │ │ default != │
│ org setting? │ │ org setting │
│ │ │ │
│ → use default │ │ → CannotRedirect ERROR │
│ custom │ │ (user locked to PE │
└─────────────────┘ │ but admin overrode │
│ at tenant scope) │
└─────────────────────────┘
if no admin default → use PE
Source: ProjectHostProvider.tsx lines 100–213 (orgSetting fetch → defaultCustomPipelinesHost fetch → finalProjectHostEnvironmentId resolution).
What this skill does NOT do
These are deliberate non-goals (each based on a hard constraint or a destructive blast-radius — see Design Constraints below):
- Does not silently provision anything. Any action that creates an env or binds the source env to a host requires explicit user confirmation, with the tenant name + tenant ID echoed back. PE is tenant-singleton and admin-non-deletable, so the Phase 4.0 pre-call confirmation gate is the principal mitigation against wrong-tenant provisioning. The
getOrCreateendpoint is idempotent — calling it on a tenant that already has a PE returns the existing one rather than creating a duplicate. - Does not call
Force Linkto rebind an environment to a different host. Force Link is destructive (makers lose access to existing pipelines in the previous host) and is hidden behind a separate confirmation gate, only reachable when the user explicitly says "rebind". - **Does not