From golang
Zog schema validation library: schema definition, parsing, validation, error handling, HTTP/JSON/env integration, custom tests, and transforms. Invoke whenever task involves any interaction with Zog — writing schemas, parsing input, validating structs, handling errors, or integrating with HTTP handlers.
npx claudepluginhub xobotyi/cc-foundry --plugin golangThis skill uses the workspace's default tool permissions.
Zod-inspired schema validation for Go. Declarative schema builder with runtime parsing and validation. Import as
Generates design tokens/docs from CSS/Tailwind/styled-components codebases, audits visual consistency across 10 dimensions, detects AI slop in UI.
Records polished WebM UI demo videos of web apps using Playwright with cursor overlay, natural pacing, and three-phase scripting. Activates for demo, walkthrough, screen recording, or tutorial requests.
Delivers idiomatic Kotlin patterns for null safety, immutability, sealed classes, coroutines, Flows, extensions, DSL builders, and Gradle DSL. Use when writing, reviewing, refactoring, or designing Kotlin code.
Zod-inspired schema validation for Go. Declarative schema builder with runtime parsing and validation. Import as
z "github.com/Oudwins/zog".
z.Shape{} must match struct field names, not input data keys — use struct tags (json, form,
zog) for input key mappingZogIssueListlen(errs) > 0, not errs != nilTwo entry points, same schemas:
schema.Parse(data, &dest, ...opts) — coerces untyped input into destination. Use at IO boundaries (HTTP, JSON, env)schema.Validate(&value, ...opts) — validates existing Go values. No coercion. More efficient when data is already
typedKey difference: Validate treats zero values as missing when Required() is set. Use z.Ptr() + .NotNil() to
distinguish "not provided" from "zero value":
// Parse can distinguish 0 from missing
z.Int().Required().Parse(0, &dest) // ok
// Validate cannot — use pointer
z.Ptr(z.Int()).NotNil().Validate(&valPtr) // nil = missing, *0 = valid
Prefer Validate when data is already typed. Use Parse when accepting external input that needs coercion.
All primitive .Parse() / .Validate() return ZogIssueList.
String:
z.String() — base string schema.Trim() — transform: trims whitespace.Min(n), .Max(n), .Len(n) — length validators.Email(), .URL(), .UUID(), .IPv4() — format validators.Match(regex) — regex match.Contains(s), .ContainsUpper(), .ContainsDigit(), .ContainsSpecial() — content validators.HasPrefix(s), .HasSuffix(s) — prefix/suffix validators.OneOf([]string{...}) — enum-like validation (replaces Zod's z.Enum()).Not() — negates the next testNumbers:
z.Int(), z.Int32(), z.Int64(), z.Float32(), z.Float64() — numeric schemas.GT(n), .GTE(n), .LT(n), .LTE(n), .EQ(n) — comparison validators.OneOf([]T{...}) — enum-like validation.Not() — negates the next testBool:
z.Bool() — boolean schema.True(), .False(), .EQ(v) — value validatorsTime:
z.Time() — validates time.Time.After(t), .Before(t), .Is(t) — temporal validatorsz.Time(z.Time.Format(layout)) — parse strings using layout (default: time.RFC3339). Coercion only works with
Parse(), not Validate()Struct:
schema := z.Struct(z.Shape{
"name": z.String().Required(),
"age": z.Int().GT(0),
})
.Pick("key1", map[string]bool{"a": true}) — shallow copy with only specified fields.Omit("key1", map[string]bool{"a": true}) — shallow copy without specified fields.Extend(z.Shape{...}) — shallow copy with additional fields.Merge(other1, other2) — merge schemas, last wins on conflictRequired() or Optional() — use z.Ptr(z.Struct(...)) for optional structsSlice:
schema := z.Slice(z.String().Required())
.Min(n), .Max(n), .Length(n) — size validators.Contains(val) — element presence validator.Not() — negates the next testPointer:
z.Ptr(z.String()) // pointer to string
.NotNil() — equivalent to Required() for other typesBoxed:
z.Boxed[BoxType, InnerType](innerSchema, unboxFunc, boxFunc)
Wraps a schema with custom box/unbox logic for types like sql.NullString, driver.Valuer, or custom wrappers. The
unboxFunc extracts the inner value; boxFunc creates the wrapper from validated value (can be nil if boxing not
needed).
For named types based on primitives:
type Env string
z.StringLike[Env]().OneOf([]Env{"prod", "dev"})
Available: z.StringLike[T](), z.IntLike[T](), z.FloatLike[T](), z.UintLike[T](), z.BoolLike[T]()
Quick validation for non-primitive types without defining a full schema:
z.CustomFunc(func(valPtr *uuid.UUID, ctx z.Ctx) bool {
return valPtr.IsValid()
}, z.Message("invalid uuid"))
Does not support coercion.
Available on all schema types:
.Required() — field must be present and non-zero.Optional() — field can be absent (default behavior).Default(val) / .DefaultFunc(fn) — use this value when input is zero. Takes priority over Required(). Tests
still run.Catch(val) / .CatchFunc(fn) — on any error, set destination to this value and stop execution.Test(z.Test{...}) — complex custom test (like Zod's superRefine).TestFunc(fn, ...opts) — simple custom test (like Zod's refine).Transform(func(valPtr *T, ctx z.Ctx) error) — post-validation in-place mutationExecution order: nil check → default/required → coerce → validation loop (tests + transforms in order) → catch on error
Schema keys match struct field names by default. Use struct tags for input key mapping:
json — JSON inputform — form dataquery — query paramsenv — environment variableszog — catch-all, works for any inputPriority: json/form/query/env → zog → schema field name
type User struct {
Name string `zog:"first-name"`
LastName string `query:"last_name" json:"last-name"`
}
Simple (refine-like): Return bool — Zog creates the issue:
z.String().TestFunc(func(data *string, ctx z.Ctx) bool {
return *data == "expected"
}, z.Message("must be expected"))
For structs/slices, the parameter is any — cast manually:
z.Struct(z.Shape{...}).TestFunc(func(dataPtr any, ctx z.Ctx) bool {
user := dataPtr.(*User)
return user.Name != ""
})
Complex (superRefine-like): Add issues manually via context:
z.String().Test(z.Test{
Func: func(val any, ctx z.Ctx) {
s := val.(string)
if !isValid(s) {
ctx.AddIssue(ctx.Issue().SetMessage("invalid value"))
}
},
})
Reusable tests: Wrap in functions returning z.Test[T]:
func MinWords(n int, opts ...z.TestOption) z.Test[any] {
options := []z.TestOption{z.Message(fmt.Sprintf("must have at least %d words", n))}
options = append(options, opts...)
return z.TestFunc(func(val any, ctx z.Ctx) bool {
s := val.(*string)
return len(strings.Fields(*s)) >= n
}, options...)
}
Post-validation mutation via pointer. Runs in declaration order with tests:
z.String().Min(3).Transform(func(valPtr *string, ctx z.Ctx) error {
*valPtr = strings.ToLower(*valPtr)
return nil
})
Struct transforms receive any — cast to struct pointer:
z.Struct(z.Shape{...}).Transform(func(dataPtr any, ctx z.Ctx) error {
user := dataPtr.(*User)
user.FullName = user.First + " " + user.Last
return nil
})
Returning an error from a transform stops execution and produces an issue.
Transform input before parsing. Pure function — creates a copy:
z.Preprocess(func(data any, ctx z.Ctx) (any, error) {
s, ok := data.(string)
if !ok {
return nil, fmt.Errorf("expected string, got %T", data)
}
return strings.Split(s, ","), nil
}, z.Slice(z.String().Email().Required()))
Footgun: With Validate(), the data argument is a pointer to the value, not the raw input.
type ZogIssue struct {
Code zconst.ZogIssueCode // issue identifier (e.g., "required", "min", "email")
Path []string // location in data structure (nil for root primitives)
Value any // input value that caused the issue
Dtype string // destination type
Params map[string]any // test parameters (may be nil)
Message string // human-readable, user-safe message
Err error // underlying error or nil
}
All schemas return ZogIssueList = []*ZogIssue. Each issue has a Path field:
nil[]string{"name"}[]string{"address", "streets", "[0]"}issue.PathString() or z.Issues.FlattenPath(issue.Path)z.Issues.Flatten(errs) — map[path][]messages. Root issues under "$root" key (zconst.ISSUE_KEY_ROOT)z.Issues.Treeify(errs) — nested tree mirroring data structure. Each node has errors array and properties/itemsz.Issues.Prettify(errs) — human-readable string with ✖ prefix and → at path linesCommon codes: required, coerce, custom, min, max, len, email, uuid, url, match, gt, gte, lt,
lte, eq, one_of_options, after, before, true, false, prefix, suffix, contains_upper,
contains_digit, contains_special, contained
HTTP-specific: invalid_json, invalid_form, invalid_query
Per-test: z.Message("text"), z.MessageFunc(fn), z.IssueCode("code"), z.IssuePath("path")
z.String().Min(5, z.Message("must be at least 5 chars"))
Per-execution: z.WithIssueFormatter(fn) — overrides all messages for one Parse/Validate call
Global: Override conf.DefaultIssueMessageMap[zconst.TypeString][zconst.IssueCodeRequired] or replace
conf.IssueFormatter
Options passed to any test:
z.Message("...") — static issue messagez.MessageFunc(func(e *ZogIssue, ctx z.Ctx)) — dynamic issue messagez.IssueCode("...") — override issue codez.IssuePath("...") — override issue pathOptions passed to Parse() / Validate():
z.WithCoercer(fn) — per-schema coercion override (Parse only)z.WithIssueFormatter(fn) — override message formatting for this executionz.WithCtxValue(key, val) — pass custom data to tests/transforms via ctx.Get(key)z.Ctx interface available in tests, transforms, and preprocessors:
ctx.Get(key) — retrieve value set via z.WithCtxValue()ctx.AddIssue(issue) — add a custom issuectx.Issue() — create a new issue pre-filled with current schema context (path, value, type)import "github.com/Oudwins/zog/zhttp"
errs := userSchema.Parse(zhttp.Request(r), &user)
zhttp.Request(r) auto-detects content type (JSON, form, query params). Only supports parsing into structs.
Invalid input produces a root issue with code invalid_json, invalid_form, or invalid_query — the schema does not
run.
import "github.com/Oudwins/zog/parsers/zjson"
errs := userSchema.Parse(zjson.Decode(bytes.NewReader(jsonBytes)), &user)
Accepts io.Reader or io.ReaderCloser. Only supports structs.
import "github.com/Oudwins/zog/zenv"
errs := envSchema.Parse(zenv.NewDataProvider(), &cfg)
Use env or zog struct tags for key mapping. Coercion handles string-to-type conversion automatically.
import (
"github.com/Oudwins/zog/i18n"
"github.com/Oudwins/zog/i18n/en"
"github.com/Oudwins/zog/i18n/es"
)
// Setup
i18n.SetLanguagesErrsMap(map[string]i18n.LangMap{
"en": en.Map,
"es": es.Map,
}, "en") // default language
// Per-execution
schema.Parse(data, &dest, z.WithCtxValue(i18n.LangKey, "es"))
Single language: set conf.DefaultErrMsgMap = es.Map.
Via github.com/Oudwins/zog/conf:
conf.Coercers.Float64 = func(data any) (any, error) {...} — override type coercionconf.DefaultCoercers.Float64(data) — fallback to default coercerconf.DefaultIssueMessageMap — override issue messages per type and codeconf.IssueFormatter — replace the global issue formattervar userSchema = z.Struct(z.Shape{
"ID": z.Int().Required(),
"Name": z.String().Required().Min(2),
})
func (u *User) Validate() z.ZogIssueList {
return userSchema.Validate(u)
}
func handleCreate(w http.ResponseWriter, r *http.Request) {
var user User
if errs := userSchema.Parse(zhttp.Request(r), &user); len(errs) > 0 {
w.WriteHeader(http.StatusBadRequest)
json.NewEncoder(w).Encode(z.Issues.Flatten(errs))
return
}
// user is valid and populated
}
var envSchema = z.Struct(z.Shape{
"PORT": z.Int().GT(1000).LT(65535).Default(3000),
"DB_HOST": z.String().Default("localhost"),
})
var Env = func() Config {
var c Config
if errs := envSchema.Parse(zenv.NewDataProvider(), &c); len(errs) > 0 {
log.Fatal(z.Issues.Prettify(errs))
}
return c
}()
z.Map() schemazhttp and zjson only parse into structsCatch(); structs do not support Default()Pick, Omit, Extend, Merge are not type-safeWhen writing code with Zog: apply all conventions silently — don't narrate each rule. Always check errors with
len(errs) > 0. Define schemas as package-level var, not inside functions. If an existing codebase contradicts a
convention, follow the codebase and flag the divergence once.
When reviewing code with Zog: cite the specific violation and show the fix inline. Proactively flag: errs != nil
checks (must be len(errs) > 0), missing Required() on mandatory fields, schema keys not matching struct field names,
and missing struct tags for external input mapping.
The golang skill governs Go language conventions. This skill governs Zog-specific API and patterns. When both apply,
Zog idioms (e.g., z.Shape{} key naming) take precedence over general Go naming rules within schema definitions.