Skip to main content
skill Claude Code CX Codex Cursor GitHub Copilot

golang-samber-mo — Claude Code skill: what it does, how to install

This skill applies samber/mo in Go with Option, Result, Either, and related types. Use it when working with github.com/samber/mo.

Install into Claude Code · Skills CLI (Vercel) All methods and platforms ↓
npx skills add samber/cc-skills-golang --skill golang-samber-mo -a claude-code
Open on GitHub

What golang-samber-mo does

This skill covers functional patterns in Go with Option, Result, Either, Future, IO, Task, and State. These types represent absent values, failures, valid alternatives, and deferred computations. Pipeline subpackages handle transformations where the result type changes.

Option[T] gives nullable values an explicit type, while Result[T] models success or failure as a value. Use Either[L, R] when both branches are valid alternatives rather than treating one branch as an error. Option also implements JSON and SQL interfaces, so it can be used in structs and database models.

The library requires Go 1.18 or newer and the github.com/samber/mo dependency, added with go get. The Go type-system limit matters here: direct Result[T] methods cannot change T, so a conversion such as []byte to Config needs subpackage functions or mo.Do.

What it helps with

  • represent missing values without direct nil checks
  • compose failures through a Result[T] pipeline
  • model valid alternatives with Either[L, R]
  • transform a result while changing its type
  • use Option in JSON structs and database models

Example prompts for the agent

  • Use `Option` from `github.com/samber/mo` for an optional profile field and provide a fallback with `OrElse`.
  • Rewrite the `config.yaml` read as a `Result`, then build a pipeline from `[]byte` to `Config` and validate it.
  • Choose between `Result` and `Either` for a function that returns cached data or fresh data.

How to install golang-samber-mo

1Skills CLI (Vercel)

npx skills add samber/cc-skills-golang --skill golang-samber-mo -a claude-code

2Manually: put the files in place

~/.claude/skills/golang-samber-mo/SKILL.md

Copy the whole skill folder; for one project use .claude/skills/golang-samber-mo/

From the same set38

The whole set →
golang-code-style samber A skill for writing clear Go code: line breaking, variable declarations, control flow, when comments help. Use it when writing or reviewing Go, discussing style, or setting project standards. Claude Code CX Codex Cursor +1 44,000installs golang-error-handling samber Skill for idiomatic Go error handling: wrapping with context, chain inspection, structured logging, and samber/oops integration. Apply when creating, wrapping, inspecting, or logging errors in Go code. Claude Code CX Codex Cursor +1 43,200installs golang-security samber Identifies Go vulnerabilities, models threats with STRIDE and DREAD, and fixes injections, secret leaks, and cryptography flaws. Claude Code CX Codex Cursor +1 42,100installs golang-design-patterns samber This skill guides idiomatic Go design for APIs, resource lifecycles, graceful shutdown, and architecture. Use it when designing or reviewing Go code. Claude Code CX Codex Cursor +1 41,900installs golang-performance samber Guides AI coding agents through profiling, memory allocation cuts, and CPU optimization in Go projects using a strict measurement-first cycle. Claude Code CX Codex Cursor +1 41,800installs golang-concurrency samber The skill sets rules for concurrent Go code: goroutine lifecycle, channels and select, mutexes, errgroup, singleflight, worker pools, and fan-out/fan-in pipelines. Claude Code CX Codex Cursor +1 41,600installs golang-database samber Go database guidelines for database/sql, sqlx, and pgx. Enforces parameterized queries, context passing, and explicit connection pool handling without ORMs. Claude Code CX Codex Cursor +1 40,700installs golang-naming samber A Go naming skill for writing, reviewing, and refactoring code. It covers packages, types, errors, booleans, enums, and tests. Claude Code CX Codex Cursor +1 40,700installs

Similar

python-anti-patterns Seth Hobson A checklist skill for common Python mistakes. The agent runs it over your code before merge or while debugging. Claude Code CX Codex Cursor 13,278installs migrate-to-shoehorn Matt Pocock Replaces as type assertions in tests with helpers from @total-typescript/shoehorn. Use it when tests need partial objects or deliberately invalid data. Claude Code 475,388installs write-swift emilkowalski This skill guides Swift coding, reviews, and migrations using the language’s current practices. Use it to investigate concurrency errors, hangs, data races, or retain cycles. Claude Code CX Codex Cursor +1 117,500installs megacave JuliusBrussee Switches agent responses to Classical Chinese (wenyan) to reduce terminal output. Activated via /megacave or /caveman wenyan. Claude Code CX Codex Cursor +1 24,400installs find-docs upstash Pulls up-to-date documentation, API references and code examples for any library through the Context7 CLI. Useful when the model's training data lags behind the API. Claude Code CX Codex Cursor +1 9,400installs typescript-advanced-types Seth Hobson Guides an agent through advanced TypeScript types, from generics to conditional and mapped types. Use it for typed libraries, API clients, or strict configuration objects. Claude Code CX Codex Cursor 92,169installs smart-explore thedotmack Uses tree-sitter to map code structure and find symbols. Useful when you need to explore a codebase without loading every full file. Claude Code CX Codex Cursor +1 7,300installs

