Official agent skill

fp-go Lenses for Go Structs

by IBM in IBM/fp-go

Generates or hand-writes composable lenses for the fp-go library so nested Go structs can be read and updated immutably.

OfficialApache-2.0Auto-check passedDevelopment

Install fp-go Lenses for Go Structs

skills CLI
$ npx skills add IBM/fp-go --skill fp-go-lens -a claude-code

Project install by default; add -g for ~/.claude/skills/.

GitHub CLI
$ gh skill install IBM/fp-go fp-go-lens --agent claude-code

Project scope by default; add --scope user for a personal install. Needs GitHub CLI 2.90.0 or later (public preview).

Manual copy
$ 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-src

Use ~/.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/

Facts

Skill name
fp-go-lens
GitHub stars
2k
Token cost
~4.3k tokens
SKILL.md length
760 words
Files
1
Skills in repo
10
Repo updated
First seen
Licence
Apache-2.0

At a glance

Generates or hand-writes composable lenses for the fp-go library so nested Go structs can be read and updated immutably.

  • Adding immutable get and set access to a nested Go struct field
  • SKILL.md covers Overview, Before You Generate, Code Generation (Recommended) and Manual Lens Creation, plus 7 more sections
  • Calls go
  • Generating lenses and prisms for a struct with code generation

What it does

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.

When your agent uses it

  • 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

Example prompts

  • “Add fp-go lenses to this struct so I can update the nested address field immutably.”
  • “Generate the lenses and ref-lenses for this struct with go generate.”
  • “Write a manual lens for one field since this struct won't use code generation.”

Requirements

  • Go 1.24 or later
  • The fp-go library

What it can do on your machine

Read from SKILL.md and the folder at commit 446fd0a. It shows what the files ask for, not the result of running them.

  • Tool permissions

    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.

  • Runs code

    Shell commands in SKILL.md call:

    • go

    From the folder's file list and the shell code blocks in SKILL.md.

  • Network

    Links to these hosts (documentation or services it may open):

    • pkg.go.dev
    • medium.com

    From URLs in SKILL.md, links to its own repository left out.

  • Credentials

    Names no API keys, tokens, secrets or passwords.

    From names ending in _API_KEY, _TOKEN, _SECRET, _KEY or _PASSWORD in SKILL.md.

Context cost

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.

Always · name and description, kept in context so the agent knows when to use it
~161
When it runs · the whole SKILL.md, loaded when a task matches
~4.3k

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.

Safety

Auto-check passed

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.

SKILL.md

The full file from IBM/fp-go at commit 446fd0a, republished under its Apache-2.0 licence (© IBM). 760 words, ~4,282 tokens.

Download SKILL.mdSave it as .claude/skills/fp-go-lens/SKILL.md (or your agent's skills folder).
name
fp-go-lens
description
Use this skill when working with lenses and optics in Go using the fp-go library (github.com/IBM/fp-go/v2/optics/lens). Trigger on mentions of lenses, optics, MakeLens, MakeLensRef, MakeLensStrict, lens composition, immutable updates to nested structs, accessing nested data structures, Compose, ComposeRef, ComposeOption, FromNillable, FromNillableRef, Modify, getter/setter patterns, or functional updates to Go structs. Also trigger when the user needs to update deeply nested fields immutably or work with optional fields in struct hierarchies. Also trigger for `// fp-go:Lens` annotation or go generate for lens code generation.

fp-go Lenses for Structs

Overview

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.

go
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"
)

Before You Generate

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
//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 typeDescription
PersonLensesLenses for Person (value type)
PersonRefLensesLenses for *Person (pointer type)
PersonPrismsPrisms for Person
PersonRefPrismsPrisms for *Person

Each type has fields for every struct field, with both a required lens and an optional lens:

go
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:

go
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.


Manual Lens Creation

Use manual creation when code generation is not suitable or for one-off lenses.

MakeLens — Value Types

Use MakeLens for structs passed by value. The setter receives a copy automatically.

go
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):

go
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.

MakeLensRef — Pointer Types

Use MakeLensRef for structs passed by pointer. The framework handles copying automatically — your setter modifies the pointer directly.

go
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 unchanged

Setter signature: func(*S, A) *S — pointer first, value second. No manual copy needed.

MakeLensStrict — Pointer Types with Comparable Fields (Optimization)

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).

go
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].

MakeLensWithEq — Pointer Types with Custom Equality

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.

go
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.

Comparison
ConstructorSource typeCopy responsibilityBest for
MakeLensS (value)Automatic (value copy)Structs by value
MakeLensRef*S (pointer)Automatic (framework)Structs by pointer
MakeLensStrict*S (pointer)Automatic + equality skipComparable fields, performance-sensitive
MakeLensWithEq*S (pointer)Automatic + custom EqNon-comparable fields with equality

Composing Lenses

Compose — Value Outer Structure

Compose[S](ab)(sa) combines a Lens[S, A] and a Lens[A, B] into a Lens[S, B].

go
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)
Show full SKILL.md (309 more words)Show less
ComposeRef — Pointer Outer Structure

ComposeRef[S](ab)(sa) is the pointer version — use when the outer lens is Lens[*S, A].

go
// Composes Lens[*Person, Address] with Lens[Address, string] → Lens[*Person, string]
personStreetNameLens := F.Pipe1(addressRefLens, L.ComposeRef[Person](streetNameLens))

Working with Optional Fields

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).

FromNillable — Pointer Field to Option

