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.
npx skills add samber/cc-skills-golang --skill golang-samber-mo -a claude-codeWhat 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
nilchecks - compose failures through a
Result[T]pipeline - model valid alternatives with
Either[L, R] - transform a result while changing its type
- use
Optionin 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-code2Manually: put the files in place
~/.claude/skills/golang-samber-mo/SKILL.mdCopy the whole skill folder; for one project use .claude/skills/golang-samber-mo/
1Skills CLI (Vercel)
npx skills add samber/cc-skills-golang --skill golang-samber-mo -a codex2Manually: put the files in place
.agents/skills/golang-samber-mo/SKILL.mdFor all projects use ~/.agents/skills/
1Skills CLI (Vercel)
npx skills add samber/cc-skills-golang --skill golang-samber-mo -a cursor2Manually: put the files in place
.cursor/skills/golang-samber-mo/SKILL.mdCursor also reads .agents/skills/ and .claude/skills/
1GitHub CLI
gh skill install samber/cc-skills-golang golang-samber-mo2Manually: put the files in place
.github/skills/golang-samber-mo/SKILL.md1Skills CLI (Vercel)
npx skills add samber/cc-skills-golang --skill golang-samber-mo -a gemini-cli2Platform CLI
gemini skills install https://github.com/samber/cc-skills-golang --path skills/golang-samber-moManually: put the files in place
.devin/skills/golang-samber-mo/SKILL.mdThe legacy .windsurf/skills/ path still works
Skills CLI (Vercel)
npx skills add samber/cc-skills-golang --skill golang-samber-mo -a opencodeClaude.ai
Zip the folder and upload it in Settings → Capabilities → Skills
From the same set38
The whole set →Similar
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