Skip to content
Development
Skill

/audit-ppmplugin

Statically audit a built `.ppmplugin` before wrap testing. Checks archive layout, manifest compatibility, bundle consistency, Android DEX integrity and SDK leakage, iOS framework structure, native source-to-receiver alignment, and the PCF composite-key/sendAsync transport

From plugin
power-platform-skills
86896 skills19 agents4 MCP
Install
$ npx -y skills add microsoft/power-platform-skills --skill audit-ppmplugin --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/audit-ppmplugin

Context preview

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

Statically audit a built `.ppmplugin` before wrap testing. Checks archive layout, manifest compatibility, bundle consistency, Android DEX integrity and SDK leakage, iOS framework structure, native source-to-receiver alignment, and the PCF composite-key/sendAsync transport

SKILL.md

audit-ppmplugin.SKILL.md
name: audit-ppmplugin
description: "Statically audit a built `.ppmplugin` before wrap testing. Checks archive layout, manifest compatibility, bundle consistency, Android DEX integrity and SDK leakage, iOS framework structure, native source-to-receiver alignment, and the PCF composite-key/sendAsync transport contract. Reports CRITICAL, WARNING, and INFO findings with fixes routed to the owning stage; never modifies the archive. Requires `jar`; `dexdump` or `strings` improves DEX inspection. Run after /assemble-ppmplugin or standalone on an existing bundle."
allowed-tools: Read, Write, Edit, Bash, Glob, Grep, AskUserQuestion, Skill
model: sonnet

/audit-ppmplugin

The verification gate. `/assemble-ppmplugin` proves the bundle is *well-formed*; this skill proves it will *actually load and dispatch* on the wrap runtime. Most `.ppmplugin` failures are silent — the bundle uploads fine, then a method returns `native module 'X' not loaded`, the runtime cannot instantiate the package class, or the upload is rejected with `0x80040265` (canonical-prefix violation). Those cost a full wrap-build round-trip to discover. This skill surfaces them in seconds, on disk.

It is **read-only on the bundle** — it unzips to a temp dir for inspection and never mutates the `.ppmplugin`. Fixes route back upstream (`/generate-ppmplugin-manifest` for manifest issues, the build skills for binary issues), then re-assemble + re-audit.

Read [`shared/ppmplugin-format.md`](../../shared/ppmplugin-format.md) §1 (layout), §3 (canonical-prefix), §4 (validator rules), §5 (Android DEX requirements) — this skill enforces all four against the *built artifact*.

What this skill does NOT do

  • Does not build, zip, or author anything — it inspects a finished `.ppmplugin`. Fixes are made upstream and re-assembled.
  • Does not patch the zip in place — a bundle is an immutable deliverable; mutating it would desync it from the staged sources. It points at the upstream skill instead.
  • Does not upload to Dataverse / wire into a canvas app (Stage 3 — deferred). "READY TO UPLOAD"

means *passes local verification*, not *uploaded*.

---

Step 1 — Read shared docs + resolve the artifact + prereqs

1. Read [`shared/shared-instructions.md`](../../shared/shared-instructions.md) and [`shared/ppmplugin-format.md`](../../shared/ppmplugin-format.md). 2. **Resolve the bundle to audit:**

  • If the user passed a path, use it. If it's a directory, look for `<dir>/*.ppmplugin` (prompt if multiple).
  • Else default to the assemble output: the single `ppmplugin/<name>.ppmplugin` at the repo root (the most-recently-built if several).
  • If none found, STOP with `NEEDS_CONTEXT: no .ppmplugin to audit — run /assemble-ppmplugin first, or pass a path`.

3. Prereq block (shared-instructions §9.2). **Policy: resolve, don't punt** (§1.5) — locate a tool by path before failing:

| Check | Verify | If missing | |---|---|---| | `jar` (JDK) | `jar --version` — used to list + extract the bundle | STOP `BLOCKED: jar not found — install a JDK (JDK 17)` | | DEX scanner | `dexdump` (preferred — locate in Android SDK `build-tools/*/dexdump` like `/build-android-binary` resolves `$D8`); else `strings` (mac/linux ships it) | If neither: the DEX **string** checks degrade to WARNING ("DEX scan skipped — no dexdump/strings"); structural checks (magic, size) still run. On Windows without either, note the gap. |

4. **Extract** the bundle to a fresh temp dir for inspection (read-only on the original):

   work=$(mktemp -d); ( cd "$work" && jar xf "<abs path to .ppmplugin>" )
   $work = New-Item -ItemType Directory -Force (Join-Path $env:TEMP "ppm-audit"); Push-Location $work; jar xf "<abs path>"; Pop-Location

Each subsequent step appends findings to a running list as `[SEVERITY] <check-id>: <result>`. Don't stop at the first CRITICAL — collect everything so the user fixes in one pass. Severities: **CRITICAL** (will fail at upload or on device — blocks), **WARNING** (likely-wrong, may still work), **INFO** (style / advisory).

---

Step 2 — Category A: Zip structure

Listing comes from `jar tf "<.ppmplugin>"`. The bundle is **native-only** ([format §1](../../shared/ppmplugin-format.md)): `manifest.json` at root + only the declared `android/` / `ios/` slices.

| Check | Asserts | Severity | |---|---|---| | `zip-manifest-at-root` | `manifest.json` is at the archive root | CRITICAL | | `zip-only-native-slices` | top-level entries ⊆ { `manifest.json`, `android/`, `ios/` } | CRITICAL | | `zip-no-ts-js-layer` | NO `src/`, `*.ts`, `*.tsx`, `*.js`, `extension.js`, `extension.hbc` anywhere — the bundle ships no TS/JS layer | CRITICAL | | `zip-no-build-dirs` | NO `android-build/`, `ios-build/`, `node_modules/`, `dist/`, `build/` leaked in | CRITICAL | | `zip-no-stray-files` | NO `META-INF/`, `.DS_Store`, dotfiles, nested `*.zip`/`*.ppmplugin` | WARNING | | `zip-reasonable-size` | bundle < 50 MB (a larger one usually means React or node_modules got swept in) | WARNING |

A `src/` tree, an `extension.js`/`.hbc`, or any `*.ts` is **SDK-era / JS-layer leakage** — flag CRITICAL and point at [format §6](../../shared/ppmplugin-format.md) (the bundle is native binaries only).

---

Step 3 — Category B: Manifest schema, validator rules + field leakage

Read the extracted `manifest.json`. Re-run **every** [`ppmplugin-format §4`](../../shared/ppmplugin-format.md) rule against the *built artifact* (defense in depth — the manifest may have been hand-edited after `/generate-ppmplugin-manifest`):

| Check | Asserts | Severity | |---|---|---| | `mf-name-shape` | `name` matches `^[a-z0-9][a-z0-9-]{0,63}$` | CRITICAL | | `mf-canonical-prefix` | each `receivers[].nativeModule` starts with the canonical prefix of `name` (split on `-`/`_`, PascalCase each segment, join — [§3](../../shared/ppmplugin-format.md)) (Ordinal, case-sensitive) | CRITICAL | | `mf-reserved-prefix` | no `nativeModule` starts with a reserved prefix (case-insensitive list

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.