.agents/skills/zod-validation-expert/SKILL.md
Expert in Zod schema validation — parsing, custom errors, refinements, type inference, integration with React Hook Form and Next.js Server Actions. Use when defining validation schemas.
npx skillsauth add sdn0303/terrasight zod-validation-expertInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
Define schema once, derive TypeScript type with z.infer. Never maintain duplicate interfaces.
const TransactionSchema = z.object({
id: z.string().uuid(),
areaCode: z.string().regex(/^\d{5}$/, 'Area code must be 5 digits'),
pricePerSqm: z.number().int().positive(),
transactionDate: z.coerce.date(),
propertyType: z.enum(['residential', 'commercial', 'industrial']),
location: z.object({
lat: z.number().min(-90).max(90),
lng: z.number().min(-180).max(180),
}),
});
export type Transaction = z.infer<typeof TransactionSchema>;
Always validate external data at boundaries:
const GeoJSONResponseSchema = z.object({
type: z.literal('FeatureCollection'),
features: z.array(z.object({
type: z.literal('Feature'),
geometry: z.object({
type: z.enum(['Point', 'Polygon', 'MultiPolygon']),
coordinates: z.unknown(),
}),
properties: z.record(z.unknown()),
})),
});
// Use safeParse, not parse (avoid try/catch)
const result = GeoJSONResponseSchema.safeParse(apiResponse);
if (!result.success) {
console.error('Invalid GeoJSON:', result.error.flatten());
return null;
}
import { zodResolver } from '@hookform/resolvers/zod';
import { useForm } from 'react-hook-form';
const FilterSchema = z.object({
areaCode: z.string().min(1, 'Area code is required'),
priceMin: z.coerce.number().min(0).optional(),
priceMax: z.coerce.number().positive().optional(),
propertyType: z.enum(['all', 'residential', 'commercial']).default('all'),
});
type FilterValues = z.infer<typeof FilterSchema>;
export function FilterForm() {
const { register, handleSubmit, formState: { errors } } = useForm<FilterValues>({
resolver: zodResolver(FilterSchema),
});
}
'use server';
export async function createFilter(prevState: unknown, formData: FormData) {
const raw = Object.fromEntries(formData.entries());
const result = FilterSchema.safeParse(raw);
if (!result.success) {
return { errors: result.error.flatten().fieldErrors };
}
// result.data is fully typed
return { success: true, data: result.data };
}
const envSchema = z.object({
REINFOLIB_API_KEY: z.string().min(1),
DATABASE_URL: z.string().url(),
NODE_ENV: z.enum(['development', 'test', 'production']).default('development'),
PORT: z.coerce.number().default(3000),
});
export const env = envSchema.parse(process.env);
safeParse over parse (returns Result, no try/catch needed)z.coerce for FormData and URLSearchParamssrc/features/*/schemas/).flatten() or .format() for serializable error objectsdevelopment
Rust coding rules for Axum/Tokio/SQLx backends in services/backend. 179 rules split into 14 category files covering ownership, error handling, async, API design, and more. Use when writing, reviewing, or refactoring Rust code, designing error types, async flows, or public APIs.
content-media
PostgreSQL and PostGIS patterns for schema design, spatial queries, query optimization, indexing, and zero-downtime migrations. Use when writing SQL, creating tables, optimizing queries, or writing migration files.
development
Mapbox GL JS v3 development patterns for real estate data visualization. Use when working with Mapbox maps, Standard Style configuration, layer slots, 3D lighting, expressions, react-map-gl/mapbox integration, or migrating from MapLibre GL JS.
development
MapLibre GL JS + PostGIS integration patterns for real estate data visualization. Use when working on map layers, spatial queries, GeoJSON data pipelines, or 3D extrusion effects.