/nw-fp-clojure
Clojure language-specific patterns, data-first modeling, REPL-driven development, and spec
$ npx -y skills add nWave-ai/nWave --skill nw-fp-clojure --agent claude-codeHow it fires
How this skill gets triggered: by you, by Claude, or both.
- Fires itselfAuto-invocation. Claude auto-loads it when your prompt matches the work.Auto-invocation is when the right skill fires by itself at the right moment, driven by a FLOW.md router and a hook, instead of you invoking it by name. It is the difference between a skill being installed and a skill actually getting used.Read the full definition →
- You can call itInvoke it directly when you want it.
- Slash command
/nw-fp-clojure
Context preview
The summary Claude sees to decide when to auto-load this skill.
Clojure language-specific patterns, data-first modeling, REPL-driven development, and spec
SKILL.md
nw-fp-clojure.SKILL.mdname: nw-fp-clojure
agent: nw-functional-software-crafter
description: Clojure language-specific patterns, data-first modeling, REPL-driven development, and spec
user-invocable: false
disable-model-invocation: true
FP in Clojure -- Functional Software Crafter Skill
Cross-references: [fp-principles](../nw-fp-principles/SKILL.md) | [fp-domain-modeling](../nw-fp-domain-modeling/SKILL.md)
When to Choose Clojure
- Best for: data-centric domains | REPL-driven exploration | rapid prototyping | frequently evolving data shapes
- Not ideal for: teams wanting compile-time type safety | Android | teams unfamiliar with Lisp syntax
[STARTER] Quick Setup
# Install Clojure CLI
brew install clojure/tools/clojure # macOS
# Create project
mkdir -p order-service/src/order_service order-service/test/order_service
# Run REPL: clj | Run tests: clj -X:test
**Namespace caveat**: Clojure namespaces use `-` but filenames use `_` (JVM requirement). `order-service.core` lives in `order_service/core.clj`.
[STARTER] Domain Modeling with Spec
Clojure is dynamically typed. Domain modeling uses maps with qualified keywords, validated at runtime.
(require '[clojure.spec.alpha :as s])
;; Domain wrappers as specs
(s/def ::order-id pos-int?)
(s/def ::email (s/and string? #(clojure.string/includes? % "@")))
(s/def ::customer-name (s/and string? #(> (count %) 0)))
;; Record types as spec'd maps
(s/def ::customer (s/keys :req [::customer-name ::email] :opt [::phone]))
;; Choice types as spec alternatives
(s/def ::payment-method
(s/or :credit-card (s/keys :req [::card-number ::expiry-date])
:bank-transfer (s/keys :req [::account-number])
:cash #{:cash}))[STARTER] Validated Construction
(defn make-email [raw-email]
(if (s/valid? ::email raw-email)
{:ok raw-email}
{:error (str "Invalid email: " raw-email)}))[INTERMEDIATE] Auto-Generated Test Data from Specs
(require '[clojure.spec.gen.alpha :as gen]
'[clojure.spec.test.alpha :as stest])
(gen/sample (s/gen ::customer) 5) ;; random valid customers
;; Auto-test functions against their specs
(s/fdef validate-order
:args (s/cat :raw-order ::raw-order)
:ret (s/or :ok ::validated-order :error ::validation-error))
(stest/check `validate-order)Define specs, get generators and function tests for free.
[INTERMEDIATE] Composition Style
Threading Macros
;; Thread-first (data through first arg) / Thread-last (for collections)
(-> raw-order validate-order price-order confirm-order)
(->> orders (filter active?) (map :customer-name) (sort))
;; comp composes right-to-left; partial for partial application
(def process-order (comp confirm-order price-order validate-order))
Error-Track Pipeline (Convention-Based)
(defn bind-result [result f]
(if (:ok result) (f (:ok result)) result))
(defn place-order [raw-order]
(-> {:ok raw-order}
(bind-result validate-order)
(bind-result price-order)
(bind-result confirm-order)))No stdlib Result/Either -- by convention using `{:ok v}` / `{:error r}` maps.
[INTERMEDIATE] Effect Management
Side effects managed by convention and architecture, not the type system.
Pure Core / Imperative Shell
;; Pure domain logic (no I/O, no state)
(defn calculate-discount [order]
(if (> (count (:lines order)) 10) {:rate 0.1} {:rate 0.0}))
;; Imperative shell (I/O at edges)
(defn place-order-handler! [deps raw-order]
(let [result (-> raw-order
validate-order
(bind-result (partial price-order (:get-price deps)))
(bind-result confirm-order))]
(when (:ok result)
((:save-order! deps) (:ok result)))
result))[ADVANCED] Hexagonal Architecture with Functions
;; Functions as dependencies (idiomatic Clojure)
(defn make-place-order-handler [find-order-fn save-order-fn!]
(fn [raw-order]
(let [result (validate-and-price raw-order)]
(when (:ok result) (save-order-fn! (:ok result)))
result)))
;; Composition root
(def handler
(make-place-order-handler
(partial find-order-in-db datasource)
(partial save-order-in-db! datasource)))For lifecycle management, use Component, Integrant, or Mount:
(require '[integrant.core :as ig])
(defmethod ig/init-key ::order-repo [_ {:keys [datasource]}]
(->PostgresOrderRepo datasource))[INTERMEDIATE] Testing
**Frameworks**: clojure.test (built-in) | test.check (PBT) | Kaocha (test runner).
Property Test with test.check
(require '[clojure.test.check.clojure-test :refer [defspec]]
'[clojure.test.check.generators :as gen]
'[clojure.test.check.properties :as prop])
(defspec serialization-round-trips 100
(prop/for-all [order (s/gen ::order)]
(= order (deserialize (serialize order)))))Custom Generator
(def gen-valid-email
(gen/fmap (fn [[user domain]] (str user "@" domain ".com"))
(gen/tuple
(gen/such-that not-empty (gen/string-alphanumeric))
(gen/such-that not-empty (gen/string-alphanumeric)))))[ADVANCED] Idiomatic Patterns
Data-First Domain Modeling
(def order
{::order-id 42
::customer {::customer-name "Alice" ::email "alice@example.com"}
::lines [{::product-code "W-1234" ::quantity 10 ::price 25.0}]
::status :validated})"Data is better than types." Domain models are maps. Validation happens at boundaries.
Multimethods for State Machines
(defmulti handle-command (fn [state _command] (:status state)))
(defmethod handle-command :empty [_state {:keys [item]}]
{:status :active :lines [item]})
(defmethod handle-command :active [state {:keys [action] :as command}]
(case action
:add-item (update state :lines conj (:item command))
:pay (assoc state :status :paid)
state))
(defmethod handle-command :paid [state _command]
state)Read more
name: nw-fp-clojure agent: nw-functional-software-crafter description: Clojure language-specific patterns, data-first modeling, REPL-driven development, and spec user-invocable: false disable-model-invocation: true
FP in Clojure -- Functional Software Crafter Skill
Cross-references: [fp-principles](../nw-fp-principles/SKILL.md) | [fp-domain-modeling](../nw-fp-domain-modeling/SKILL.md)
When to Choose Clojure
- Best for: data-centric domains | REPL-driven exploration | rapid prototyping | frequently evolving data shapes
- Not ideal for: teams wanting compile-time type safety | Android | teams unfamiliar with Lisp syntax
[STARTER] Quick Setup
# Install Clojure CLI brew install clojure/tools/clojure # macOS # Create project mkdir -p order-service/src/order_service order-service/test/order_service # Run REPL: clj | Run tests: clj -X:test
**Namespace caveat**: Clojure namespaces use `-` but filenames use `_` (JVM requirement). `order-service.core` lives in `order_service/core.clj`.
[STARTER] Domain Modeling with Spec
Clojure is dynamically typed. Domain modeling uses maps with qualified keywords, validated at runtime.
(require '[clojure.spec.alpha :as s])
;; Domain wrappers as specs
(s/def ::order-id pos-int?)
(s/def ::email (s/and string? #(clojure.string/includes? % "@")))
(s/def ::customer-name (s/and string? #(> (count %) 0)))
;; Record types as spec'd maps
(s/def ::customer (s/keys :req [::customer-name ::email] :opt [::phone]))
;; Choice types as spec alternatives
(s/def ::payment-method
(s/or :credit-card (s/keys :req [::card-number ::expiry-date])
:bank-transfer (s/keys :req [::account-number])
:cash #{:cash}))[STARTER] Validated Construction
(defn make-email [raw-email]
(if (s/valid? ::email raw-email)
{:ok raw-email}
{:error (str "Invalid email: " raw-email)}))[INTERMEDIATE] Auto-Generated Test Data from Specs
(require '[clojure.spec.gen.alpha :as gen]
'[clojure.spec.test.alpha :as stest])
(gen/sample (s/gen ::customer) 5) ;; random valid customers
;; Auto-test functions against their specs
(s/fdef validate-order
:args (s/cat :raw-order ::raw-order)
:ret (s/or :ok ::validated-order :error ::validation-error))
(stest/check `validate-order)Define specs, get generators and function tests for free.
[INTERMEDIATE] Composition Style
Threading Macros
;; Thread-first (data through first arg) / Thread-last (for collections) (-> raw-order validate-order price-order confirm-order) (->> orders (filter active?) (map :customer-name) (sort)) ;; comp composes right-to-left; partial for partial application (def process-order (comp confirm-order price-order validate-order))
Error-Track Pipeline (Convention-Based)
(defn bind-result [result f]
(if (:ok result) (f (:ok result)) result))
(defn place-order [raw-order]
(-> {:ok raw-order}
(bind-result validate-order)
(bind-result price-order)
(bind-result confirm-order)))No stdlib Result/Either -- by convention using `{:ok v}` / `{:error r}` maps.
[INTERMEDIATE] Effect Management
Side effects managed by convention and architecture, not the type system.
Pure Core / Imperative Shell
;; Pure domain logic (no I/O, no state)
(defn calculate-discount [order]
(if (> (count (:lines order)) 10) {:rate 0.1} {:rate 0.0}))
;; Imperative shell (I/O at edges)
(defn place-order-handler! [deps raw-order]
(let [result (-> raw-order
validate-order
(bind-result (partial price-order (:get-price deps)))
(bind-result confirm-order))]
(when (:ok result)
((:save-order! deps) (:ok result)))
result))[ADVANCED] Hexagonal Architecture with Functions
;; Functions as dependencies (idiomatic Clojure)
(defn make-place-order-handler [find-order-fn save-order-fn!]
(fn [raw-order]
(let [result (validate-and-price raw-order)]
(when (:ok result) (save-order-fn! (:ok result)))
result)))
;; Composition root
(def handler
(make-place-order-handler
(partial find-order-in-db datasource)
(partial save-order-in-db! datasource)))For lifecycle management, use Component, Integrant, or Mount:
(require '[integrant.core :as ig])
(defmethod ig/init-key ::order-repo [_ {:keys [datasource]}]
(->PostgresOrderRepo datasource))[INTERMEDIATE] Testing
**Frameworks**: clojure.test (built-in) | test.check (PBT) | Kaocha (test runner).
Property Test with test.check
(require '[clojure.test.check.clojure-test :refer [defspec]]
'[clojure.test.check.generators :as gen]
'[clojure.test.check.properties :as prop])
(defspec serialization-round-trips 100
(prop/for-all [order (s/gen ::order)]
(= order (deserialize (serialize order)))))Custom Generator
(def gen-valid-email
(gen/fmap (fn [[user domain]] (str user "@" domain ".com"))
(gen/tuple
(gen/such-that not-empty (gen/string-alphanumeric))
(gen/such-that not-empty (gen/string-alphanumeric)))))[ADVANCED] Idiomatic Patterns
Data-First Domain Modeling
(def order
{::order-id 42
::customer {::customer-name "Alice" ::email "alice@example.com"}
::lines [{::product-code "W-1234" ::quantity 10 ::price 25.0}]
::status :validated})"Data is better than types." Domain models are maps. Validation happens at boundaries.
Multimethods for State Machines
(defmulti handle-command (fn [state _command] (:status state)))
(defmethod handle-command :empty [_state {:keys [item]}]
{:status :active :lines [item]})
(defmethod handle-command :active [state {:keys [action] :as command}]
(case action
:add-item (update state :lines conj (:item command))
:pay (assoc state :status :paid)
state))
(defmethod handle-command :paid [state _command]
state)AI agents that guide you from idea to working code, with human judgment at every gate. nWave runs inside Claude Code. It breaks feature delivery into seven waves (discover, diverge, discuss, design, devops, distill, deliver).
Repo: nWave-ai/nWave
Other skills on nwave.
- /nw-ab-critique-dimensions
Review dimensions for validating agent quality - template compliance, safety, testing, and priority validation
Open skill - /nw-abr-critique-dimensions
Review dimensions for validating agent quality - template compliance, safety, testing, and priority validation
Open skill - /nw-ad-critique-dimensions
Review dimensions for acceptance test quality - happy path bias, GWT compliance, business language purity, coverage completeness, walking skeleton user-centricity, priority validation, observable behavior assertions, traceability coverage, and walking skeleton boundary proof
Open skill - /nw-agent-creation-workflow
Detailed 5-phase workflow for creating agents - from requirements analysis through validation and iterative refinement
Open skill - /nw-agent-testing
5-layer testing approach for agent validation including adversarial testing, security validation, and prompt injection resistance
Open skill - /nw-architectural-styles-tradeoffs
Architectural style selection decision matrices, trade-off analysis, structural enforcement rules, and combination patterns. Load when choosing or evaluating architecture styles.
Open skill

