new-module
Scaffold a new feature slice in src/features/<name> with the canonical structure — public-API index, ui screen, model (Zod schema + Zustand store), lib, and colocated tests. Use whenever work needs a
SKILL.md.claude/skills/new-module/SKILL.md
GitHubTask
Scaffold src/features/$ARGUMENTS/ by running the generator, then mirroring the canonical slice src/features/tasks/ — read it first; it is the template.
- Generate the skeleton: run
npm run new:feature -- $ARGUMENTS. This creates:
src/features/$ARGUMENTS/
index.ts ← public API (exports the screen; keep minimal)
ui/$ARGUMENTS-screen.tsx ← screen shell built from @/shared/ui (Screen, AppText, …)
ui/ ← (add more components here)
model/ ← (empty — add schema + store, below)
lib/ ← (pure helpers)
__tests__/$ARGUMENTS-screen.test.tsx ← render smoke test
Add the model, mirroring
src/features/tasks/model/:model/schema.ts— Zod schema for the slice's core entity + inferred types. Everything entering the slice (input, storage rehydration, network) validates through it (Constitution Art. IX).model/store.ts— a Zustand store; subscribe via selectors, never store derived data (docs/architecture/state-management.md). For a painted-door experiment, the store's action is a no-op + counter that cannot mutate real state (docs/process/painted-door.md).__tests__/store.test.ts— one real assertion per action.
Rules that make the scaffold correct (not just present):
index.tsis the entire public surface; deep imports from outside the slice fail ESLint (boundaries/*). No cross-feature or upward imports.- UI uses
className+ NativeWind only (cn()for conditionals), shared primitives fromsrc/shared/ui, a designed empty state, and atestID(kebab-case, feature-prefixed) on every interactive/assertable element. - No route is created here; routes are thin composition in
src/app/and belong to the feature's tasks. - User-facing copy uses typographic apostrophes (’) — docs-lint scans UI text.
Finish: run
npm run lint && npm run typecheck && npm test(all green with the stubs), then list the created files and the next task from the spec'stasks.md.