Skip to content
Merged
Show file tree
Hide file tree
Changes from 8 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
81 changes: 0 additions & 81 deletions .claude-plugin/marketplace.json

This file was deleted.

1 change: 1 addition & 0 deletions .claude-plugin/marketplace.json
4 changes: 1 addition & 3 deletions .claude/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,7 @@
"Bash(dir:*)",
"Read",
"Write",
"Edit",
"mcp__playwright__*",
"mcp__*__browser_*"
"Edit"
]
}
}
3 changes: 3 additions & 0 deletions .github/workflows/validate-repository-metadata.yml
Original file line number Diff line number Diff line change
Expand Up @@ -22,5 +22,8 @@ jobs:
- name: validate-kebab-case-plugin-names
run: node scripts/validate-plugin-names.js

- name: validate-legacy-compatibility
run: node scripts/validate-legacy-compatibility.js
Comment thread
priyanshu92 marked this conversation as resolved.
Outdated

- name: validate-skill-descriptions
run: node scripts/validate-skill-descriptions.js
27 changes: 21 additions & 6 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,18 +4,21 @@ This file provides guidance to AI Agents when working with code in this reposito

## What This Repo Is

A **plugin marketplace** for Power Platform development by Microsoft. The marketplace manifest (`.claude-plugin/marketplace.json`) references individual plugins in `plugins/`. Each plugin has its own `AGENTS.md` with plugin-specific guidance.
A **plugin marketplace** for Power Platform development by Microsoft. The Open Plugins marketplace manifest (`marketplace.json`) references individual plugins in `plugins/`. Each plugin has its own `AGENTS.md` with plugin-specific guidance.

## Repository Structure

