name: scaffold-form description: Scaffold a new react-hook-form + Zod form following the gorun-client conventions — Zod schema in lib/validations/, form component using components/ui/form.tsx, i18n labels via next-intl, useFieldArray for dynamic fields. Use when the user asks to create a new form or convert an ad-hoc form to RHF.
Scaffold a Form
Inputs
- Form name (e.g.,
PromoCodeForm,EventRegistrationForm) - Domain (e.g.,
admin,events,registration) - Field list with types
- Whether it's a create vs edit form
- The matching API mutation hook (or "needs to be added" → also invoke the api-integrator agent)
Procedure
- Read reference templates first:
- Canonical form:
components/admin/AdminEventForm.tsx - Canonical schema:
lib/validations/admin-event.ts - Template file in this skill:
reference/form-template.tsx.txt
- Canonical form:
- Author the Zod schema at
lib/validations/<feature>.ts:- One
schemaexport export type <Feature>FormValues = z.infer<typeof schema>- For bilingual content fields, use the
pair(min, max, field)helper pattern - For numeric fields that may be empty, use
emptyNumberToUndefinedfromlib/forms/number-field
- One
- Author the form component at
components/<domain>/<FormName>.tsx:"use client"at the topuseForm<FormValues>({ resolver: zodResolver(schema), defaultValues: ... })- Wrap with
<Form>fromcomponents/ui/form.tsx - Each field uses
<FormField control={form.control} name="..." render={({ field }) => (<FormItem><FormLabel>{t("...")}</FormLabel><FormControl>...</FormControl><FormMessage/></FormItem>)} /> - Submit button uses the GoRun variants (
<Button variant="brand" type="submit">{t("submit")}</Button>) - For dynamic field sets,
useFieldArray({ control: form.control, name: "..." })
- Add i18n keys to BOTH
messages/en.jsonandmessages/uk.json(use theadd-translation-keyskill). - Wire up submission: import the matching mutation hook from
hooks/use<Domain>.ts. The hook handles toasts and cache invalidation; the form just calls.mutate(values). - Run
npm run type-checkto catch resolver / type mismatches. - Author a test (use the
write-vitest-testskill).
File shape
See reference/form-template.tsx.txt for the exact starting skeleton.
Anti-patterns
- Inline Zod schema in the component file — extract to
lib/validations/ useStatefor individual field values — use RHFregister/control- Missing
<FormMessage />— breaks error UX - Direct
axios.postinonSubmit— use the React Query mutation hook - Hardcoded English labels — use
useTranslations