From pgedge-skills
Use when the user asks to scaffold, set up, create, or bootstrap a new full-stack pgEdge web application or web client. Trigger on phrases like 'new web app', 'scaffold a frontend', 'set up a React app', 'new pgEdge web project', 'create a new client', or when working in an empty/new directory and the user mentions React, MUI, or login pages in the context of starting from scratch. Do NOT trigger for edits to an existing app, for adding a single component, or for purely backend Go work.
How this skill is triggered — by the user, by Claude, or both
Slash command
/pgedge-skills:pgedge-webappThe summary Claude sees in its skill listing — used to decide when to auto-load this skill
This skill scaffolds a full-stack pgEdge web application from a single
PLACEHOLDERS.mdtemplate/Makefiletemplate/README.mdtemplate/client/eslint.config.jstemplate/client/index.htmltemplate/client/package.jsontemplate/client/public/favicon.icotemplate/client/src/App.test.tsxtemplate/client/src/App.tsxtemplate/client/src/assets/images/logo-dark.pngtemplate/client/src/assets/images/logo-light.pngtemplate/client/src/components/EllieChatPanel/ChatFAB.tsxtemplate/client/src/components/EllieChatPanel/ChatInput.tsxtemplate/client/src/components/EllieChatPanel/ChatMessage.tsxtemplate/client/src/components/EllieChatPanel/__tests__/ChatMessage.test.tsxtemplate/client/src/components/EllieChatPanel/__tests__/EllieChatPanel.test.tsxtemplate/client/src/components/EllieChatPanel/index.tsxtemplate/client/src/components/ErrorBoundary.tsxtemplate/client/src/components/Header.tsxtemplate/client/src/components/Header/ChangePasswordDialog.tsxThis skill scaffolds a full-stack pgEdge web application from a single template tree. The scaffolded project ships with locked-in design, configuration, accessibility, and test-coverage conventions. Every future pgEdge web app inherits the same UI patterns, the same form-label CSS, the same auth flow, and the same 90% coverage gate.
Activates when the user asks to scaffold, bootstrap, or set up a new full-stack pgEdge web application. Does not activate when editing an existing app, when adding a single component, or for backend-only work.
The skill copies the entire template/ tree wholesale into the target
directory, then walks the result to substitute placeholders.
Ask one question at a time. Validate as you go. Defaults are shown in parentheses.
<PROJECT_NAME> — the docs
theme already shows the pgEdge logo, so re-adding the prefix to the
project name doubles it up. Result must be the same regardless of
whether the user supplied "pgEdge My App" or just "My App".^[a-z][a-z0-9-]*$.my-app-server)./.org/repo slug used in the README's CI badge URLs).
When the module path starts with github.com/, default to the next
two path segments (e.g. github.com/pgEdge/foo/server/src →
pgEdge/foo); otherwise prompt.Execute the following steps in order. Surface any failure verbatim and stop. Do not report success on a broken scaffold.
cp -r operation.PLACEHOLDERS.md.tools/genhash <password> to produce the bcrypt hash, then
substitute <SEEDED_ADMIN_PASSWORD_HASH> in
server/src/cmd/<binary>/seed.go.client/src/App.tsx to import EllieChatPanel and ChatFAB,
add useState for chatOpen, and render both inside the main
layout. Concrete diff is in the Wiring Ellie section below.go build ./...,
go vet ./..., npm install, npm run typecheck,
npm run lint. Surface any error.go test -race ./... and
npm run test:coverage. Confirm both report 90%+ coverage.http://localhost:5173 for
vite, http://localhost:<port> for the server), the seeded
admin username (do not print the password), a reminder to
rotate the seed password after first login.pgedge-docs.These rules are non-negotiable and apply during scaffolding and during later edits to projects scaffolded from this template.
Every <TextField>, <Select>, and <Autocomplete> must use:
<TextField
label="..."
InputLabelProps={{ shrink: true }}
sx={{ ...textFieldSx, ...SELECT_FIELD_SX }}
/>
Use SELECT_FIELD_SX for fields on background.paper surfaces (dialogs,
cards). Use SELECT_FIELD_DEFAULT_BG_SX for fields on
background.default (full-page panels). For other surfaces, call
getSelectFieldSx('your.bg.color') rather than inventing styles. The
textFieldSx per-component object provides hover and focus border
colors; copy the pattern from WelcomeCard.tsx.
pgedgeTheme.ts. No raw hex inline.theme.spacing(). No raw px for spacing.theme.shape.borderRadius.localStorage['theme-mode']. Components check
theme.palette.mode === 'dark' via useTheme(), not
prefers-color-scheme.Every component file declares its sx objects as named constants at
the top of the file before the component body, with banner comments
delimiting the section. Theme-aware styles are factory functions:
const getAppBarSx = (theme: Theme) => ({ ... }).
ComponentName/index.tsx plus peer files plus __tests__/.__tests__/ directories.ContextName.tsx, consumer hook in
useContextName.ts (separate files for fast-refresh).import type.All HTTP requests go through apiClient.ts. All requests use
credentials: 'include'. Errors are Error instances and surface via
<Alert severity="error">. Response types are explicit generics — no
any.
fmt.Errorf("doing X: %w", err).http.Handler interfaces, not raw functions.os.Getenv calls in cmd/, internal/config/, or
internal/auth/. Configuration enters via CLI flags and YAML only.*slog.Logger. No log.Print*, no
global logger.SELECT_FIELD_SX.No comments restating what code does. Comments earn their place by explaining a non-obvious why: a workaround, an invariant, a load-bearing constraint.
Scaffolded projects ship with .devcontainer/devcontainer.json plus
post-create.sh, mirroring the pgedge-skills repo's own pattern. The
container provisions Go 1.26 and Node 24, installs Helm via
post-create.sh, runs go mod download and npm ci so the dev loop
starts hot, and forwards the templated HTTP port. The
overrideFeatureInstallOrder block is load-bearing — it ensures Node
lands on PATH before later steps. Do not remove or reorder it.
WCAG 2.1 AA at minimum. Tests assert zero AA violations via vitest-axe. Hard rules:
<IconButton> carries an explicit aria-label.<TextField label> or
explicit htmlFor/id.aria-labelledby.<CircularProgress aria-label="Loading application" />).onClick on a generic <div>/<Box> without role/tabIndex/
onKeyDown — use <Button> or <IconButton> instead.@media (prefers-reduced-motion: no-preference) so they resolve to
static positions when the user prefers reduced motion.vitest.config.js enforces 90% on lines/branches/functions/
statements. Excluded: src/test/, src/main.tsx, config files.make coverage-check runs the local
tools/coverage-check and fails below 90%. Excluded:
cmd/<binary>/main.go. Adding new exclusions requires reviewer
approval — flag any such request.renderWithTheme, never raw render from RTL.fetch globally via vi.fn() in beforeEach.screen.getByRole / getByLabelText over getByTestId.The template ships with three GitHub Actions workflows:
.github/workflows/ci-server.yml — Go 1.26: go mod verify, vet,
gofmt, golangci-lint, build, coverage gate..github/workflows/ci-client.yml — Node 22 + 24 matrix:
typecheck, lint, test:coverage..github/workflows/ci-docs.yml — mkdocs build --strict with
mkdocs-material + mkdocs-redoc-tag. Requires the project's docs site
to be scaffolded by pgedge-docs; skips silently when no
docs/** paths changed.The template README.md carries badges for all three. Substitute
<GITHUB_REPO> so the URLs resolve.
Both run lint, vet/typecheck, build, and the coverage gate. Coverage
artifacts are uploaded from the latest version of each runtime.
If the user opted to include Ellie, edit client/src/App.tsx and:
import EllieChatPanel from './components/EllieChatPanel';
import ChatFAB from './components/EllieChatPanel/ChatFAB';
AppContent, after the useEffect that persists mode,
add:const [chatOpen, setChatOpen] = useState(false);
<Box sx={styles.mainLayoutBody}>,
add <EllieChatPanel open={chatOpen} onClose={() => setChatOpen(false)} />
alongside <WelcomeCard />. After the closing </Box> for
mainLayoutBody, before the closing </Box> for
mainLayoutRoot, add:<ChatFAB onClick={() => setChatOpen(true)} isOpen={chatOpen} />
ellie_wired: true in .pgedge-webapp.json.After scaffolding, ask: "Scaffold user-facing documentation now?" On
yes, invoke pgedge-docs. The docs skill recognizes the
.pgedge-webapp.json marker and applies its In-App Help Panel rules
when authoring content under client/src/components/HelpPanel/pages/.
Print files-created counts, commands to run, URLs, admin username (not the password), the rotate-the-password reminder, and a one-line note about pgedge-docs availability if the user declined the hand-off.
When the skill is reinvoked on a project containing
.pgedge-webapp.json, run a consistency check before any edit:
<TextField> instances using SELECT_FIELD_SX and
shrink: true?<IconButton> missing aria-label?os.Getenv calls in the server?Report findings before applying the user's actual request. Apply the conventions automatically during the edit.
These are forbidden. Refuse to add or accept them:
os.Getenv in cmd/, internal/config/, or internal/auth/.<binary-dir>/<binary>.yaml). The binary's parent directory is not
a configuration source.apiClient.ts with raw fetch.pgedgeTheme.ts.<TextField> without SELECT_FIELD_SX and shrink: true.<IconButton> without aria-label.console.* outside utils/logger.ts.npx claudepluginhub pgedge/pgedge-skills --plugin pgedge-skillsCreates, edits, and optimizes skills for Claude Code, including drafting, evaluating with test prompts, iterating on performance, and improving skill descriptions for better triggering accuracy.