```
power-platform-skills/
├── .claude-plugin/
│ └── marketplace.json # Marketplace manifest (lists all available plugins)
├── marketplace.json # Open Plugins marketplace manifest (lists all available plugins)
├── .claude-plugin/ # Legacy symlinks for existing subscriptions
│ └── marketplace.json
├── plugins/ # Directory containing individual plugins
│ └── <plugin-name>/ # Individual plugin (e.g., power-pages)
│ ├── .claude-plugin/
│ ├── .plugin/
│ │ └── plugin.json # Plugin manifest
│ ├── .claude-plugin/
│ │ └── plugin.json # Legacy manifest mirror
│ ├── AGENTS.md # Plugin-specific development guidelines
│ ├── agents/ # Agent persona files
│ ├── commands/ # Command entry points
Expand All @@ -42,7 +45,8 @@ No root-level build, lint, or test commands exist. Build/test tooling lives insi

Each plugin follows this structure:

- `.claude-plugin/plugin.json` — Plugin metadata (name, version, keywords)
- `.plugin/plugin.json` — Open Plugins metadata (name, version, keywords)
- `.claude-plugin/plugin.json` — legacy symlink to `.plugin/plugin.json` kept for existing subscriptions
- `.mcp.json` — MCP server configuration (optional)
- `agents/` — Agent definitions (`.md` files with YAML frontmatter)
- `skills/` — Skill definitions, each in its own subdirectory with a `SKILL.md`
Expand All @@ -61,7 +65,7 @@ Skills that apply to all plugins live in `shared/skills/<skill-name>/`. The work
- `plugins/<plugin>/skills/<skill-name>/SKILL.md` — Per-plugin wrapper generated from the template above
- `plugins/<plugin>/skills/<skill-name>/<workflow>.md` — Symlink to the shared workflow when the plugin must work after installing only its own plugin directory

This keeps the skill discoverable in each plugin while preserving install-time portability. Marketplace installs copy only the plugin directory, so per-plugin wrappers must not reference repo-root `shared/` paths at runtime. Instead, point the wrapper at `${CLAUDE_PLUGIN_ROOT}/skills/<skill-name>/<workflow>.md` and keep a symlink from that per-plugin path to the repo-root shared workflow; marketplace installers dereference same-marketplace symlinks into the installed plugin cache. When updating a shared skill, edit the workflow file and/or `SKILL.template.md` in `shared/`, then update the per-plugin wrappers (frontmatter + bundled workflow reference, with `{{PLUGIN_NAME}}` substituted) and ensure any per-plugin symlinks still resolve under `plugins/<plugin>/skills/<skill-name>/`. Commit the shared source and per-plugin symlinks together.
This keeps the skill discoverable in each plugin while preserving install-time portability. Marketplace installs copy only the plugin directory, so per-plugin wrappers must not reference repo-root `shared/` paths at runtime. Instead, point the wrapper at `${PLUGIN_ROOT}/skills/<skill-name>/<workflow>.md` and keep a symlink from that per-plugin path to the repo-root shared workflow; marketplace installers dereference same-marketplace symlinks into the installed plugin cache. When updating a shared skill, edit the workflow file and/or `SKILL.template.md` in `shared/`, then update the per-plugin wrappers (frontmatter + bundled workflow reference, with `{{PLUGIN_NAME}}` substituted) and ensure any per-plugin symlinks still resolve under `plugins/<plugin>/skills/<skill-name>/`. Commit the shared source and per-plugin symlinks together.

## Shared Telemetry

Expand All @@ -71,6 +75,17 @@ Edit `shared/telemetry/` directly — the symlink makes changes live for every a

Current adopters: `power-pages`. Others adopt on demand.

## Legacy Marketplace Compatibility

Keep the root `.claude-plugin/marketplace.json` as a symlink to
`../marketplace.json`, and keep each plugin's `.claude-plugin/plugin.json` as a
symlink to `../.plugin/plugin.json`. The shared root marketplace must stay
dual-compatible: use repository-root-relative plugin `source` paths and preserve
legacy `category`/`tags` fields alongside Open Plugins metadata. Existing
marketplace subscriptions may still resolve the legacy paths during auto-update,
so removing or drifting these files can force users to reinstall. Run
`node scripts/validate-legacy-compatibility.js` after metadata changes.

## Code Conventions

**DRY (Don't Repeat Yourself):** Never duplicate logic across files. Each plugin has shared utilities (e.g., `scripts/lib/`) and shared reference docs (e.g., `references/`). Always check for and reuse existing helpers before writing new code. When adding shared logic, put it in the plugin's shared modules — not in individual skill directories.
Expand Down
38 changes: 31 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,8 @@ If you prefer to install manually, run these commands inside a Claude Code or Gi
```bash
/plugin install power-pages@power-platform-skills
/plugin install model-apps@power-platform-skills
/plugin install code-apps@power-platform-skills
/plugin install mcp-apps@power-platform-skills
/plugin install code-apps-preview@power-platform-skills
/plugin install canvas-apps@power-platform-skills
```

Expand All @@ -64,6 +65,12 @@ Build and deploy Power Apps generative pages for model-driven apps.

**Stack**: React + TypeScript + Fluent, deployed via PAC CLI

### [MCP Apps](plugins/mcp-apps/README.md) (`plugins/mcp-apps`)

Generate interactive MCP App widgets for MCP tools.

**Stack**: HTML widgets using the MCP Apps protocol

### [Code Apps](plugins/code-apps/AGENTS.md) (`plugins/code-apps`)

Build and deploy Power Apps code apps connected to Power Platform via connectors.
Expand All @@ -86,6 +93,7 @@ To develop and test plugins locally, follow these steps:
```bash
claude --plugin-dir /path/to/power-platform-skills/plugins/power-pages
claude --plugin-dir /path/to/power-platform-skills/plugins/model-apps
claude --plugin-dir /path/to/power-platform-skills/plugins/mcp-apps
claude --plugin-dir /path/to/power-platform-skills/plugins/code-apps
claude --plugin-dir /path/to/power-platform-skills/plugins/canvas-apps
```
Expand Down Expand Up @@ -155,39 +163,55 @@ See the [Copilot CLI docs](https://docs.github.com/en/copilot/how-tos/use-copilo

```text
power-platform-skills/
├── .claude-plugin/
│ └── marketplace.json # Marketplace manifest (lists all plugins)
├── marketplace.json # Open Plugins marketplace manifest (lists all plugins)
├── .claude-plugin/ # Legacy marketplace shim for existing subscriptions
│ └── marketplace.json
├── .claude/
│ └── settings.json # Auto-allowed tools (pac, node, dotnet, etc.)
├── plugins/
│ ├── power-pages/ # Power Pages plugin
│ │ ├── .claude-plugin/
│ │ ├── .plugin/
│ │ │ └── plugin.json
│ │ ├── .claude-plugin/ # Legacy manifest mirror
│ │ │ └── plugin.json
│ │ ├── commands/
│ │ ├── shared/
│ │ └── skills/
│ ├── model-apps/ # Model Apps plugin
│ | ├── .claude-plugin/
│ | ├── .plugin/
│ │ └── plugin.json
│ | ├── commands/
│ | ├── skills/
│ | ├── shared/ # Shared references + samples
│ | └── github/ # GitHub Copilot instructions
│ ├── mcp-apps/ # MCP Apps widget generator plugin
│ │ ├── .plugin/
│ │ │ └── plugin.json
│ │ ├── references/
│ │ ├── samples/
│ │ └── skills/
│ ├── code-apps/ # Code Apps plugin
│ │ ├── .claude-plugin/
│ │ ├── .plugin/
│ │ │ └── plugin.json
│ │ ├── agents/
│ │ ├── skills/
│ │ └── shared/ # Shared instructions + references
│ └── canvas-apps/ # Canvas Apps plugin
│ ├── .claude-plugin/
│ ├── .plugin/
│ │ └── plugin.json
│ ├── references/ # Technical + design guides
│ └── skills/
├── AGENTS.md # Development guidelines
└── README.md
```

The `.claude-plugin` files are compatibility symlinks for users who subscribed
before the Open Plugins migration. The root legacy marketplace points to
`../marketplace.json`, and per-plugin legacy manifests point to
`../.plugin/plugin.json`. The shared marketplace uses repository-root-relative
plugin `source` paths so existing subscriptions can auto-update without
requiring users to remove and reinstall the marketplace or plugins.

## Documentation

- [Power Pages Code Sites](https://learn.microsoft.com/en-us/power-pages/configure/create-code-sites)
Expand Down
2 changes: 1 addition & 1 deletion evals/model-apps/genpage/evals.json
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@
"Phase 2: Entity-builder is SKIPPED (no entities to create)",
"Phase 4: pac model genpage generate-types --data-sources 'account' --output-file <working-dir>/RuntimeTypes.ts is run",
"Phase 5b (single-page fast path): Plan has 1 page so orchestrator inlines the build — NO Task subagent dispatched for the page-builder",
"Phase 5b: Orchestrator reads ${CLAUDE_PLUGIN_ROOT}/references/verified-icons.txt before writing the .tsx",
"Phase 5b: Orchestrator reads ${PLUGIN_ROOT}/references/verified-icons.txt before writing the .tsx",
"Phase 5b: A relevant sample file is read (e.g., 7-responsive-cards.tsx for card layout)",
"Phase 5b: Generated .tsx uses only column names verified from RuntimeTypes.ts — no guessed names",
"Phase 5b: After writing, orchestrator greps the .tsx for `from \"@fluentui/react-icons\"` imports and verifies each named import against verified-icons.txt — rewrites if any are missing",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@
- Plan has 1 page → fast path taken (inlined build, no Task subagent dispatched for the page-builder)
- Data mode: dataverse
- Read sample: plugins/model-apps/samples/7-responsive-cards.tsx (closest match for card layout)
- Read ${CLAUDE_PLUGIN_ROOT}/references/verified-icons.txt to source icon names
- Read ${PLUGIN_ROOT}/references/verified-icons.txt to source icon names
- Wrote page.tsx
- Post-write icon verification: grep `from "@fluentui/react-icons"` in page.tsx; verified `BuildingRegular`, `MailRegular`, `PhoneRegular`, `GlobeRegular` against verified-icons.txt — all present

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,8 +52,8 @@
- Plan has 1 page → fast path taken (inlined build, no Task subagent dispatched)
- Data mode: dataverse
- Read sample: plugins/model-apps/samples/9-list-with-caching.tsx (Dataverse list pattern)
- Read ${CLAUDE_PLUGIN_ROOT}/references/localization.md (multi-language + RTL pattern)
- Read ${CLAUDE_PLUGIN_ROOT}/references/verified-icons.txt
- Read ${PLUGIN_ROOT}/references/localization.md (multi-language + RTL pattern)
- Read ${PLUGIN_ROOT}/references/verified-icons.txt
- Wrote page.tsx with:
- Xrm.Utility.getGlobalContext().userSettings.languageId for language detection
- LOCALE_MAP for 1033/1025/1036 → BCP-47 + isRtl
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@
- Plan has 1 page → fast path taken (inlined build, no Task subagent dispatched)
- Data mode: dataverse
- Read sample: plugins/model-apps/samples/2-wizard-multi-step.tsx (wizard pattern reference)
- Read ${CLAUDE_PLUGIN_ROOT}/references/verified-icons.txt to source icon names
- Read ${PLUGIN_ROOT}/references/verified-icons.txt to source icon names
- Wrote page.tsx (~7 KB)
- Post-write icon verification: grep `from "@fluentui/react-icons"` in page.tsx; verified `PersonRegular`, `DocumentRegular`, `CheckmarkCircleRegular` against verified-icons.txt — all present

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@
- ## Entity Creation Required has 2 entities with suffix-only names (jobrequisition, candidate)