Questions about golang-samber-mo

How do I install `golang-samber-mo` in Claude Code?

Run npx skills add samber/cc-skills-golang --skill golang-samber-mo -a claude-code, then run npx skills add samber/cc-skills-golang --skill golang-samber-mo -a claude-code again. The skill file is at ~/.claude/skills/golang-samber-mo/SKILL.md.

What does `golang-samber-mo` do?

It helps apply Option, Result, Either, Future, IO, Task, and State in Go projects. It also covers pipelines from the samber/mo subpackages.

What should I know when changing the type inside a `Result`?

Methods on Result[T] keep the same type parameter because Go methods cannot introduce new type parameters. For a conversion such as []byte to Config, use functions from the result subpackage or mo.Do.

Source text

SKILL.md · MIT
---
name: golang-samber-mo
description: "Monadic types for Golang using samber/mo — Option, Result, Either, Future, IO, Task, and State types for type-safe nullable values, error handling, and functional composition with pipeline sub-packages. Apply when using or adopting samber/mo, when the codebase imports `github.com/samber/mo`, or when considering functional programming patterns as a safety design for Golang. Not for nil-safety and zero-value design without this library (→ See `samber/cc-skills-golang@golang-safety` skill), nor for native error wrapping with fmt.Errorf, errors.Is and errors.As (→ See `samber/cc-skills-golang@golang-error-handling` skill)."
user-invocable: true
license: MIT
compatibility: Designed for Claude Code, Codex or similar harness, and for projects using Golang.
metadata:
  author: samber
  version: "1.1.2"
  openclaw:
    emoji: "🎭"
    homepage: https://github.com/samber/cc-skills-golang
    requires:
      bins:
        - go
    install: []
    skill-library-version: "1.16.0"
allowed-tools: Read Edit Write Glob Grep Bash(go:*) Bash(golangci-lint:*) Bash(git:*) Agent WebFetch mcp__context7__resolve-library-id mcp__context7__query-docs AskUserQuestion Bash(godig:*) Bash(gopls:*) LSP mcp__gopls__*
paths:
  - "**/*.go"
---

**Persona:** You are a Go engineer bringing functional programming safety to Go. You use monads to make impossible states unrepresentable — nil checks become type constraints, error handling becomes composable pipelines.

**Thinking mode:** Reason as thoroughly as possible when designing multi-step Option/Result/Either pipelines — wrong type choice creates unnecessary wrapping/unwrapping that defeats the purpose of monads. On Claude Code, use `ultrathink` to trigger extended thinking explicitly.

# samber/mo — Monads and Functional Abstractions for Go

Go 1.18+ library providing type-safe monadic types with zero dependencies. Inspired by Scala, Rust, and fp-ts.

**Official Resources:**

