A plugin for creating, deploying, and managing Power Pages code sites. Supports static SPA frameworks (React, Vue, Angular, Astro) with Dataverse integration, Web API access, and browser-based previews via Playwright.
Server-rendered frameworks (Next.js, Nuxt, Remix, SvelteKit) are NOT supported.
Read PLUGIN_DEVELOPMENT_GUIDE.md for UX and reliability standards when creating new skills and agents.
- DRY — Never duplicate logic. Shared scripts live in
scripts/(e.g.,generate-uuid.js,scripts/lib/validation-helpers.js). Shared reference docs live inreferences/. Always check for existing helpers before writing new code. - Validation scripts must import from
scripts/lib/validation-helpers.jsfor boilerplate, path finders, auth helpers, and constants. - UUID generation must use the shared
scripts/generate-uuid.js— never copy it into skill-specific directories. - Power Pages config loading must reuse
scripts/lib/powerpages-config.jsanywhere a script reads.powerpages-sitetable-permission or site-setting YAML. Keep that module focused on loading/parsing code-site config only; put validation or business rules in separate validator modules. - Script changes require tests — Whenever you add a new script or modify an existing script, add or update
node:testcoverage underscripts/tests/. Prefer one*.test.jsfile per script/module being tested, and keep the PowerShell test command passing:$files = Get-ChildItem .\plugins\power-pages\scripts\tests\*.test.js | ForEach-Object { $_.FullName }followed bynode --test $files. Validator changes are not an exception; they must always ship with test coverage. - Dataverse-backed validation must stay opt-in for local runs only. Do not require live Dataverse connectivity in CI workflows or default test runs; gate it behind explicit local flags such as
--validate-dataverse-relationships. - Reference docs shared across skills live in
references/— reference via${CLAUDE_PLUGIN_ROOT}/references/paths, don't duplicate. - Templates use
__PLACEHOLDER__tokens (e.g.,__SITE_NAME__) replaced during scaffolding. Thegitignorefile is stored without the dot prefix and renamed to.gitignoreduring scaffolding. - Hooks are defined centrally in
hooks/hooks.json, usingPostToolUsewith matcherSkillso validation runs when a tracked Power Pages skill completes.
All skills follow these patterns. See existing skills for examples.
Every skill is a sequence of phases (typically 5-8): Prerequisites, Discover/Gather, Plan/Review, Implement, Verify (mandatory standalone phase), Deploy/Summarize. Never skip or reorder phases.
Create all tasks upfront at Phase 1 start using TaskCreate (one per phase). Each task needs subject (imperative), activeForm (present continuous for spinner), and description. Mark in_progress when starting, completed when done. Include a progress tracking table at the end of the SKILL.md.
---
name: <skill-name>
description: >-
<when to use this skill>
user-invocable: true
argument-hint: <optional>
allowed-tools: Read, Write, Edit, Bash, Glob, Grep, Task, TaskCreate, TaskUpdate, TaskList, AskUserQuestion
model: opus
---Note: allowed-tools must be a comma-separated list, not JSON array or YAML list syntax. Do not add hooks to skill frontmatter; Power Pages skills register lifecycle hooks centrally.
Every SKILL.md must include the following line immediately after the closing --- of the frontmatter (before the # title):
> **Plugin check**: Run `node "${CLAUDE_PLUGIN_ROOT}/scripts/check-version.js"` — if it outputs a message, show it to the user before proceeding.This runs a lightweight check comparing the local plugin version against origin/main and shows an update notice if a newer version is available.
- User confirmation — Pause with
AskUserQuestionafter gathering requirements, after presenting a plan, after implementation, and before deployment. - Deployment prompt — Skills that modify site artifacts should end by asking "Ready to deploy?" and invoke
/deploy-siteif yes. - Lifecycle hooks — If a skill needs command validation or checklist enforcement, update
hooks/hooks.jsonandscripts/lib/powerpages-hook-utils.js. Do not define hook registration in individualSKILL.mdfiles. - Graceful failure — Track API call results, never auto-rollback, report failures clearly, continue with remaining items.
- Token refresh — Refresh Azure CLI token every ~20 records / 3-4 tables / ~60 seconds.
- Git commits — Commit after every significant milestone (each page/component, design foundations, phase completion).
- Agent spawning — Process sequentially (not parallel), wait for completion, present output for approval.
- Skill tracking — Every skill must record usage in its final phase via
> Reference: ${CLAUDE_PLUGIN_ROOT}/references/skill-tracking-reference.md(pointer pattern, not hardcoded command). When adding a new skill, also add its entry to the skill name mapping table inreferences/skill-tracking-reference.md. - Dataverse API calls — Use deterministic Node.js scripts (in the skill's
scripts/directory) for Dataverse API queries. Scripts should importgetAuthTokenandmakeRequestfromscripts/lib/validation-helpers.js. Never use inline PowerShellInvoke-RestMethodfor API calls — scripts are more reliable, testable, and cross-platform.
These patterns have caused repeated PR review feedback. Check for them before submitting changes to skills, validators, or hooks.
- Phase cross-references break silently — When renumbering or reordering phases in a SKILL.md, also update:
references/docs that mention phase numbers, the Key Decision Points section, and any other files that cross-reference this skill's phases. After any phase reorder, grep for the old phase number across the skill directory and its references. - Validators must match the exact constraint — If the rule is "no exports at all", block all
module.exports/exports— don't just check if exported names are in an allowlist. If the rule is "try/catch required", verify bothtryANDcatchexist. Re-read the exact constraint from SKILL.md and test the boundary cases. - Hook scripts run on every Skill tool use — The PostToolUse hook fires for all tracked skills, so unconditional
process.stderr.writecreates noise. Gate debug logging behindprocess.env.DEBUG. Only errors should go to stderr unconditionally. - Template placeholders in
<script>blocks need special care —render-template.jsinjects string values as-is (no encoding), which is safe for HTML text contexts but risky inside JavaScript. Avoid declaring JS variables with"__PLACEHOLDER__"in script blocks; prefer reading from the DOM or usingJSON.stringifyfor JS contexts. - Guidance must be consistent within a skill — If one section says "always use raw fetch", a framework-specific table in the same file must not recommend a different HTTP client without qualification. Reviewers will flag contradictions.
Update when plugin structure or conventions change or you learn something which can be useful for new skills or agents.
Keep this file concise — detailed docs belong in PLUGIN_DEVELOPMENT_GUIDE.md or individual SKILL.md / agent files.