--- name: genpage version: 2.2.0 description: Creates, updates, and deploys Power Apps generative pages for model-driven apps using React v17, TypeScript, and Fluent UI V9. Orchestrates specialist agents for planning, entity creation, and code generation. Use it when user asks to build, retrieve, or update a page in an existing Microsoft Power Apps model-driven app. Use it when user mentions "generative page", "page in a model-driven", or "genux". author: Microsoft Corporation argument-hint: " | edit" user-invocable: true model: sonnet allowed-tools: Read, Write, Edit, Bash, Glob, Grep, WebFetch, Task, AskUserQuestion, TaskCreate, TaskUpdate, TaskList --- # Power Apps Generative Pages Builder **Triggers:** genpage, generative page, create genpage, genux page, build genux, power apps page, model page **Keywords:** power apps, generative pages, genux, model-driven, dataverse, react, fluent ui, pac cli **Aliases:** /genpage, /gen-page, /genux ## Overview This skill orchestrates four specialist agents across the create and edit flows: **Create flow:** 1. **`genpage-planner`** — validates prerequisites, gathers requirements, detects what entities and apps exist, presents a plan for approval, writes `genpage-plan.md` 2. **`genpage-entity-builder`** — creates Dataverse entities (tables, columns, relationships, choices, sample data) via the plugin's Node.js Web API scripts 3. **`genpage-page-builder`** — generates one complete `.tsx` file per page; multiple builders run in parallel for multi-page requests **Edit flow:** 4. **`genpage-edit-planner`** — reads the downloaded page artifacts, gathers change requirements, presents an edit plan, writes `genpage-edit-plan.md` You (the skill) coordinate the agents and own app creation, RuntimeTypes generation, deployment, browser verification, and the inline application of planned edits. ## References - **Code generation rules**: [rules.md](../../references/rules.md) - **Troubleshooting**: [troubleshooting.md](../../references/troubleshooting.md) - **Sample pages**: [samples/](../../samples/) ## Development Standards - **React 17 + TypeScript** — all generated code - **Fluent UI V9** — `@fluentui/react-components` exclusively (DatePicker from `@fluentui/react-datepicker-compat`, TimePicker from `@fluentui/react-timepicker-compat`) - **Single file architecture** — all components, utilities, styles in one `.tsx` file - **No external libraries** — only React, Fluent UI V9, approved Fluent icons, D3.js for charts - **Type-safe DataAPI** — use RuntimeTypes when Dataverse entities are involved - **Responsive design** — flexbox, relative units, never `100vh`/`100vw` - **Accessibility** — WCAG AA, ARIA labels, keyboard navigation, semantic HTML - **Complete code** — no placeholders, TODOs, or ellipses in final output --- ## Instructions Follow these phases in order for every `/genpage` invocation. ### Phase 0: Create Working Directory Derive a short folder name from the user's requirements: 1. Extract the page name or a 2-4 word summary from `$ARGUMENTS` 2. Convert to kebab-case (e.g., "Candidate Tracker" → `candidate-tracker`) 3. Create the folder: `mkdir -p ` 4. Resolve its absolute path — this is the **working directory** for all subsequent phases ### Phase 0.5: Initialize Local-Dev Manifest Write `package.json` and `genpage.d.ts` into the working directory so the developer can `npm install` and get IntelliSense, type-checking, and "go to definition" in their editor. Versions come from `references/supported-dependencies.md` (single source of truth: `scripts/lib/supported-dependencies.js`). ```bash node "${CLAUDE_PLUGIN_ROOT}/scripts/generate-page-manifest.js" ``` - `` is the same slug used for the working directory. - Add `--features charts,datepicker,timepicker` (comma-separated) only when the requirements clearly call for them; otherwise omit and keep the manifest lean. - The script is **idempotent** — it skips files that already exist. Pass `--force` to overwrite (used in regeneration flows when versions drift). - Output is a JSON summary on stdout; pipe to stderr for visibility but do not block the workflow if the script returns non-zero — the manifest is a dev-ergonomics aid, not part of the deployed artifact. ### Phase 1: Plan > **⚠️ CRITICAL — you MUST invoke `genpage-planner` via the `Task` tool. You MUST > NOT inline the planner's questions yourself with `AskUserQuestion`.** > > The planner is not optional or skippable. It runs: > 1. Prerequisite validation (`node --version`, `pac help` version >= 2.7.0) > 2. Auth verification (`pac auth list`, environment selection) > 3. The structured "Create new / Edit existing" question (via `AskUserQuestion` > inside the planner subagent, not here) > 4. Language detection (`pac model list-languages`) — only on new-page path > 5. Entity existence detection (`pac model list-tables --search`) > 6. App detection (`pac model list`) with proper selection prompts > 7. Plan-mode presentation and approval > 8. Writes `genpage-plan.md` to the working directory > > Reasons to **NEVER** ask "new or edit?" yourself before invoking the planner: > - You would skip prereq + auth (the planner is the only thing that runs them) > - The structured question gives the user labeled options; an inline free-text > prompt forces them to guess > - The planner returns `{ "action": "edit" }` as a contract — your inline > question can't produce that signal cleanly > > Even if `$ARGUMENTS` looks like it tells you the intent, **still invoke the > planner**. Pass the intent in the prompt — the planner uses it to skip its > own Question 1 if appropriate, but the prereq/auth/env steps still run. #### Steps 1. Invoke `genpage-planner` via `Task` with the prompt below. 2. Wait for it to finish (it returns a summary). 3. If the return includes `{ "action": "edit" }`, jump to the **Edit Flow** section. 4. Otherwise the planner has written `genpage-plan.md`. Proceed to Phase 2. #### Invocation prompt Pass a prompt that includes: - The user's requirements: `$ARGUMENTS` - The working directory (absolute path from Phase 0) - The plugin root path: `${CLAUDE_PLUGIN_ROOT}` Example: > You are the genpage-planner agent. Plan generative page(s) for the following requirements: > > [paste $ARGUMENTS here verbatim, or "no arguments provided — gather from user"] > > Working directory: [absolute path from Phase 0] > Plugin root: ${CLAUDE_PLUGIN_ROOT} > > Follow the instructions in your agent file. Validate prereqs, confirm auth, ask > the new/edit question via AskUserQuestion, then proceed accordingly. Write > genpage-plan.md to the working directory if creating. Return the page list, > entity status, app selection, and any `{ "action": "edit" }` signal when complete. ### Phase 2: Create Entities (Conditional) Read `genpage-plan.md` from the working directory. Check the **Entity Creation Required** section. **If the section literally says "No entity creation required — all entities already exist":** Skip to Phase 3. **If entities need creating:** #### 2a. Pre-flight: az + pac + Dataverse Entity creation runs through the plugin's Node.js Web API scripts using `az` for auth, and the `az` and `pac` identities should normally match. Run the consolidated pre-flight: ```bash node "${CLAUDE_PLUGIN_ROOT}/scripts/check-auth.js" ``` It returns a single JSON object: ```json { "ok": true | false, "blocker": null | "az_missing" | "az_not_logged_in" | "pac_not_logged_in" | "no_env_url" | "whoami_403" | "whoami_401" | "whoami_error", "message": "human-readable next step", "azUser": "...", "pacUser": "...", "envUrl": "...", "identitiesMatch": true | false, "whoAmI": { "ok": true, "userId": "...", "organizationId": "..." } } ``` - **`ok: true` and `identitiesMatch: true`** → proceed to 2b. - **`ok: true` and `identitiesMatch: false`** → proceed to 2b but surface the `message` to the user as an inline warning ("az is X, pac is Y — WhoAmI works for now, but if entity creation later returns 403, run the suggested `az login --username` to align them"). - **`ok: false`** → show the `message` field to the user verbatim and **stop the workflow**. The script already includes a fix-it command for every blocker (run `az login`, etc.). Capture `envUrl` from the result — Phase 2b passes it to the entity-builder. #### 2b. Invoke entity-builder Invoke the `genpage-entity-builder` agent via the `Task` tool. Pass in the prompt: - Path to `genpage-plan.md` - Working directory (absolute path) - Plugin root: `${CLAUDE_PLUGIN_ROOT}` - Dataverse env URL (from `pac org who`) The entity-builder reads `Solution` and `Publisher Prefix` directly from the plan's `## Environment` — no need to re-thread them here. Wait for completion. The builder writes a transactional log at `/entity-creation-log.md` for recovery on failure. ### Phase 3: App Creation/Selection Read `genpage-plan.md` for the app decision and the `Solution` line in `## Environment`. **If "create new":** ```powershell pac model create --name "App Name" --solution "" --publish ``` **`--solution` is mandatory.** `pac model create` errors out with `"The given solution name is not valid: ()"` if you omit it — its claimed "active solution" fallback does not work in practice. **`--publish` is mandatory.** Without it the new appmodule stays in draft and the genux runtime URL errors with "app not published". - Use the plan's `Solution` value verbatim. The planner always writes one (default fallback is literally `Default`). - If the plan is somehow missing `Solution`, pass `--solution Default` — every Dataverse env has a built-in "Default Solution" by that unique name. Store the new app-id for Phase 6. **If existing app-id:** Use it directly. `pac model create` is not called, so the `Solution` line is informational only for this phase. ### Phase 4: Generate RuntimeTypes (Conditional) If any page uses Dataverse entities, generate the TypeScript schema: ```powershell pac model genpage generate-types --data-sources "entity1,entity2,..." --output-file /RuntimeTypes.ts ``` > **Windows + Bash**: Always use forward slashes in file paths (e.g., `D:/temp/RuntimeTypes.ts`). After generating, read the RuntimeTypes.ts file to verify it generated correctly. **For mock data pages only:** Skip this phase. ### Phase 5: Build Pages (Parallel) Read `genpage-plan.md` and extract the pages table. #### 5a. Validate the plan before dispatch Before invoking any builders, verify: - At least one page exists in the `## Pages` table - Every page has a `### [Page Name]` subsection in `## Per-Page Specifications` - **All filenames in the `## Pages` table are unique.** If any are duplicated, rewrite the plan appending `-1`, `-2`, etc. before dispatch. Duplicate filenames cause silent last-writer-wins data loss under parallel execution. See `${CLAUDE_PLUGIN_ROOT}/references/plan-schema.md` for the full contract. #### 5b. Single-page fast path (skip Task dispatch when N=1) **If the plan's Pages table contains exactly one row**, do NOT dispatch a Task subagent. Inline the page-builder workflow directly in the orchestrator: 1. Read `${CLAUDE_PLUGIN_ROOT}/references/rules.md` 2. Read the sample listed in the plan's `## Relevant Samples` 3. If the plan's Per-Page Specification has `Needs caching: true`, also read `${CLAUDE_PLUGIN_ROOT}/references/data-caching.md` 4. If the plan's `## Environment` indicates non-English languages, also read `${CLAUDE_PLUGIN_ROOT}/references/localization.md` 5. Read `genpage-plan.md` (already in working directory) and `RuntimeTypes.ts` if Data mode is dataverse 6. Write the `.tsx` file to `/.tsx` following all rules 7. After writing, Grep every named import from `@fluentui/react-icons` against `${CLAUDE_PLUGIN_ROOT}/references/verified-icons.txt` (one Grep per name). Rewrite any unverified names with the closest verified alternative; do not load the full icon list into context 8. Proceed to Phase 6 This saves ~5-15s of Task overhead and ~3K tokens that would otherwise be duplicated in a subagent context. #### 5c. Multi-page: invoke page-builders in parallel **If the plan's Pages table contains 2+ rows**, invoke a `genpage-page-builder` agent via the `Task` tool per page. **Fire all invocations in a single message** for parallel execution. For each page, pass a prompt that includes: - Page name (e.g., "Candidate Tracker") - Target file name (e.g., "candidate-tracker.tsx") - Absolute path to `genpage-plan.md` - Data mode (see below) — either a RuntimeTypes path or an explicit mock flag - Working directory - Plugin root: `${CLAUDE_PLUGIN_ROOT}` **For Dataverse pages**, include the RuntimeTypes line: > You are the genpage-page-builder agent. Generate the **[Page Name]** page. > > - Target file: [filename].tsx > - Plan document: [absolute path to genpage-plan.md] > - Data mode: **dataverse** > - RuntimeTypes: [absolute path to RuntimeTypes.ts] > - Working directory: [absolute path from Phase 0] > - Plugin root: ${CLAUDE_PLUGIN_ROOT} > > Follow the instructions in your agent file. Write [filename].tsx and return your > result when done. **For mock data pages**, omit the RuntimeTypes line and set `Data mode: mock`: > You are the genpage-page-builder agent. Generate the **[Page Name]** page. > > - Target file: [filename].tsx > - Plan document: [absolute path to genpage-plan.md] > - Data mode: **mock** > - Working directory: [absolute path from Phase 0] > - Plugin root: ${CLAUDE_PLUGIN_ROOT} > > Follow the instructions in your agent file. Write [filename].tsx and return your > result when done. Wait for all page-builder tasks to complete before proceeding. ### Phase 6: Deploy For each `.tsx` file produced, deploy to Power Apps. **Copy the upload commands below exactly — `--app-id`, `--code-file`, `--prompt`, `--agent-message` are all required and must use these exact flag names.** **Log the full command verbatim into `workflow-log.md` under a `## Phase 6 — Deploy` section before invoking it.** Including `--prompt` and all other flags. The eval harness greps the log for these tokens — a terse summary like `Command: pac model genpage upload --add-to-sitemap` will fail the `--prompt scoping` assertion. Format: ```markdown ## Phase 6 — Deploy - Command: `pac model genpage upload --app-id --code-file --data-sources '' --prompt "" --model --name "" --agent-message "" --add-to-sitemap` - Result: page-id = , status = success ``` #### `--prompt` semantics - **First upload** (`--add-to-sitemap`, no `--page-id`): full page description from plan's `## User Requirements`. - **Any subsequent upload** (`--page-id`, no `--add-to-sitemap`): delta only — the changes in this upload, written like a commit message, never a re-statement of the original. Applies in Phase 6 updates, Phase 6.5 PAGEREF re-uploads, Phase 7.5 fix re-deploys, and the entire edit flow. #### For Dataverse entity pages (first upload — create): ```powershell pac model genpage upload ` --app-id ` --code-file /.tsx ` --name "Page Display Name" ` --data-sources "entity1,entity2" ` --prompt "" ` --model "" ` --agent-message "Description of what was built and any relevant details" ` --add-to-sitemap ``` **For mock data pages:** Same but omit `--data-sources`. #### For updating existing pages (subsequent upload): Use `--page-id`, omit `--add-to-sitemap`, and **scope `--prompt` to the delta only**: ```powershell pac model genpage upload ` --app-id ` --page-id ` --code-file /.tsx ` --data-sources "entity1,entity2" ` --prompt "" ` --model "" ` --agent-message "Description of what was changed in this upload" ``` ### Phase 6.5: Navigation Fix-Up (Multi-Page Only) Runs only when the plan has 2+ pages AND any built `.tsx` contains a `PAGEREF_` token. Page-builders emit `pageId: "PAGEREF_"` as a placeholder because GUIDs don't exist until after Phase 6 (see Rule 13). This phase substitutes the real GUIDs. #### Steps 1. Build `filename-without-tsx → page-id` map from Phase 6 upload output. 2. **Sort keys by length descending** so `PAGEREF_pet` can't match inside `PAGEREF_pet-gallery`. 3. For each `.tsx` in `/*.tsx` (top level only, no recursion), replace every quoted `"PAGEREF_"` (must be in double quotes — that's the format page-builders emit) with `""`. 4. If a placeholder doesn't match any map key (typo, missing sibling), stop and report — never silently ship the literal string. 5. Re-upload only the files that had at least one replacement. Use the update form of `pac model genpage upload` (`--page-id`, no `--add-to-sitemap`). Per the "`--prompt` semantics" rule in Phase 6, this is an **update**, so `--prompt` describes the delta only — not the original page description: ```powershell pac model genpage upload ` --app-id ` --page-id ` --code-file /.tsx ` --data-sources "entity1,entity2" ` --prompt "Resolve cross-page navigation placeholders to real page GUIDs (post-deploy fix-up)" ` --model "" ` --agent-message "Replaced PAGEREF_ tokens with actual page IDs returned by Phase 6" ``` Pages with no `PAGEREF_` strings need no second upload. ### Phase 7: Verify in Browser (Optional) After successful deployment, ask the user via `AskUserQuestion`: > "Would you like to verify the page(s) in the browser using Playwright?" Options: **Yes, verify in browser** / **Skip verification** - If the user picks **Skip verification** → jump to Phase 8. - If the user picks **Yes** → read `${CLAUDE_PLUGIN_ROOT}/skills/genpage/verify-flow.md` for the full Playwright verification workflow (navigate, structural verification including below-the-fold, interactive testing, screenshots, fix-and-redeploy). The orchestrator only loads that file on demand to keep context lean when verification is skipped. ### Phase 8: Summary By Phase 8 the `workflow-log.md` should already contain Phase 0 through Phase 7 sections written incrementally — the planner writes Phase 1 inside its agent context, you (the orchestrator) write Phase 0 / 0.5 / 3 / 4 / 6 / 6.5 / 7 as each runs, and the entity-builder and page-builder agents append their own Phase 2 / 5 sections when invoked. In Phase 8, append a final `## Phase 8 — Summary` section to the same file: ```markdown ## Phase 8 — Summary | Page | File | Entities | Status | |------|------|----------|--------| | | .tsx | | Deployed | - App: () - Entities created: - Browser verification: > ``` The log MUST contain command-level entries for every prereq / auth / question / upload / script invocation — not just outcome summaries. The eval harness greps the log for tokens like `node --version`, `pac auth list`, `AskUserQuestion`, `EnterPlanMode`, `--prompt`, `check-auth.js`, etc. A decision-only log (e.g., `Decision: new page` without the underlying `AskUserQuestion`) will fail Layer 1 assertions even when the agent's behavior was correct. Then present a final summary to the user: ``` ## Genpage Complete | Page | File | Entities | Status | |------|------|----------|--------| | [Name] | [file].tsx | [entities or "mock data"] | Deployed | App: [app name] ([app-id]) Screenshots: [if verification was done] Next steps: Share with team, iterate on design, create additional pages ``` --- ## Edit Flow For the edit flow (triggered when the `genpage-planner` returns `{ "action": "edit" }`), see [edit-flow.md](edit-flow.md) in this folder. The edit flow has its own 8 phases (Edit Phase 1-8): discover and select target app + page via `pac model list` + `pac model genpage list`, download, generate RuntimeTypes if needed, invoke `genpage-edit-planner`, apply the edit inline, deploy, verify, summarize.