## Phase 2a — Pre-flight auth check
- node ${CLAUDE_PLUGIN_ROOT}/scripts/check-auth.js → returned `{ ok: true, ... }`
- node ${PLUGIN_ROOT}/scripts/check-auth.js → returned `{ ok: true, ... }`
- Identity match between pac and az verified

## Phase 2b — Entity Builder (genpage-entity-builder agent invoked via Task)
Expand Down Expand Up @@ -76,7 +76,7 @@
- Plan has 1 page → fast path taken (inlined build, no Task subagent dispatched)
- Data mode: dataverse
- Read sample: plugins/model-apps/samples/9-list-with-caching.tsx (Dataverse list + window cache)
- Read ${CLAUDE_PLUGIN_ROOT}/references/verified-icons.txt
- Read ${PLUGIN_ROOT}/references/verified-icons.txt
- Wrote page.tsx
- Post-write icon verification: grep `from "@fluentui/react-icons"` in page.tsx; verified `PeopleRegular`, `BriefcaseRegular` against verified-icons.txt — all present

Expand Down
2 changes: 1 addition & 1 deletion evals/model-apps/genpage/lib/assertions-layer-1.js
Original file line number Diff line number Diff line change
Expand Up @@ -500,7 +500,7 @@ PHASE_EXPECTATIONS.set(
);