- [pkg.go.dev/github.com/samber/mo](https://pkg.go.dev/github.com/samber/mo)
- [github.com/samber/mo](https://github.com/samber/mo)

This skill is not exhaustive — refer to library documentation and code examples for more information:

- For Go package docs, symbols, versions, importers, and known vulnerabilities, → See `samber/cc-skills-golang@golang-pkg-go-dev` skill (`godig`), preferred over Context7 for Go package facts.
- To navigate this library's usage in your own code (definitions, call sites, diagnostics), → See `samber/cc-skills-golang@golang-gopls` skill (`gopls`).
- Context7 remains a fallback for docs not indexed on pkg.go.dev.

```bash
go get github.com/samber/mo
```

For an introduction to functional programming concepts and why monads are valuable in Go, see [Monads Guide](./references/monads-guide.md).

## Core Types at a Glance

| Type | Purpose | Think of it as... |
| --- | --- | --- |
| `Option[T]` | Value that may be absent | Rust's `Option`, Java's `Optional` |
| `Result[T]` | Operation that may fail | Rust's `Result<T, E>`, replaces `(T, error)` |
| `Either[L, R]` | Value of one of two types | Scala's `Either`, TypeScript discriminated union |
| `EitherX[L, R]` | Value of one of X types | Scala's `Either`, TypeScript discriminated union |
| `Future[T]` | Async value not yet available | JavaScript `Promise` |
| `IO[T]` | Lazy synchronous side effect | Haskell's `IO` |
| `Task[T]` | Lazy async computation | fp-ts `Task` |
| `State[S, A]` | Stateful computation | Haskell's `State` monad |

## Option[T] — Nullable Values Without nil

Represents a value that is either present (`Some`) or absent (`None`). Eliminates nil pointer risks at the type level.

```go
import "github.com/samber/mo"

name := mo.Some("Alice")          // Option[string] with value
empty := mo.None[string]()        // Option[string] without value
fromPtr := mo.PointerToOption(ptr) // nil pointer -> None

// Safe extraction
name.OrElse("Anonymous")  // "Alice"
empty.OrElse("Anonymous")  // "Anonymous"

// Transform if present, skip if absent
upper := name.Map(func(s string) (string, bool) {
    return strings.ToUpper(s), true
})
```

**Key methods:** `Some`, `None`, `Get`, `MustGet`, `OrElse`, `OrEmpty`, `Map`, `FlatMap`, `Match`, `ForEach`, `ToPointer`, `IsPresent`, `IsAbsent`.

Option implements `json.Marshaler/Unmarshaler`, `sql.Scanner`, `driver.Valuer` — use it directly in JSON structs and database models.

For full API reference, see [Option Reference](./references/option.md).

## Result[T] — Error Handling as Values

Represents success (`Ok`) or failure (`Err`). Equivalent to `Either[error, T]` but specialized for Go's error pattern.

```go
// Wrap Go's (value, error) pattern
result := mo.TupleToResult(os.ReadFile("config.yaml"))

// Same-type transform — errors short-circuit automatically
upper := mo.Ok("hello").Map(func(s string) (string, error) {
    return strings.ToUpper(s), nil
})
// Ok("HELLO")

// Extract with fallback
val := upper.OrElse("default")
```

**Go limitation:** Direct methods (`.Map`, `.FlatMap`) cannot change the type parameter — `Result[T].Map` returns `Result[T]`, not `Result[U]`. Go methods cannot introduce new type parameters. For type-changing transforms (e.g. `Result[[]byte]` to `Result[Config]`), use sub-package functions or `mo.Do`:

```go
import "github.com/samber/mo/result"

// Type-changing pipeline: []byte -> Config -> ValidConfig
parsed := result.Pipe2(
    mo.TupleToResult(os.ReadFile("config.yaml")),
    result.Map(func(data []byte) Config { return parseConfig(data) }),
    result.FlatMap(func(cfg Config) mo.Result[ValidConfig] { return validate(cfg) }),
)
```

**Key methods:** `Ok`, `Err`, `Errf`, `TupleToResult`, `Try`, `Get`, `MustGet`, `OrElse`, `Map`, `FlatMap`, `MapErr`, `Match`, `ForEach`, `ToEither`, `IsOk`, `IsError`.

For full API reference, see [Result Reference](./references/result.md).

## Either[L, R] — Discriminated Union of Two Types

Represents a value that is one of two possible types. Unlike Result, neither side implies success or failure — both are valid alternatives.

```go
// API that returns either cached data or fresh data
func fetchUser(id string) mo.Either[CachedUser, FreshUser] {
    if cached, ok := cache.Get(id); ok {
        return mo.Left[CachedUser, FreshUser](cached)
    }
    return mo.Right[CachedUser, FreshUser](db.Fetch(id))
}

// Pattern match
result := fetchUser("user-123")
result.Match(
    func(cached CachedUser) mo.Either[CachedUser, FreshUser] { /* use cached */ },
    func(fresh FreshUser) mo.Either[CachedUser, FreshUser] { /* use fresh */ },
)
```

**When to use Either vs Result:** Use `Result[T]` when one path is an error. Use `Either[L, R]` when both paths are valid alternatives (cached vs fresh, left vs right, strategy A vs B).

`Either3[T1, T2, T3]`, `Either4`, and `Either5` extend this to 3-5 type variants.

For full API reference, see [Either Reference](./references/either.md).

## Do Notation — Imperative Style with Monadic Safety

`mo.Do` wraps imperative code in a `Result`, catching panics from `MustGet()` calls:

```go
result := mo.Do(func() int {
    // MustGet panics on None/Err — Do catches it as Result error
    a := mo.Some(21).MustGet()
    b := mo.Ok(2).MustGet()
    return a * b  // 42
})
// result is Ok(42)

result := mo.Do(func() int {
    val := mo.None[int]().MustGet()  // panics
    return val
})
// result is Err("no such element")
```

Do notation bridges imperative Go style with monadic safety — write straight-line code, get automatic error propagation.

## Pipeline Sub-Packages vs Direct Chaining

samber/mo provides two ways to compose operations:

**Direct methods** (`.Map`, `.FlatMap`) — work when the output type equals the input type:

```go
opt := mo.Some(42)
doubled := opt.Map(func(v int) (int, bool) {
    return v * 2, true
})  // Option[int]
```

**Sub-package functions** (`option.Map`, `result.Map`) — required when the output type differs from input:

```go
import "github.com/samber/mo/option"

// int -> string type change: use sub-package Map
strOpt := option.Map(func(v int) string {
    return fmt.Sprintf("value: %d", v)
})(mo.Some(42))  // Option[string]
```

**Pipe functions** (`option.Pipe3`, `result.Pipe3`) — chain multiple type-changing transformations readably:

```go
import "github.com/samber/mo/option"

result := option.Pipe3(
    mo.Some(42),
    option.Map(func(v int) string { return strconv.Itoa(v) }),
    option.Map(func(s string) []byte { return []byte(s) }),
    option.FlatMap(func(b []byte) mo.Option[string] {
        if len(b) > 0 { return mo.Some(string(b)) }
        return mo.None[string]()
    }),
)
```

**Rule of thumb:** Use direct methods for same-type transforms. Use sub-package functions + pipes when types change across steps.

For detailed pipeline API reference, see [Pipelines Reference](./references/pipelines.md).

## Common Patterns

### JSON API responses with Option

```go
type UserResponse struct {
    Name     string            `json:"name"`
    Nickname mo.Option[string] `json:"nickname"`  // omits null gracefully
    Bio      mo.Option[string] `json:"bio"`
}
```

### Database nullable columns

```go
type User struct {
    ID       int
    Email    string
    Phone    mo.Option[string]  // implements sql.Scanner + driver.Valuer
}

err := row.Scan(&u.ID, &u.Email, &u.Phone)
```

### Wrapping existing Go APIs

```go
// Convert map lookup to Option
func MapGet[K comparable, V any](m map[K]V, key K) mo.Option[V] {
    return mo.TupleToOption(m[key])  // m[key] returns (V, bool)
}
```

### Uniform extraction with Fold

`mo.Fold` works uniformly across Option, Result, and Either via the `Foldable` interface:

```go
str := mo.Fold[error, int, string](
    mo.Ok(42),  // works with Option, Result, or Either
    func(v int) string { return fmt.Sprintf("got %d", v) },
    func(err error) string { return "failed" },
)
// "got 42"
```

## Best Practices

1. **Prefer `OrElse` over `MustGet`** — `MustGet` panics on absent/error values; use it only inside `mo.Do` blocks where panics are caught, or when you are certain the value exists
2. **Use `TupleToResult` at API boundaries** — convert Go's `(T, error)` to `Result[T]` at the boundary, then chain with `Map`/`FlatMap` inside your domain logic
3. **Use `Result[T]` for errors, `Either[L, R]` for alternatives** — Result is specialized for success/failure; Either is for two valid types
4. **Option for nullable fields, not zero values** — `Option[string]` distinguishes "absent" from "empty string"; use plain `string` when empty string is a valid value
5. **Chain, don't nest** — `result.Map(...).FlatMap(...).OrElse(default)` reads left-to-right; avoid nested if/else patterns when monadic chaining is cleaner
6. **Use sub-package pipes for multi-step type transformations** — when 3+ steps each change the type, `option.Pipe3(...)` is more readable than nested function calls

For advanced types (Future, IO, Task, State), see [Advanced Types Reference](./references/advanced-types.md).

If you encounter a bug or unexpected behavior in samber/mo, open an issue at <https://github.com/samber/mo/issues>.

## Cross-References

- → See `samber/cc-skills-golang@golang-samber-lo` skill for functional collection transforms (Map, Filter, Reduce on slices) that compose with mo types
- → See `samber/cc-skills-golang@golang-error-handling` skill for idiomatic Go error handling patterns
- → See `samber/cc-skills-golang@golang-safety` skill for nil-safety and defensive Go coding
- → See `samber/cc-skills-golang@golang-database` skill for database access patterns
- → See `samber/cc-skills-golang@golang-design-patterns` skill for functional options and other Go patterns

© samber · MIT · samber/cc-skills-golang

See also

Project sponsors

Companies that keep this analytics open
Gold sponsor

Impressions, clicks and code copies — open statistics. We keep the numbers public for the same reason NeBlask itself is public. Become a sponsor