RTK Rust Design Patterns
rtk-ai/rtk
Describes seven Rust design patterns for the RTK CLI filter modules, with when to use each, RTK examples, and notes on when a pattern is overkill.
Generates or hand-writes composable lenses for the fp-go library so nested Go structs can be read and updated immutably.
$ npx skills add IBM/fp-go --skill fp-go-lens -a claude-codeProject install by default; add -g for ~/.claude/skills/.
$ gh skill install IBM/fp-go fp-go-lens --agent claude-codeProject scope by default; add --scope user for a personal install. Needs GitHub CLI 2.90.0 or later (public preview).
$ git clone --depth 1 https://github.com/IBM/fp-go.git skills-src && mkdir -p .claude/skills && cp -r skills-src/skills/fp-go-lens .claude/skills/fp-go-lens && rm -rf skills-srcUse ~/.claude/skills/ instead of .claude/skills for a personal install. The folder must contain SKILL.md.
Claude Code skills documentation · loads skills from .claude/skills/
Install the "fp-go-lens" agent skill from https://github.com/IBM/fp-go/tree/main/skills/fp-go-lens into .claude/skills/fp-go-lens/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "fp-go-lens", then confirm the skill loads.Claude Code copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$skill-installer install https://github.com/IBM/fp-go/tree/main/skills/fp-go-lensType this inside Codex. $skill-installer <name> installs a curated skill from openai/skills. The installer writes to $CODEX_HOME/skills (default ~/.codex/skills). Restart Codex if the skill does not show up.
$ npx skills add IBM/fp-go --skill fp-go-lens -a codexProject install goes to .agents/skills/; add -g for ~/.codex/skills/.
$ gh skill install IBM/fp-go fp-go-lens --agent codexProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/IBM/fp-go.git skills-src && mkdir -p .agents/skills && cp -r skills-src/skills/fp-go-lens .agents/skills/fp-go-lens && rm -rf skills-srcUse ~/.agents/skills/ instead of .agents/skills for a personal install.
Codex skills documentation · loads skills from .agents/skills/
Install the "fp-go-lens" agent skill from https://github.com/IBM/fp-go/tree/main/skills/fp-go-lens into .agents/skills/fp-go-lens/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "fp-go-lens", then confirm the skill loads.Codex copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ npx skills add IBM/fp-go --skill fp-go-lens -a cursorProject install goes to .agents/skills/; add -g for ~/.cursor/skills/.
$ gh skill install IBM/fp-go fp-go-lens --agent cursorProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/IBM/fp-go.git skills-src && mkdir -p .cursor/skills && cp -r skills-src/skills/fp-go-lens .cursor/skills/fp-go-lens && rm -rf skills-srcUse ~/.cursor/skills/ instead of .cursor/skills for a personal install.
Cursor skills documentation · loads skills from .cursor/skills/, .agents/skills/, .claude/skills/, .codex/skills/
Install the "fp-go-lens" agent skill from https://github.com/IBM/fp-go/tree/main/skills/fp-go-lens into .cursor/skills/fp-go-lens/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "fp-go-lens", then confirm the skill loads.Cursor copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ gemini skills install https://github.com/IBM/fp-go.git --path skills/fp-go-lens--scope user (default) or --scope workspace; --path is the subfolder of the repo that holds the skill; --consent skips the security confirmation prompt.
$ npx skills add IBM/fp-go --skill fp-go-lens -a gemini-cliProject install goes to .agents/skills/; add -g for ~/.gemini/skills/.
$ gh skill install IBM/fp-go fp-go-lens --agent gemini-cliProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/IBM/fp-go.git skills-src && mkdir -p .gemini/skills && cp -r skills-src/skills/fp-go-lens .gemini/skills/fp-go-lens && rm -rf skills-srcUse ~/.gemini/skills/ instead of .gemini/skills for a personal install, then run /skills reload.
Gemini CLI skills documentation · loads skills from .gemini/skills/, .agents/skills/
Install the "fp-go-lens" agent skill from https://github.com/IBM/fp-go/tree/main/skills/fp-go-lens into .gemini/skills/fp-go-lens/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "fp-go-lens", then confirm the skill loads.Gemini CLI copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ gh skill install IBM/fp-go fp-go-lensInstalls for Copilot at project scope by default; add --scope user for a personal install. Preview a skill first with gh skill preview. Needs GitHub CLI 2.90.0 or later (public preview).
$ npx skills add IBM/fp-go --skill fp-go-lens -a github-copilotProject install goes to .agents/skills/; add -g for ~/.copilot/skills/.
$ git clone --depth 1 https://github.com/IBM/fp-go.git skills-src && mkdir -p .github/skills && cp -r skills-src/skills/fp-go-lens .github/skills/fp-go-lens && rm -rf skills-srcUse ~/.copilot/skills/ instead of .github/skills for a personal install. Commit .github/skills so cloud agent and code review can use it.
GitHub Copilot skills documentation · loads skills from .github/skills/, .claude/skills/, .agents/skills/
Install the "fp-go-lens" agent skill from https://github.com/IBM/fp-go/tree/main/skills/fp-go-lens into .github/skills/fp-go-lens/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "fp-go-lens", then confirm the skill loads.GitHub Copilot copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ npx skills add IBM/fp-go --skill fp-go-lens -a opencodeOpenCode documents no install command of its own. Project install goes to .agents/skills/; add -g for ~/.config/opencode/skills/.
$ gh skill install IBM/fp-go fp-go-lens --agent opencodeProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/IBM/fp-go.git skills-src && mkdir -p .opencode/skills && cp -r skills-src/skills/fp-go-lens .opencode/skills/fp-go-lens && rm -rf skills-srcUse ~/.config/opencode/skills/ instead of .opencode/skills for a personal install.
OpenCode skills documentation · loads skills from .opencode/skills/, .claude/skills/, .agents/skills/
Install the "fp-go-lens" agent skill from https://github.com/IBM/fp-go/tree/main/skills/fp-go-lens into .opencode/skills/fp-go-lens/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "fp-go-lens", then confirm the skill loads.OpenCode copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
fp-go-lensGenerates or hand-writes composable lenses for the fp-go library so nested Go structs can be read and updated immutably.
A Lens focuses on one field inside a structure and provides a getter and a setter that returns a modified copy rather than mutating in place. Because fp-go is uncommon in training data, the skill tells the agent to look up any combinator not already shown through the fp-go MCP server's search and example tools rather than guessing, and to run go build and go vet afterward and fix any type-parameter or argument-order errors before presenting the code.
The recommended path is code generation: annotating a struct with a lens comment and running go generate produces a file with four generated types per struct, such as lenses for the value type and the pointer type plus matching prism types, each with both a required lens and an optional one for every field, along with constructor functions. Pointer fields automatically get optional lenses, and embedded structs and generic types are supported, generating a lens for every promoted field. Manual lens creation for value-type structs is covered for cases where generation is not suitable or the need is a one-off.
Read from SKILL.md and the folder at commit 446fd0a. It shows what the files ask for, not the result of running them.
Pre-approves nothing: there is no allowed-tools line, so your agent's usual permission prompts apply.
From allowed-tools in the SKILL.md frontmatter.
Shell commands in SKILL.md call:
goFrom the folder's file list and the shell code blocks in SKILL.md.
Links to these hosts (documentation or services it may open):
pkg.go.devmedium.comFrom URLs in SKILL.md, links to its own repository left out.
Names no API keys, tokens, secrets or passwords.
From names ending in _API_KEY, _TOKEN, _SECRET, _KEY or _PASSWORD in SKILL.md.
fp-go Lenses for Go Structs loads about 4.3k tokens when it runs. Until then it costs about 161 tokens; SKILL.md has 760 words of instructions outside code blocks.
Estimates: characters ÷ 4, the usual rule of thumb; real counts depend on the model's tokenizer. Scripts and assets cost tokens only if the agent reads them.
The automated check found no risky patterns in SKILL.md.
Automated static check — not a guarantee. Review scripts before installing. It scans the text of SKILL.md for risky patterns (piping downloads into a shell, reading credential files, hidden Unicode, destructive commands); files beside SKILL.md are not scanned.
The full file from IBM/fp-go at commit 446fd0a, republished under its Apache-2.0 licence (© IBM). 760 words, ~4,282 tokens.
.claude/skills/fp-go-lens/SKILL.md (or your agent's skills folder).Lenses are functional optics that provide immutable access to nested data structures. A Lens[S, A] focuses on a field A within a structure S, providing Get (read) and Set (immutable update) operations.
import (
L "github.com/IBM/fp-go/v2/optics/lens"
LO "github.com/IBM/fp-go/v2/optics/lens/option"
F "github.com/IBM/fp-go/v2/function"
O "github.com/IBM/fp-go/v2/option"
)fp-go is low-frequency in training data, so signatures are easy to misremember.
For any combinator not shown below, look it up via the fp-go MCP server's
search_examples / get_example tools (see the fp-go-mcp skill) instead of
guessing. After writing code, run go build ./... and go vet ./... and fix any
type-parameter or argument-order errors before presenting it.
The fastest way to create lenses is via code generation. Annotate any struct with // fp-go:Lens and run go generate ./....
//go:generate go run github.com/IBM/fp-go/v2 lens --dir . --filename gen_lens.go
// fp-go:Lens
type Person struct {
Name string
Age int
Phone *string // pointer → optional lens auto-generated
}Running go generate ./... produces a gen_lens.go file with:
| Generated type | Description |
|---|---|
PersonLenses | Lenses for Person (value type) |
PersonRefLenses | Lenses for *Person (pointer type) |
PersonPrisms | Prisms for Person |
PersonRefPrisms | Prisms for *Person |
Each type has fields for every struct field, with both a required lens and an optional lens:
type PersonLenses struct {
Name L.Lens[Person, string] // required lens
NameO LO.LensO[Person, string] // optional lens (LensO = Lens[S, Option[A]])
Age L.Lens[Person, int]
AgeO LO.LensO[Person, int]
Phone L.Lens[Person, *string]
PhoneO LO.LensO[Person, *string] // pointer fields auto-get optional variant
}Constructor functions:
lenses := MakePersonLenses() // PersonLenses
refLenses := MakePersonRefLenses() // PersonRefLenses
// Usage
person := Person{Name: "Alice", Age: 30}
updated := lenses.Name.Set("Bob")(person) // Person{Name: "Bob", Age: 30}
name := lenses.Name.Get(person) // "Alice"Pointer fields (*string, *SomeStruct) automatically generate optional lenses using LO.FromNillable.
Embedded structs and generic types are also supported — for embedded structs, lenses are generated for each promoted field.
Use manual creation when code generation is not suitable or for one-off lenses.
Use MakeLens for structs passed by value. The setter receives a copy automatically.
type Person struct {
Name string
Age int
}
nameLens := L.MakeLens(
func(p Person) string { return p.Name },
func(p Person, name string) Person { p.Name = name; return p },
)
person := Person{Name: "Alice", Age: 30}
updated := nameLens.Set("Bob")(person) // Person{Name: "Bob", Age: 30}
name := nameLens.Get(person) // "Alice"Method expressions also work (receiver becomes first argument):
func (p Person) GetName() string { return p.Name }
func (p Person) SetName(name string) Person { p.Name = name; return p }
nameLens := L.MakeLens(Person.GetName, Person.SetName)Setter signature: func(S, A) S — struct first, value second.
Use MakeLensRef for structs passed by pointer. The framework handles copying automatically — your setter modifies the pointer directly.
type Address struct {
Street string
City string
}
streetLens := L.MakeLensRef(
func(a *Address) string { return a.Street },
func(a *Address, s string) *Address { a.Street = s; return a },
)
addr := &Address{Street: "Main St", City: "Boston"}
updated := streetLens.Set("Oak Ave")(addr) // new *Address, original unchangedSetter signature: func(*S, A) *S — pointer first, value second. No manual copy needed.
Use MakeLensStrict for pointer structs when the field type is comparable (string, int, pointers, etc.). If the new value equals the current value, the original pointer is returned unchanged (no allocation).
nameLens := L.MakeLensStrict(
func(p *Person) string { return p.Name },
func(p *Person, name string) *Person { p.Name = name; return p },
)
// Setting the same value → returns original pointer (no copy)
same := nameLens.Set("Alice")(person) // same == person
// Setting a different value → creates a new copy
updated := nameLens.Set("Bob")(person)For non-comparable types use MakeLensWithEq with a custom Eq[A].
Use MakeLensWithEq when the field type is not comparable (slices, maps, structs containing those). Provide an Eq[A] to determine equality; if values are equal, the original pointer is returned unchanged without copying.
import A "github.com/IBM/fp-go/v2/array"
// []string is not comparable, so MakeLensStrict cannot be used.
// array.StrictEquals[string]() compares slices element-by-element using slices.Equal.
tagsLens := L.MakeLensWithEq(
A.StrictEquals[string](),
func(p *Person) []string { return p.Tags },
func(p *Person, t []string) *Person { p.Tags = t; return p },
)For custom element equality (e.g. case-insensitive strings or struct slices), use EQ.FromEquals(func(a, b []T) bool { ... }) instead. For comparable types, EQ.FromStrictEquals[T]() is equivalent to using MakeLensStrict.
| Constructor | Source type | Copy responsibility | Best for |
|---|---|---|---|
MakeLens | S (value) | Automatic (value copy) | Structs by value |
MakeLensRef | *S (pointer) | Automatic (framework) | Structs by pointer |
MakeLensStrict | *S (pointer) | Automatic + equality skip | Comparable fields, performance-sensitive |
MakeLensWithEq | *S (pointer) | Automatic + custom Eq | Non-comparable fields with equality |
Compose[S](ab)(sa) combines a Lens[S, A] and a Lens[A, B] into a Lens[S, B].
type Street struct { Name string }
type Address struct { Street Street }
addressLens := L.MakeLens(
func(p Person) Address { return p.Address },
func(p Person, a Address) Person { p.Address = a; return p },
)
streetNameLens := L.MakeLens(
func(a Address) string { return a.Street.Name },
func(a Address, n string) Address { a.Street.Name = n; return a },
)
// Compose: Person → Address → string
personStreetNameLens := F.Pipe1(addressLens, L.Compose[Person](streetNameLens))
updated := personStreetNameLens.Set("Oak Ave")(person)ComposeRef[S](ab)(sa) is the pointer version — use when the outer lens is Lens[*S, A].
// Composes Lens[*Person, Address] with Lens[Address, string] → Lens[*Person, string]
personStreetNameLens := F.Pipe1(addressRefLens, L.ComposeRef[Person](streetNameLens))Optional field lenses have type LensO[S, A] (alias for Lens[S, Option[A]]). Get returns Option[A]; Set takes Option[A].
All functions below are in the optics/lens/option package (imported as LO).
LO.FromNillable converts a Lens[S, *A] to a LensO[S, *A]. Get returns None when the pointer is nil.
type Company struct {
Name string
Address *Address // optional
}
addressPtrLens := L.MakeLens(
func(c Company) *Address { return c.Address },
func(c Company, a *Address) Company { c.Address = a; return c },
)
// LensO[Company, *Address]
optAddressLens := LO.FromNillable(addressPtrLens)
company := Company{Name: "Acme"}
result := optAddressLens.Get(company) // None[*Address]
withAddr := optAddressLens.Set(O.Some(&Address{City: "Boston"}))(company)
cleared := optAddressLens.Set(O.None[*Address]())(withAddr)For pointer outer structs use LO.FromNillableRef (Lens[*S, *A] → LensO[*S, *A]).
LO.ComposeOption[S, B](defaultA)(ab) composes a LensO[S, A] (optional container) with a Lens[A, B] (required field) into a LensO[S, B].
None[B] when A is absentdefaultA if absenttype Config struct { Database *Database }
dbLens := LO.FromNillable(L.MakeLens(
func(c Config) *Database { return c.Database },
func(c Config, db *Database) Config { c.Database = db; return c },
))
portLens := L.MakeLensRef(
func(db *Database) int { return db.Port },
func(db *Database, p int) *Database { db.Port = p; return db },
)
defaultDB := &Database{Host: "localhost", Port: 5432}
configPortLens := F.Pipe1(dbLens, LO.ComposeOption[Config, int](defaultDB)(portLens))
config := Config{}
port := configPortLens.Get(config) // None[int]
updated := configPortLens.Set(O.Some(3306))(config) // Database created from defaultDBLO.Compose[S, B](defaultA)(ab) is like ComposeOption but ab is a LensO[A, B] (the inner field is also optional).
// Both the Settings container and MaxRetries field are optional pointers
settingsLens := LO.FromNillable(settingsPtrLens) // LensO[Config, *Settings]
retriesLens := LO.FromNillable(retriesPtrLens) // LensO[*Settings, *int]
defaultSettings := &Settings{}
configRetriesLens := F.Pipe1(settingsLens, LO.Compose[Config, *int](defaultSettings)(retriesLens))Use F.Pipe2 / F.Pipe3 to chain compose steps. Choose the compose function based on the type of the inner lens (ab):
| Function | ab type | Use when |
|---|---|---|
LO.ComposeOption | Lens[A, B] — required field | The inner field always exists once A is present |
LO.Compose | LensO[A, B] — optional field | The inner field is itself optional |
// Person.Address (*Address, optional) → Address.Street (*Street, optional) → Street.Name (string, required)
defaultAddress := &Address{}
defaultStreet := &Street{}
streetNameLens := L.MakeLensStrict(
func(s *Street) string { return s.Name },
func(s *Street, n string) *Street { s.Name = n; return s },
)
// LensO[*Address, *Street] — Street pointer is optional
addressStreetLens := LO.FromNillableRef(L.MakeLensRef(
func(a *Address) *Street { return a.Street },
func(a *Address, s *Street) *Address { a.Street = s; return a },
))
// LensO[Person, *Address] — Address pointer is optional
personAddressLens := LO.FromNillable(L.MakeLens(
func(p Person) *Address { return p.Address },
func(p Person, a *Address) Person { p.Address = a; return p },
))
streetNameInPerson := F.Pipe2(
personAddressLens, // LensO[Person, *Address]
LO.Compose[Person, *Street](defaultAddress)(addressStreetLens), // ab is LensO → LO.Compose
LO.ComposeOption[Person, string](defaultStreet)(streetNameLens), // ab is Lens → LO.ComposeOption
)
// streetNameInPerson is LensO[Person, string]Modify applies a transformation function to the focused value:
type Counter struct { Value int }
valueLens := L.MakeLens(
func(c Counter) int { return c.Value },
func(c Counter, v int) Counter { c.Value = v; return c },
)
counter := Counter{Value: 5}
incremented := valueLens.Modify(N.Add(1))(counter)
// incremented.Value == 6, counter.Value == 5 (unchanged)Or using the package-level function in pipelines:
incremented := F.Pipe1(valueLens, L.Modify[Counter](N.Add(1)))(counter)lenses.AtContext[V](key) is a LensO[context.Context, V] onto a typed context.Context value. Get returns Some(v) if the key holds a V, otherwise None (never panics); Set(Some(v)) derives a child context via context.WithValue, Set(None) returns the context unchanged.
import LS "github.com/IBM/fp-go/v2/optics/lenses"
type ctxKey string
const userKey ctxKey = "user"
userL := LS.AtContext[string](userKey)
ctx2 := userL.Set(O.Some("Alice"))(ctx)
user := userL.Get(ctx2) // Some("Alice")Inside context/* pipelines prefer the monadic operators AskValue[V](key) / WithValue[A](key, v); use the lens when you need optics composition over the context.
import (
L "github.com/IBM/fp-go/v2/optics/lens" // MakeLens, MakeLensRef, MakeLensStrict, MakeLensWithEq, Compose, ComposeRef, Modify
LO "github.com/IBM/fp-go/v2/optics/lens/option" // LensO, FromNillable, FromNillableRef, ComposeOption, Compose
F "github.com/IBM/fp-go/v2/function" // Pipe1, Pipe2, Pipe3, ...
O "github.com/IBM/fp-go/v2/option" // Some, None, Option
EQ "github.com/IBM/fp-go/v2/eq" // FromStrictEquals, FromEquals (for MakeLensWithEq)
A "github.com/IBM/fp-go/v2/array" // StrictEquals, Eq (for MakeLensWithEq with slice fields)
N "github.com/IBM/fp-go/v2/number" // Add, Sub, Mul, ... (arithmetic on numeric fields)
)package main
import (
F "github.com/IBM/fp-go/v2/function"
L "github.com/IBM/fp-go/v2/optics/lens"
LO "github.com/IBM/fp-go/v2/optics/lens/option"
O "github.com/IBM/fp-go/v2/option"
)
type Street struct {
Name string
}
type Address struct {
City string
Street *Street // optional
}
type Person struct {
Name string
Age int
Address *Address // optional
}
func main() {
// Leaf lens: *Street.Name (comparable → use Strict for optimization)
streetNameLens := L.MakeLensStrict(
func(s *Street) string { return s.Name },
func(s *Street, n string) *Street { s.Name = n; return s },
)
// Mid lens: *Address.Street (pointer field → optional)
addressStreetLens := LO.FromNillableRef(L.MakeLensRef(
func(a *Address) *Street { return a.Street },
func(a *Address, s *Street) *Address { a.Street = s; return a },
))
// Root lens: Person.Address (pointer field → optional)
personAddressLens := LO.FromNillable(L.MakeLens(
func(p Person) *Address { return p.Address },
func(p Person, a *Address) Person { p.Address = a; return p },
))
// Compose all levels
defaultAddress := &Address{City: "Unknown"}
defaultStreet := &Street{}
streetNameInPerson := F.Pipe2(
personAddressLens,
LO.Compose[Person, *Street](defaultAddress)(addressStreetLens),
LO.ComposeOption[Person, string](defaultStreet)(streetNameLens),
)
// Update deeply nested field immutably
person := Person{
Name: "Alice",
Age: 30,
Address: &Address{
City: "Boston",
Street: &Street{Name: "Main St"},
},
}
updated := streetNameInPerson.Set(O.Some("Oak Ave"))(person)
// person.Address.Street.Name == "Main St" (original unchanged)
// updated.Address.Street.Name == "Oak Ave"
// Person with no address: default values are used
noAddr := Person{Name: "Bob"}
withAddr := streetNameInPerson.Set(O.Some("Elm St"))(noAddr)
// withAddr.Address == &Address{City: "Unknown", Street: &Street{Name: "Elm St"}}
}// fp-go:Lens annotation details© IBM, Apache-2.0. Rendered from Markdown: HTML in the file is shown as text, images as links, and headings moved down two levels. Raw file
Just SKILL.md in skills/fp-go-lens of IBM/fp-go.
Open the folder on GitHubat commit 446fd0a
fp-go Lenses for Go Structs next to the 5 skills that share the most tags, products or categories with it. Stars are the repository's; “used in” counts other GitHub owners with a copy.
| Skill | Stars | Used in | Tokens | Auto-check | Licence | Repo updated |
|---|---|---|---|---|---|---|
| fp-go Lenses for Go Structs this skillIBM/fp-go | 2k | — | ~4.3k | Automated safety check: Pass | Apache-2.0 | |
| RTK Rust Design Patternsrtk-ai/rtk | 83k | — | ~1.9k | Automated safety check: Pass | Apache-2.0 | |
| Effect Client WrapperUsefulSoftwareCo/executor | 4.1k | 1 repos | ~1.4k | Automated safety check: Pass | MIT | |
| GitVersion .NET DevelopmentGitTools/GitVersion | 3.1k | — | ~1.7k | Automated safety check: Pass | MIT | |
| AST Visitor Pattern for Unionsprisma/orm | 48k | — | ~830 | Automated safety check: Pass | Apache-2.0 | |
| Valgocohesivestack/valgo | 508 | — | ~2.4k | Automated safety check: Pass | MIT |
rtk-ai/rtk
Describes seven Rust design patterns for the RTK CLI filter modules, with when to use each, RTK examples, and notes on when a pattern is overkill.
UsefulSoftwareCo/executor
Pattern for wrapping third-party SDK clients (Stripe, Resend, AWS, etc.) with Effect.
GitTools/GitVersion
Gives repository-specific .NET guidance for GitVersion: build and test commands, central package management, project layout and coding conventions.
prisma/orm
Replaces a plain TypeScript union plus switch statements with frozen subclasses and a visitor interface when several places dispatch on the same variants.
cohesivestack/valgo
Add, refactor, debug, review, explain, or migrate type-safe validation in consumer Go applications using github.com/cohesivestack/valgo.
context-labs/whip
Golang project layouts and workspaces. An agent skill from context-labs/whip.
IBM/fp-go
Covers handling Go's context.Context idiomatically in fp-go code: reading and scoping context through operators, timeouts, cancellation and converting ctx-first functions.
IBM/fp-go
Teaches an agent to write fp-go v2 services with the Effect type, carrying dependencies in its type parameter instead of in context.Context or parameters.
IBM/fp-go
Shows how to build composable, context-aware HTTP pipelines in Go using fp-go's ReaderIOResult monad instead of raw net/http calls.
IBM/fp-go
Adds logging to fp-go functional pipelines with Tap operators, entry and exit logs and error context, so that logging never changes the value or error flowing through.
IBM/fp-go
Configures and queries the fp-go MCP server so Claude Code, Claude Desktop or another MCP client can search fp-go's examples and skills directly.
IBM/fp-go
Guides writing or reviewing point-free, first-match-wins case lists in fp-go v2 Go code instead of switch statements and if-else chains.
Works with
Categories
Generates or hand-writes composable lenses for the fp-go library so nested Go structs can be read and updated immutably. A Lens focuses on one field inside a structure and provides a getter and a setter that returns a modified copy rather than mutating in place. Because fp-go is uncommon in training data, the skill tells the agent to look up any combinator not already shown through the fp-go MCP server's search and example tools rather than guessing, and to run go build and go vet afterward and fix any type-parameter or argument-order errors before presenting the code.
fp-go Lenses for Go Structs fits situations like: adding immutable get and set access to a nested Go struct field; generating lenses and prisms for a struct with code generation; composing lenses to reach a deeply nested or optional field; writing a one-off lens by hand instead of using code generation.
Run `npx skills add IBM/fp-go --skill fp-go-lens -a claude-code`. Or copy the skill folder (skills/fp-go-lens in IBM/fp-go) into .claude/skills/fp-go-lens in your project. Claude Code loads it when a task matches its description.
Run `npx skills add IBM/fp-go --skill fp-go-lens -a codex`. Or copy the skill folder (skills/fp-go-lens in IBM/fp-go) into .agents/skills/fp-go-lens in your project. Codex loads it when a task matches its description.
Cursor, Gemini CLI, GitHub Copilot and OpenCode also load SKILL.md folders. With the skills CLI, run `npx skills add IBM/fp-go --skill fp-go-lens -a cursor` (or -a gemini-cli, github-copilot or opencode for the others). To copy it by hand, put the folder in .cursor/skills/fp-go-lens, .gemini/skills/fp-go-lens, .github/skills/fp-go-lens and .opencode/skills/fp-go-lens in your project.
Going by SKILL.md and its folder, fp-go Lenses for Go Structs needs the command-line tools its instructions call (go). Our summary lists: Go 1.24 or later; The fp-go library.
SKILL.md names 2 domains. As links in the text: pkg.go.dev and medium.com. This is read from the text; nothing was executed.
Our automated static check of SKILL.md found no risky patterns, such as piping downloads into a shell, reading credential files or hidden Unicode. It is not a guarantee. Review the folder before installing.
fp-go Lenses for Go Structs is published under the Apache-2.0 licence (the repository's licence). It allows redistribution, so the full SKILL.md is shown on this page.
About 4.3k tokens (SKILL.md is roughly 17k characters). Agents keep only the skill's name and description in context until a task matches; then they load SKILL.md in full.
Skills that share tags, products or a category with fp-go Lenses for Go Structs: RTK Rust Design Patterns (rtk-ai/rtk, 83k stars), Effect Client Wrapper (UsefulSoftwareCo/executor, 4.1k stars), GitVersion .NET Development (GitTools/GitVersion, 3.1k stars) and AST Visitor Pattern for Unions (prisma/orm, 48k stars). The comparison table on this page puts their stars, adoption, token cost, safety result and licence side by side.
IBM (a GitHub organization, an official publisher) maintains it in IBM/fp-go, which has 2,030 GitHub stars. The repository holds 10 skills in this directory. The repository was last updated on October 10, 2026.
Source: IBM/fp-go on GitHub. Facts on this page come from the repository at the commit we read; the author's words are quoted as theirs.