Skip to content
Development
Skill

/generate-pcf-companion

Generate the dispatcher PCF for a third-party `.ppmplugin` (wrap-runtime) control. Runs `pac pcf init` in the pcf/ subfolder, rewrites ControlManifest.Input.xml from ARCHITECTURE §6, and writes index.ts derived from ARCHITECTURE §4 (message contract), §8 (PCF surface), §9 (error

From plugin
power-platform-skills
86896 skills19 agents4 MCP
Install
$ npx -y skills add microsoft/power-platform-skills --skill generate-pcf-companion --agent claude-code

How it fires

How this skill gets triggered: by you, by Claude, or both.

  • Fires itselfAuto-invocation. Claude auto-loads it when your prompt matches the work.Auto-invocation is when the right skill fires by itself at the right moment, driven by a FLOW.md router and a hook, instead of you invoking it by name. It is the difference between a skill being installed and a skill actually getting used.Read the full definition →
  • You can call itInvoke it directly when you want it.
  • Slash command/generate-pcf-companion

Context preview

The summary Claude sees to decide when to auto-load this skill.

Generate the dispatcher PCF for a third-party `.ppmplugin` (wrap-runtime) control. Runs `pac pcf init` in the pcf/ subfolder, rewrites ControlManifest.Input.xml from ARCHITECTURE §6, and writes index.ts derived from ARCHITECTURE §4 (message contract), §8 (PCF surface), §9 (error

SKILL.md

generate-pcf-companion.SKILL.md
name: generate-pcf-companion
description: Generate the dispatcher PCF for a third-party `.ppmplugin` (wrap-runtime) control. Runs `pac pcf init` in the pcf/ subfolder, rewrites ControlManifest.Input.xml from ARCHITECTURE §6, and writes index.ts derived from ARCHITECTURE §4 (message contract), §8 (PCF surface), §9 (error UX) — no placeholders. The bridge dispatches the composite key `<name>/<receiver>` to `NativeModules.<nativeModule>.<method>` via the host-injected `window.PowerApps.NativeExtension.sendAsync` global (never `cordova.exec` — not in the PCF sandbox); also emits a `PowerAppsNativeExtension.d.ts` ambient declaration. Responses are peeled with `extractResponse`. Emits structured JSON debug/error logs. Validated by `npm run build`. **Local only** — does not deploy. Needs only `pac` CLI. Run after the native module exists. Uses npm (not pnpm).
allowed-tools: Read, Write, Edit, Bash, Glob, Grep, AskUserQuestion, Skill
model: opus

/generate-pcf-companion

Generates the dispatcher PCF — the Canvas Studio control that calls the third-party native module through the host-injected `window.PowerApps.NativeExtension.sendAsync` global, routed by the composite key `<name>/<receiver>` read from the committed `./manifest.json` (the source of truth `/generate-native-extension` authors at scaffold time). Lives at `pcf/<Pascal>PCF/` in the same repo the native module lives in. The PCF is a Studio-side companion; it is **NOT** part of the `.ppmplugin` bundle (the bundle ships native binaries only — `manifest.json` + `android/`/`ios/`).

This skill assumes the native module already exists in the repo. Run it after the module is in place.

> **PCF framework reference (public Microsoft Learn docs).** Ground `pac pcf init`, the `ControlManifest.Input.xml` schema, the `init`/`updateView`/`getOutputs`/`destroy` lifecycle, and the `usage` (`bound`/`input`/`output`) rules against the official Power Apps Component Framework docs — they are the authority when this skill's templates and the live framework disagree. (The `sendAsync` transport + `extractResponse` response-unwrap specifics are this track's own, in [`shared/ppmplugin-format.md §2`](../../shared/ppmplugin-format.md) — not in these generic PCF docs.) > - Overview: <https://learn.microsoft.com/en-us/power-apps/developer/component-framework/overview> > - Create a code component: <https://learn.microsoft.com/en-us/power-apps/developer/component-framework/create-custom-controls-using-pcf> > - Custom controls overview: <https://learn.microsoft.com/en-us/power-apps/developer/component-framework/custom-controls-overview>

---

Step 1 — Read the shared docs and the PRD

1. Read [`shared/shared-instructions.md`](../../shared/shared-instructions.md), [`shared/naming-conventions.md`](../../shared/naming-conventions.md), [`shared/ppmplugin-format.md`](../../shared/ppmplugin-format.md), [`shared/repo-layout.md`](../../shared/repo-layout.md). 2. Apply the **per-skill minimal prereq policy** ([`shared-instructions.md §1.5`](../../shared/shared-instructions.md)). This skill needs Node + `pac` CLI only — `pac pcf init` is a local file generator and `npm install`/`npm run build` under `pcf/` only needs Node. It does NOT need pnpm, package-feed authentication, .NET SDK runtime, or active `pac auth`.

**Print the prereq status as a visible block per `shared-instructions.md §9.2`** before continuing:

   ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
    Prereq check — /generate-pcf-companion
   ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

    🟢 ✓ Node 20+ installed                   (for npm install + tsc under pcf/)
    🟢 ✓ pac CLI installed                    (for pac pcf init)

    🟢 2 checks passed. Ready to proceed.

If `pac` is missing, STOP with the fix command (`dotnet tool install -g Microsoft.PowerApps.CLI.Tool` — note: installing `pac` requires .NET SDK as a one-time install, but neither .NET nor `pac auth` is needed at runtime for scaffold). If Node is missing, STOP with the install instruction. Run the **`/generate-pcf-companion` check** from [`prereq-check.md`](../../shared/prereq-check.md) (Node + `pac` only — this self-contained track has no "baseline" check).

**.NET SDK + active `pac auth` are NOT checked here.** If the user later picks the optional "Yes, also deploy now" path in Step 2, the deploy prereq one-liner is run **at that point** (just-in-time, before `pac pcf push`). 3. Read `./PRD.md`. If missing or §8 (PCF surface) is incomplete (any `<NEEDS INPUT>` or missing fields in §8.1–§8.4), STOP with `BLOCKED: PRD.md §8 PCF surface is incomplete — re-run /design-native-extension-feature and complete the PCF section.` 4. Read `./.extension-state.md`. If Phase isn't at least `scaffold`, STOP with `BLOCKED: run /generate-native-extension first.` The structural patterns this skill needs to emit (manifest shape, `index.ts` bridge wiring, output mapping) are fully prescribed in this SKILL.md (§4–§5) and in [`shared/ppmplugin-format.md`](../../shared/ppmplugin-format.md) §2 (Runtime dispatch contract). Do NOT fetch the reference extension repo at runtime — its lessons are already encoded here, and fetching it would risk reference-specific UI logic bleeding into an unrelated PCF.

---

Step 1.5 — Resolve the dispatch contract from `./manifest.json` and the native module

The wrap **runtime dispatch contract** ([`shared/ppmplugin-format.md`](../../shared/ppmplugin-format.md) §2) is the **authoritative specification** of how a host call reaches the bundle. The `.ppmplugin` bundle is native-only (no TS `handleMessageAsync` layer *in the bundle*), but the **companion PCF** dispatches through the host-injected **`window.PowerApps.NativeExtension.sendAsync`** global — it must **NEVER** call `cordova.exec` directly (the raw `cordova` global is not exposed to the PCF sandbox; a direct call is a silent no-op on device, worst on Android). `sendAsync` performs the underlying `cordova.exec("SendMessag

Read more
Ships withpower-platform-skills

Official agent skills/plugins for Power Platform development by Microsoft.

Get the whole plugin

Other skills on power-platform-skills.