create-site
SkillCloud & infraCreates a new Power Pages code site (SPA) using React, Angular, Vue, or Astro. Guides through the full process from initial concept to deployed site: requirements discovery, scaffolding, component planning, design, implementation, validation, and deployment. Use when the user wants to create, build, or scaffold a new Power Pages website or portal.
Available today. Use it from your connected AI after setup.
No other account needed.
Connect ahel once, and every AI you use reads what you have installed.
Then ask your AI: use the create-site skill
What this skill tells your AI
The instructions your AI receives, as published by microsoft/power-platform-skills in plugins/power-pages/skills/create-site/SKILL.md and read by ahel’s review.
Plugin check: Run
node "${PLUGIN_ROOT}/scripts/check-version.js"— if it outputs a message, show it to the user before proceeding.
Create Power Pages Code Site
Guide the user through creating a complete, production-quality Power Pages code site from initial concept to deployed site. Follow a systematic approach: discover requirements, scaffold and launch immediately, plan components and design, implement with design applied, validate, review, and deploy.
Core Principles
- Use best judgement for design details: Once the user picks an aesthetic direction and mood, make confident decisions about specific fonts, colors, page layouts, and component behavior. Do not ask the user to specify every detail — use the design reference and your own taste to make creative, distinctive choices.
- Use TaskCreate/TaskUpdate: Track all progress throughout all phases — create the todo list upfront with all phases before starting any work.
- Scaffold early, design with intention: Get the dev server running immediately after discovery so the user has something to look at. Then plan the design and features while the scaffold is live — apply the chosen aesthetic during implementation.
- Live preview feedback loop: The dev server MUST be running before any customization begins. Browse the site via Playwright (
browser_navigate+browser_snapshot) to verify every significant change. Do NOT take screenshots — only use accessibility snapshots to check page structure and content. - Keep the scaffold loader in sync with reality: The scaffold loader polls
public/scaffold-status.json. Update this file before everyAskUserQuestion(to raise the "waiting for your input" banner so the user doesn't miss a terminal prompt) and before each implementation step in Phase 5 (so the progress-bar label matches what you're actually doing while the decorative spinner continues its default cycle). See Live Preview Status Protocol. - Use real images: Source high-quality photos from Unsplash wherever pages need visual content — hero sections, feature cards, about pages, backgrounds, etc. Use
https://images.unsplash.com/photo-{id}?w={width}&h={height}&fit=cropURLs with specific photo IDs found viaWebSearch. Never leave image placeholders or broken<img>tags pointing to nonexistent files. - Git checkpoints: Commit after every individual page and component — each gets its own commit so breaking changes can be reverted.
Constraint: Only static SPA frameworks are supported (React, Vue, Angular, Astro). NOT supported: Next.js, Nuxt.js, Remix, SvelteKit, Liquid.
Initial request: $ARGUMENTS
Live Preview Status Protocol
While the scaffold loading screen is visible (from Phase 2.6 until the Home page itself is replaced in Phase 5), the loader polls GET /scaffold-status.json every 1.5 seconds. The message you write into <PROJECT_ROOT>/public/scaffold-status.json appears as the label under the progress bar, and awaitingInput controls the "waiting for your input" banner. The decorative spinner above the progress bar continues its built-in phrase cycle; keep the progress-bar label current so the loader still reflects what is actually happening.
Why this matters: When the browser with the loader takes over the user's screen, a prompt in the terminal can sit unanswered for a long time because the user doesn't realize anything is waiting. The banner makes it obvious.
File shape (all fields optional — omit any field you don't want to change):
{
"message": "Creating Contact page",
"awaitingInput": false,
"inputPrompt": "Please check your terminal to respond."
}
message— one short present-participle phrase shown as the status line under the progress bar in the loader (replacing the default "Getting started…" / "Setting up infrastructure…" cycle). Include the grouping context inline when it helps (e.g.,"Creating Footer component (shared components)").awaitingInput— whentrue, a prominent pulsing banner appears at the top of the loader and stays visible until this field is cleared. Set this before everyAskUserQuestioncall and clear it (false) immediately after the user answers.inputPrompt— short context for the banner (e.g.,"Choose a framework"). Optional.
When to update the file:
- After scaffold launches (end of Phase 2): write an initial status like
{ "message": "Planning your site", "awaitingInput": false }. - Before any
AskUserQuestionthat runs while the scaffold is visible (Phases 3, 4, and any in-scaffold prompt in Phase 5): setawaitingInput: truewith a shortinputPrompt. After the user answers, write again withawaitingInput: false. - Before each implementation step in Phase 5 — applying design tokens, creating each shared component, creating each page, updating the router, updating navigation — update
messageto the specific action. Examples:"Applying design tokens","Creating Navbar component","Creating Contact page". - At the end of Phase 5, after the Home page has been replaced: delete
public/scaffold-status.jsonso it isn't deployed with the site.
Write the file with the Write tool (atomic overwrite). You do not need to read it first.
Phase 1: Discovery
Goal: Understand what site needs to be built and what problem it solves
Actions:
🚦 Gate (plan · create-site:1.purpose): Multi-question prompt collecting site name, framework, purpose, audience, and target directory. Determines what gets scaffolded. Fires only on the "site purpose unclear" branch (step 3 below).
Trigger: Phase 1 when site purpose was not provided in
$ARGUMENTS. Why we ask: Wrong framework picked → wrong template copied into the wrong directory; cleanup is annoying. Cancel leaves: Nothing — no scaffolding has started yet.
-
Create todo list with all 8 phases (see Progress Tracking table)
-
If site purpose is clear from arguments:
- Summarize understanding
- Identify site type (portal, dashboard, landing page, blog, etc.)
-
If site purpose is unclear, use
AskUserQuestion:Question Header Options What should the site be called? (e.g., "Contoso Portal", "HR Dashboard") Site Name (free text — use a single generic option so the user types a custom name via "Other") Which frontend framework? Framework React (Recommended), Vue, Angular, Astro What is the site's purpose? Purpose Company Portal, Blog/Content, Dashboard, Landing Page Who is the target audience? Audience Internal (employees, partners), External (public-facing customers) Where should the project be created? Location Current directory, New folder in current directory (Recommended), Any other directory -
Resolve the project location:
- If "Current directory": Project root =
<cwd>. - If "New folder in current directory": Create a folder named
__SITE_NAME__inside the cwd. Project root =<cwd>/__SITE_NAME__/. - If "Any other directory": Ask for the full path. Verify/create it. Project root = provided path.
After resolving, confirm: "The site will be created at
<resolved path>."Store this as
PROJECT_ROOT. - If "Current directory": Project root =
-
From the user's answers, derive:
__SITE_NAME__(Title Case, e.g.,Contoso Portal)__SITE_SLUG__(kebab-case derived from site name, e.g.,contoso-portal)__SITE_DESCRIPTION__(one-line description based on name + purpose)
-
Summarize understanding and confirm with user before proceeding
Audience influences site generation:
- Internal: Prioritize data tables, dashboards, authentication, navigation depth, functional over flashy design
- External: Prioritize landing page appeal, SEO-friendly structure, contact forms, clean marketing-oriented layout
Output: Clear statement of site purpose, framework, audience, derived naming values, and project location
Phase 2: Scaffold & Launch Dev Server
Goal: Get a running site immediately so the user has something to preview while features and design are planned
The scaffold is a temporary branded loading screen — it shows a Power Pages animated "Building your site" experience with orbiting elements, status messages, and feature cards. Its only purpose is to get the dev server running quickly so the user has something to look at while you plan and build. During Phase 5 (Implementation), the entire scaffold — including theme.css, Layout, Home page, and all placeholder components — is completely replaced with the user's actual site: their chosen typography, color palette, pages, components, and navigation. Do NOT try to build on top of the loading screen; replace it entirely.
See
${PLUGIN_ROOT}/references/framework-conventions.mdfor the full framework → build tool → router → output path mapping.
Actions:
2.1 Copy Template
${PLUGIN_ROOT}is already resolved to the plugin's absolute path at runtime. Use it directly in Glob/Read paths — do NOT search for the plugin directory.
Read and copy all files from the matching asset template to the project directory:
| Framework | Asset Directory |
|---|---|
| React | ${PLUGIN_ROOT}/skills/create-site/assets/react/ |
| Vue | ${PLUGIN_ROOT}/skills/create-site/assets/vue/ |
| Angular | ${PLUGIN_ROOT}/skills/create-site/assets/angular/ |
| Astro | ${PLUGIN_ROOT}/skills/create-site/assets/astro/ |
Use Glob to discover all files in the asset directory, Read each file, then Write to the project directory preserving the relative path structure.
Also copy the shared loader icon that the scaffold references from its CSS (url('/power-pages-icon.png')):
Read the binary file ${PLUGIN_ROOT}/skills/create-site/assets/shared/power-pages-icon.png and Write it to <PROJECT_ROOT>/public/power-pages-icon.png. (All four supported frameworks serve public/ at the web root, so the same /power-pages-icon.png URL works for every framework.)
Seed the live status file so the loader shows a real message the moment it mounts. Write <PROJECT_ROOT>/public/scaffold-status.json:
{ "message": "Planning your site", "awaitingInput": false }
See Live Preview Status Protocol for the full contract — from here on, update this file before every AskUserQuestion and before each Phase 5 implementation step.
2.2 Replace Placeholders
After copying, replace all __PLACEHOLDER__ tokens in every file. Use Edit with replace_all: true on each file.
- Name/slug/description placeholders: Use the actual values from Phase 1 (
__SITE_NAME__,__SITE_SLUG__,__SITE_DESCRIPTION__).
Note: The scaffold loading screen uses hardcoded Power Pages branding colors — there are no color placeholders (
__PRIMARY_COLOR__, etc.) to replace. The user's chosen color palette is applied fresh during Phase 5 when the scaffold is completely replaced.
2.3 Rename gitignore
Rename gitignore → .gitignore in the project root (stored without dot prefix to avoid git interference in the plugin repo).
2.4 Install Dependencies
Run npm install before initializing git so that package-lock.json is included in the initial commit:
cd "<PROJECT_ROOT>"
npm install
Astro requires Node 22.12 or newer. Astro 7 exits with
Node.js vX is not supported by Astro!on anything older, so when the chosen framework is Astro, runnode --versionfirst and ask the user to upgrade before continuing.
2.5 Initialize Git Repository
Initialize a git repo and make the first commit. This captures all template files AND package-lock.json in one clean baseline:
cd "<PROJECT_ROOT>"
git init
git add -A
git commit -m "Initial scaffold: __SITE_NAME__ (__FRAMEWORK__)"
From this point, commit after every significant milestone so any breaking change can be reverted.
2.6 Start Dev Server
This MUST happen now — before any planning or customization begins. The dev server gives the user a live preview while features and design are being planned:
cd "<PROJECT_ROOT>"
npm run dev
Run npm run dev in the background using Bash with run_in_background: true. Note the local URL (typically http://localhost:5173 for Vite or http://localhost:4200 for Angular or http://localhost:4321 for Astro).
2.7 Verify in Playwright & Share URL
Immediately after the dev server starts, verify the scaffold is working:
- Use
mcp__plugin_power-pages_playwright__browser_navigateto open the dev server URL - Use
mcp__plugin_power-pages_playwright__browser_snapshotto verify the page loaded correctly (do NOT take screenshots — only use accessibility snapshots) - Share the dev server URL with the user so they can preview the site in their own browser (e.g., "Your site is running at
http://localhost:5173— open it in your browser to follow along as I build.")
GATE: Do NOT proceed to Phase 3 until ALL of the following are true:
- Template files copied and placeholders replaced
- Git repo initialized with initial scaffold commit
npm installcompleted successfully- Dev server is running in the background (
npm run dev)- Playwright has opened the site and verified it loads via
browser_snapshot- The dev server URL has been shared with the user
If any of these are not done, complete them now before moving on.
Output: Running dev server with verified scaffold, URL shared with user
Phase 3: Component Planning
Goal: Determine what pages, components, and design elements the site needs — while the user previews the running scaffold
🚦 Gate (plan · create-site:3.requirements): Three sub-prompts (features multi-select, aesthetic, mood) — shape the Phase 4 plan and the Phase 5 implementation. Fires at step 2 of the action list below.
Trigger: Phase 3 entry; scaffold loader is up. Why we ask: Wrong feature set / aesthetic gets baked into the rendered plan — the Phase 4.7 gate would still catch most errors, but it's wasteful to defer the catch. Cancel leaves: Nothing — scaffold loader files are throwaway artifacts replaced wholesale in Phase 5.
Actions:
-
Raise the "awaiting input" banner so the user notices the terminal prompt even while the browser loader is full-screen.
Write<PROJECT_ROOT>/public/scaffold-status.json:{ "message": "Planning your site", "awaitingInput": true, "inputPrompt": "Features, aesthetic, and mood — please answer in the terminal." }Immediately after the user answers,
Writethe same file again with"awaitingInput": falseso the banner disappears. -
Use
AskUserQuestionto collect feature and design requirements:Question Header Options Which features? (multi-select) Features (generate 3-4 context-aware options based on the site name, purpose, and audience from Phase 1) What aesthetic direction do you want? Aesthetic Minimal & Clean (Recommended), Bold & Vibrant, Dark & Moody, Warm & Organic What's the overall mood? Mood Professional & Trustworthy (Recommended), Creative & Playful, Technical & Precise, Elegant & Premium Feature options are NOT hardcoded. Infer relevant features from Phase 1 answers. For example:
- "HR Dashboard" + Internal → Employee Directory, Leave Requests, Announcements, Org Chart
- "Contoso Portal" + External → Contact Form, Service Catalog, Knowledge Base, FAQ
- "Partner Hub" + Internal → Document Library, Partner Directory, Deal Tracker, Notifications
Always generate options that make sense for the specific site — never reuse a fixed list.
If you include an Authentication feature option, describe it generically as "Login/signup for tracking application status" or similar. Do NOT mention a specific identity provider (e.g., "Entra ID", "SAML", "Google") in the feature description — the
/power-pages:setup-authskill will ask the user which provider they want. -
AI Component Planning — Based on Phase 1 answers (site name, purpose, audience) and the feature selection above, propose which of the Power Pages generative-AI summarization APIs the site might use. The site itself does not depend on them — the page ships with reserved slots and runs without AI;
/add-ai-webapipopulates the slots later when the user is ready. UseAskUserQuestionwith multi-select to let the user opt in:Question Header Options Which AI summarization features should the site have? (multi-select — each can be added later with /add-ai-webapi)AI Summaries (generate 2-4 context-aware options plus "None for now") Options are NOT hardcoded. Infer relevant AI summary features from Phase 1 and the features picked above. Examples:
- "HR Dashboard" + Leave Requests feature → "Data summarization for leave requests", "Search summary on the knowledge base"
- "Contoso Portal" + Knowledge Base → "Search summary on site-wide search", "Data summarization for articles"
- "Customer Self-Service" + Support Cases / Incidents → "Data summarization for support cases (Microsoft-shipped recipe)", "Data summarization for attached knowledge articles"
Treat the standard
incidenttable like any other Dataverse table — propose Data Summarization for it when the site handles support cases, but don't force the Microsoft-shipped recipe ($select=description,title+ the portal-comments expand) unless that genuinely fits the user's UX. A custom case-like table or a different facet of the standard incident is a regular Data Summarization pick. Always include None for now so the user can defer. Do NOT integrate the APIs in this skill — only record the user's picks so Phase 4's plan can mention them and Phase 8 can suggest/add-ai-webapias a recommended next step.Capture the selection in memory as
AI_SUMMARY_PICKS— a list of one or more of:search-summary,data-summarization. -
Map picks to target pages. For each entry in
AI_SUMMARY_PICKS, decide which page will carry the AI surface and store the mapping asAI_SUMMARY_PLACEMENTS. This is what Phase 4 shows the user and what Phase 5 reserves slots for. Use the feature selection from step 2 — and treat this mapping as an input to the page list Claude proposes in step 7: if a pick has no natural target page, add one to the plan so the summary has a home:Pick Default target page If no matching page is planned search-summaryA search / search-results page (e.g., SearchResults,Search)Add a search page to the plan so the summary has a home data-summarizationThe detail page of the table the user called out (e.g., ProductDetailfor products,CaseDetailfor support cases) — ask the user if ambiguousPropose adding a detail page; if rejected, fall back to a list/dashboard page AI_SUMMARY_PLACEMENTSshape: one record per placement, e.g.[{ pick: "data-summarization", targetPage: "CaseDetail", marker: "POWERPAGES:AI-SLOT kind=data-summarization" }].The
markerstring is the comment tag Phase 5 emits into the page source as a reserved anchor that/add-ai-webapilater finds. Keep the shape uniform — one marker per placement, always the same tag, so the follow-up skill's explore step can grep for them deterministically. -
Read the design aesthetics reference:
${PLUGIN_ROOT}/skills/create-site/references/design-aesthetics.md -
Map aesthetic + mood to design choices using the Aesthetic x Mood Mapping table from the design reference. Record the chosen font direction, color direction, and motion direction.
-
Analyze requirements and determine needed components. If
AI_SUMMARY_PLACEMENTSfrom step 4 implies a page that wasn't already in the plan (e.g., aCaseDetailpage for a data-summarization pick on the support-case table), add it to the page list now. Present the component plan to the user as a table:| Component Type | Count | Details | |---------------------|-------|---------| | Pages | 4 | Home, About, Services, Contact | | Shared Components | 3 | Navbar, Footer, ContactForm | | Design Elements | 4 | Google Fonts (Playfair Display + Source Sans Pro), Color palette (6 CSS vars), Page transitions, Gradient backgrounds | | Routes | 4 | /, /about, /services, /contact | -
Use best judgement to determine the final color palette based on the chosen aesthetic + mood. These will be written fresh into a new
theme.cssduring Implementation (Phase 5) when the scaffold loading screen is completely replaced:CSS Variable Description Value --color-primaryPrimary hex color (choose based on aesthetic + mood) --color-secondaryComplementary hex color (choose based on aesthetic + mood) --color-bgBackground color (choose based on aesthetic + mood) --color-surfaceSurface/card color (choose based on aesthetic + mood) --color-textMain text color (choose based on aesthetic + mood) --color-text-mutedMuted text color (choose based on aesthetic + mood)
Output: Confirmed list of pages, components, design elements, and routes to create
Phase 4: Plan Approval
Goal: Render the implementation plan as an HTML document, open it in the user's default browser, and get approval before starting implementation.
Why HTML instead of a chat message: A structured HTML plan (like the ones produced by
/integrate-backend,/add-server-logic, and/add-cloud-flow) lets the user skim sections, compare swatches, and preview typography — all impossible in a terminal. The scaffold loader in their browser may also be full-screen, so surfacing the plan in a new tab puts it where they can actually read it.
4.1 Read the Design Reference
Read the design aesthetics reference: ${PLUGIN_ROOT}/skills/create-site/references/design-aesthetics.md. Every field you populate below should be justified by the chosen aesthetic + mood from Phase 3.
AI Readiness in the plan. If
AI_SUMMARY_PLACEMENTSfrom Phase 3 is non-empty, reflect each placement in the matchingPAGES_DATAentry'sdescriptionorcontent— e.g., "Reserved slot for an AI summary card; populated later by/add-ai-webapi. The page ships without AI." This keeps the user's expectation honest: the site does not depend on generative-AI features being enabled on the tenant, and there is no "Run /add-ai-webapi" placeholder visible to end-users. IfAI_SUMMARY_PLACEMENTSis empty, omit any AI references from the plan.
4.2 Build the Plan Data
Assemble a single JSON object with the following keys. The plan template rejects any data that's missing a required key, so include all of them.
Shortened here. Read the whole file on GitHub.
Signals
- GitHub stars
- 859
- Forks
- 176
- Last commit
- Sep 2026
Advanced
- Catalog kind
- skill
- Gateway key
create-site- Source
- github.com/microsoft/power-platform-skills