LO.FromNillable converts a Lens[S, *A] to a LensO[S, *A]. Get returns None when the pointer is nil.

go
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]).

ComposeOption — Optional Container, Required Field

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].

  • Get: returns None[B] when A is absent
  • Set(Some[B]): updates B in A, creating A from defaultA if absent
  • Set(None[B]): removes A entirely
go
type 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 defaultDB
Compose (Option Package) — Optional Container, Optional Field

LO.Compose[S, B](defaultA)(ab) is like ComposeOption but ab is a LensO[A, B] (the inner field is also optional).

go
// 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))
Chaining Multiple Optional Levels

Use F.Pipe2 / F.Pipe3 to chain compose steps. Choose the compose function based on the type of the inner lens (ab):

Functionab typeUse when
LO.ComposeOptionLens[A, B] — required fieldThe inner field always exists once A is present
LO.ComposeLensO[A, B] — optional fieldThe inner field is itself optional
go
// 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]

Modifying Values

Modify applies a transformation function to the focused value:

go
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:

go
incremented := F.Pipe1(valueLens, L.Modify[Counter](N.Add(1)))(counter)

Context Values as a Lens

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.

go
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 Reference

go
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)
)

Complete Manual Example

go
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"}}
}

Further Reading

© 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

Files

Just SKILL.md in skills/fp-go-lens of IBM/fp-go.

Open the folder on GitHubat commit 446fd0a

Compare with similar skills

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.

fp-go Lenses for Go Structs compared with similar skills
SkillStarsUsed inTokensAuto-checkLicenceRepo updated
fp-go Lenses for Go Structs this skillIBM/fp-go2k—~4.3kAutomated safety check: PassApache-2.0
RTK Rust Design Patternsrtk-ai/rtk83k—~1.9kAutomated safety check: PassApache-2.0
Effect Client WrapperUsefulSoftwareCo/executor4.1k1 repos~1.4kAutomated safety check: PassMIT
GitVersion .NET DevelopmentGitTools/GitVersion3.1k—~1.7kAutomated safety check: PassMIT
AST Visitor Pattern for Unionsprisma/orm48k—~830Automated safety check: PassApache-2.0
Valgocohesivestack/valgo508—~2.4kAutomated safety check: PassMIT

Similar skills

  • 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.

    83k GitHub stars~1.9k tokensUpdated yesterday
    DevelopmentAuto-check passed
  • Effect Client Wrapper

    UsefulSoftwareCo/executor

    Pattern for wrapping third-party SDK clients (Stripe, Resend, AWS, etc.) with Effect.

    4.1k GitHub starsUsed in 1 repo~1.4k tokens
    DevelopmentAuto-check passed
  • GitVersion .NET Development

    GitTools/GitVersion

    Gives repository-specific .NET guidance for GitVersion: build and test commands, central package management, project layout and coding conventions.

    3.1k GitHub stars~1.7k tokensUpdated yesterday
    DevelopmentAuto-check passed
  • Official

    Replaces a plain TypeScript union plus switch statements with frozen subclasses and a visitor interface when several places dispatch on the same variants.

    48k GitHub stars~830 tokensUpdated yesterday
    DevelopmentAuto-check passed
  • Valgo

    cohesivestack/valgo

    Add, refactor, debug, review, explain, or migrate type-safe validation in consumer Go applications using github.com/cohesivestack/valgo.

    508 GitHub stars~2.4k tokensUpdated 1 mo ago
    DevelopmentAuto-check passed
  • Golang Project Layout

    context-labs/whip

    Golang project layouts and workspaces. An agent skill from context-labs/whip.

    1.1k GitHub starsUsed in 1 repo~1.8k tokens
    DevelopmentAuto-check passed

More from IBM/fp-go

All 10 skills in this repo
  • Official

    Covers handling Go's context.Context idiomatically in fp-go code: reading and scoping context through operators, timeouts, cancellation and converting ctx-first functions.

    2k GitHub stars~4.2k tokensUpdated today
    Auto-check passed
  • 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.

    2k GitHub stars~4.3k tokensUpdated today
    Auto-check passed
  • Official

    Shows how to build composable, context-aware HTTP pipelines in Go using fp-go's ReaderIOResult monad instead of raw net/http calls.

    2k GitHub stars~4.4k tokensUpdated today
    Auto-check passed
  • Official

    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.

    2k GitHub stars~3.7k tokensUpdated today
    Auto-check passed
  • Official

    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.

    2k GitHub stars~3.3k tokensUpdated today
    Auto-check passed
  • Official

    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.

    2k GitHub stars~2.8k tokensUpdated today
    Auto-check passed

Works with

Categories

Questions about fp-go Lenses for Go Structs

What does fp-go Lenses for Go Structs do?

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.

When should I use fp-go Lenses for Go Structs?

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.

How do I install fp-go Lenses for Go Structs in Claude Code?

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.

How do I install fp-go Lenses for Go Structs in Codex?

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.

Can I use fp-go Lenses for Go Structs in Cursor, Gemini CLI or GitHub Copilot?

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.

What does fp-go Lenses for Go Structs need to run?

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.

Does fp-go Lenses for Go Structs access the network?

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.

Is fp-go Lenses for Go Structs safe to install?

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.

What licence does fp-go Lenses for Go Structs use?

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.

How many tokens does fp-go Lenses for Go Structs use?

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.

What are the alternatives to fp-go Lenses for Go Structs?

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.

Who maintains fp-go Lenses for Go Structs?

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.