name: module-onboarding description: Scaffold a new federated module under packages/. Runs mod-arch-installer, allocates ports, registers the feature flag and SupportedArea in the host, verifies the build (type-check, port validation, container image). Pass the module name in kebab-case as the argument.
Module Onboarding
Scaffold a new federated module (Module Federation remote with optional Go BFF) in the ODH Dashboard monorepo. The module is ready to build and run after this skill completes.
See reference.md for naming conventions, port ranges, templates, and troubleshooting. See .claude/rules/module-onboarding.md for the full manual guide.
Arguments
$ARGUMENTS — Module name in kebab-case (e.g., my-module). If empty, ask the user.
Phase 0: Parse & Validate
Extract the module name from
$ARGUMENTS. If empty, ask the user for a name.Validate the name:
- Must be non-empty, lowercase, kebab-case (only
[a-z0-9-], no leading/trailing hyphens). - Must not already exist: check that
packages/<name>/does not exist.
- Must be non-empty, lowercase, kebab-case (only
Compute all name variants (see reference.md § Name Transformation Rules):
kebab-case: my-module camelCase: myModule UPPER_SNAKE_CASE: MY_MODULE Title Case: My ModuleAnd derived identifiers:
Package: @odh-dashboard/my-module SupportedArea: PLUGIN_MY_MODULE = 'plugin-my-module' Feature flag: myModule MF name: myModule Proxy path: /my-module/apiAsk the user: Include a Go BFF (backend-for-frontend)? Default: yes.
Phase 1: Port Allocation
Scan existing frontend ports:
jq -r '."module-federation".local.port // empty' packages/*/package.json 2>/dev/null | awk '$1>=9100 && $1<=9399' | sort -nThis reads every
packages/*/package.jsonthat has amodule-federationkey and collectsmodule-federation.local.portvalues. Find the next unused integer in the 9100–9399 range.Scan existing BFF ports (if BFF included):
grep -r 'PROXY_PORT=' packages/*/Makefile | grep -oP '\d{4,5}' | sort -nFind the next unused integer in the 4000–4099 range.
Report the chosen ports to the user:
- Frontend dev port:
<port> - BFF proxy port:
<port>(if applicable)
- Frontend dev port:
Phase 2: Scaffold with mod-arch-installer
Step 1: Run the installer
cd packages && npx mod-arch-installer -n <name>
If the installer fails (network error, not found, etc.), fall back to manual scaffolding: copy the structure from an existing federated module like packages/eval-hub/ and replace all name references. See reference.md § Module Federation Config for the package.json template.
Step 2: Verify and patch the generated output
After the installer completes, verify the following files exist and are correct. Patch any that need fixing:
packages/<name>/package.json:
nameis@odh-dashboard/<name>module-federation.nameis the correct<camelCase>module-federation.local.portmatches the allocated frontend port from Phase 1module-federation.proxy[0].pathis/<name>/apimodule-federation.service.portis8043If BFF included, add
bffConfigsection:"bffConfig": { "enabled": true, "port": 8080, "healthEndpoint": "/healthcheck", "startCommand": "make dev-bff-e2e-mock" }Dependencies include
@odh-dashboard/plugin-coreand@odh-dashboard/internalexportsincludes"./extensions": "./frontend/src/odh/extensions.ts"
packages/<name>/frontend/config/moduleFederation.js:
namematches<camelCase>sharedincludes all required singletons (see reference.md § Shared Singletons)exposesincludes'./extensions': './src/odh/extensions'
packages/<name>/frontend/src/odh/extensions.ts:
- Contains
app.areaextension withidreferencing the module's area constant andfeatureFlagsreferencing the feature flag name - Contains
app.navigation/sectionorapp.navigation/hrefstub - Contains
app.routestub with a lazy-loaded placeholder component
packages/<name>/Makefile:
PORTvariable matches the allocated frontend portPROXY_PORTvariable matches the allocated BFF port (if applicable)- Has standard targets:
dev-install-dependencies,dev-frontend-federated,dev-start-federated - If BFF included: has
dev-bff-federated,dev-bff-e2e-mock,dev-bff-e2e-clustertargets
packages/<name>/tsconfig.json, jest.config.ts, .eslintrc.js:
- Present and correctly extending shared configs
Step 3: Create placeholder component (if not generated)
If the installer didn't create a page component, create a minimal placeholder:
// packages/<name>/frontend/src/app/pages/OverviewPage.tsx
import React from 'react';
import {
EmptyState,
EmptyStateBody,
EmptyStateVariant,
PageSection,
} from '@patternfly/react-core';
import { CubesIcon } from '@patternfly/react-icons';
const OverviewPage: React.FC = () => (
<PageSection hasBodyWrapper={false}>
<EmptyState
headingLevel="h1"
icon={CubesIcon}
titleText="<Title Case>"
variant={EmptyStateVariant.full}
>
<EmptyStateBody>This module is under development.</EmptyStateBody>
</EmptyState>
</PageSection>
);
export default OverviewPage;
Ensure the extensions file's route component import points to this file.
Phase 3: Register in Host
This phase modifies three files in the host application. Read each file first to find the correct insertion point.
1. Add feature flag type — frontend/src/k8sTypes.ts
Read the file and find the DashboardCommonConfig type. Add the new flag as an optional boolean in the tech-preview section (near the end of the type, where the other optional ?: boolean flags are):
<camelCase>?: boolean;
2. Add SupportedArea enum — frontend/src/concepts/areas/types.ts
Read the file and find the SupportedArea enum. Add the new entry under the /* Plugins */ comment section:
PLUGIN_<UPPER_SNAKE> = 'plugin-<kebab>',
3. Add flag default + state map — frontend/src/concepts/areas/const.ts
a) Add the flag default to devTemporaryFeatureFlags:
<camelCase>: false,
b) Add an entry to SupportedAreasStateMap (at the end, before the closing };):
[SupportedArea.PLUGIN_<UPPER_SNAKE>]: {
featureFlags: ['<camelCase>'],
},
Phase 4: Dockerfile Verification
- Check that
packages/<name>/Dockerfile.workspaceexists. - Read it and verify:
ARG MODULE_NAMEdefault matches<name>- Multi-stage build has Node builder stage (frontend) and, if BFF included, Go builder stage
- Final stage copies built artifacts correctly
- If the Dockerfile is missing, copy from
packages/plugin-template/Dockerfile.workspaceand patch theMODULE_NAMEdefault.
Phase 5: Install & Build Verification
Run these sequentially. Stop and fix on first failure before proceeding.
Step 1: Install workspace
npm install
This wires up the new package in the npm workspace. Must succeed before other steps.
Step 2: Validate ports
npm run validate:ports
If this fails, a port conflict exists. Fix the conflicting port in package.json and re-run.
Step 3: Type-check
npm run type-check
This verifies:
- The feature flag is correctly typed in
DashboardCommonConfig - The
SupportedAreaenum entry is valid - The
SupportedAreasStateMapreferences are correct - The extensions file compiles
If it fails with a flag name error, the flag was likely not added to k8sTypes.ts. Fix and re-run.
Step 4: BFF compilation (if BFF included)
cd packages/<name>/bff && go build ./cmd
If it fails, run go mod tidy first and retry.
Step 5: Container build
podman build --file ./packages/<name>/Dockerfile.workspace .
If podman is not available, try docker build instead. This confirms the full build pipeline works end-to-end.
If this step is slow or the user wants to skip it, it can be deferred — the earlier steps already confirm correctness. Ask before running.
Phase 6: Report
Summarize the completed onboarding:
- Files created — list all new files under
packages/<name>/ - Host files modified —
k8sTypes.ts,types.ts,const.ts - Port assignments — frontend port, BFF port (if applicable)
- Build results — pass/fail for each verification step
- Next steps for the team:
- Write feature code in
packages/<name>/frontend/src/app/ - Add unit tests in
packages/<name>/__tests__/ - Add E2E tests in
packages/cypress/cypress/tests/e2e/<name>/ - Add contract tests in
packages/<name>/contract-tests/(if BFF) - Start the dev server:
cd packages/<name> && make dev-start-federated - Enable the feature locally: set
<camelCase>: truein the dashboard config
- Write feature code in