spa:create generator pulls the spa source from the upstream skeleton repository, marks the module as a spa in its yml config, links it to a design module, assigns a free dev port, and installs the spa dependencies. After it finishes you have a working frontend you can start with one command.
If you are new to spa modules, read the spa overview first. This page is the friendly walkthrough; for the terse flag reference see spa:create.
CLI command
Examples
Options
| Option | Description | Default |
|---|---|---|
--name | Spa name. Normalized to PascalCase with any trailing Module stripped; the module folder uses its kebab-case form. | Prompted if omitted |
--design | Design module the spa uses. An existing design can be chosen interactively, or a new name is scaffolded. | Prompted if omitted |
--cwd | Project directory the spa is created in. | Current working directory |
--silent | Suppress prompts, spinners, and output. | false |
The command clones the spa source and installs packages, so it needs
git
and network access. If either is unavailable the create will not complete.The design link
Every spa composes a design module — atype: "design" module that holds the shared UI building blocks. During create you choose which one:
- Pick an existing design. If your project already has
type: "design"modules, you choose one interactively (or pass it with--design). - Name a new one. Give a name that does not exist yet and the generator scaffolds it for you with
design:create.
design: in the spa’s yml config, so the link between the spa and its design module is explicit and persistent.
What happens
When you runspa:create, the generator works through these steps in order:
Scaffold the base module
A base module is scaffolded under
modules/<kebab-name>/, using the kebab-case form of the name you gave.Detach it from the backend
A spa is a frontend, not part of the backend — so it is un-registered from
AppModule and SharedModule, and its root tsconfig path alias is removed.Remove the backend module class
The scaffolded
<Pascal>Module.ts and its spec file are deleted; a spa does not ship a backend module class.Mark it as a spa
The module yml is marked
type: "spa" and records design: "<kebab>" for the design module you chose.Add Vite scripts and assign a port
Vite
dev, build, and preview scripts are added to the module package.json. The dev script gets a free dev port — 5000 by default, or the next free port if 5000 is taken (the generator scans other modules’ --port usage to find a free one).Clone the spa source
The upstream
skeleton-spa repo is cloned (shallow) into the module’s src/, and every shared/ sub-layer is ensured to exist via .gitkeep: assets, components, hooks, layouts, services, store, styles, types, and utils.What you get
You end up with a self-contained spa module undermodules/<kebab-name>/ — its own Vite setup, a src/ populated from the skeleton, the full shared/ layer in place, a dedicated dev port, and a recorded link to its design module. See the spa structure for a tour of the generated layout.
Start and stop the spa
Run the spa from the project root withapp:start. The --spa flag narrows the run to spa modules, so only the dev servers come up:
Next steps
Run the dev server
Start the spa from the project root with
ooneex app:start --spa — Vite
serves it on the assigned port.Add features
Build out pages and flows with
spa:feature:create.Use with Claude and Codex
The generator ships a matchingspa:create skill. It runs the scaffold and then guides your AI agent through what comes next — choosing or naming the design module, starting the dev server, and adding the first features. Initialize the skills once for your agent:
- Claude
- Codex
Prompt
spa:create --name=dashboard --design=ui.
For the full command reference, see spa:create.