| name | scaffold-code-app |
| description | Scaffold a new Power Apps Code App — clone the Vite starter template, pin the Power Apps SDK, and initialise the app against a Power Platform environment. Use when asked to "scaffold a Code App", "set up a new Power Apps Code App", or "bootstrap the Code Apps starter". |
| metadata | {"author":"chuckytesla","version":"2.0.0","argument-hint":"-n '<app display name>' -e <environment-id>"} |
Scaffold a Power Apps Code App
Bootstraps a new Power Apps Code App
in the current directory: it clones the official Vite starter, pins the Power Apps SDK, and runs
init against your Power Platform environment. The skill is a generic engine — the app name and
environment are inputs you provide (or the agent asks for); nothing project-specific is baked into
the skill.
This skill only scaffolds — it does not sign you in and it does not push the app into a solution.
Sign-in is owned by the dataverse-scaffold-tables skill (it runs npx power-apps login); pushing
the built app into a Dataverse solution is the separate deploy-code-app skill, run last.
Inputs (provide, derive, or ask)
| Input | How it's used | If unknown |
|---|
| App display name | init -n '<name>' | Ask the user. Don't invent one. |
| Power Platform environment ID | init -e <id> | Try power.config.json (environmentId) or .env; otherwise ask the user. |
Never hardcode these — they belong to the project/user, not the skill.
Steps (run in order, from the app's root directory)
1. Clone the Code Apps starter template
npx degit github:microsoft/PowerAppsCodeApps/templates/vite --force
--force overwrites files in the current directory. Run this in the intended app root. If the
directory already has work in it, confirm with the user before overwriting.
Then install dependencies:
npm install
2. Pin the Power Apps SDK to 1.2.2
Set the @microsoft/power-apps dependency in package.json to 1.2.2 (exact). Edit the
dependencies entry directly:
"@microsoft/power-apps": "1.2.2"
Then npm install again so the lockfile and node_modules match.
3. Initialise the Code App
Populate both the app display name and the environment ID. If either is unknown, ask the user —
do not guess.
npx power-apps init -n '<APP_DISPLAY_NAME>' -e "<POWER_PLATFORM_ENVIRONMENT_ID>"
This writes power.config.json (appDisplayName, environmentId, region, etc.). Interactive
sign-in is handled later by the dataverse-scaffold-tables skill — don't run power-apps login here.
4. Set up the quality tooling (make the app verifiable)
The Vite starter ships no test runner and at most a minimal linter, but every build task is gated
by npm run verify. Make the project verifiable now, before any feature work. Do not paraphrase this
list or trust a gate that merely "looks right": the gate only protects the build if it runs the
compiler, so set the scripts exactly as below.
a. Test runner. Add Vitest + React Testing Library + jsdom, wired to npm test. Add
src/setupTests.ts importing @testing-library/jest-dom, referenced from the Vitest config.
b. Linter. Add ESLint + typescript-eslint + eslint-plugin-react-hooks (plus the Vite
react-refresh plugin the starter expects), wired to npm run lint. Set the ESLint
languageOptions.ecmaVersion to 2022 to match the app's target, not the starter's 2020.
c. The gate must typecheck. Set these package.json scripts verbatim. The typecheck step is
what catches the class of error a fast model produces (reading a response by the wrong property, a
string where a Choice integer is required, a create payload missing a required field). A gate without
it passes green while the build is broken:
"typecheck": "tsc -b",
"lint": "eslint .",
"test": "vitest",
"verify": "npm run typecheck && npm run lint && npm run test -- --run"
npm run verify must run tsc. If it only runs lint and test, type errors stay hidden until
npm run build at deploy. That is a configuration failure, the exact failure mode this harness exists
to remove.
d. Keep test types out of the app build, but still typecheck the tests. Tests must not force their
globals into the production compile, yet they must still be type-checked by the gate. Three moves:
-
In tsconfig.app.json, exclude the test files and keep types to app types only (no
vitest/globals):
"exclude": ["src/**/*.test.ts", "src/**/*.test.tsx", "src/setupTests.ts"]
-
Add a tsconfig.test.json that includes the test files and carries the test globals:
"types": ["vite/client", "vitest/globals", "@testing-library/jest-dom"].
-
Reference both from the root tsconfig.json so tsc -b (the gate's typecheck and the build's
first half) checks the app and test projects in one pass.
This is why the app build never needs vitest/globals bolted into tsconfig.app.json: the tests get
their globals from their own project, and a wrong fixture shape still fails tsc at the gate.
e. Keep the Power Apps Vite plugin (CDN-safe asset base path). The template's vite.config.ts
includes powerApps() from @microsoft/power-apps-vite. Leave it in the plugins array. A Code
App is served from the Power Platform CDN at a non-root base path, and this plugin sets the asset base
so Vite's bundled asset URLs and images resolve once deployed. Remove it (or drop the base) and the
app's images and hashed assets 404 on the CDN. If a project ever does not use the plugin, set
base: './' in vite.config.ts instead. Images are referenced by bundled import from src/, not
from public/ by absolute path (see the instantiation's "Brand assets and wiring").
See AGENTS.md (repo root) → Stack notes for the exact pins and the test-authoring rules (typed
fixtures, one un-mocked smoke render). After this, npm run verify runs clean on the empty app, so
the first task gate (Task 1) has a working harness to run against rather than being set up live.
After scaffolding
- Verify
power.config.json has the expected appDisplayName and environmentId.
- Confirm
package.json shows @microsoft/power-apps at 1.2.2.
- Confirm
npm run verify runs clean on the empty app, so the gate is ready before Task 1.
- Next, scaffold/seed the Dataverse tables and add them as data sources — the
dataverse-scaffold-tables skill signs you in (npx power-apps login) before it creates the
schema, then dataverse-create-records and dataverse-add-data-source wire the data in.
- To publish the app into a solution, use the separate
deploy-code-app skill (build + push) —
run it last, after the tables are scaffolded into that same solution.