Skip to main content
dingo Use when working with Dingo meta-language for Go, implementing optionals/results, using generics shortcuts, or transpiling .dingo files to .go while maintaining Go compatibility.
Ir a la instalación Skills Marketplace Descubre y explora habilidades de IA creadas por la comunidad.
Instalar con Codex o Claude Copia este prompt, pégalo en Codex, Claude u otro asistente, y deja que revise la página de la skill y la instale por ti.
Copiar promptMostrar detalles del prompt Un comando directo omite el prompt de revisión. Revisa el origen antes de ejecutarlo.
npx skills add https://github.com/MadAppGang/magus --skill dingoEl comando permanece en una sola línea. Desplázate horizontalmente para revisarlo antes de copiarlo.
¿Prefieres una copia local? Descarga los archivos que SkillsMP tiene disponibles ahora.
Descargar Zip Descargando... Más de este repositorio Picks the browser-use agent brain LLM per task. Use when choosing a model for retry_with_browser_use_agent or a cloud session, or the user mentions a cheap, slow, or smart model.
Reference for the Browser Use MCP tools — parameters, returns, session lifecycle. Use when navigating, clicking, typing, evaluating JS, or extracting page content.
Visual UI debugging — screenshot capture and analysis, responsive layout checking at multiple viewport sizes, CSS validation via DOM state, visual regression detection, before/after state comparison.
SOC
Basado en la clasificación ocupacional SOC
name dingo description Use when working with Dingo meta-language for Go, implementing optionals/results, using generics shortcuts, or transpiling .dingo files to .go while maintaining Go compatibility. disable-model-invocation true
Dingo Language Patterns
Overview
Dingo is a meta-language for Go that transpiles .dingo files to .go files, providing modern language features while maintaining 100% Go ecosystem compatibility.
Repository: https://github.com/MadAppGang/dingo
When to use Dingo:
You want concise error handling with the ? operator
You need sum types (enums) and pattern matching
You prefer functional patterns with lambdas
You want Option[T] and Result[T,E] types
You need safe navigation (?.) and null coalescing (??)
Key Philosophy:
Dingo makes common Go patterns more concise and safer without departing from Go idioms. The transpiled Go code is clean and idiomatic.
Project Structure
project/
├── cmd/
│ └── api/
│ └── main.dingo # Entry point
├── internal/
│ ├── handlers/ # HTTP handlers (.dingo files)
│ ├── services/ # Business logic
│ ├── repositories/ # Data access
│ └── models/ # Domain models
├── pkg/ # Public packages
├── configs/ # Configuration
├── go.mod # Go module file
├── go.sum # Go dependencies
└── .dingo/ # Generated .go files (gitignored)
Build & Development Workflow
Commands dingo build
dingo run main.dingo
dingo go
dingo fmt
Development Cycle
Write : Edit .dingo files
Transpile : Run dingo go to generate .go files in .dingo/
Type Check : gopls works on generated .go files for IDE support
Build : dingo build or go build on generated files
IDE Integration gopls (Go language server) works on the generated .go files:
.dingo/
├── cmd/api/main.go
├── internal/handlers/user.go
└── internal/services/user.go
Configure your editor to watch .dingo/ for Go analysis.
CI/CD Pipeline
steps:
- name: Install Dingo
run: go install github.com/MadAppGang/dingo/cmd/dingo@latest
- name: Generate Go files
run: dingo go
- name: Build
run: go build -o app ./.dingo/cmd/api
- name: Test
run: go test ./.dingo/...
Transpilation Errors Dingo reports errors with source locations in .dingo files:
error: mismatched types in match expression
--> internal/handlers/user.dingo:42:5
|
42 | match status {
| ^^^^^ expected Status, found string
Fix errors in .dingo source, then re-run dingo go.
Built-in Types Important: Option[T], Result[T,E], Some(), None(), Ok(), Err() are built-in Dingo syntax , not Go imports. The transpiler generates all necessary type definitions.
// These are built-in - no import needed
func findUser(id string) Option[User] {
// ...
return Some(user) // Built-in function
return None() // Built-in function
}
func divide(a, b int) Result[int, string] {
if b == 0 {
return Err("division by zero") // Built-in
}
return Ok(a / b) // Built-in
}
Only import dgo if writing pure Go code that interoperates with Dingo-generated types.
Error Propagation (? Operator) The ? operator provides concise error handling, similar to Rust.
Basic Propagation // Before: verbose Go pattern
func loadUser(id string) (*User, error) {
user, err := db.FindByID(id)
if err != nil {
return nil, err
}
return user, nil
}
// After: concise Dingo
func loadUser(id string) (*User, error) {
user := db.FindByID(id)?
return user, nil
}
Error Context Add context to propagated errors:
func processOrder(id string) (*Order, error) {
// Wrap error with message
order := db.FindOrder(id) ? "failed to find order"
// Validates and wraps
validated := validateOrder(order) ? "order validation failed"
// Process with full context
result := processPayment(validated) ? "payment processing failed"
return result, nil
}
Error Transform Transform errors with closures:
func createUser(input CreateUserInput) (*User, error) {
// Rust-style closure
user := db.Create(input) ? |e| fmt.Errorf("db error: %w", e)
// TypeScript-style arrow
profile := createProfile(user.ID) ? e => AppError.Wrap(e, "profile creation")
return user, nil
}
Error Propagation in Lambdas When using ? inside lambda bodies, the error propagates to the enclosing function:
func processAllUsers(ids []string) (*Summary, error) {
// Error in lambda propagates to processAllUsers
results := map(ids, |id| {
user := db.FindUser(id)? // Propagates to processAllUsers, not the lambda
return transform(user)
})
return summarize(results), nil
}
// For lambdas that should handle errors internally:
func processAllUsersSafe(ids []string) []Result[User, error] {
return map(ids, |id| {
user, err := db.FindUser(id)
if err != nil {
return Err(err)
}
return Ok(user)
})
}
Important: The ? operator inside lambdas propagating to the enclosing function is intentional Dingo design . When the transpiler sees ? inside a lambda body, it generates special code that propagates errors to the enclosing function rather than the lambda itself. This is the most common use case for error handling in functional chains. If you need the lambda to handle errors internally (e.g., to return Result types), use explicit Go-style error checking as shown in processAllUsersSafe above.
Option[T] Type Use Option[T] for optional values instead of nullable pointers.
Basic Usage func findUser(id string) Option[User] {
user, err := db.FindByID(id)
if err != nil {
return None()
}
return Some(user)
}
// Usage
user := findUser("123")
if user.IsSome() {
fmt.Println(user.Unwrap().Name)
}
// With default
name := findUser("123").Map(|u| u.Name).UnwrapOr("Anonymous")
Option Methods opt := Some("hello")
opt.IsSome() // true
opt.IsNone() // false
opt.Unwrap() // "hello" (panics if None)
opt.UnwrapOr("default") // "hello"
opt.UnwrapOrElse(|| "computed") // "hello"
opt.Map(|s| len(s)) // Some(5)
opt.FlatMap(|s| Some(s + "!")) // Some("hello!")
Result[T, E] Type Use Result[T, E] for explicit error modeling.
Type Parameter Inference: Type parameters can be inferred when the context makes them clear (e.g., function return type), but explicit parameters are needed in standalone expressions like Ok[int, string](42).
Basic Usage func divide(a, b int) Result[int, string] {
if b == 0 {
return Err("division by zero")
}
return Ok(a / b)
}
// Usage
result := divide(10, 2)
if result.IsOk() {
fmt.Println(result.Unwrap()) // 5
}
// With default
value := divide(10, 0).UnwrapOr(0) // 0
Result Methods ok := Ok[int, string](42)
err := Err[int, string]("failed")
ok.IsOk() // true
ok.IsErr() // false
ok.Unwrap() // 42
ok.UnwrapErr() // panics
ok.UnwrapOr(0) // 42
ok.Map(|n| n * 2) // Ok(84)
err.UnwrapOr(0) // 0
err.UnwrapErr() // "failed"
Sum Types (Enums) Define algebraic data types with named variants.
Basic Enum enum Status {
Pending
Active
Suspended { reason: string }
Deleted { deletedAt: time.Time, deletedBy: string }
}
func (s Status) String() string {
match s {
Pending => "pending",
Active => "active",
Suspended(reason) => fmt.Sprintf("suspended: %s", reason),
Deleted(at, by) => fmt.Sprintf("deleted at %v by %s", at, by),
}
}
Enum Instantiation Use constructor syntax to create enum variants:
// Simple variants (no fields)
status := Status.Pending
active := Status.Active
// Variants with fields - constructor syntax
suspended := Status.Suspended("policy violation")
deleted := Status.Deleted(time.Now(), "admin@example.com")
Event Sourcing Example enum UserEvent {
Created { userID: int, email: string, createdAt: time.Time }
EmailChanged { userID: int, oldEmail: string, newEmail: string }
Deactivated { userID: int, reason: string }
Reactivated { userID: int }
}
// Creating events - use constructor syntax
func recordUserCreation(id int, email string) UserEvent {
return UserEvent.Created(id, email, time.Now())
}
func recordEmailChange(id int, old, new string) UserEvent {
return UserEvent.EmailChanged(id, old, new)
}
func processEvent(event UserEvent) {
match event {
Created(id, email, _) => {
fmt.Printf("User %d created with email %s\n", id, email)
},
EmailChanged(id, old, new) => {
fmt.Printf("User %d changed email from %s to %s\n", id, old, new)
},
Deactivated(id, reason) => {
fmt.Printf("User %d deactivated: %s\n", id, reason)
},
Reactivated(id) => {
fmt.Printf("User %d reactivated\n", id)
},
}
}
Pattern Matching (match) Exhaustive pattern matching with guards.
Basic Matching func describe(n int) string {
match n {
0 => "zero",
1 => "one",
_ if n < 0 => "negative",
_ if n > 100 => "large",
_ => "other",
}
}
With Enum Destructuring enum Shape {
Circle { radius: float64 }
Rectangle { width: float64, height: float64 }
Triangle { base: float64, height: float64 }
}
func area(shape Shape) float64 {
match shape {
Circle(r) => 3.14159 * r * r,
Rectangle(w, h) => w * h,
Triangle(b, h) => 0.5 * b * h,
}
}
Nested Match with Guards Complex matching scenarios with nested patterns:
enum Response {
Success { data: Option[User], cached: bool }
Error { code: int, message: string }
}
func handleResponse(resp Response) string {
match resp {
// Nested pattern: match on enum variant AND option state
Success(Some(user), true) => {
fmt.Sprintf("Cached user: %s", user.Name)
},
Success(Some(user), false) => {
fmt.Sprintf("Fresh user: %s", user.Name)
},
Success(None(), _) => "No user data",
// Guard on nested field
Error(code, msg) if code >= 500 => {
fmt.Sprintf("Server error %d: %s", code, msg)
},
Error(code, msg) if code >= 400 => {
fmt.Sprintf("Client error %d: %s", code, msg)
},
Error(code, msg) => {
fmt.Sprintf("Unknown error %d: %s", code, msg)
},
}
}
Wildcard Ignoring func getOrderSummary(event OrderEvent) string {
match event {
OrderPlaced(id, _, amount) => fmt.Sprintf("Order %s: $%.2f", id, amount),
OrderShipped(id, _, _) => fmt.Sprintf("Order %s shipped", id),
_ => "Unknown event",
}
}
Lambda Expressions Concise function literals with two syntax styles.
Rust-Style (Pipe Syntax) users := []User{...}
// Single argument
activeUsers := filter(users, |u| u.Active)
// Multiple arguments
sorted := sort(users, |a, b| a.Name < b.Name)
// With block body
processed := map(users, |u| {
name := strings.ToUpper(u.Name)
return fmt.Sprintf("%s (%d)", name, u.Age)
})
TypeScript-Style (Arrow Syntax) // Single argument
activeUsers := filter(users, u => u.Active)
// Multiple arguments (parentheses required)
sorted := sort(users, (a, b) => a.CreatedAt.Before(b.CreatedAt))
// With block
processed := map(users, u => {
return u.Name + " - " + u.Email
})
Practical Examples // Filtering
adults := filter(people, |p| p.Age >= 18)
// Mapping
names := map(users, |u| u.Name)
// Reducing
total := reduce(orders, 0, |sum, o| sum + o.Amount)
// Chaining with Option
result := findUser(id)
.Map(|u| u.Profile)
.FlatMap(|p| p.Avatar)
.UnwrapOr(defaultAvatar)
Safe Navigation (?.) and Null Coalescing (??) Handle nullable chains safely.
Safe Navigation type Config struct {
Database *DatabaseConfig
}
type DatabaseConfig struct {
Primary *ConnectionInfo
}
type ConnectionInfo struct {
Host string
Port int
}
// Safe navigation through nullable chain
host := config?.Database?.Primary?.Host ?? "localhost"
port := config?.Database?.Primary?.Port ?? 5432
Chained Safe Navigation with Null Coalescing // Deep chain with fallback
dbHost := appConfig?.Database?.Primary?.Host
?? appConfig?.Database?.Fallback?.Host
?? envConfig?.DbHost
?? "localhost"
// Method chains
userName := response?.Data?.User?.Profile?.DisplayName
?? response?.Data?.User?.Name
?? "Anonymous"
// With function calls in fallback
timeout := config?.Timeout ?? getDefaultTimeout()
Null Coalescing // Simple default
name := user.Nickname ?? user.Name ?? "Anonymous"
// With function call
timeout := config.Timeout ?? getDefaultTimeout()
// Combined with safe navigation
dbHost := appConfig?.Database?.Host ?? envConfig?.DbHost ?? "localhost"
Ternary Operator Simple conditional expressions.
// Basic ternary
status := user.Active ? "Active" : "Inactive"
// Nested (use sparingly)
role := user.IsAdmin ? "Admin" : user.IsModerator ? "Moderator" : "User"
// In function calls
greet(user.Preferred ? user.Nickname : user.FullName)
// With expressions
discount := order.Total > 100 ? order.Total * 0.1 : 0
Tuples Lightweight compound values.
Tuple Types type Point2D = (float64, float64)
type Range = (int, int)
type NamedResult = (string, int, error)
Tuple Destructuring func getCoordinates() (float64, float64) {
return (42.5, 73.2)
}
// Destructure in assignment
(x, y) := getCoordinates()
// Ignore values with _
(lat, _) := getCoordinates()
// Multiple return handling
(user, err) := fetchUser(id)
if err != nil {
return err
}
Tuple in Functions func minMax(numbers []int) (int, int) {
min := numbers[0]
max := numbers[0]
for _, n := range numbers {
if n < min { min = n }
if n > max { max = n }
}
return (min, max)
}
(lo, hi) := minMax([]int{3, 1, 4, 1, 5, 9})
Guard Statement Early returns with clear error handling.
Use guard x := f() else |err| { ... } when f() returns (T, error) or Result[T, E] - the error value is bound to err for custom handling
Use guard x := f() else { ... } when f() returns Option[T] - None has no error value to bind
Basic Guard func processUser(id string) Result[User, error] {
// Guard with error handling
guard user := findUser(id) else |err| {
return Err(fmt.Errorf("user not found: %w", err))
}
guard profile := user.Profile else {
return Err(errors.New("user has no profile"))
}
// Both user and profile are now available
return Ok(user)
}
Guard with Option func getDisplayName(userId string) string {
guard user := findUser(userId) else {
return "Unknown User"
}
guard nickname := user.Nickname else {
return user.FullName
}
return nickname
}
Multiple Guards func createOrder(req CreateOrderRequest) (*Order, error) {
guard user := findUser(req.UserID) else |err| {
return nil, fmt.Errorf("invalid user: %w", err)
}
guard cart := getCart(user.ID) else |err| {
return nil, fmt.Errorf("cart not found: %w", err)
}
guard len(cart.Items) > 0 else {
return nil, errors.New("cart is empty")
}
guard total := calculateTotal(cart) else |err| {
return nil, fmt.Errorf("calculation failed: %w", err)
}
return createOrderFromCart(user, cart, total)
}
HTTP Handler Patterns
Handler with Error Propagation // Standard Go imports apply - import net/http, encoding/json, etc.
import "github.com/go-chi/chi/v5"
func (h *Handler) GetUser(w http.ResponseWriter, r *http.Request) {
id := chi.URLParam(r, "id")
user := h.userService.FindByID(r.Context(), id) ? |e| {
h.handleError(w, e)
return
}
h.respond(w, http.StatusOK, user)
}
func (h *Handler) CreateUser(w http.ResponseWriter, r *http.Request) {
var req CreateUserRequest
json.NewDecoder(r.Body).Decode(&req) ? |e| {
h.respondError(w, http.StatusBadRequest, "invalid request body")
return
}
user := h.userService.Create(r.Context(), req) ? |e| {
h.handleError(w, e)
return
}
h.respond(w, http.StatusCreated, user)
}
Service Layer with Result Types type UserService struct {
repo UserRepository
}
func (s *UserService) FindByID(ctx context.Context, id string) Result[User, error] {
guard user := s.repo.FindByID(ctx, id) else |err| {
if errors.Is(err, sql.ErrNoRows) {
return Err(NotFoundError("user"))
}
return Err(InternalError(err))
}
return Ok(user)
}
func (s *UserService) Create(ctx context.Context, req CreateUserRequest) Result[User, error] {
// Check if email exists
existing := s.repo.FindByEmail(ctx, req.Email)
if existing.IsSome() {
return Err(ConflictError("email already exists"))
}
hashedPassword := hashPassword(req.Password)?
user := s.repo.Create(ctx, User{
Email: req.Email,
PasswordHash: hashedPassword,
Name: req.Name,
})?
return Ok(user)
}
Repository Pattern type UserRepository interface {
FindByID(ctx context.Context, id string) Result[User, error]
FindByEmail(ctx context.Context, email string) Option[User]
Create(ctx context.Context, user User) Result[User, error]
Update(ctx context.Context, user User) Result[User, error]
Delete(ctx context.Context, id string) Result[bool, error]
}
type postgresUserRepo struct {
db *sql.DB
}
func (r *postgresUserRepo) FindByID(ctx context.Context, id string) Result[User, error] {
var user User
err := r.db.QueryRowContext(ctx,
"SELECT id, email, name, created_at FROM users WHERE id = $1",
id,
).Scan(&user.ID, &user.Email, &user.Name, &user.CreatedAt)
if err != nil {
if errors.Is(err, sql.ErrNoRows) {
return Err(NotFoundError("user"))
}
return Err(err)
}
return Ok(user)
}
func (r *postgresUserRepo) FindByEmail(ctx context.Context, email string) Option[User] {
var user User
err := r.db.QueryRowContext(ctx,
"SELECT id, email, name FROM users WHERE email = $1",
email,
).Scan(&user.ID, &user.Email, &user.Name)
if err != nil {
return None()
}
return Some(user)
}
Testing
Unit Tests with Option/Result func TestUserService_FindByID(t *testing.T) {
repo := mocks.NewMockUserRepository(t)
service := NewUserService(repo)
t.Run("returns user when found", func(t *testing.T) {
expected := User{ID: "123", Name: "John"}
repo.EXPECT().FindByID(mock.Anything, "123").Return(Ok(expected))
result := service.FindByID(context.Background(), "123")
assert.True(t, result.IsOk())
assert.Equal(t, expected, result.Unwrap())
})
t.Run("returns error when not found", func(t *testing.T) {
repo.EXPECT().FindByID(mock.Anything, "456").Return(
Err[User, error](NotFoundError("user")),
)
result := service.FindByID(context.Background(), "456")
assert.True(t, result.IsErr())
assert.Contains(t, result.UnwrapErr().Error(), "not found")
})
}
Testing Pattern Matching func TestEventProcessing(t *testing.T) {
tests := []struct {
name string
event UserEvent
expected string
}{
{
name: "created event",
event: UserEvent.Created(1, "test@example.com", time.Now()),
expected: "User 1 created",
},
{
name: "deactivated event",
event: UserEvent.Deactivated(1, "violation"),
expected: "User 1 deactivated",
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
result := processEvent(tt.event)
assert.Contains(t, result, tt.expected)
})
}
}
Best Practices
Prefer Dingo Idioms Over Go Patterns Go Pattern Dingo Idiom if err != nil { return err }x := f()?*T for optional valuesOption[T](T, error) returnsResult[T, E] for typed errorsinterface{} + type switchenum + matchfunc(x int) int { return x * 2 }|x| x * 2nil checks chain ?. safe navigationif x != nil { x } else { default }x ?? defaultMulti-line if-else condition ? a : b
Error Handling Guidelines
Use ? for simple propagation
Add context with ? "message" or ? \|e\| wrap(e)
Use Result[T, E] when callers need error type information
Use guard for early returns that simplify the happy path
Type Safety Guidelines
Prefer Option[T] over *T for optional values
Use Result[T, E] for operations that can fail
Use enum for closed sets of variants
Always handle all match cases (exhaustive matching)
Lambda Guidelines
Use |x| expr for simple transforms
Use (a, b) => expr for multi-arg comparators
Add block { ... } for multi-line bodies
Prefer named functions for complex logic
Project Organization
Keep .dingo files in the same structure as a Go project
The .dingo/ directory contains generated Go files
Add .dingo/ to .gitignore
Run dingo go before go build in CI
Dingo language patterns for Go meta-programming