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 UX) — no placeholder…
Install / Use
npx skills add microsoft/power-platform-skills --skill generate-pcf-companionInstalls into whichever agent you are using.
SKILL.md
Installable skill definition
Quality Score
Category
LegalSupported Platforms
Tags
Our assessment of generate-pcf-companion
generate-pcf-companion scores 85/100 on our quality scale, 119th of 207 Legal skills we index.
Its SKILL.md is 92 KB long, well organised into 47 sections with 21 code examples: long enough that it reads more like full documentation than a focused instruction file, which agents can find harder to follow.
It has 919 GitHub stars, a meaningful sign that others use it.
Maintenance, license and trust
- The repository was last updated 12 days ago, so generate-pcf-companion is actively maintained.
- It is released under the MIT license, a permissive license that allows use, modification and commercial use with attribution.
- Its trust signals score 100/100, with no cautions. These come from repository metadata, not a code audit — read the skill file before letting an agent act on it.
generate-pcf-companion compared with similar skills
All 4 of these similar skills score higher than generate-pcf-companion; compare them before choosing.
| Skill | Score | Stars | Updated | Format |
|---|---|---|---|---|
| generate-pcf-companion (this skill)by microsoft | 85 | 919 | 12d ago | SKILL.md |
| algorithmic-artby anthropics | 100 | 177.9k | 14d ago | SKILL.md |
| pptxby anthropics | 100 | 177.9k | 14d ago | SKILL.md |
| designby nextlevelbuilder | 100 | 130.2k | 15d ago | SKILL.md |
| ui-ux-pro-maxby nextlevelbuilder | 100 | 130.2k | 15d ago | SKILL.md |
Frequently asked questions
- How do I install generate-pcf-companion?
- Run
npx skills add microsoft/power-platform-skills --skill generate-pcf-companion. The install tabs above show the steps for each supported agent. - Which AI agents does generate-pcf-companion work with?
- It is written for Universal, as a SKILL.md file. Other agents that read the same format can often use it too.
- Is generate-pcf-companion safe to use?
- It is MIT-licensed and scores 100/100 on trust signals. Skills are instructions an agent will follow, so read the file before installing it and do not approve commands you do not understand.
- Is generate-pcf-companion still maintained?
- The repository was last updated 12 days ago, so generate-pcf-companion is actively maintained.
Skill content
View source on GitHubname: 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, theControlManifest.Input.xmlschema, theinit/updateView/getOutputs/destroylifecycle, and theusage(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. (ThesendAsynctransport +extractResponseresponse-unwrap specifics are this track's own, inshared/ppmplugin-format.md §2— 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
-
Read
shared/shared-instructions.md,shared/naming-conventions.md,shared/ppmplugin-format.md,shared/repo-layout.md. -
Apply the per-skill minimal prereq policy (
shared-instructions.md §1.5). This skill needs Node +pacCLI only —pac pcf initis a local file generator andnpm install/npm run buildunderpcf/only needs Node. It does NOT need pnpm, package-feed authentication, .NET SDK runtime, or activepac auth.Print the prereq status as a visible block per
shared-instructions.md §9.2before 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
pacis missing, STOP with the fix command (dotnet tool install -g Microsoft.PowerApps.CLI.Tool— note: installingpacrequires .NET SDK as a one-time install, but neither .NET norpac authis needed at runtime for scaffold). If Node is missing, STOP with the install instruction. Run the/generate-pcf-companioncheck fromprereq-check.md(Node +paconly — this self-contained track has no "baseline" check)..NET SDK + active
pac authare 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, beforepac pcf push). -
Read
./PRD.md. If missing or §8 (PCF surface) is incomplete (any<NEEDS INPUT>or missing fields in §8.1–§8.4), STOP withBLOCKED: PRD.md §8 PCF surface is incomplete — re-run /design-native-extension-feature and complete the PCF section. -
Read
./.extension-state.md. If Phase isn't at leastscaffold, STOP withBLOCKED: run /generate-native-extension first.The structural patterns this skill needs to emit (manifest shape,index.tsbridge wiring, output mapping) are fully prescribed in this SKILL.md (§4–§5) and inshared/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 §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("SendMessagePlugin", …) transport inside the host context and routes to the React Native module the binary ships:
PCF → window.PowerApps.NativeExtension.sendAsync("<name>/<receiver>", { method, args: [request] })
→ host global (host context): cordova.exec("SendMessagePlugin", "<name>/<receiver>", [JSON.stringify({method,args}), corrId])
→ proxy → NativeModules[<nativeModule>][<method>].apply(mod, <args-array>)
The composite routing key <name>/<receiver> is what the host resolves to a module; the method is one entry from that receiver's methods[]. One PCF drives both iOS and Android through this global — no platform branch.
⚠️ TWO invariants — both confirmed on device; getting either wrong = silent failure:
- Dispatch via
sendAsync, NEVERcordova.exec. The envelope is a RAW object{ method, args: [request] }— the PCF does not stringify it;sendAsyncdoes theJSON.stringifyinternally. A PCF that callscordova.execdirectly, or that pre-stringifies the payload, fails silently on the first device tap (no error on screen; nothing dispatches — worst on Android).- The inner
argsMUST be a JSON ARRAY (ppmplugin-format §2). After parsing the envelope the proxy runsArray.isArray(parsed.args) ? parsed.args : []thenfn.apply(mod, args)— spreading it as positional arguments. A bare object → dropped → the native method gets no request data. Our convention:args: [request]— one request object, and the native method takes exactly oneReadableMap/NSDictionaryfirst parameter.
On status === "ok", sendAsync resolves result.data — the native method's resolved string. The wrap host both re-stringifies it once and nests it in a { isUpdate, message } transport container, so the PCF normalizes it with an extractResponse helper (parse result.data, then — if the parsed object has no top-level status — unwrap the message container to reach the module's {status, result} object; total-fail → PARSE error). A bare single parse lands on the container and fails every call with UNEXPECTED_PAYLOAD though native succeeded — see shared/ppmplugin-format.md §2. status !== "ok" → surface result.error (fall back to BRIDGE_FAILED); missing host global → NOT_IN_WRAP.
Required reads — must succeed before Step 2
-
Resolve the composite routing key
<name>/<receiver>from the committed./manifest.json— the source of truth/generate-native-extensionwrites at scaffold time, so on the normal flow it already exists when this skill runs. Prefer it; fall back to the staged copy, then ARCHITECTURE only if no manifest exists yet (a hand-authored module). OS-neutral: read./manifest.jsonwith the Read tool and parse the JSON directly — don't shell out togrep/sed(the bash below is illustrative; it won't run on Windows):MANIFEST=$( [ -f ./manifest.json ] && echo ./manifest.json || echo ppmplugin/staging/manifest.json ) if [ -f "$MANIFEST" ]; then NAME=$(grep -o '"name"[[:space:]]*:[[:space:]]*"[^"]*"' "$MANIFEST" | head -1 | sed 's/.*"\([^"]*\)"$/\1/') echo "manifest ($MANIFEST) name: $NAME — receiver/nativeModule/methods read from receivers[]" else echo "no manifest.json yet (hand-authored module) — derive <name>=kebab(className), <receiver>=<Pascal>Extension, nativeModule=<className> from ARCHITECTURE; /generate-ppmplugin-manifest will author it" fiThe dispatch key the PCF binds and the receiver the manifest registers MUST match — a PCF that dispatches
<name>/<receiver>while the manifest registers a different receiver fails on first dispatch. Because./manifest.jsonis authored before this skill runs (at native-gen), the PCF follows the manifest's receiver — bind exactly thereceivers[].nameit declares. -
Read
manifest.jsonreceivers[](canonical dispatch target):receivers[].name— the<receiver>half of the composite keyreceivers[].nativeModule— what the host resolves asNativeModules.<nativeModule>(the module'sgetName())receivers[].methods— theMethodvalues the host may dispatch; each is a real@ReactMethod/RCT_EXPORT_METHODname. The PCF'sonTriggercalls one of these.
-
Native source (verification only —
ios/RCT<Pascal>Module.m,android/src/main/java/.../<Pascal>Module.kt):- Android
getName()/ iOS+ (NSString *)moduleNameMUST equalreceivers[].nativeModule - Every
methodthe PCF dispatches MUST be a real@ReactMethod/RCT_EXPORT_METHODon the module (an unknown method =method '<m>' not foundon device) - If native drifts from the manifest, STOP with
NEEDS_CONTEXT: native module drifted from manifest.json receivers[]; reconcile and re-run
- Android
Compose the resolved contract
Transport (host global — fixed):
window.PowerApps.NativeExtension.sendAsync("<name>/<receiver>", { method, args: [request] })
↑ envelope is a RAW object; sendAsync stringifies it internally
result.status === "ok" → extractResponse(result.data) yields the module's response object (unwraps the wrap `message` container)
result.status !== "ok" → bridge/transport failure (result.error ?? BRIDGE_FAILED); parse-fail → PARSE
no window.PowerApps.NativeExtension → NOT_IN_WRAP (Studio preview / non-PAM host / CordovaV2 off)
Dispatch target (from manifest.json receivers[]):
Composite key: <name>/<receiver>
nativeModule: <NativeModules.<nativeModule>>
method: <one of methods[]>
args: [request] — a JSON ARRAY (spread positionally via fn.apply). Our convention: ONE request
object at args[0]; the @ReactMethod / RCT_EXPORT_METHOD takes one ReadableMap/NSDictionary param.
Response shape: <list — module's own {status, result, error, message}> (message = human-readable failure reason)
Module
Truncated for display — read the full file on GitHub.
Related Skills
algorithmic-art
177.9kCreating algorithmic art using p5.js with seeded randomness and interactive parameter exploration. Use this when users request creating art using code, generative art, algorithmic art, flow fields, or particle systems.
pptx
177.9kUse this skill any time a .pptx or .potx file is involved in any way — as input, output, or both. This includes: creating slide decks, pitch decks, or presentations; reading, parsing, or extracting text from any .pptx or .potx file (even if the extracted content will be used elsewhere, like in an em…
design
130.2kComprehensive design skill: brand identity, design tokens, UI styling, logo generation (55 styles, Gemini, Atlas Cloud, or MuAPI AI), corporate identity program (50 deliverables, CIP mockups), HTML presentations (Chart.js), banner design (22 styles, social/ads/web/print), icon design (15 styles, SVG…
ui-ux-pro-max
130.2kUI/UX design intelligence for web, mobile, and desktop. This skill should be used when designing, building, reviewing, or fixing interfaces, including pages, components, design systems, accessibility, interaction, responsive layout, typography, color, charts, and stack-specific UI implementation.
Languages
Trust signals
From repository metadata: license, adoption, age and documentation. Not a code audit — see the Safety scan above for what the skill file itself contains.
