Awesome-omni-skill cue

CUE schema patterns for *.cue files, 3-step parsing flow, validation matrix, error formatting. Use when editing invowkfile_schema.cue, invowkmod_schema.cue, config_schema.cue, or working with cueutil parsing.

install
source · Clone the upstream repo
git clone https://github.com/diegosouzapw/awesome-omni-skill
Claude Code · Install into ~/.claude/skills/
T=$(mktemp -d) && git clone --depth=1 https://github.com/diegosouzapw/awesome-omni-skill "$T" && mkdir -p ~/.claude/skills && cp -r "$T/skills/development/cue" ~/.claude/skills/diegosouzapw-awesome-omni-skill-cue && rm -rf "$T"
manifest: skills/development/cue/SKILL.md
source content

CUE Schema Patterns

Use this skill when:

  • Working with CUE schema files (
    *.cue
    )
  • Modifying parse functions in
    pkg/invowkfile/
    ,
    pkg/invowkmod/
    , or
    internal/config/
  • Adding new CUE definitions or corresponding Go struct fields
  • Debugging CUE validation errors

Schema Locations

  • pkg/invowkfile/invowkfile_schema.cue
    defines invowkfile structure.
  • pkg/invowkmod/invowkmod_schema.cue
    defines invowkmod structure.
  • internal/config/config_schema.cue
    defines config.

Schema Compilation Pattern (3-Step Flow)

All CUE parsing in Invowk follows a consistent 3-step pattern:

// Step 1: Compile the schema (embedded via //go:embed)
ctx := cuecontext.New()
schemaValue := ctx.CompileString(embeddedSchema)
if schemaValue.Err() != nil {
    return nil, fmt.Errorf("internal error: failed to compile schema: %w", schemaValue.Err())
}

// Step 2: Compile user data and unify with schema
userValue := ctx.CompileBytes(data, cue.Filename(path))
if userValue.Err() != nil {
    return nil, formatCUEError(userValue.Err(), path)
}

schema := schemaValue.LookupPath(cue.ParsePath("#DefinitionName"))
unified := schema.Unify(userValue)
if err := unified.Validate(cue.Concrete(true)); err != nil {
    return nil, formatCUEError(err, path)
}

// Step 3: Decode to Go struct
var result GoStructType
if err := unified.Decode(&result); err != nil {
    return nil, formatCUEError(err, path)
}

Key Points:

  • Schema is embedded via
    //go:embed
    for single-binary distribution
  • Use
    LookupPath()
    to get the root definition (e.g.,
    #Invowkfile
    ,
    #Config
    )
  • Use
    Validate(cue.Concrete(true))
    to ensure all values are concrete
  • Use
    cue.Concrete(false)
    for config files where some fields may be optional
  • Always use
    Decode()
    for type-safe extraction (see Decode Usage Rules below)

Reference Implementations:

  • pkg/invowkfile/parse.go:ParseBytes()
    - Invowkfile parsing
  • pkg/invowkmod/invowkmod.go:ParseInvowkmodBytes()
    - Invowkmod parsing
  • internal/config/config.go:loadCUEIntoViper()
    - Config loading

Validation Responsibility Matrix

Validation is split between CUE and Go based on what each can handle:

CUE Handles (Declarative, Schema-Level)

Validation TypeCUE ConstructExample
Type checkingNative
name: string
Field format (regex)
=~
name: =~"^[a-zA-Z][a-zA-Z0-9_-]*$"
Enum valuesDisjunction
"native" | "virtual" | "container"
Length limits
strings.MaxRunes()
& strings.MaxRunes(256)
Range constraintsExpressions
>=0 & <=65535
Required fieldsNo
?
suffix
name: string
(required)
Optional fields
?
suffix
description?: string
(optional)
Closed structs
close({})
Rejects unknown fields
Mutual exclusivityXOR constraintsSee runtime config patterns
Non-empty listsPattern
[_, ...]
(at least one)

Go Handles (Dynamic, Runtime-Level)

