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.
git clone https://github.com/diegosouzapw/awesome-omni-skill
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"
skills/development/cue/SKILL.mdCUE Schema Patterns
Use this skill when:
- Working with CUE schema files (
)*.cue - Modifying parse functions in
,pkg/invowkfile/
, orpkg/invowkmod/internal/config/ - Adding new CUE definitions or corresponding Go struct fields
- Debugging CUE validation errors
Schema Locations
defines invowkfile structure.pkg/invowkfile/invowkfile_schema.cue
defines invowkmod structure.pkg/invowkmod/invowkmod_schema.cue
defines config.internal/config/config_schema.cue
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
for single-binary distribution//go:embed - Use
to get the root definition (e.g.,LookupPath()
,#Invowkfile
)#Config - Use
to ensure all values are concreteValidate(cue.Concrete(true)) - Use
for config files where some fields may be optionalcue.Concrete(false) - Always use
for type-safe extraction (see Decode Usage Rules below)Decode()
Reference Implementations:
- Invowkfile parsingpkg/invowkfile/parse.go:ParseBytes()
- Invowkmod parsingpkg/invowkmod/invowkmod.go:ParseInvowkmodBytes()
- Config loadinginternal/config/config.go:loadCUEIntoViper()
Validation Responsibility Matrix
Validation is split between CUE and Go based on what each can handle:
CUE Handles (Declarative, Schema-Level)
| Validation Type | CUE Construct | Example |
|---|---|---|
| Type checking | Native | |
| Field format (regex) | | |
| Enum values | Disjunction | |
| Length limits | | |
| Range constraints | Expressions | |
| Required fields | No suffix | (required) |
| Optional fields | suffix | (optional) |
| Closed structs | | Rejects unknown fields |
| Mutual exclusivity | XOR constraints | See runtime config patterns |
| Non-empty lists | Pattern | (at least one) |
Go Handles (Dynamic, Runtime-Level)
| Validation Type | Why Go-Only | Example |
|---|---|---|
| ReDoS prevention | CUE cannot analyze regex complexity | |
| File existence | Requires filesystem access | |
| Path traversal | Cross-platform normalization | checks |
| Cross-field logic | Conditional requirements | Runtime-specific fields |
| Command hierarchy | Requires tree analysis | Leaf-only args constraint |
| Length limits (defense-in-depth) | Some limits enforced in Go too | 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
for type-safe extraction.value.Decode(&goStruct)
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:
- Review Changelog: Check for breaking changes in the CUE release notes
- Run Full Test Suite:
including all schema sync testsmake test - Check API Deprecations: Search for deprecated function usage
- Verify Error Formats: Manually test that error messages still include paths
- Update Documentation: If CUE behavior changes, update this rules file
- 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:
is experimental; we use sync tests insteadgengotypes - Context is Stateful: Create a new
for each parse operationcuecontext.New()
Rules
- All CUE structs must be closed (use
) so unknown fields cause validation errors.close({ ... }) - When adding new CUE struct fields or definitions, always include appropriate validation constraints (e.g.,
, regex patterns withstrings.MaxRunes()
, range constraints like=~
) - not just type declarations. This ensures defense-in-depth validation.>=0 & <=255 - Schema sync tests MUST exist for every Go struct that corresponds to a CUE definition.
- Go-only validations MUST have
comments explaining why CUE cannot handle them.[GO-ONLY]
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:
- Invowkfile, Command, Implementation, etc.pkg/invowkfile/sync_test.go
- Invowkmod, ModuleRequirementpkg/invowkmod/sync_test.go
- Config, VirtualShellConfig, UIConfig, etc.internal/config/sync_test.go
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.