Nuxt Content
secondsky/claude-skills
Nuxt Content v3 Git-based CMS for Markdown/MDC content sites.
Schema validation with Valibot, the modular and type-safe schema library.
$ npx skills add aidenlx/zotlit --skill valibot -a claude-codeProject install by default; add -g for ~/.claude/skills/.
$ gh skill install aidenlx/zotlit valibot --agent claude-codeProject scope by default; add --scope user for a personal install. Needs GitHub CLI 2.90.0 or later (public preview).
$ git clone --depth 1 https://github.com/aidenlx/zotlit.git skills-src && mkdir -p .claude/skills && cp -r skills-src/.agents/skills/valibot .claude/skills/valibot && rm -rf skills-srcUse ~/.claude/skills/ instead of .claude/skills for a personal install. The folder must contain SKILL.md.
Claude Code skills documentation · loads skills from .claude/skills/
Install the "valibot" agent skill from https://github.com/aidenlx/zotlit/tree/main/.agents/skills/valibot into .claude/skills/valibot/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "valibot", then confirm the skill loads.Claude Code copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$skill-installer install https://github.com/aidenlx/zotlit/tree/main/.agents/skills/valibotType this inside Codex. $skill-installer <name> installs a curated skill from openai/skills. The installer writes to $CODEX_HOME/skills (default ~/.codex/skills). Restart Codex if the skill does not show up.
$ npx skills add aidenlx/zotlit --skill valibot -a codexProject install goes to .agents/skills/; add -g for ~/.codex/skills/.
$ gh skill install aidenlx/zotlit valibot --agent codexProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/aidenlx/zotlit.git skills-src && mkdir -p .agents/skills && cp -r skills-src/.agents/skills/valibot .agents/skills/valibot && rm -rf skills-srcUse ~/.agents/skills/ instead of .agents/skills for a personal install.
Codex skills documentation · loads skills from .agents/skills/
Install the "valibot" agent skill from https://github.com/aidenlx/zotlit/tree/main/.agents/skills/valibot into .agents/skills/valibot/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "valibot", then confirm the skill loads.Codex copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ npx skills add aidenlx/zotlit --skill valibot -a cursorProject install goes to .agents/skills/; add -g for ~/.cursor/skills/.
$ gh skill install aidenlx/zotlit valibot --agent cursorProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/aidenlx/zotlit.git skills-src && mkdir -p .cursor/skills && cp -r skills-src/.agents/skills/valibot .cursor/skills/valibot && rm -rf skills-srcUse ~/.cursor/skills/ instead of .cursor/skills for a personal install.
Cursor skills documentation · loads skills from .cursor/skills/, .agents/skills/, .claude/skills/, .codex/skills/
Install the "valibot" agent skill from https://github.com/aidenlx/zotlit/tree/main/.agents/skills/valibot into .cursor/skills/valibot/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "valibot", then confirm the skill loads.Cursor copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ gemini skills install https://github.com/aidenlx/zotlit.git --path .agents/skills/valibot--scope user (default) or --scope workspace; --path is the subfolder of the repo that holds the skill; --consent skips the security confirmation prompt.
$ npx skills add aidenlx/zotlit --skill valibot -a gemini-cliProject install goes to .agents/skills/; add -g for ~/.gemini/skills/.
$ gh skill install aidenlx/zotlit valibot --agent gemini-cliProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/aidenlx/zotlit.git skills-src && mkdir -p .gemini/skills && cp -r skills-src/.agents/skills/valibot .gemini/skills/valibot && rm -rf skills-srcUse ~/.gemini/skills/ instead of .gemini/skills for a personal install, then run /skills reload.
Gemini CLI skills documentation · loads skills from .gemini/skills/, .agents/skills/
Install the "valibot" agent skill from https://github.com/aidenlx/zotlit/tree/main/.agents/skills/valibot into .gemini/skills/valibot/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "valibot", then confirm the skill loads.Gemini CLI copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ gh skill install aidenlx/zotlit valibotInstalls for Copilot at project scope by default; add --scope user for a personal install. Preview a skill first with gh skill preview. Needs GitHub CLI 2.90.0 or later (public preview).
$ npx skills add aidenlx/zotlit --skill valibot -a github-copilotProject install goes to .agents/skills/; add -g for ~/.copilot/skills/.
$ git clone --depth 1 https://github.com/aidenlx/zotlit.git skills-src && mkdir -p .github/skills && cp -r skills-src/.agents/skills/valibot .github/skills/valibot && rm -rf skills-srcUse ~/.copilot/skills/ instead of .github/skills for a personal install. Commit .github/skills so cloud agent and code review can use it.
GitHub Copilot skills documentation · loads skills from .github/skills/, .claude/skills/, .agents/skills/
Install the "valibot" agent skill from https://github.com/aidenlx/zotlit/tree/main/.agents/skills/valibot into .github/skills/valibot/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "valibot", then confirm the skill loads.GitHub Copilot copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ npx skills add aidenlx/zotlit --skill valibot -a opencodeOpenCode documents no install command of its own. Project install goes to .agents/skills/; add -g for ~/.config/opencode/skills/.
$ gh skill install aidenlx/zotlit valibot --agent opencodeProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/aidenlx/zotlit.git skills-src && mkdir -p .opencode/skills && cp -r skills-src/.agents/skills/valibot .opencode/skills/valibot && rm -rf skills-srcUse ~/.config/opencode/skills/ instead of .opencode/skills for a personal install.
OpenCode skills documentation · loads skills from .opencode/skills/, .claude/skills/, .agents/skills/
Install the "valibot" agent skill from https://github.com/aidenlx/zotlit/tree/main/.agents/skills/valibot into .opencode/skills/valibot/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "valibot", then confirm the skill loads.OpenCode copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
valibotSchema validation with Valibot, the modular and type-safe schema library.
Valibot is an agent skill from aidenlx/zotlit. Schema validation with Valibot, the modular and type-safe schema library. Use when the user needs to validate data, create schemas, parse inputs, or work with Valibot in their project. Also use when migrating from Zod to Valibot.
Its SKILL.md is about 4.7k tokens, which your agent loads only when the skill is triggered. It is a single SKILL.md file with no bundled scripts.
It sits in Frontend & Design, covering Forms and validation and Type safety. It works with Zod. The repository describes itself as: Bring your Zotero library into Obsidian. Create literature notes, insert citations, and annotate PDFs without leaving your vault. The licence is MIT.
3 steps, taken from the step headings in SKILL.md.
Read from SKILL.md and the folder at commit 27f5752. It shows what the files ask for, not the result of running them.
Pre-approves nothing: there is no allowed-tools line, so your agent's usual permission prompts apply.
From allowed-tools in the SKILL.md frontmatter.
Shell commands in SKILL.md call:
npmyarnpnpmbunFrom the folder's file list and the shell code blocks in SKILL.md.
Links to these hosts (documentation or services it may open):
valibot.devgithub.comFrom URLs in SKILL.md, links to its own repository left out.
Names these keys or tokens, usually read from environment variables:
API_KEYFrom names ending in _API_KEY, _TOKEN, _SECRET, _KEY or _PASSWORD in SKILL.md.
Valibot loads about 4.7k tokens when it runs. Until then it costs about 59 tokens; SKILL.md has 620 words of instructions outside code blocks.
Estimates: characters ÷ 4, the usual rule of thumb; real counts depend on the model's tokenizer. Scripts and assets cost tokens only if the agent reads them.
The automated check found no risky patterns in SKILL.md.
Automated static check — not a guarantee. Review scripts before installing. It scans the text of SKILL.md for risky patterns (piping downloads into a shell, reading credential files, hidden Unicode, destructive commands); files beside SKILL.md are not scanned.
The full file from aidenlx/zotlit at commit 27f5752, republished under its MIT licence (© aidenlx). 620 words, ~4,716 tokens.
.claude/skills/valibot/SKILL.md (or your agent's skills folder).This skill helps you work effectively with Valibot, the modular and type-safe schema library for validating structural data.
Valibot and Zod have different APIs. Never mix them up!
| Feature | Zod ❌ | Valibot ✅ |
|---|---|---|
| Import | import { z } from 'zod' | import * as v from 'valibot' |
| Validations | Chained methods: .email().min(5) | Pipeline: v.pipe(v.string(), v.email(), v.minLength(5)) |
| Parsing | schema.parse(data) | v.parse(schema, data) |
| Safe parsing | schema.safeParse(data) | v.safeParse(schema, data) |
| Optional | z.string().optional() | v.optional(v.string()) |
| Nullable | z.string().nullable() | v.nullable(v.string()) |
| Default | z.string().default('x') | v.optional(v.string(), 'x') |
| Transform | z.string().transform(fn) | v.pipe(v.string(), v.transform(fn)) |
| Refine/Check | z.string().refine(fn) | v.pipe(v.string(), v.check(fn)) |
| Enum | z.enum(['a', 'b']) | v.picklist(['a', 'b']) |
| Native enum | z.nativeEnum(MyEnum) | v.enum(MyEnum) |
| Union | z.union([a, b]) | v.union([a, b]) |
| Discriminated union | z.discriminatedUnion('type', [...]) | v.variant('type', [...]) |
| Intersection | z.intersection(a, b) | v.intersect([a, b]) |
| Min/max length | .min(5).max(10) | v.minLength(5), v.maxLength(10) |
| Min/max value | .gte(5).lte(10) | v.minValue(5), v.maxValue(10) |
| Infer type | z.infer<typeof Schema> | v.InferOutput<typeof Schema> |
| Infer input | z.input<typeof Schema> | v.InferInput<typeof Schema> |
// ❌ WRONG - This is Zod syntax, NOT Valibot!
const Schema = v.string().email().min(5);
const result = Schema.parse(data);
// ✅ CORRECT - Valibot uses functions and pipelines
const Schema = v.pipe(v.string(), v.email(), v.minLength(5));
const result = v.parse(Schema, data);// ❌ WRONG - Zod-style optional
const Schema = v.object({
name: v.string().optional(),
});
// ✅ CORRECT - Valibot wraps with optional()
const Schema = v.object({
name: v.optional(v.string()),
});// ❌ WRONG - Zod-style default
const Schema = v.string().default("hello");
// ✅ CORRECT - Valibot uses second argument
const Schema = v.optional(v.string(), "hello");npm install valibot # npm
yarn add valibot # yarn
pnpm add valibot # pnpm
bun add valibot # bunImport with a wildcard (recommended):
import * as v from "valibot";Or with individual imports:
import { object, string, pipe, email, parse } from "valibot";Valibot's API is divided into three main concepts:
Schemas define the expected data type. They are the starting point.
import * as v from "valibot";
// Primitive schemas
const StringSchema = v.string();
const NumberSchema = v.number();
const BooleanSchema = v.boolean();
const DateSchema = v.date();
// Complex schemas
const ArraySchema = v.array(v.string());
const ObjectSchema = v.object({
name: v.string(),
age: v.number(),
});Methods help you use or modify schemas. The schema is always the first argument.
// Parsing
const result = v.parse(StringSchema, "hello");
const safeResult = v.safeParse(StringSchema, "hello");
// Type guard
if (v.is(StringSchema, data)) {
// data is typed as string
}Actions validate or transform data within a pipe(). They MUST be used inside pipelines.
// Actions are used in pipe()
const EmailSchema = v.pipe(
v.string(),
v.trim(),
v.email(),
v.endsWith("@example.com"),
);Pipelines extend schemas with validation and transformation actions. A pipeline always starts with a schema, followed by actions.
import * as v from "valibot";
const UsernameSchema = v.pipe(
v.string(),
v.trim(),
v.minLength(3, "Username must be at least 3 characters"),
v.maxLength(20, "Username must be at most 20 characters"),
v.regex(
/^[a-z0-9_]+$/i,
"Username can only contain letters, numbers, and underscores",
),
);
const AgeSchema = v.pipe(
v.number(),
v.integer("Age must be a whole number"),
v.minValue(0, "Age cannot be negative"),
v.maxValue(150, "Age cannot exceed 150"),
);String validations:
v.email() — Valid email formatv.url() — Valid URL formatv.uuid() — Valid UUID formatv.regex(pattern) — Match regex patternv.minLength(n) — Minimum lengthv.maxLength(n) — Maximum lengthv.length(n) — Exact lengthv.nonEmpty() — Not empty stringv.startsWith(str) — Starts with stringv.endsWith(str) — Ends with stringv.includes(str) — Contains stringNumber validations:
v.minValue(n) — Minimum value (>=)v.maxValue(n) — Maximum value (<=)v.gtValue(n) — Greater than (>)v.ltValue(n) — Less than (<)v.integer() — Must be integerv.finite() — Must be finitev.safeInteger() — Safe integer rangev.multipleOf(n) — Must be multiple of nArray validations:
v.minLength(n) — Minimum itemsv.maxLength(n) — Maximum itemsv.length(n) — Exact item countv.nonEmpty() — At least one itemv.includes(item) — Contains itemv.excludes(item) — Does not contain itemconst PasswordSchema = v.pipe(
v.string(),
v.minLength(8),
v.check(
(input) => /[A-Z]/.test(input),
"Password must contain an uppercase letter",
),
v.check((input) => /[0-9]/.test(input), "Password must contain a number"),
);These actions modify the value without changing its type:
String transformations:
v.trim() — Remove leading/trailing whitespacev.trimStart() — Remove leading whitespacev.trimEnd() — Remove trailing whitespacev.toLowerCase() — Convert to lowercasev.toUpperCase() — Convert to uppercaseNumber transformations:
v.toMinValue(n) — Clamp to minimum value (if less than n, set to n)v.toMaxValue(n) — Clamp to maximum value (if greater than n, set to n)const NormalizedEmailSchema = v.pipe(
v.string(),
v.trim(),
v.toLowerCase(),
v.email(),
);
// Clamp number to range 0-100
const PercentageSchema = v.pipe(v.number(), v.toMinValue(0), v.toMaxValue(100));For converting between data types, use these built-in transformation actions:
v.toNumber() — Convert to numberv.toString() — Convert to stringv.toBoolean() — Convert to booleanv.toBigint() — Convert to bigintv.toDate() — Convert to Date// Convert string to number
const PortSchema = v.pipe(v.string(), v.toNumber(), v.integer(), v.minValue(1));
// Convert ISO string to Date
const TimestampSchema = v.pipe(v.string(), v.isoDateTime(), v.toDate());
// Convert to boolean
const FlagSchema = v.pipe(v.string(), v.toBoolean());For custom transformations, use v.transform():
const DateStringSchema = v.pipe(
v.string(),
v.isoDate(),
v.transform((input) => new Date(input)),
);
// Custom object transformation
const UserSchema = v.pipe(
v.object({
firstName: v.string(),
lastName: v.string(),
}),
v.transform((input) => ({
...input,
fullName: `${input.firstName} ${input.lastName}`,
})),
);const UserSchema = v.object({
id: v.number(),
name: v.string(),
email: v.pipe(v.string(), v.email()),
age: v.optional(v.number()),
});
type User = v.InferOutput<typeof UserSchema>;// Regular object - strips unknown keys (default)
const ObjectSchema = v.object({ key: v.string() });
// Loose object - allows and preserves unknown keys
const LooseObjectSchema = v.looseObject({ key: v.string() });
// Strict object - throws on unknown keys
const StrictObjectSchema = v.strictObject({ key: v.string() });
// Object with rest - validates unknown keys against a schema
const ObjectWithRestSchema = v.objectWithRest(
{ key: v.string() },
v.number(), // unknown keys must be numbers
);const ProfileSchema = v.object({
// Required
name: v.string(),
// Optional (can be undefined or missing)
nickname: v.optional(v.string()),
// Optional with default
role: v.optional(v.string(), "user"),
// Nullable (can be null)
avatar: v.nullable(v.string()),
// Nullish (can be null or undefined)
bio: v.nullish(v.string()),
// Nullish with default
theme: v.nullish(v.string(), "light"),
});const BaseSchema = v.object({
id: v.number(),
name: v.string(),
email: v.string(),
password: v.string(),
});
// Pick specific keys
const PublicUserSchema = v.pick(BaseSchema, ["id", "name"]);
// Omit specific keys
const UserWithoutPasswordSchema = v.omit(BaseSchema, ["password"]);
// Make all optional
const PartialUserSchema = v.partial(BaseSchema);
// Make all required
const RequiredUserSchema = v.required(PartialUserSchema);
// Merge objects
const ExtendedUserSchema = v.object({
...BaseSchema.entries,
createdAt: v.date(),
});const RegistrationSchema = v.pipe(
v.object({
password: v.pipe(v.string(), v.minLength(8)),
confirmPassword: v.string(),
}),
v.forward(
v.partialCheck(
[["password"], ["confirmPassword"]],
(input) => input.password === input.confirmPassword,
"Passwords do not match",
),
["confirmPassword"],
),
);const TagsSchema = v.pipe(
v.array(v.string()),
v.minLength(1, "At least one tag required"),
v.maxLength(10, "Maximum 10 tags allowed"),
);
// Array of objects
const UsersSchema = v.array(
v.object({
id: v.number(),
name: v.string(),
}),
);// Fixed-length array with specific types
const CoordinatesSchema = v.tuple([v.number(), v.number()]);
// Type: [number, number]
// Tuple with rest
const ArgsSchema = v.tupleWithRest(
[v.string()], // first arg is string
v.number(), // rest are numbers
);
// Type: [string, ...number[]]const StringOrNumberSchema = v.union([v.string(), v.number()]);
const StatusSchema = v.union([
v.literal("pending"),
v.literal("active"),
v.literal("inactive"),
]);// Simpler than union of literals
const StatusSchema = v.picklist(["pending", "active", "inactive"]);
const PrioritySchema = v.picklist([1, 2, 3]);Use variant for better performance with discriminated unions:
const EventSchema = v.variant("type", [
v.object({
type: v.literal("click"),
x: v.number(),
y: v.number(),
}),
v.object({
type: v.literal("keypress"),
key: v.string(),
}),
v.object({
type: v.literal("scroll"),
direction: v.picklist(["up", "down"]),
}),
]);import * as v from "valibot";
const EmailSchema = v.pipe(v.string(), v.email());
try {
const email = v.parse(EmailSchema, "jane@example.com");
console.log(email); // 'jane@example.com'
} catch (error) {
console.error(error); // ValiError
}const result = v.safeParse(EmailSchema, input);
if (result.success) {
console.log(result.output); // Valid data
} else {
console.log(result.issues); // Array of issues
}if (v.is(EmailSchema, input)) {
// input is typed as string
}// Abort early - stop at first error
v.parse(Schema, data, { abortEarly: true });
// Abort pipe early - stop pipeline at first error
v.parse(Schema, data, { abortPipeEarly: true });import * as v from "valibot";
const UserSchema = v.object({
name: v.string(),
age: v.pipe(v.string(), v.transform(Number)),
role: v.optional(v.string(), "user"),
});
// Output type (after transformations and defaults)
type User = v.InferOutput<typeof UserSchema>;
// { name: string; age: number; role: string }
// Input type (before transformations)
type UserInput = v.InferInput<typeof UserSchema>;
// { name: string; age: string; role?: string | undefined }
// Issue type
type UserIssue = v.InferIssue<typeof UserSchema>;const LoginSchema = v.object({
email: v.pipe(
v.string("Email must be a string"),
v.nonEmpty("Please enter your email"),
v.email("Invalid email format"),
),
password: v.pipe(
v.string("Password must be a string"),
v.nonEmpty("Please enter your password"),
v.minLength(8, "Password must be at least 8 characters"),
),
});const result = v.safeParse(LoginSchema, data);
if (!result.success) {
const flat = v.flatten(result.issues);
// { nested: { email: ['Invalid email format'], password: ['...'] } }
}Each issue contains:
kind: 'schema' | 'validation' | 'transformation'type: Function name (e.g., 'string', 'email', 'min_length')input: The problematic inputexpected: What was expectedreceived: What was receivedmessage: Human-readable messagepath: Array of path items for nested issues// Static fallback
const NumberSchema = v.fallback(v.number(), 0);
v.parse(NumberSchema, "invalid"); // Returns 0
// Dynamic fallback
const DateSchema = v.fallback(v.date(), () => new Date());import * as v from "valibot";
type TreeNode = {
value: string;
children: TreeNode[];
};
const TreeNodeSchema: v.GenericSchema<TreeNode> = v.object({
value: v.string(),
children: v.lazy(() => v.array(TreeNodeSchema)),
});For async operations (e.g., database checks), use async variants:
import * as v from "valibot";
const isUsernameAvailable = async (username: string) => {
// Check database
return true;
};
const UsernameSchema = v.pipeAsync(
v.string(),
v.minLength(3),
v.checkAsync(isUsernameAvailable, "Username is already taken"),
);
// Must use parseAsync
const username = await v.parseAsync(UsernameSchema, "john");import { toJsonSchema } from "@valibot/to-json-schema";
import * as v from "valibot";
const EmailSchema = v.pipe(v.string(), v.email());
const jsonSchema = toJsonSchema(EmailSchema);
// { type: 'string', format: 'email' }export const User = v.object({
name: v.string(),
email: v.pipe(v.string(), v.email()),
});
export type User = v.InferOutput<typeof User>;
// Usage
const users: User[] = [];
users.push(v.parse(User, data));export const UserSchema = v.object({
name: v.string(),
age: v.pipe(v.string(), v.transform(Number)),
});
export type UserInput = v.InferInput<typeof UserSchema>;
export type UserOutput = v.InferOutput<typeof UserSchema>;const LoginSchema = v.object({
email: v.pipe(
v.string(),
v.nonEmpty("Please enter your email"),
v.email("Invalid email address"),
),
password: v.pipe(
v.string(),
v.nonEmpty("Please enter your password"),
v.minLength(8, "Password must be at least 8 characters"),
),
});const ApiResponseSchema = v.variant("status", [
v.object({
status: v.literal("success"),
data: v.unknown(),
}),
v.object({
status: v.literal("error"),
error: v.object({
code: v.string(),
message: v.string(),
}),
}),
]);const EnvSchema = v.object({
NODE_ENV: v.picklist(["development", "production", "test"]),
PORT: v.pipe(v.string(), v.transform(Number), v.integer(), v.minValue(1)),
DATABASE_URL: v.pipe(v.string(), v.url()),
API_KEY: v.pipe(v.string(), v.minLength(32)),
});
const env = v.parse(EnvSchema, process.env);// String to Date
const DateFromStringSchema = v.pipe(
v.string(),
v.isoDate(),
v.transform((input) => new Date(input)),
);
// Date validation
const FutureDateSchema = v.pipe(
v.date(),
v.minValue(new Date(), "Date must be in the future"),
);© aidenlx, MIT. Rendered from Markdown: HTML in the file is shown as text, images as links, and headings moved down two levels. Raw file
Just SKILL.md in .agents/skills/valibot of aidenlx/zotlit.
Open the folder on GitHubat commit 27f5752
Valibot next to the 5 skills that share the most tags, products or categories with it. Stars are the repository's; “used in” counts other GitHub owners with a copy.
| Skill | Stars | Used in | Tokens | Auto-check | Licence | Repo updated |
|---|---|---|---|---|---|---|
| Valibot this skillaidenlx/zotlit | 1k | — | ~4.7k | Automated safety check: Pass | MIT | |
| Nuxt Contentsecondsky/claude-skills | 227 | — | ~4.3k | Automated safety check: Pass | MIT | |
| React Hook Form Zodsecondsky/claude-skills | 227 | — | ~4.8k | Automated safety check: Pass | MIT | |
| Typescript Patternssoftspark/ai-toolkit | 179 | — | ~1.6k | Automated safety check: Pass | Apache-2.0 | |
| Zod Validation Utilitiesgiuseppe-trisciuoglio/developer-kit | 356 | — | ~1.7k | Automated safety check: Notes | MIT | |
| Zodjasonjgardner/blockbench-mcp-plugin | 495 | 3 repos | ~1.4k | Automated safety check: Pass | GPL-3.0 |
secondsky/claude-skills
Nuxt Content v3 Git-based CMS for Markdown/MDC content sites.
secondsky/claude-skills
Type-safe React forms with React Hook Form and Zod validation.
softspark/ai-toolkit
TypeScript types: generics, discriminated unions, Zod, satisfies, branded types.
giuseppe-trisciuoglio/developer-kit
Creates reusable Zod v4 schemas, validates API payloads, forms, and configuration input, transforms and coerces data safely, and handles validation errors with strong type inference for TypeScript…
jasonjgardner/blockbench-mcp-plugin
Zod schema validation best practices for type safety, parsing, and error handling.
irahardianto/awesome-agv
Hono lightweight web framework patterns: type-safe route handlers, middleware composition, Zod validation, and RPC clients for Cloudflare Workers, Node, or Bun.
aidenlx/zotlit
Obsidian house style for the wording of user-facing UI strings — command names, setting labels, button text, notices, modal copy.
aidenlx/zotlit
Style Obsidian plugin UI with Tailwind + native components. An agent skill from aidenlx/zotlit.
aidenlx/zotlit
Typed regex authoring with arkregex in this repo. An agent skill from aidenlx/zotlit.
aidenlx/zotlit
Write a user-facing changelog entry under apps/docs/content/changelog/.
aidenlx/zotlit
Draft a Discord announcement from a changelog entry. An agent skill from aidenlx/zotlit.
aidenlx/zotlit
Define ZotLit UI messages in the Inlang Message Format and consume them through the generated JSON Language Pack facade.
Works with
Categories
Schema validation with Valibot, the modular and type-safe schema library. Valibot is an agent skill from aidenlx/zotlit. Schema validation with Valibot, the modular and type-safe schema library.
Valibot fits situations like: the user needs to validate data; work with Valibot in their project; migrating from Zod to Valibot.
Run `npx skills add aidenlx/zotlit --skill valibot -a claude-code`. Or copy the skill folder (.agents/skills/valibot in aidenlx/zotlit) into .claude/skills/valibot in your project. Claude Code loads it when a task matches its description.
Run `npx skills add aidenlx/zotlit --skill valibot -a codex`. Or copy the skill folder (.agents/skills/valibot in aidenlx/zotlit) into .agents/skills/valibot in your project. Codex loads it when a task matches its description.
Cursor, Gemini CLI, GitHub Copilot and OpenCode also load SKILL.md folders. With the skills CLI, run `npx skills add aidenlx/zotlit --skill valibot -a cursor` (or -a gemini-cli, github-copilot or opencode for the others). To copy it by hand, put the folder in .cursor/skills/valibot, .gemini/skills/valibot, .github/skills/valibot and .opencode/skills/valibot in your project.
Going by SKILL.md and its folder, Valibot needs the command-line tools its instructions call (npm, yarn, pnpm and bun) and credentials named API_KEY. Our summary lists: Node.js.
SKILL.md names 2 domains. As links in the text: valibot.dev and github.com. This is read from the text; nothing was executed.
Our automated static check of SKILL.md found no risky patterns, such as piping downloads into a shell, reading credential files or hidden Unicode. It is not a guarantee. Review the folder before installing.
Valibot is published under the MIT licence (declared in SKILL.md). It allows redistribution, so the full SKILL.md is shown on this page.
About 4.7k tokens (SKILL.md is roughly 19k characters). Agents keep only the skill's name and description in context until a task matches; then they load SKILL.md in full.
Skills that share tags, products or a category with Valibot: Nuxt Content (secondsky/claude-skills, 227 stars), React Hook Form Zod (secondsky/claude-skills, 227 stars), Typescript Patterns (softspark/ai-toolkit, 179 stars) and Zod Validation Utilities (giuseppe-trisciuoglio/developer-kit, 356 stars). The comparison table on this page puts their stars, adoption, token cost, safety result and licence side by side.
aidenlx (a GitHub user) maintains it in aidenlx/zotlit, which has 1,028 GitHub stars. The repository holds 16 skills in this directory. The repository was last updated on October 9, 2026.
Source: aidenlx/zotlit on GitHub. Facts on this page come from the repository at the commit we read; the author's words are quoted as theirs.