| name | custom-frontend-psu |
| description | Build PowerShell Universal experiences with a standard JavaScript, HTML, and CSS frontend hosted by PowerShell Universal published folders, while using PSU custom API endpoints or the Management API as the backend. Use this skill when a user wants React, Vue, Angular, Svelte, Vite, Tailwind, Bootstrap, or other frontend libraries instead of generating PowerShell Universal App Framework code directly. |
custom-frontend-psu
Use PowerShell Universal (PSU) as the backend and static file host for a custom frontend built with standard web tooling. This approach is for projects where the frontend should be ordinary HTML, CSS, and JavaScript, while PSU provides authentication, authorization, APIs, automation, jobs, scripts, and hosting.
The goal is to build a conventional static web application, publish its compiled output with New-PSUPublishedFolder, and call PSU APIs from the browser. Avoid producing PSU App Framework code unless the user explicitly asks for it.
When to use
- The user wants a PSU-backed app but asks for React, Vue, Angular, Svelte, Vite, vanilla JavaScript, Tailwind CSS, Bootstrap, Bulma, or another standard frontend library.
- The user wants full control over client-side layout, routing, assets, styling, or component libraries.
- The user wants an AI-generated UI but does not want PowerShell Universal App Framework components.
- The frontend should call PSU custom endpoints, scripts, jobs, or the Management API.
- The output can be hosted as static files from a PSU published folder.
Avoid this skill when
- The user specifically asks for a PowerShell Universal App Framework app, dashboard, or component implementation.
- The app must be authored entirely as PSU app PowerShell code.
- The task is only about configuring a published folder and has no custom frontend concerns.
Gather requirements first
If the request is incomplete, ask only for the missing details that materially affect implementation:
- Frontend framework and package manager, such as React with Vite, Vue, Angular, Svelte, vanilla JavaScript, npm, pnpm, or yarn.
- Published folder request path, such as
/dashboard, /tools/inventory, or /reports.
- API routes the frontend should call and the expected JSON shapes.
- Authentication requirements for the frontend files and for each API endpoint.
- Required roles or role-specific UI behavior.
- Build output folder, such as
dist, build, or wwwroot.
- Whether development should use a local frontend dev server, a PSU sandbox, or an existing PSU instance.
Do not ask for all of these when the user has already provided enough context. Choose sensible defaults that fit the framework and the existing repository.
Architecture
Create two clear pieces:
- A static frontend built with normal web tooling.
- PSU backend configuration that exposes data and actions through custom API endpoints, and publishes the compiled frontend output.
Prefer this flow:
- Scaffold or update the frontend project.
- Configure the frontend build base path to match the PSU published folder request path.
- Implement API calls with relative URLs and
credentials: 'same-origin'.
- Add or update PSU custom API endpoints for application-specific data and actions.
- Build the frontend.
- Publish only the compiled output folder with
New-PSUPublishedFolder.
- Verify the production build and the hosted path.
Request path and base path
Always align the frontend build base path with the PSU published folder request path.
Use a request path that does not conflict with PSU routes. Avoid /portal because it conflicts with the built-in PowerShell Universal Portal. Avoid custom endpoint URLs that conflict with /api/v1 Management API routes.
For Vite applications, set base in vite.config.ts or vite.config.js.
import { defineConfig } from 'vite'
export default defineConfig({
base: '/dashboard/'
})
For Angular applications, set the base href during the build.
ng build --base-href /dashboard/
If the app uses client-side routing, configure the router to use the published request path. Use hash-based routing when direct deep links do not need server-side fallback behavior.
Frontend API calls
Use relative URLs in production so calls return to the same PSU instance that served the frontend.
For authenticated endpoints, include same-origin credentials.
const response = await fetch('/frontend/profile', {
credentials: 'same-origin'
})
if (!response.ok) {
throw new Error(`Request failed: ${response.status}`)
}
const profile = await response.json()
For JSON requests, send Content-Type: application/json and serialize the request body.
await fetch('/frontend/tickets', {
method: 'POST',
credentials: 'same-origin',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({ title: 'Reset development environment' })
})
Implement loading, error, empty, and unauthorized states in the frontend. Do not leave backend errors invisible to the user.
PSU custom endpoints
Use custom API endpoints for most application-specific frontend calls. They keep the browser contract small and let PSU handle validation, role checks, and server-side logic.
New-PSUEndpoint -Url '/frontend/profile' -Method Get -Authentication -Endpoint {
[PSCustomObject]@{
UserName = $User.Identity.Name
ServerTime = Get-Date
}
}
For JSON POST requests, parse $Body or define a param block that matches the endpoint binding style used by the target PSU version and repository.
New-PSUEndpoint -Url '/frontend/tickets' -Method Post -Authentication -Endpoint {
$Ticket = ConvertFrom-Json $Body
[PSCustomObject]@{
Id = [guid]::NewGuid()
Title = $Ticket.Title
Created = Get-Date
}
}
For user-facing workflows, prefer a purpose-built custom endpoint over direct browser calls to broad administrative APIs. Use the PSU Management API under /api/v1 only when building an administrative frontend for users with the required permissions.
Authentication and security
Published folders and API endpoints can require authentication and roles independently.
Protect the frontend files when users must sign in before loading the UI.
New-PSUPublishedFolder -Name 'Dashboard' -Path 'C:\Apps\Dashboard\dist' -RequestPath '/dashboard' -DefaultDocument 'index.html' -Authentication -Role 'Operator'
Protect backend endpoints separately. Do not rely on hiding UI controls as the only authorization boundary.
New-PSUEndpoint -Url '/frontend/admin-data' -Method Get -Authentication -Role 'Administrator' -Endpoint {
Get-Date
}
Never embed app tokens in browser JavaScript, local storage, frontend configuration files, generated bundles, or source control. App tokens are for automation, trusted clients, server-to-server calls, or controlled administrative scenarios. If the browser needs an elevated operation, create a custom authenticated endpoint that performs the operation server-side.
When a trusted non-browser client needs an app token, use the Authorization header.
Authorization: Bearer <app-token>
Use X-PSU-Authorization only for scenarios where a reverse proxy or upstream component needs the standard Authorization header for another purpose.
Hosting with published folders
Publish the compiled output folder, not the frontend source folder.
New-PSUPublishedFolder -Name 'Dashboard' -Path 'C:\Apps\Dashboard\dist' -RequestPath '/dashboard' -DefaultDocument 'index.html'
The -DefaultDocument value should usually be index.html for single-page applications. Static assets, generated JavaScript chunks, fonts, and images can live inside the same output folder. If shared assets are needed across multiple frontends, publish a separate folder such as /assets.
Do not publish source directories containing .env files, package metadata, lock files, framework configuration, source maps with sensitive paths, test fixtures, or other files that should not be downloadable. If source maps are generated, decide whether they are acceptable for the deployment environment.
Development workflow
During development, it is fine to run the frontend framework's dev server and call PSU APIs from the browser. If the frontend dev server uses a different origin than PSU, configure one of these:
- PSU
CorsHosts for the frontend dev server origin.
- The frontend dev server's proxy feature so API requests are proxied to PSU.
In production, prefer relative URLs rather than hard-coded hosts.
If a disposable PSU instance is useful for testing, use the install-sandbox-psu skill when available to run an isolated PSU sandbox, then publish the frontend output and backend endpoints into that sandbox.
Implementation checklist
- Confirm or choose the frontend framework, published request path, and build output folder.
- Configure the bundler base path to match the published request path.
- Use same-origin
fetch calls for production API access.
- Add PSU custom endpoints for frontend-specific data and actions.
- Add authentication and role requirements to both published folders and API endpoints as needed.
- Keep app tokens out of browser code and generated assets.
- Build the frontend and publish only the generated output folder.
- Verify the hosted root path, static assets, API calls, authentication behavior, and client-side routes.
Useful prompt pattern
When delegating frontend implementation to another agent or tool, include PSU constraints in the prompt.
Build a React and Vite frontend for PowerShell Universal. It will be hosted at /dashboard from a published folder. Configure the Vite base path for /dashboard/. Use relative fetch calls to /frontend/profile and /frontend/tickets with same-origin credentials. Do not store app tokens in the browser. Include loading, error, empty, and unauthorized states.
Final response guidance
When reporting completion to the user, include:
- The frontend framework and build command used.
- The PSU published folder command or file changed.
- The API endpoint routes created or expected.
- Any authentication or role requirements configured.
- Any verification that was run, such as production build, local dev server, browser check, or PSU endpoint test.