open-circle/agent-skillsMIT2 files

Valibot

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.

Specification
Skill ID
open-circle/agent-skills/valibot
Publisher
open-circle
Repository
agent-skills
Installs
0
Files
2
License
MIT
Synced
Sep 23, 2026
How to use it

Open any RiverX project, open the Skills panel in the chat, and search for this identifier. The files are fetched from the source repository at install time.

open-circle/agent-skills/valibotInstalls these files
  • .claude-plugin/plugin.json
  • SKILL.md

What this skill tells the agent

Valibot

This skill helps you work effectively with Valibot, the modular and type-safe schema library for validating structural data.

When to use this skill

  • When the user asks about schema validation with Valibot
  • When creating or modifying Valibot schemas
  • When parsing or validating user input
  • When the user mentions Valibot, schema, or validation
  • When migrating from Zod to Valibot

CRITICAL: Valibot vs Zod — Do Not Confuse!

Valibot and Zod have different APIs. Never mix them up!

Key Differences

FeatureZod ❌Valibot ✅
Importimport { z } from 'zod'import * as v from 'valibot'
ValidationsChained methods: .email().min(5)Pipeline: v.pipe(v.string(), v.email(), v.minLength(5))
Parsingschema.parse(data)v.parse(schema, data)
Safe parsingschema.safeParse(data)v.safeParse(schema, data)
Optionalz.string().optional()v.optional(v.string())
Nullablez.string().nullable()v.nullable(v.string())
Defaultz.string().default('x')v.optional(v.string(), 'x')
Transformz.string().transform(fn)v.pipe(v.string(), v.transform(fn))
Refine/Checkz.string().refine(fn)v.pipe(v.string(), v.check(fn))
Enumz.enum(['a', 'b'])v.picklist(['a', 'b'])
Native enumz.nativeEnum(MyEnum)v.enum(MyEnum)
Unionz.union([a, b])v.union([a, b])
Discriminated unionz.discriminatedUnion('type', [...])v.variant('type', [...])
Intersectionz.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 typez.infer<typeof Schema>v.InferOutput<typeof Schema>
Infer inputz.input<typeof Schema>v.InferInput<typeof Schema>

Common Mistakes to Avoid

// ❌ 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");

Installation

npm install valibot     # npm
yarn add valibot        # yarn
pnpm add valibot        # pnpm
bun add valibot         # bun

Import with a wildcard (recommended):

import * as v from "valibot";

Or with individual imports:

import { object, string, pipe, email, parse } from "valibot";

Mental Model

Valibot's API is divided into three main concepts:

1. Schemas

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(),
});

2. Methods

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
}

3. Actions

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

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"),
);

Common Validation Actions

String validations:

  • v.email() — Valid email format
  • v.url() — Valid URL format
  • v.uuid() — Valid UUID format
  • v.regex(pattern) — Match regex pattern
  • v.minLength(n) — Minimum length
  • v.maxLength(n) — Maximum length
  • v.length(n) — Exact length
  • v.nonEmpty() — Not empty string
  • v.startsWith(str) — Starts with string
  • v.endsWith(str) — Ends with string
  • v.includes(str) — Contains string

Number 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 integer
  • v.finite() — Must be finite
  • v.safeInteger() — Safe integer range
  • v.multipleOf(n) — Must be multiple of n

Array validations:

  • v.minLength(n) — Minimum items
  • v.maxLength(n) — Maximum items
  • v.length(n) — Exact item count
  • v.nonEmpty() — At least one item
  • v.includes(item) — Contains item
  • v.excludes(item) — Does not contain item

Custom Validation with check()

const 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"),
);

Value Transformations

These actions modify the value without changing its type:

String transformations:

  • v.trim() — Remove leading/trailing whitespace
  • v.trimStart() — Remove leading whitespace
  • v.trimEnd() — Remove trailing whitespace
  • v.toLowerCase() — Convert to lowercase
  • v.toUpperCase() — Convert to uppercase

Number 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));

Type Transformations

Use this skill in a project

Open any RiverX project, search the Skills panel for open-circle/agent-skills/valibot, and install it in one click.

Use this skill