Validation TypeWhy Go-OnlyExample
ReDoS preventionCUE cannot analyze regex complexity
ValidateRegexPattern()
File existenceRequires filesystem access
os.Stat()
Path traversalCross-platform normalization
filepath.Clean()
checks
Cross-field logicConditional requirementsRuntime-specific fields
Command hierarchyRequires tree analysisLeaf-only args constraint
Length limits (defense-in-depth)Some limits enforced in Go too
MaxNameLength
checks

Justification Comments

All Go-only validations MUST include a

[GO-ONLY]
comment explaining why:

// ValidateRegexPattern validates a user-provided regex pattern for safety.
// [GO-ONLY] ReDoS (Regular Expression Denial of Service) prevention MUST be in Go.
// CUE cannot analyze regex complexity or detect catastrophic backtracking patterns.
func ValidateRegexPattern(pattern string) error { ... }
// validateEnvFilePath validates an env file path for security.
// [GO-ONLY] Path traversal prevention and cross-platform path handling require Go.
// CUE cannot perform filesystem operations or cross-platform path normalization.
func validateEnvFilePath(path string) error { ... }

Decode Usage Rules

ALWAYS use

value.Decode(&goStruct)
for type-safe extraction.

Correct Pattern

var invowkfile Invowkfile
if err := unified.Decode(&invowkfile); err != nil {
    return nil, formatCUEError(err, path)
}

Why Not Manual Extraction?

Manual extraction methods (

String()
,
Int64()
,
Bool()
) are error-prone:

  • No compile-time type checking
  • Requires manual error handling for each field
  • Easy to forget optional field handling
  • Doesn't leverage CUE's type system

Exception: Manual extraction is acceptable only for truly dynamic scenarios (e.g., extracting arbitrary user-defined keys). Document such cases.

Field Naming Convention

CUE uses

snake_case
, Go uses
PascalCase
. The JSON tag bridges them:

// CUE Schema (snake_case)
#Config: close({
    container_engine: #ContainerEngine
    includes:         [...#IncludeEntry]
    default_runtime:  #RuntimeType
})
// Go Struct (PascalCase with JSON tags)
type Config struct {
    ContainerEngine ContainerEngine `json:"container_engine"`
    Includes        []IncludeEntry  `json:"includes"`
    DefaultRuntime  RuntimeMode     `json:"default_runtime"`
}

Rule: Every CUE field name MUST have a matching JSON tag in the corresponding Go struct.

Verification: Schema sync tests (in

*_sync_test.go
files) catch mismatches at CI time.

Error Formatting Requirements

All CUE errors MUST include JSON path prefixes for clear error messages:

Error Format

<file-path>: <json-path>: <message>

Examples:

invowkfile.cue: cmds[0].implementations[2].script: value exceeds maximum length
config.cue: container.auto_provision.enabled: expected bool, got string

Implementation Pattern

Use the

formatCUEError()
helper (available in each package):

import "cuelang.org/go/cue/errors"

func formatCUEError(err error, filePath string) error {
    if err == nil {
        return nil
    }

    cueErrors := errors.Errors(err)
    if len(cueErrors) == 0 {
        return fmt.Errorf("%s: %w", filePath, err)
    }

    var lines []string
    for _, e := range cueErrors {
        path := errors.Path(e)
        pathStr := formatPath(path)  // Convert ["cmds", "0", "script"] to "cmds[0].script"
        msg := e.Error()

        if pathStr != "" {
            lines = append(lines, fmt.Sprintf("%s: %s", pathStr, msg))
        } else {
            lines = append(lines, msg)
        }
    }

    if len(lines) == 1 {
        return fmt.Errorf("%s: %s", filePath, lines[0])
    }
    return fmt.Errorf("%s: validation failed:\n  %s", filePath, strings.Join(lines, "\n  "))
}

Important: Import

cuelang.org/go/cue/errors
, NOT the standard library
errors
. Only CUE's error package provides
Errors()
and
Path()
functions.

CUE Library Version Pinning

Current Version

CUE is pinned in

go.mod
:

cuelang.org/go v0.15.4

Upgrade Process

