advanced-lokstra-validate-consistency
Ensures application integrity through static and runtime consistency checks.
Install
mkdir -p .claude/skills/advanced-lokstra-validate-consistency && curl -L -o skill.zip "https://agentskills.codes/api/skills/download/10553" && unzip -o skill.zip -d .claude/skills/advanced-lokstra-validate-consistency && rm skill.zipInstalls to .claude/skills/advanced-lokstra-validate-consistency
Activation
This is the description your AI agent reads to decide when to run this skill — the better it matches your request, the more reliably it fires.
Validate application consistency - circular dependencies, schema validation, config checks, annotation validation, and service registration. Use after all code is implemented to identify issues before deployment.Key capabilities
- →Detect circular dependencies
- →Validate schema against migrations
- →Check configuration completeness
- →Verify annotation correctness
- →Validate service registration
How it works
Performs static analysis on annotations and imports, runtime resolution checks, and database schema verification.
Inputs & outputs
When to use advanced-lokstra-validate-consistency
- →Validate configuration completeness
- →Check for circular service dependencies
- →Verify database schema against migrations
- →Run pre-deployment consistency checks
About this skill
Advanced: Validate Consistency
Overview
This skill provides comprehensive validation tools for Lokstra applications to ensure:
- Code quality and dependency correctness
- Configuration completeness and validity
- Database schema consistency
- Annotation correctness
- Service registration and injection validity
Validation Categories:
- Static Analysis - Runs without starting the app (annotations, imports, config files)
- Runtime Validation - Runs at application startup (service resolution, DI)
- Database Validation - Requires database connection (schema, migrations)
When to Use
Use this skill when:
- Before merging code to production branch
- Checking for circular dependencies between services
- Validating configuration completeness
- Ensuring database schema matches migrations
- Detecting configuration mismatches
- Pre-deployment validation
- CI/CD pipeline integration
Prerequisites:
- ✅ All code implemented (Phase 1-2 complete)
- ✅ Configuration finalized (config.yaml, configs/*.yaml)
- ✅ Database migrations created
- ✅ Ready for deployment
Quick Validation Commands
# 1. Compile-time check (catches most errors)
go build ./...
# 2. Run with --generate-only (validates annotations without running server)
go run . --generate-only
# 3. Run all tests
go test ./... -v
# 4. Run specific validation scripts
go run scripts/validate_config.go
go run scripts/validate_deps.go
go run scripts/validate_annotations.go
# 5. Full pre-deployment check
bash scripts/pre_deploy_check.sh
1. Annotation Validation
Validate @Handler, @Service, @Route, @Inject Annotations
Lokstra generates code from annotations. Invalid annotations cause runtime failures.
File: scripts/validate_annotations.go
package main
import (
"fmt"
"go/ast"
"go/parser"
"go/token"
"os"
"path/filepath"
"regexp"
"strings"
)
type ValidationError struct {
File string
Line int
Message string
}
var (
handlerPattern = regexp.MustCompile(`@Handler\s+(?:name\s*=\s*"([^"]+)")?`)
servicePattern = regexp.MustCompile(`@Service\s+"([^"]+)"`)
routePattern = regexp.MustCompile(`@Route\s+"(GET|POST|PUT|PATCH|DELETE|HEAD|OPTIONS)\s+([^"]+)"`)
injectPattern = regexp.MustCompile(`@Inject\s+"([^"]+)"`)
)
func main() {
root := "./modules"
errors := validateAnnotations(root)
if len(errors) > 0 {
fmt.Println("❌ ANNOTATION VALIDATION ERRORS:")
for _, err := range errors {
fmt.Printf(" %s:%d - %s\n", err.File, err.Line, err.Message)
}
os.Exit(1)
}
fmt.Println("✅ All annotations are valid")
}
func validateAnnotations(root string) []ValidationError {
var errors []ValidationError
handlerNames := make(map[string]string) // name -> file
serviceNames := make(map[string]string) // name -> file
filepath.Walk(root, func(path string, info os.FileInfo, err error) error {
if err != nil || info.IsDir() || !strings.HasSuffix(path, ".go") {
return nil
}
// Skip generated files
if strings.HasSuffix(path, "_lokstra_gen.go") {
return nil
}
fset := token.NewFileSet()
f, parseErr := parser.ParseFile(fset, path, nil, parser.ParseComments)
if parseErr != nil {
errors = append(errors, ValidationError{
File: path,
Line: 0,
Message: fmt.Sprintf("Parse error: %v", parseErr),
})
return nil
}
// Extract comments and validate annotations
for _, cg := range f.Comments {
for _, c := range cg.List {
line := fset.Position(c.Pos()).Line
text := c.Text
// Validate @Handler
if strings.Contains(text, "@Handler") {
if match := handlerPattern.FindStringSubmatch(text); match != nil {
name := match[1]
if name == "" {
errors = append(errors, ValidationError{
File: path,
Line: line,
Message: "@Handler missing required 'name' parameter",
})
} else if existing, exists := handlerNames[name]; exists {
errors = append(errors, ValidationError{
File: path,
Line: line,
Message: fmt.Sprintf("Duplicate @Handler name '%s' (already in %s)", name, existing),
})
} else {
handlerNames[name] = path
}
}
}
// Validate @Service
if strings.Contains(text, "@Service") {
if match := servicePattern.FindStringSubmatch(text); match != nil {
name := match[1]
if existing, exists := serviceNames[name]; exists {
errors = append(errors, ValidationError{
File: path,
Line: line,
Message: fmt.Sprintf("Duplicate @Service name '%s' (already in %s)", name, existing),
})
} else {
serviceNames[name] = path
}
}
}
// Validate @Route
if strings.Contains(text, "@Route") {
if !routePattern.MatchString(text) {
// Check for common mistakes
if strings.Contains(text, `@Route "`) {
errors = append(errors, ValidationError{
File: path,
Line: line,
Message: "@Route format should be: @Route \"METHOD /path\" (e.g., @Route \"GET /users\")",
})
}
}
}
// Validate @Inject
if strings.Contains(text, "@Inject") {
if match := injectPattern.FindStringSubmatch(text); match != nil {
value := match[1]
// Check for empty inject
if strings.TrimSpace(value) == "" {
errors = append(errors, ValidationError{
File: path,
Line: line,
Message: "@Inject value cannot be empty",
})
}
}
}
}
}
return nil
})
return errors
}
Run with: go run scripts/validate_annotations.go
2. Circular Dependency Detection
Module-Level Dependencies
Lokstra uses DDD bounded contexts (modules). Cross-module dependencies should be unidirectional.
File: scripts/validate_deps.go
package main
import (
"fmt"
"go/parser"
"go/token"
"os"
"path/filepath"
"strings"
)
type Dependency struct {
From string
To string
}
func main() {
root := "./modules"
deps := findDependencies(root)
cycles := findCycles(deps)
if len(cycles) > 0 {
fmt.Println("❌ CIRCULAR DEPENDENCIES DETECTED:")
for _, cycle := range cycles {
fmt.Println(" ", strings.Join(cycle, " -> "))
}
fmt.Println("")
fmt.Println("💡 Solutions:")
fmt.Println(" 1. Extract shared types to modules/shared/domain/")
fmt.Println(" 2. Use interfaces for cross-module communication")
fmt.Println(" 3. Use event-driven patterns for decoupling")
os.Exit(1)
}
fmt.Println("✅ No circular dependencies found")
}
func findDependencies(root string) []Dependency {
var deps []Dependency
filepath.Walk(root, func(path string, info os.FileInfo, err error) error {
if err != nil || info.IsDir() || !strings.HasSuffix(path, ".go") {
return nil
}
fset := token.NewFileSet()
f, err := parser.ParseFile(fset, path, nil, parser.ImportsOnly)
if err != nil {
return nil
}
module := extractModuleName(path)
if module == "" || module == "shared" {
return nil // Skip shared module
}
for _, imp := range f.Imports {
importPath := strings.Trim(imp.Path.Value, "\"")
if strings.Contains(importPath, "/modules/") {
importedModule := extractModuleFromPath(importPath)
if importedModule != "" && importedModule != module && importedModule != "shared" {
deps = append(deps, Dependency{
From: module,
To: importedModule,
})
}
}
}
return nil
})
return deps
}
func extractModuleName(path string) string {
parts := strings.Split(filepath.ToSlash(path), "/")
for i, part := range parts {
if part == "modules" && i+1 < len(parts) {
return parts[i+1]
}
}
return ""
}
func extractModuleFromPath(importPath string) string {
parts := strings.Split(importPath, "/")
for i, part := range parts {
if part == "modules" && i+1 < len(parts) {
return parts[i+1]
}
}
return ""
}
func findCycles(deps []Dependency) [][]string {
// Build adjacency list
graph := make(map[string]map[string]bool)
for _, dep := range deps {
if graph[dep.From] == nil {
graph[dep.From] = make(map[string]bool)
}
graph[dep.From][dep.To] = true
}
// DFS to find cycles
var cycles [][]string
visited := make(map[string]int) // 0=unvisited, 1=in-progress, 2=done
var dfs func(node string, path []string) bool
dfs = func(node string, path []string) bool {
if visited[node] == 1 {
// Found cycle - extract cycle from path
cycleStart := -1
for i, n := range path {
if n == node {
cycleStart = i
break
}
}
if cycleStart >= 0 {
cycle := append(path[cycleStart:], node)
cycles = append(cycles, cycle)
}
return true
}
if visited[node] == 2 {
return false
}
visited[node] = 1
path = append(path, node)
for neighbor := range graph[node] {
dfs(neighbor, path)
}
visited[node] = 2
return false
}
for module := range graph {
if visited[module] == 0 {
dfs(module, nil)
}
}
return cycles
}
3. Configuration Validation
Validate config.yaml and configs/*.yaml
File: scripts/validate_config.go
package main
import (
"fmt"
"os"
"path/filepath"
"gopkg.in/yaml.v3"
)
type ConfigValidationError struct {
File string
Path string
Message string
}
func main() {
errors := []ConfigValidationError{}
// Load all config files
configFiles := []string{"config.yaml"}
if entries, err := os.ReadDir("configs"); err == nil {
for _, entry := range entries {
if !entry.IsDir() && (filepath.Ext(entry.Name()) == ".yaml" || filepath.Ext(entry.Name()) == ".yml") {
configFiles = append(configFiles, filepath.Join("configs", entry.Name()))
}
}
}
merged := make(map[string]any)
// Parse and merge all configs
for _, file := range configFiles {
data, err := os.ReadFile(file)
if err != nil {
if file == "config.yaml" {
errors = append(errors, ConfigValidationError{
File: file,
Message: fmt.Sprintf("Cannot read config file: %v", err),
})
}
c
---
*Content truncated.*
When not to use it
- →When database migrations are missing
Prerequisites
Limitations
- →Requires database connection for schema validation
How it compares
Automates pre-deployment consistency checks that typically require manual verification.
Compared to similar skills
advanced-lokstra-validate-consistency side by side with the closest alternatives in the catalog.
| Skill | Installs | Updated | Safety | Difficulty |
|---|---|---|---|---|
| advanced-lokstra-validate-consistency (this skill) | 0 | 6mo | Review | Advanced |
| run-tests | 1 | 5mo | Review | Intermediate |
| dbx-regenerate | 1 | 6mo | Review | Intermediate |
| litestream | 0 | 6mo | Review | Advanced |
Try saying
Example prompts that trigger this skill in your AI assistant.
You might also like
run-tests
pgschema
Run pgschema automated tests (go test) to validate diff logic, plan generation, and dump functionality using test fixtures
dbx-regenerate
storj
Regenerate DBX code after making changes to .dbx schema files. Runs code generation, shows diff summary, validates compilation, and reports any errors.
litestream
benbjohnson
Expert knowledge for contributing to Litestream, a standalone disaster recovery tool for SQLite. Provides architectural understanding, code patterns, critical rules, and debugging procedures for WAL monitoring, LTX replication format, storage backend implementation, multi-level compaction, and SQLite page management. Use when working with Litestream source code, writing storage backends, debugging replication issues, implementing compaction logic, or handling SQLite WAL operations.
passion-dev
awalvie
Passion climbing training app development. Use for: adding handlers, modifying DB models, creating templates, understanding project architecture, running/testing the app, YAML import features.
drizzle-orm
EpicenterHQ
Drizzle ORM patterns for type branding and custom types. Use when working with Drizzle column definitions, branded types, or custom type conversions.
database-design
davila7
Database design principles and decision-making. Schema design, indexing strategy, ORM selection, serverless databases.