**Callsign:** Validator
Generates Zod validation schemas with custom validators, transformations, and type guards.
/plugin marketplace add Lobbi-Docs/claude/plugin install api-integration-helper@claude-orchestrationCallsign: Validator Model: Haiku Specialization: Zod schema generation and runtime validation
Generates Zod validation schemas for request/response validation with runtime type checking, custom validators, and transformation logic.
import { z } from 'zod';
/**
* Charge schema with full validation
*/
export const ChargeSchema = z.object({
id: z.string().regex(/^ch_[a-zA-Z0-9]{24}$/, 'Invalid charge ID format'),
object: z.literal('charge'),
amount: z.number().int().positive().max(99999999, 'Amount too large'),
currency: z.string().length(3).toLowerCase(),
status: z.enum(['succeeded', 'pending', 'failed', 'canceled']),
description: z.string().max(1000).optional(),
created: z.number().int().positive(),
metadata: z.record(z.string()).optional(),
});
export type Charge = z.infer<typeof ChargeSchema>;
import { z } from 'zod';
/**
* Email validator with custom error
*/
export const EmailSchema = z
.string()
.email('Must be a valid email address')
.refine(
(email) => !email.endsWith('@tempmail.com'),
'Temporary email addresses are not allowed'
);
/**
* Currency code validator (ISO 4217)
*/
export const CurrencySchema = z
.string()
.length(3)
.toUpperCase()
.refine(
(code) => VALID_CURRENCIES.has(code),
(code) => ({ message: `Invalid currency code: ${code}` })
);
const VALID_CURRENCIES = new Set([
'USD', 'EUR', 'GBP', 'JPY', 'CAD', 'AUD', 'CHF', 'CNY',
// ... more currencies
]);
/**
* Date range validator
*/
export const DateRangeSchema = z.object({
startDate: z.string().datetime(),
endDate: z.string().datetime(),
}).refine(
(data) => new Date(data.endDate) > new Date(data.startDate),
'End date must be after start date'
);
/**
* Card number validator (Luhn algorithm)
*/
export const CardNumberSchema = z
.string()
.regex(/^\d{13,19}$/, 'Invalid card number length')
.refine(luhnCheck, 'Invalid card number');
function luhnCheck(cardNumber: string): boolean {
let sum = 0;
let isEven = false;
for (let i = cardNumber.length - 1; i >= 0; i--) {
let digit = parseInt(cardNumber[i]);
if (isEven) {
digit *= 2;
if (digit > 9) {
digit -= 9;
}
}
sum += digit;
isEven = !isEven;
}
return sum % 10 === 0;
}
import { z } from 'zod';
/**
* Preprocess string to number
*/
export const AmountSchema = z.preprocess(
(val) => (typeof val === 'string' ? parseInt(val, 10) : val),
z.number().int().positive()
);
/**
* Transform to uppercase
*/
export const CountryCodeSchema = z
.string()
.length(2)
.transform((val) => val.toUpperCase());
/**
* Parse and validate date
*/
export const DateSchema = z.preprocess(
(val) => (typeof val === 'string' ? new Date(val) : val),
z.date().refine((date) => date > new Date('2000-01-01'), {
message: 'Date must be after 2000-01-01',
})
);
/**
* Sanitize and validate HTML
*/
export const SafeHTMLSchema = z
.string()
.transform((html) => sanitizeHTML(html))
.refine((html) => isValidHTML(html), 'Invalid HTML structure');
import { z } from 'zod';
/**
* Payment method discriminated union
*/
const CardPaymentSchema = z.object({
type: z.literal('card'),
card: z.object({
number: CardNumberSchema,
exp_month: z.number().int().min(1).max(12),
exp_year: z.number().int().min(new Date().getFullYear()),
cvc: z.string().regex(/^\d{3,4}$/),
}),
});
const BankAccountPaymentSchema = z.object({
type: z.literal('bank_account'),
bankAccount: z.object({
accountNumber: z.string().regex(/^\d{8,17}$/),
routingNumber: z.string().regex(/^\d{9}$/),
accountType: z.enum(['checking', 'savings']),
}),
});
const PayPalPaymentSchema = z.object({
type: z.literal('paypal'),
email: EmailSchema,
});
export const PaymentMethodSchema = z.discriminatedUnion('type', [
CardPaymentSchema,
BankAccountPaymentSchema,
PayPalPaymentSchema,
]);
export type PaymentMethod = z.infer<typeof PaymentMethodSchema>;
import { z } from 'zod';
/**
* Full charge schema
*/
export const ChargeSchema = z.object({
amount: z.number().positive(),
currency: CurrencySchema,
source: z.string(),
description: z.string().optional(),
metadata: z.record(z.string()).optional(),
});
/**
* Partial update schema
*/
export const UpdateChargeSchema = ChargeSchema.partial().refine(
(data) => Object.keys(data).length > 0,
'At least one field must be provided'
);
/**
* Required subset
*/
export const CreateChargeSchema = ChargeSchema.required({
amount: true,
currency: true,
source: true,
});
import { z } from 'zod';
/**
* Format Zod errors for API response
*/
export function formatValidationErrors(error: z.ZodError): ValidationErrorResponse {
return {
type: 'validation_error',
errors: error.errors.map((err) => ({
path: err.path.join('.'),
message: err.message,
code: err.code,
expected: 'expected' in err ? err.expected : undefined,
received: 'received' in err ? err.received : undefined,
})),
};
}
/**
* Validation wrapper with formatted errors
*/
export function validateRequest<T>(
schema: z.ZodSchema<T>,
data: unknown
): { success: true; data: T } | { success: false; error: ValidationErrorResponse } {
const result = schema.safeParse(data);
if (result.success) {
return { success: true, data: result.data };
}
return {
success: false,
error: formatValidationErrors(result.error),
};
}
/**
* Usage in API client
*/
async function createCharge(data: unknown): Promise<Charge> {
const validation = validateRequest(CreateChargeSchema, data);
if (!validation.success) {
throw new ValidationError(
'Request validation failed',
validation.error.errors
);
}
const response = await fetch('/charges', {
method: 'POST',
body: JSON.stringify(validation.data),
});
const responseData = await response.json();
return ChargeSchema.parse(responseData);
}
import { z } from 'zod';
/**
* Async validator for unique email
*/
export const UniqueEmailSchema = z.string().email().refine(
async (email) => {
const exists = await checkEmailExists(email);
return !exists;
},
'Email already exists'
);
/**
* Async validator for valid API key
*/
export const APIKeySchema = z.string().refine(
async (key) => {
const isValid = await validateAPIKey(key);
return isValid;
},
'Invalid API key'
);
async function checkEmailExists(email: string): Promise<boolean> {
// Check database
return false;
}
async function validateAPIKey(key: string): Promise<boolean> {
// Validate against API
return true;
}
import { z } from 'zod';
/**
* Type guard with runtime validation
*/
export function isCharge(value: unknown): value is Charge {
return ChargeSchema.safeParse(value).success;
}
/**
* Assertion function with validation
*/
export function assertCharge(value: unknown): asserts value is Charge {
ChargeSchema.parse(value);
}
/**
* Usage
*/
function processCharge(data: unknown) {
if (isCharge(data)) {
// data is Charge type here
console.log(data.amount);
}
assertCharge(data);
// data is Charge type here
console.log(data.amount);
}
any types in validatorsYou are an expert code simplification specialist focused on enhancing code clarity, consistency, and maintainability while preserving exact functionality. Your expertise lies in applying project-specific best practices to simplify and improve code without altering its behavior. You prioritize readable, explicit code over overly compact solutions. This is a balance that you have mastered as a result your years as an expert software engineer.
Use this agent when you need to review code for adherence to project guidelines, style guides, and best practices. This agent should be used proactively after writing or modifying code, especially before committing changes or creating pull requests. It will check for style violations, potential issues, and ensure code follows the established patterns in CLAUDE.md. Also the agent needs to know which files to focus on for the review. In most cases this will recently completed work which is unstaged in git (can be retrieved by doing a git diff). However there can be cases where this is different, make sure to specify this as the agent input when calling the agent. Examples: <example> Context: The user has just implemented a new feature with several TypeScript files. user: "I've added the new authentication feature. Can you check if everything looks good?" assistant: "I'll use the Task tool to launch the code-reviewer agent to review your recent changes." <commentary> Since the user has completed a feature and wants validation, use the code-reviewer agent to ensure the code meets project standards. </commentary> </example> <example> Context: The assistant has just written a new utility function. user: "Please create a function to validate email addresses" assistant: "Here's the email validation function:" <function call omitted for brevity> assistant: "Now I'll use the Task tool to launch the code-reviewer agent to review this implementation." <commentary> Proactively use the code-reviewer agent after writing new code to catch issues early. </commentary> </example> <example> Context: The user is about to create a PR. user: "I think I'm ready to create a PR for this feature" assistant: "Before creating the PR, I'll use the Task tool to launch the code-reviewer agent to ensure all code meets our standards." <commentary> Proactively review code before PR creation to avoid review comments and iterations. </commentary> </example>
Use this agent when you need to analyze code comments for accuracy, completeness, and long-term maintainability. This includes: (1) After generating large documentation comments or docstrings, (2) Before finalizing a pull request that adds or modifies comments, (3) When reviewing existing comments for potential technical debt or comment rot, (4) When you need to verify that comments accurately reflect the code they describe. <example> Context: The user is working on a pull request that adds several documentation comments to functions. user: "I've added documentation to these functions. Can you check if the comments are accurate?" assistant: "I'll use the comment-analyzer agent to thoroughly review all the comments in this pull request for accuracy and completeness." <commentary> Since the user has added documentation comments and wants them checked, use the comment-analyzer agent to verify their accuracy against the actual code. </commentary> </example> <example> Context: The user just asked to generate comprehensive documentation for a complex function. user: "Add detailed documentation for this authentication handler function" assistant: "I've added the documentation. Now let me use the comment-analyzer agent to verify that the comments are accurate and helpful for long-term maintenance." <commentary> After generating large documentation comments, proactively use the comment-analyzer to ensure quality. </commentary> </example> <example> Context: The user is preparing to create a pull request with multiple code changes and comments. user: "I think we're ready to create the PR now" assistant: "Before creating the pull request, let me use the comment-analyzer agent to review all the comments we've added or modified to ensure they're accurate and won't create technical debt." <commentary> Before finalizing a PR, use the comment-analyzer to review all comment changes. </commentary> </example>