When upgrading the CUE library version:

  1. Review Changelog: Check for breaking changes in the CUE release notes
  2. Run Full Test Suite:
    make test
    including all schema sync tests
  3. Check API Deprecations: Search for deprecated function usage
  4. Verify Error Formats: Manually test that error messages still include paths
  5. Update Documentation: If CUE behavior changes, update this rules file
  6. Test Cross-Platform: Run CI on all platforms (Linux, macOS, Windows)

Known CUE Limitations

  • No Encode API: CUE can decode Go structs but has no production-ready encoder
  • No Code Generation:
    gengotypes
    is experimental; we use sync tests instead
  • Context is Stateful: Create a new
    cuecontext.New()
    for each parse operation

Rules

  • All CUE structs must be closed (use
    close({ ... })
    ) so unknown fields cause validation errors.
  • When adding new CUE struct fields or definitions, always include appropriate validation constraints (e.g.,
    strings.MaxRunes()
    , regex patterns with
    =~
    , range constraints like
    >=0 & <=255
    ) - not just type declarations. This ensures defense-in-depth validation.
  • Schema sync tests MUST exist for every Go struct that corresponds to a CUE definition.
  • Go-only validations MUST have
    [GO-ONLY]
    comments explaining why CUE cannot handle them.

Schema Sync Tests

Sync tests verify Go struct JSON tags match CUE schema field names at CI time. They catch misalignments before they cause silent parsing failures.

Test Files:

  • pkg/invowkfile/sync_test.go
    - Invowkfile, Command, Implementation, etc.
  • pkg/invowkmod/sync_test.go
    - Invowkmod, ModuleRequirement
  • internal/config/sync_test.go
    - Config, VirtualShellConfig, UIConfig, etc.

Pattern:

func TestStructNameSchemaSync(t *testing.T) {
    schema, _ := getCUESchema(t)
    cueFields := extractCUEFields(t, lookupDefinition(t, schema, "#DefinitionName"))
    goFields := extractGoJSONTags(t, reflect.TypeFor[GoStructType]())

    assertFieldsSync(t, "StructName", cueFields, goFields)
}

When to Add Sync Tests:

  • Adding a new CUE definition with a corresponding Go struct
  • Adding new fields to existing CUE/Go types
  • Renaming fields (test will fail until both are updated)

Common Pitfalls

Unclosed CUE Structs

Problem: Open structs allow arbitrary unknown fields, bypassing validation.

// WRONG: Open struct - unknown fields silently accepted
#Config: {
    name: string
}

// CORRECT: Closed struct - unknown fields rejected
#Config: close({
    name: string
})

Redundant Validation

Problem: Same validation in both CUE and Go creates maintenance burden.

Rule: Validation lives in ONE place. CUE handles format/type validation. Go handles security/filesystem/cross-field logic.

Anti-Pattern:

// WRONG: Duplicates CUE regex validation
if !regexp.MustCompile(`^[a-zA-Z][a-zA-Z0-9_-]*$`).MatchString(name) {
    return fmt.Errorf("invalid name format")
}

Correct Pattern:

// CORRECT: CUE handles format; Go handles length (defense-in-depth)
// [GO-ONLY] Length limit not in CUE for simplicity; checked here for defense-in-depth.
if len(name) > MaxNameLength {
    return fmt.Errorf("name too long (%d chars, max %d)", len(name), MaxNameLength)
}

Missing JSON Tags

Problem: Go struct field without JSON tag won't be populated by

Decode()
.

Symptom: Field is always zero value despite being in CUE file.

Fix: Add JSON tag matching the CUE field name:

type Config struct {
    Includes  []IncludeEntry `json:"includes"`  // Matches CUE field
    CachePath string         // No JSON tag - will be empty!
}

Wrong Error Import

Problem: Using standard library

errors
instead of CUE's error package.

// WRONG: Standard library - no Path() function
import "errors"

// CORRECT: CUE error package with path extraction
import "cuelang.org/go/cue/errors"

Stale Schema Sync Tests

Problem: Sync test exclusions become outdated after refactoring.

Fix: After any CUE/Go struct changes, run

make test
and verify sync tests pass. Remove obsolete exclusions.