Install
$ agentstack add skill-anbturki-claude-toolkit-zod-schema ✓ scanned · ✓ verified, works with Claude Code, Cursor, and more.
Security review
✓ PassedNo issues found. Passed automated security review. · v0.1.0 How review works →
- ✓ Prompt-injection patterns
- ✓ Secret / credential exfiltration
- ✓ Dangerous shell & filesystem operations
- ✓ Untrusted network calls
- ✓ Known-malicious package signatures
What it can access
- ✓ Network access No
- ✓ Filesystem access No
- ✓ Shell / process execution No
- ✓ Environment & secrets No
- ✓ Dynamic code execution No
From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.
Verified badge
Passed review? Show it. Paste this badge into your README, it links to the public security report.
Reliability & compatibility
Declared compatibility
Compatibility is declared by the source manifest. End-to-end runtime verification is coming, see below.
We're building live execution health for every listing: tool-call success rate, median latency, uptime, and last-checked timestamps, measured, not self-reported. It isn't live yet, so we don't show numbers we can't stand behind.
How agent discovery & health will work →About
Create Zod Schema
Scaffold validation schemas for $ARGUMENTS.
Step 1: Learn Project Patterns
- Read CLAUDE.md for validation conventions
- Find existing schemas:
`` Glob("**/schemas/**/*.ts") Glob("**/validators/**/*.ts") ``
- Read 2-3 existing schemas — learn:
- Import style (
import { z } from "zod"vsimport * as z) - How common schemas are reused (pagination, etc.)
- Type export patterns
- Where schemas live in the project
Step 2: Scaffold Schemas
File location: Match existing schema file locations.
import { z } from "zod";
// Reuse common schemas if they exist in the project
// import { paginationSchema } from "./common";
// List/filter schema (for GET query params)
export const list${Name}sSchema = z.object({
search: z.string().optional(),
limit: z.coerce.number().min(1).max(100).optional().default(50),
offset: z.coerce.number().min(0).optional().default(0),
// Add filter fields
});
// Create schema (for POST body)
export const create${Name}Schema = z.object({
name: z.string().min(1, "Name is required").max(255),
// Add required fields with validation
});
// Update schema (for PUT body)
export const update${Name}Schema = z.object({
name: z.string().min(1).max(255).optional(),
// Optional fields for partial updates
});
// Export inferred types — NEVER define these manually
export type List${Name}sInput = z.infer;
export type Create${Name}Input = z.infer;
export type Update${Name}Input = z.infer;
Common Patterns
Query Parameters (coerce from strings)
z.coerce.number() // "50" → 50
z.coerce.boolean() // "true" → true
z.string().optional() // already a string from URL
Enums
export const statusSchema = z.enum(["active", "inactive", "pending"]);
type Status = z.infer; // "active" | "inactive" | "pending"
Arrays
z.array(z.string()).min(1).max(10) // 1-10 strings
z.array(z.string().uuid()).optional() // optional UUID array
Refinements
z.string().regex(/^#[0-9A-Fa-f]{6}$/, "Invalid hex color")
z.string().email("Invalid email")
z.string().url("Invalid URL")
z.string().min(8, "Password must be at least 8 characters")
Nested Objects
export const create${Name}Schema = z.object({
name: z.string().min(1),
address: z.object({
street: z.string(),
city: z.string(),
zip: z.string(),
}).optional(),
tags: z.array(z.string()).default([]),
});
Extending Schemas
// Update = Create with all fields optional
export const update${Name}Schema = create${Name}Schema.partial();
// List = pagination + filters
export const list${Name}sSchema = paginationSchema.extend({
status: statusSchema.optional(),
search: z.string().optional(),
});
Discriminated Unions
const eventSchema = z.discriminatedUnion("type", [
z.object({ type: z.literal("click"), x: z.number(), y: z.number() }),
z.object({ type: z.literal("scroll"), offset: z.number() }),
]);
Step 3: After Creation
- Export from schemas index file
- Export types — always co-export inferred types
- Wire to routes — pass schemas to route validation
- Wire to forms — use with
@hookform/resolvers/zodfor React Hook Form
Rules
- Always export inferred types —
z.infer, never manual interfaces - Coerce query params — URL values are strings, use
z.coerce.number()etc. - Reuse common schemas — pagination, sorting, filtering if they exist
- Meaningful validation messages —
.min(1, "Name is required") .default()for optional with defaults —z.number().optional().default(50).partial()for update schemas — derive from create schema when possible
Source & license
This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.
- Author: anbturki
- Source: anbturki/claude-toolkit
- License: MIT
Install and usage instructions live in the source repository linked above.
Reviews
No reviews yet, be the first.
Write a review
Versions
- v0.1.0 Imported from the upstream source.