Generate feature package
Scaffolds a new feature domain package under features/<name>/ matching the structure defined in
this skill's references/feature-architecture.md: one folder per zone, with the files that zone
always needs — a barrel (index) where the zone re-exports its public API (components/,
types/, server/db/, test/builders/), a ready-to-fill stub where it doesn't
(schemas/<name>-schema.ts, server/db/schema.ts, server/permissions.ts, etc.). A bundled
script does the deterministic file creation — invoke it, don't hand-create the files, so every
feature comes out identical.
Paths in this skill are relative to the skill's own directory (provided to you when the skill is
invoked), not to the target project. The skill operates on whatever project the user is in: the
script finds that project's root by walking up to the nearest package.json.
Input
The feature name is the argument to the skill: /generate-feature-package <name>. It must be
kebab-case (lowercase, dash-separated) — e.g. orders, email-templates, order-tracking —
because it becomes the domain folder name. If the user gave a name in another form (PascalCase,
spaces, plural/singular preference), convert it to kebab-case and confirm only if ambiguous.
If no name was provided, ask for one before running.
Steps
Run the bundled scaffold script with Node, passing the feature name. The script lives next to this SKILL.md at
scripts/scaffold-feature.mjs— use its absolute path, built from this skill's directory (do not assume a.claude/skills/...location, since the skill may be installed anywhere):node "<skill-dir>/scripts/scaffold-feature.mjs" <name>Add
--dry-runfirst if you want to preview the file list without writing anything. The script:- validates the name is kebab-case and that
features/<name>/does not already exist (it refuses to overwrite), - locates the target project root (nearest
package.json) so it works from any working directory, - creates the zone folders and barrel files listed below.
- validates the name is kebab-case and that
Report the created tree to the user and point them at the next step: filling in tables, types, components, etc., then re-exporting them from each zone's
index.
Do not run npm run type-check/lint afterwards — empty barrels use export {};, which is valid,
but there is nothing to type-check yet.
What gets created
features/<name>/
├── components/index.tsx # barrel — components only
├── schemas/<name>-schema.ts # Zod + *FormData stub for the domain
├── types/index.ts # barrel — client-safe domain types
├── server/
│ ├── actions/.gitkeep # filled with {verb}-<name>.action.ts later
│ ├── db/
│ │ ├── schema.ts # data model + inferred row types
│ │ ├── queries.ts # read operations, one per function
│ │ ├── mutations.ts # write operations, one per function
│ │ └── index.ts # re-exports queries + mutations only
│ ├── services/.gitkeep # filled with <name>.service.ts later
│ └── permissions.ts # canDoX guards, starts with import "server-only"
└── test/builders/index.ts # barrel — builders
Design choices baked into the scaffold (so they match the spec — don't second-guess them):
- No top-level
index.tsfor the feature, and noserver/index.tsbarrel either. Consumers import from a client-safe barrel (components/,types/,schemas/) or, on the server, directly from the file they need (e.g.~/features/<name>/server/services/<name>.service) — deep imports intoserver/are expected, not a smell. server/db/index.tsis the one internal sub-barrel, and it re-exportsqueries+mutationsonly — neverschema.ts. There is intentionally noserver/actions/index.tsorserver/services/index.ts(deeper barrels there are noise).constants/,server/api/,utils/,context/, andhooks/are optional zones, added on demand when a feature actually needs them — the script does not scaffold empty folders for them.- Barrel-less folders (
server/actions,server/services) get a.gitkeepso git tracks them while empty. - Empty barrels contain
export {};so they are valid ES modules underisolatedModules.
For the rules that govern what goes in each zone (naming suffixes, the server/client boundary,
return types per layer), read this skill's references/feature-architecture.md — consult it if the
user asks to go beyond scaffolding into populating the feature.
Examples
Example 1
Input: /generate-feature-package invoices
Action: run node "<skill-dir>/scripts/scaffold-feature.mjs" invoices (with the skill's real
directory), then report the created features/invoices/ tree.
Example 2
Input: "scaffold a new feature called Email Templates"
Action: convert to kebab-case → email-templates, run the script with that name, report the tree.
Example 3
Input: "/generate-feature-package orders" when features/orders/ already exists
Action: the script exits with an error refusing to overwrite — relay that to the user and ask
whether they want a different name.