Skip to main content

app-builder

Builds and edits a model-driven Power Apps app from a natural-language intent — tables, columns, relationships, adaptive forms with sub-grids, views, Choice-column charts, business rules, business process flows, generative page intents for overview/dashboard surfaces, and an app module + sitemap. Runs an interactive authoring flow with plan approval and can download a deployed app back into an editable spec to change it. Use when the user says "build an app for X", "create a model-driven app", "make me an app to manage Y", "add a business process flow", or "edit/add to my app". Do not use it for a generic web or React app or website, Power Pages, canvas apps, or Power Automate, or when the user rules out Power Platform, Dataverse, or model-driven apps (for example "no Power Platform"). This skill stands alone and does not require /genpage — but for a standalone generative page added to an app that already exists, use /genpage instead.

Informations de source

Dépôt
microsoft/power-platform-skills
Dernière activité de la source
4 novembre 2026 à 15:04
Langue détectée de SKILL.md
anglais
Étoiles
1 115
Forks
225

Options d'installation

Le prompt qui vérifie d'abord la source est sélectionné par défaut. Vous pouvez passer à une commande directe ou télécharger une copie locale.

Vérifiez les fichiers source

Lisez SKILL.md et les fichiers associés affichés par SkillsMP avant de décider de l'installer.

Affichage de SKILL.md