PHASE_EXPECTATIONS.set(
'Phase 5b: Orchestrator reads ${CLAUDE_PLUGIN_ROOT}/references/verified-icons.txt before writing the .tsx',
'Phase 5b: Orchestrator reads ${PLUGIN_ROOT}/references/verified-icons.txt before writing the .tsx',
({ fixture }) => {
const log = fixture.workflowLog;
if (!log) return fail('no workflow-log.md');
Expand Down
2 changes: 1 addition & 1 deletion evals/power-pages/create-site/evals.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
"Dev server is started in background via 'npm run dev' and the localhost URL is shared with the user",
"Playwright browser_navigate and browser_snapshot are used to verify the scaffold loads (no screenshots taken)",
"Component planning asks for features (context-aware options for an external company portal), aesthetic direction (Bold & Vibrant selected), and mood",
"Design aesthetics reference is read from ${CLAUDE_PLUGIN_ROOT}/skills/create-site/references/design-aesthetics.md",
"Design aesthetics reference is read from ${PLUGIN_ROOT}/skills/create-site/references/design-aesthetics.md",
"A component plan table is presented showing pages, shared components, design elements, and routes",
"Color palette is determined with 6 CSS variables (--color-primary, --color-secondary, --color-bg, --color-surface, --color-text, --color-text-muted)",
"Implementation plan is presented with Section A (Design & Pages) and Section B (Review & Deployment) and user approval is requested",
Expand Down
2 changes: 1 addition & 1 deletion evals/power-pages/setup-auth/evals.json
Original file line number Diff line number Diff line change
Expand Up @@ -541,7 +541,7 @@
"expectations": [
"Detects the site as a React framework project",
"Asks the optional features question in Phase 2.1 and the user selects Terms and Conditions",
"Runs `node \"${CLAUDE_PLUGIN_ROOT}/scripts/check-solution-installed.js\" --solutionName \"msdynce_PortalPrivacyExtensions\"` BEFORE asking the GDPR prerequisite question",
"Runs `node \"${PLUGIN_ROOT}/scripts/check-solution-installed.js\" --solutionName \"msdynce_PortalPrivacyExtensions\"` BEFORE asking the GDPR prerequisite question",
"Parses the script's stdout JSON result and branches based on the `installed` boolean",
"When the script returns installed: true, skips the manual prerequisite confirmation entirely and tells the user the solution is detected (including the version from the JSON) before proceeding to collect Terms content",
"When the script returns installed: false, tells the user clearly that Terms and Conditions will NOT be enforced by the server until msdynce_PortalPrivacyExtensions is installed (Authentication/Registration/TermsAgreementEnabled is silently ignored without it), then asks via AskUserQuestion whether to continue scaffolding anyway or skip Terms entirely (two options, not three)",
Expand Down
Loading
Loading