/nw-code-design-fp
FP code-design SSOT — the WHAT-to-design catalog (algebra-driven design, domain modelling with types, railway/error-track isolation) shared by the solution architect (design-time) and the functional crafter (execution-time).
Claude Code
$ npx -y skills add nWave-ai/nWave --skill nw-code-design-fp --agent claude-code
Codex
$ npx skills add nWave-ai/nWave --skill nw-code-design-fp -a codex -y
Cursor
$ npx skills add nWave-ai/nWave --skill nw-code-design-fp -a cursor -y
Gemini CLI
$ npx skills add nWave-ai/nWave --skill nw-code-design-fp -a gemini-cli -y
GitHub Copilot
$ npx skills add nWave-ai/nWave --skill nw-code-design-fp -a github-copilot -y
OpenCode
$ npx skills add nWave-ai/nWave --skill nw-code-design-fp -a opencode -y
Windsurf
$ npx skills add nWave-ai/nWave --skill nw-code-design-fp -a windsurf -y
SKILL.md
nw-code-design-fp.SKILL.mdname: nw-code-design-fp
description: FP code-design SSOT — the WHAT-to-design catalog (algebra-driven design, domain modelling with types, railway/error-track isolation) shared by the solution architect (design-time) and the functional crafter (execution-time).
FP Code Design
File and folder placement of the types this catalog designs follows the File layout section of nw-code-craftsmanship.
Design-time catalog for functional work. The architect loads this to design the domain algebra, the type-level model, and the error/effect tracks BEFORE DISTILL authors ATs; the functional crafter loads the same SSOT for execution. This is the WHAT-to-design subset — execution mechanics (naive/discover/freeze testing, ORM/persistence mapping, language idioms) stay in `nw-fp-algebra-driven-design`, `nw-fp-domain-modeling`, and the language skills below.
FP language skills — resolve by target language, never by default
| Language skill | Languages | PBT sibling (when one exists) | |---|---|---| | `nw-fp-clojure` | Clojure | — | | `nw-fp-erlang-elixir` | Erlang, Elixir | `nw-pbt-erlang-elixir` | | `nw-fp-fsharp` | F# | `nw-pbt-dotnet` | | `nw-fp-haskell` | Haskell | `nw-pbt-haskell` | | `nw-fp-kotlin` | Kotlin | `nw-pbt-jvm` | | `nw-fp-rust` | Rust | `nw-pbt-rust` | | `nw-fp-scala` | Scala | `nw-pbt-jvm` | | `nw-fp-typescript` | TypeScript, JavaScript | `nw-pbt-typescript` |
Same shape as the Polyglot Adapter Matrix `nw-test-design-mandates-layered-mechanics` already uses for PBT bindings — one row per target language, resolved from the contract's own target evidence, never guessed. A language NOT in this table has no dedicated FP-idiom skill: load this catalog and `nw-fp-domain-modeling` alone (both are language-agnostic) rather than silently substituting a listed language's skill — the wrong language's idioms are worse than none.
Functional Core
Inside domain and application code:
- **Pure core, effects at the edge** — domain functions take values and return
values; I/O, time, randomness and persistence stay in a thin shell that calls the core. No mutation and no shared state in the core.
- **Total functions** — every domain outcome is a case of the return type
(see Railway, rule 5); no exception or null for a domain outcome.
- **Composition** — small single-purpose functions composed through pipelines
and the railway; dependencies as leading parameters (see Dependencies).
- **Laws** — when the design declares an algebra, preserve each law; use
`nw-fp-algebra-driven-design` to implement it, never to invent a new one.
**Refactoring order within each delta, verified once with it** — first readability (names, dead code, magic values), then complexity and duplication, then move each decision into the type or function that owns its data, then replace primitives and flags with domain types and choice types, then replace conditionals on data with pattern matching over a sum type, then extract the effects to the shell. Behaviour and declared laws stay unchanged.
Algebra-Driven Design
Discover the API before implementing by specifying the rules (equations) operations must satisfy. Rules generate property tests, reveal missing features, and catch contradictions at design time (minutes) not production (days).
Design process (5 steps)
1. **Start with scope, not implementation** — do not fix data structures upfront. 2. **Define observations first** — how users extract information; observations define equality (two values equal if no observation distinguishes them). 3. **Add operations incrementally** — for each, write rules connecting it to existing ones. The web of rules IS the design. 4. **Let messy rules signal problems** — complex rules mean coarse building blocks; decompose until each rule is near-trivial. 5. **Generalize aggressively** — remove unnecessary type constraints; if operations ignore contained values, parameterize over them.
Algebraic structures (recognize → reuse known rules)
| Structure | Defining rule | Design signal / use | |-----------|---------------|---------------------| | Semigroup | `(a·b)·c = a·(b·c)` (associative) | Combining where parenthesization is irrelevant (concat, min/max, config merge) | | Monoid | Associative + identity `e·x = x = x·e` | Safe defaults, fold/reduce over collections (`(+,0)`, `(concat,[])`) | | Semilattice | Associative + commutative + idempotent | Conflict resolution, CRDTs, eventually-consistent merges (`max`) | | Functor | Preserves identity + composition under `map` | Operations agnostic to the contained type | | Applicative | Element-wise combine + uniform fill | Combining containers of differing content | | Group | Monoid + inverse `x·x⁻¹ = e` | Undo, reversible spatial transforms |
Heuristic: associative? look for an identity → monoid. Have identity? check commutativity/inverse → semilattice/group. Each upgrade unlocks new rules.
API design properties (8, three categories)
| Category | Properties | |----------|-----------| | Clarity | Compositional · Task-relevant · Interrelated (rules link every operation) | | Economy | Parsimonious · Orthogonal · Generalized (no needless type constraints) | | Safety | Closed (valid construction ⇒ valid semantics) · Complete (max structure discovered) |
Decision tree — is algebraic thinking worth it?
- Domain about COMBINING → rules (order/defaults/inverses) map to a known structure.
- Domain about TRANSFORMING → look for Functor / structure-preserving patterns.
- Small, well-understood surface → conventional design (algebra adds overhead).
- Otherwise → rules still clarify, even without standard structures.
Domain Modelling with Types
Make illegal states unrepresentable; model workflows as pipelines; push errors to the type level. Every rule encoded in a type needs no unit test.
Building blocks and wrappers
1. **AND (record types)** — value has ALL fields (Order = CustomerInfo AND Address AND OrderLines). 2. **OR (choice types)**
Read more
name: nw-code-design-fp description: FP code-design SSOT — the WHAT-to-design catalog (algebra-driven design, domain modelling with types, railway/error-track isolation) shared by the solution architect (design-time) and the functional crafter (execution-time).
FP Code Design
File and folder placement of the types this catalog designs follows the File layout section of nw-code-craftsmanship.
Design-time catalog for functional work. The architect loads this to design the domain algebra, the type-level model, and the error/effect tracks BEFORE DISTILL authors ATs; the functional crafter loads the same SSOT for execution. This is the WHAT-to-design subset — execution mechanics (naive/discover/freeze testing, ORM/persistence mapping, language idioms) stay in `nw-fp-algebra-driven-design`, `nw-fp-domain-modeling`, and the language skills below.
FP language skills — resolve by target language, never by default
| Language skill | Languages | PBT sibling (when one exists) | |---|---|---| | `nw-fp-clojure` | Clojure | — | | `nw-fp-erlang-elixir` | Erlang, Elixir | `nw-pbt-erlang-elixir` | | `nw-fp-fsharp` | F# | `nw-pbt-dotnet` | | `nw-fp-haskell` | Haskell | `nw-pbt-haskell` | | `nw-fp-kotlin` | Kotlin | `nw-pbt-jvm` | | `nw-fp-rust` | Rust | `nw-pbt-rust` | | `nw-fp-scala` | Scala | `nw-pbt-jvm` | | `nw-fp-typescript` | TypeScript, JavaScript | `nw-pbt-typescript` |
Same shape as the Polyglot Adapter Matrix `nw-test-design-mandates-layered-mechanics` already uses for PBT bindings — one row per target language, resolved from the contract's own target evidence, never guessed. A language NOT in this table has no dedicated FP-idiom skill: load this catalog and `nw-fp-domain-modeling` alone (both are language-agnostic) rather than silently substituting a listed language's skill — the wrong language's idioms are worse than none.
Functional Core
Inside domain and application code:
- **Pure core, effects at the edge** — domain functions take values and return
values; I/O, time, randomness and persistence stay in a thin shell that calls the core. No mutation and no shared state in the core.
- **Total functions** — every domain outcome is a case of the return type
(see Railway, rule 5); no exception or null for a domain outcome.
- **Composition** — small single-purpose functions composed through pipelines
and the railway; dependencies as leading parameters (see Dependencies).
- **Laws** — when the design declares an algebra, preserve each law; use
`nw-fp-algebra-driven-design` to implement it, never to invent a new one.
**Refactoring order within each delta, verified once with it** — first readability (names, dead code, magic values), then complexity and duplication, then move each decision into the type or function that owns its data, then replace primitives and flags with domain types and choice types, then replace conditionals on data with pattern matching over a sum type, then extract the effects to the shell. Behaviour and declared laws stay unchanged.
Algebra-Driven Design
Discover the API before implementing by specifying the rules (equations) operations must satisfy. Rules generate property tests, reveal missing features, and catch contradictions at design time (minutes) not production (days).
Design process (5 steps)
1. **Start with scope, not implementation** — do not fix data structures upfront. 2. **Define observations first** — how users extract information; observations define equality (two values equal if no observation distinguishes them). 3. **Add operations incrementally** — for each, write rules connecting it to existing ones. The web of rules IS the design. 4. **Let messy rules signal problems** — complex rules mean coarse building blocks; decompose until each rule is near-trivial. 5. **Generalize aggressively** — remove unnecessary type constraints; if operations ignore contained values, parameterize over them.
Algebraic structures (recognize → reuse known rules)
| Structure | Defining rule | Design signal / use | |-----------|---------------|---------------------| | Semigroup | `(a·b)·c = a·(b·c)` (associative) | Combining where parenthesization is irrelevant (concat, min/max, config merge) | | Monoid | Associative + identity `e·x = x = x·e` | Safe defaults, fold/reduce over collections (`(+,0)`, `(concat,[])`) | | Semilattice | Associative + commutative + idempotent | Conflict resolution, CRDTs, eventually-consistent merges (`max`) | | Functor | Preserves identity + composition under `map` | Operations agnostic to the contained type | | Applicative | Element-wise combine + uniform fill | Combining containers of differing content | | Group | Monoid + inverse `x·x⁻¹ = e` | Undo, reversible spatial transforms |
Heuristic: associative? look for an identity → monoid. Have identity? check commutativity/inverse → semilattice/group. Each upgrade unlocks new rules.
API design properties (8, three categories)
| Category | Properties | |----------|-----------| | Clarity | Compositional · Task-relevant · Interrelated (rules link every operation) | | Economy | Parsimonious · Orthogonal · Generalized (no needless type constraints) | | Safety | Closed (valid construction ⇒ valid semantics) · Complete (max structure discovered) |
Decision tree — is algebraic thinking worth it?
- Domain about COMBINING → rules (order/defaults/inverses) map to a known structure.
- Domain about TRANSFORMING → look for Functor / structure-preserving patterns.
- Small, well-understood surface → conventional design (algebra adds overhead).
- Otherwise → rules still clarify, even without standard structures.
Domain Modelling with Types
Make illegal states unrepresentable; model workflows as pipelines; push errors to the type level. Every rule encoded in a type needs no unit test.
Building blocks and wrappers
1. **AND (record types)** — value has ALL fields (Order = CustomerInfo AND Address AND OrderLines). 2. **OR (choice types)**
Other skills on nwave.
More skills from other plugins.
brainstorming
You MUST use this before any creative work - creating features, building components, adding functionality, modifying behavior, or…
ask-matt
Ask which skill or flow fits your situation. A router over the skills in this repo.
Questions about nw-code-design-fp.
- Which coding agents can use nw-code-design-fp?
- nw-code-design-fp installs in Claude Code, Codex, Cursor, Gemini CLI, GitHub Copilot, OpenCode and Windsurf with the skills CLI, using each agent's flag shown on this page. Flowy's auto-invocation, which fires a skill when your prompt matches, runs in Claude Code only.