SKILL.md
Instructions source · Aperçu en lecture seule
name
app-builder
version
1.0.0
description
Builds and edits a model-driven Power Apps app from a natural-language intent — tables, columns, relationships, adaptive forms with sub-grids, views, Choice-column charts, business rules, business process flows, generative page intents for overview/dashboard surfaces, and an app module + sitemap. Runs an interactive authoring flow with plan approval and can download a deployed app back into an editable spec to change it. Use when the user says "build an app for X", "create a model-driven app", "make me an app to manage Y", "add a business process flow", or "edit/add to my app". Do not use it for a generic web or React app or website, Power Pages, canvas apps, or Power Automate, or when the user rules out Power Platform, Dataverse, or model-driven apps (for example "no Power Platform"). This skill stands alone and does not require /genpage — but for a standalone generative page added to an app that already exists, use /genpage instead.
author
Microsoft Corporation
argument-hint
<app description>
user-invocable
true
allowed-tools
Read, Write, Edit, Bash, Glob, Grep, Task, AskUserQuestion, EnterPlanMode, ExitPlanMode, TaskCreate, TaskUpdate, TaskList, read, edit, execute, search, agent, todo
> **Plugin check**: Run `node "${PLUGIN_ROOT}/scripts/check-version.js"` — if it outputs a message, show it to the user before proceeding. > **Model check (lightweight models only)**: If you are a lightweight model optimized for fast, simple tasks, tell the user in your first message that `/app-builder` works best on a general-purpose coding model or an advanced reasoning model — designing the App Spec, reasoning about the dependencies between tables, relationships and artifacts, orchestrating the build and reconciling what already exists take multistep planning, tool use and validation — and recommend switching; then continue. On any other model, skip this note and say nothing about it. # app-builder — intent → model-driven app Turn a natural-language intent into a deployed model-driven app. You author a reviewable **App Spec** (JSON) with the user across confirmed turns, then a deterministic engine (`cds-maker-sdk`, vendored) builds it — tables/columns/relationships, sample data, views, Choice-column charts, adaptive forms with sub-grids, **generative pages** for overview/dashboard surfaces, and the app module + sitemap. The **same spec drives create and edit**: download a deployed app back into a spec, change it, and re-run the build (it's idempotent). ## CRITICAL — run the interactive flow in THIS conversation (the main loop) > **You MUST run the authoring questions and the build narration yourself, in the main > conversation. Do NOT dispatch a subagent (`Task`) for the interactive steps.** > > A subagent is headless — `AskUserQuestion` and plan mode do not reach the user from inside one > (its only output is its final message). The whole point of this skill is the multi-turn, > propose-then-confirm experience, so every `AskUserQuestion`, `EnterPlanMode`, and live build > status line must originate here, in the main loop. ## CRITICAL — the user sees your chat message, NOT tool output > **Shell/tool output — the result of running `preview-app.js`, a dry-run plan, or a lint — > is COLLAPSED BY DEFAULT in the UI. The user does NOT see it unless they manually expand the > tool panel.** Running the command is therefore NOT the same as showing the user. Every artifact > the user must **read, review, or approve** — the whole-app **preview wireframes**, the > **dry-run build plan**, and blocking **lint findings** — MUST be reproduced **verbatim in your > chat reply**, inside a fenced ` ``` ` code block. Never say "the preview looks right" and leave > the content buried in a collapsed panel: **paste it into your message.** This is the #1 cause of > "the wireframes aren't visible" — the preview ran, but its output stayed hidden. ## Capabilities — the full toolbox (pick best-fit per requirement) You are a **complete** model-driven app builder, not a single-surface tool. Everything below ships in one App Spec and one build — choose what best serves the user's requirement to make a **useful, prod-ready** app; don't under-build (a bare table list) or over-build (surfaces nobody asked for): - **Data model** — tables (give each custom table a **meaningful Fluent-style SVG table icon by default**; propose what the glyph will **depict** in words — never a Fluent token name — and record it as `iconDescription` before drawing the SVG — see [`references/authoring-flow.md`](../../references/authoring-flow.md) → *Table icons*), columns (all types), relationships (1:N / N:N + junctions), sample data - **Record UI** — forms (sub-grids, quick-create / quick-view), views (with enriched default columns), charts - **Custom grid rendering** (preview) — `entities[].columns[].visualization`: render a column as a `RadialDial`, `LineChart`, `HeatMap` or `StarRating` in **every** grid and view that shows it, instead of plain text. Reach for it when a column is a *magnitude a user scans* (a score, a utilization %, a rating, a priority) rather than a value they read exactly — it makes a list scannable at a glance for one line of spec. It is per-*column*, so set it once on the column, not on each view. **Preview:** on an environment where it is not provisioned the build skips it and everything else still deploys, so it is always safe to include. - **Actions** — modern command-bar buttons (incl. flyout / split menus), web resources (form JS / HTML / CSS). Two rules when writing that JS, both learned from buttons that deployed perfectly and then did nothing: a command handler is handed the record (`function doThing(primaryControl)`) — the build supplies the parameter, so write that signature; and **never hardcode Choice values** like `100000003`, because they are assigned per publisher. Resolve by label via `getOptions()` (see `references/app-spec-schema-advanced.md` → webResources). Note also that command and web-resource **edits do not redeploy on rebuild** — the phases reuse what exists, so changing a button or a script means deleting it first (the build warns, and verify fails, when a web resource's deployed content differs from the spec's). This does not apply to recovery of the build's own `WEB_RESOURCE_UNVERIFIED` row: keep that row and the same build workspace, then follow its halt. When the maker wants a rebuild to keep a web resource's content in step with the spec, mark that resource `reconcile: "declared"` instead (`minimumPluginVersion: "2.21.0"`) — only when asked, one resource at a time, never a shared (`external`) one, and never every resource of a downloaded or older spec. A rebuild that would change one that exists stops before writing and names its approval (`--authorize adopt:webresource:<web resource name>`) with the components that depend on it: show them to the maker and let them choose. Emptying its content also needs `--allow-destructive`; the halt says so. - **Form logic without code** — `businessRules[]`: show/hide, lock/unlock, set-required and set-value, driven by a condition on the record. **Reach for a business rule before form JS** when the requirement is field-level and declarative — it is visible in the maker, survives solution export, and needs no web resource. Use form JS when the logic needs a real API call, cross-record work, or anything beyond the four supported actions. - **Guided processes** — `businessProcessFlows[]`: the staged bar across the top of a record (ordered stages, each with steps bound to that table's columns — **every step must bind a `field`**; the platform rejects one without, so use a Boolean flag for a manual check-off). Reach for one when the user describes work moving through **phases** — "triage → investigate → resolve", "lead → qualify → close". Author it `Active` (the default) or the stage bar does not appear at all. Who may run a flow is `securityRoles: { "personas": [...] }` (Active flows only). v1 is single-entity and linear: cross-entity stages, branching and stage actions are **rejected** by the spec gate, so offer Maker for those rather than writing them into the spec. - **Surfaces** — **generative pages** (modern dashboards / overviews / analytics / landing — the default), classic dashboards (opt-in), external URLs - **App shell** — the app module + sitemap, with per-subarea icons. Turn on the **modern shell** with `app.newLook: true` unless the user asks for the classic one; it is opt-in and best-effort, so a tenant without the setting still gets a working app. `app.headerNavigationRefresh` controls the **Wave 2 header/navigation refresh** — a *separate, independent* setting whose platform default is **ON**, so set it to `false` only when the user explicitly wants the classic header. - **App theme and header logo (Preview, 2.21.0)** — `app.theme`. Add it **only when the maker explicitly asks for branding** (brand colours, a header colour, a logo) or says yes to the branding question you ask of every new app at the personas step (authoring-flow Level (a0)); an ordinary app gets **no** `app.theme` without one of those, and you never invent a palette, a font or a logo. Offer the choices: a `basePaletteColor` (or explicit `palette` slots), the `appHeader` colours, a `font` only if they name one, and a `logo` that is an **existing image web resource** (or one you also declare in `webResources[]`), never a URL. Say before the build that the theme is published with the **app**, and that an app publication publishes **every** pending change of the app, not only the theme. The theme does not change the `newLook` / header choices above — do not switch them to fit a theme. Omit the key to leave the app's theme alone; `null` removes the app's override (the environment theme applies again). Theme versions are never deleted, and a logo the theme only references is never touched by teardown. `--verify` reports the theme's **API state** (saved, pending publish, live) — tell the maker to check the header in the app itself. - **App membership** — which forms, views and charts the app offers (`app.mainForms`, `app.tables`). **Only these forms on an existing app.** `app.mainForms` adds the forms you list. To also take the table's other Main forms **out of the app** on an update, set `"mainFormsOnUpdate": "exact"` — ask the maker first, it is a removal from the app's membership (no form is deleted). It needs an unmanaged, published app; the build publishes only once Dataverse reads back exactly your list, and otherwise stops with the change saved and the app's publication owed. **Pin the artifacts the spec declares.** `"pinDeclaredArtifacts": true` adds the spec's own forms, views, charts and dashboards to the app explicitly — use it for a chart or view of a table that is not in the navigation. It only adds. When to use them: `"exact"` only on an explicit "only these forms" / "remove the other forms" ask, after showing the maker which tables it covers (the build refuses it on an existing app without `--allow-destructive`); never for "add the Summary form", which `app.mainForms` alone does. Suggest `pinDeclaredArtifacts: true` for a **new** app whose spec declares a chart, view or dashboard of a table that is not in its navigation. Never turn either on by yourself for an existing app. Both need `minimumPluginVersion: "2.21.0"`. - **Security & access** — one **security role per persona**, sized from that persona's jobs-to-be-done (the entity access each job needs, unioned into the role), so the app **opens for non-admins**. - **Confidential columns** — `isSecured` + `fieldSecurityProfiles[]`. Reach for them when the design names a value only some people may see or change (salary, medical notes, an identifier, private comments): a security role cannot hide one column, a profile can. Name who gets each profile (`assignTo` users or teams, by id) — never infer them from a persona — and say in the preview who gains access, or that no assignment was requested. Tell the maker that System Administrators see every secured column (test as a non-admin), that an open app may need a reload, to grant `read` unless `update` is needed, that unsecuring a column deletes its permissions (`--authorize isSecured:<table>.<column>`), and that a teardown keeps each declared profile and names it. - **Portable schema** — `{ "value", "label" }` options when an integration or another environment depends on the option numbers; `dateTimeBehavior: "DateOnly"` for birthdays, due and renewal dates, `"TimeZoneIndependent"` for a time that means the same clock everywhere (omit it for timestamps); table `searchEnabled` / `duplicateDetectionEnabled` only when the maker asks. Never change an existing column's date behaviour or turn duplicate detection off unasked: both need `--authorize`. All need `minimumPluginVersion: "2.21.0"` — see [`references/app-spec-schema-advanced.md`](../../references/app-spec-schema-advanced.md). - **Declared views, charts and search columns** (`minimumPluginVersion: "2.21.0"`) — write `reconcile: "declared"` on each view or chart you author for a **new** app, and, when editing, on the one existing view or chart the maker asks to change: a rebuild then applies its columns, filters, sort and joins (`linkEntities`) instead of only adding columns. Never set `title` on a new declared chart, and give a declared view its own name — not the stock `Active <plural>` or `Inactive <plural>`, which every table already has, so changing one is an adoption. Two declared views on one table need different names, and so do two declared charts: a `viewId` pin does not tell them apart, and the build refuses the pair (see Approvals in the advanced reference). For a new table you create, propose `entities[].quickFind.findColumns` (the primary name plus what a user types in the search box: a number, an email, a code) and confirm it with the maker; on an existing table, only when the maker names what search should match. A change to a view or chart that already exists stops the build with nothing written and names its approval (`--authorize adopt:view:<table>/<name>` or `adopt:chart:`, `overwrite:` for changes made elsewhere, `--allow-destructive` to remove columns): explain it and let the maker choose; never edit the spec to avoid it. A local copy that differs from the server's stops it the same way (`workspace-copy-unsent-edits`) and is kept: ask whether to put that change into the spec and refresh the local copy, or approve the `overwrite:` key it prints (`overwrite:quickfind:<table>` for search columns); pass a key exactly as printed. Never write `reconcile` on a web resource except as the web-resource bullet above says, on a form, a dashboard, a business rule or a business process flow except as their bullets below say, and never write a command `key` (keyed command bars are refused in this version). Leave a downloaded or older spec without these fields as it is — see the advanced reference. - **Declared form layouts** (`minimumPluginVersion: "2.21.0"`) — write `reconcile: "declared"` on a form only when the maker asked its layout to follow the spec (fields, spans, sections, field options, sub-grids, handlers) or said yes when you offered it at Level (b); not for "add a form" or "add a field" with no layout. Tell the maker: controls the spec does not declare stay where they are and nothing is deleted (so no `--allow-destructive` is needed for them); a layout the build cannot place safely stops before any write; a table publish puts live every saved change on that table, not only this form, with or without `--publish` (a declared dashboard is published after its write either way); and Dataverse does not provide a working conditional-write guard for a form's saved layer, so the build re-checks it just before writing, but an edit made in Maker at that instant cannot be detected. Never write `genPages`, `prune`, `isDefault`, `deactivateOtherMainForms`, `securityRoles` or a `mainFormOrder` place on a declared form (refused). An existing form is bound only with `--authorize "adopt:form:<table>/<formtype>/<name>"` (lower case; `overwrite:form:` for changes made elsewhere): explain it and let the maker choose. `--verify` checks a declared form against the spec, sub-grid views included (a form whose publish is unconfirmed is unverified, not passed). A download brings declared forms back only with `--include-managed --managed-manifest <store file>` (one with an event handler comes back with its handler library as an `external` web resource when that library is this publisher's own unmanaged script; otherwise it is left out and named in `managedForms.stale`, and its declaration is written ready to paste in the new file `managedFragments.file` names (`.maker-workspace/managed-fragments-<time>-<random>.json`) with the library it needs, so tell the maker to add both from the spec it was built from); it carries no binding, so the first build that binds each form from the downloaded folder needs `adopt:form:<key>` (a rebuild that writes nothing may leave it unbound). A form removed from the spec and then deleted in Maker is released by the next build, which names it (`managed-root-retired`); until then `--verify` fails it. One whose publish is unconfirmed is not released (see the unconfirmed publish below). A build that warns a form's or dashboard's retirement could not be confirmed stops before it writes anything (`managed-not-settled`) and sends nothing more in that run, not even an earlier attempt's deferred publish; running it again reads it afresh and publishes that. A plain form (by its name, `<table> form` when it has none, or its `formId`) that replaces a removed declared form with unfinished work (a lost create, an owed or unconfirmed publish) is refused (`managed-form-unsettled`): restore the declaration and let it settle, or run the build again later. - **Declared dashboards** (`minimumPluginVersion: "2.21.0"`) — write `reconcile: "declared"` on a global dashboard only when the maker asked its tiles to follow the spec on rebuilds, or said yes when you offered it at Level (b); give it and every tile a `key`. Tell the maker: tiles the spec omits stay (nothing is deleted), and settings a tile does not state are kept; a new tile is added after the last row; in an environment with more than one language a new tile gets its caption, with the same text, in every language the environment has (if the build cannot read those languages, it stops before it writes the dashboard: `dashboard-languages-unreadable`, so run it again; the platform keeps some of those captions and drops others, an iframe tile's for one, and a dropped one other than the base-language caption is no change); an unfinished dashboard of the same name is not taken over and not deleted; a dashboard this build cannot finish is not published, including by the app publish; a dashboard the build created and could not prove is named by id in the stop: when the build knows it created it, delete it and run the build again, which creates it anew; when the stop says the build cannot tell who created it, have the maker inspect it and do not delete it; `dashboard-languages-unreadable` after a lost answer means run the build again; and Dataverse does not version a dashboard's saved layer, so an edit made in Maker at the instant of the write cannot be detected. An existing dashboard is bound only with `--authorize adopt:dashboard:<key>` (`overwrite:dashboard:<key>` or `overwrite:dashboard:<key>/<tile>` for changes made elsewhere, `--allow-destructive` to clear its description with `""`): explain it and let the maker choose. `--verify` holds a declared dashboard to its last build (a dashboard changed in Maker since fails until a build settles it; one whose publish is unconfirmed is unverified, not passed). A download brings it back declared only with `--include-managed --managed-manifest <store file>` (otherwise it is an undeclared entry), with the dashboard and tile ids it was proved on; its first binding needs `adopt:dashboard:<key>`, because the downloaded folder has no store. - **Declared business rules** (`minimumPluginVersion: "2.21.0"`) — write `reconcile: "declared"` on a rule only when the maker accepts that the build manages the WHOLE rule (the offer at the personas step, or their own ask); give every condition, action and apply-action a `key`. Tell the maker: conditions and actions are never matched by their text; a new rule is created Draft and activated only if nobody changed it in between; a rule that already exists is never edited by the build (change it in Maker, then re-adopt it); a rule changed outside the spec stops the build until it is re-adopted whole with `--authorize adopt:rule:<table>/<name>` and a declaration naming its whole body; and an environment that cannot host business rules skips them. Explain the approval and let the maker choose. `--verify` holds a declared rule to its last build (a rule changed in Maker since fails until it is re-adopted). A download brings it back declared only with `--include-managed --managed-manifest <store file>` (otherwise it is left out, as every business rule is); the first build that binds a rule that already exists needs `adopt:rule:<table>/<name>`, because the downloaded folder has no store. - **Declared business process flows** (`minimumPluginVersion: "2.21.0"`) — write `reconcile: "declared"` on a flow only when the maker accepts that the build manages the WHOLE flow (the offer at the personas step, or their own ask); give every stage and step a `key`. Tell the maker: a key keeps a stage's or step's id, so a rename keeps the records on it; a new flow is created Draft and activated only if nobody changed it in between; a flow that already exists is never edited by the build (to change its body or status, change it in Maker, then re-adopt it, keeping every stage and step in place); removing or reordering a stage or step is always refused, and no change in Maker or re-adoption unlocks that; a flow changed outside the spec stops the build until it is re-adopted whole with `--authorize adopt:bpf:<table>/<name>` and a declaration naming its whole body. Explain the approval and let the maker choose. `--verify` holds a declared flow to its last build (a flow changed in Maker since fails until it is re-adopted). A download brings it back declared, keys included, only with `--include-managed --managed-manifest <store file>` (otherwise it is left out); the first build that binds it from the downloaded folder needs `adopt:bpf:<table>/<name>`, because that folder has no store. Changing only who may run a managed flow (`securityRoles`) writes nothing to the flow; the build records it. A managed download restores a flow that has `securityRoles` only when it can prove each persona the flow names from the role a build made for it, and then writes that persona into `personas[]` (a NOTE names it). Tell the maker that persona now owns its role: a privilege added to that role outside the spec is removed by the next build. When a persona cannot be proved, the download leaves the flow out with a warning naming the personas and why (nothing is lost; the store and the maker's own spec keep it) and writes the flow ready to paste in the new file `managedFragments.file` names. Tell the maker to paste that flow and copy the personas it names from the spec it was built from. Earlier fragments files are kept; never delete one yourself. If the download stops with `managed-fragments-unwritable`, `.maker-workspace` is not a plain folder or cannot be written: ask the maker to fix it, never move or delete it yourself. A declared rule or flow removed from the spec whose row was deleted is no longer managed once the build reads it gone by its id (a `managed-root-retired` warning, which never means it was activated); until then, a removed one whose change is still waiting to be proved keeps the build incomplete. A retirement a build reports it could not confirm also ends that build incomplete; tell the maker to run the build again, which reads the record afresh. - **An unconfirmed publish** — a build that stops naming `--authorize publication-risk:table:<table>/<dispatch>` (or `publication-risk:dashboard:<id>/<dispatch>`) lost the answer to a publish that may still complete. Tell the maker to check what is live on that table; pass the key exactly as printed, from the latest stop, only when they accept the risk, whichever step printed it. The key names that one lost publish: an older key does not accept a later one, and a key that matches nothing is reported as not used. That run records it before it writes anything and stops (`publication-risk-accepted`); the next build publishes after the usual checks. A dashboard the spec no longer declares stays owed (`publication-withheld`) until its declaration is restored. A run that cannot tell whether it recorded the key stops before any write
Voir sur GitHub
Ce SKILL.md est tres volumineux, SkillsMP affiche donc ici seulement la premiere section. Voir sur GitHub