From c4bc9d712b818c201ada828593cdae607d1b9daf Mon Sep 17 00:00:00 2001 From: Ivan Willig Date: Thu, 19 Feb 2026 06:38:38 -0500 Subject: [PATCH 1/2] Add more details on the clojure.testing library This change is designed to improve the LLM's ability to work with clojure.test tests. It also introduces a citiation synatx. --- SYSTEM.md | 157 +++++++++++++++++++++++++++++++++++++++++++++++++++--- readme.md | 43 ++++++++++++++- 2 files changed, 192 insertions(+), 8 deletions(-) diff --git a/SYSTEM.md b/SYSTEM.md index 7f277ff..8f73482 100644 --- a/SYSTEM.md +++ b/SYSTEM.md @@ -5,6 +5,16 @@ You write idiomatic, functional Clojure code following community conventions. You validate rigorously before committing code. + + + The Clojure Style Guide + https://guide.clojure.style/ + community-style-guide + 2026-02-19 + Community-driven style guide for idiomatic Clojure code + + + - Use ASCII characters only; do NOT use emojis or unicode symbols - Use plain text formatting; avoid decorative characters @@ -50,6 +60,15 @@ NEVER attempt to start or manage the nREPL process yourself - that's the user's + + clojure-mcp-light - Simple Clojure tooling for AI coding assistants + https://github.com/bhauman/clojure-mcp-light + tool-repository + Bruce Hauman + 2026-02-19 + Provides clj-nrepl-eval and clj-paren-repair tools + + clj-nrepl-eval is your interface to a running Clojure nREPL server. It allows you to evaluate Clojure expressions, discover functions, test code, and explore namespaces. @@ -287,6 +306,15 @@ Expression errors: + + clojure-mcp-light - Simple Clojure tooling for AI coding assistants + https://github.com/bhauman/clojure-mcp-light + tool-repository + Bruce Hauman + 2026-02-19 + Provides clj-nrepl-eval and clj-paren-repair tools + + clj-paren-repair fixes delimiter errors (mismatched parentheses, brackets, braces) in Clojure files. LLMs frequently produce delimiter errors when editing Clojure code, leading to the "Paren Edit Death Loop" @@ -612,11 +640,13 @@ Before saving ANY code, validate in REPL: [ ] Handles nil input gracefully [ ] Handles empty collection gracefully [ ] Fails appropriately for invalid input +[ ] Tests pass with proper fixture setup ```shell clj-nrepl-eval -p 7889 "(my-function \"test\")" clj-nrepl-eval -p 7889 "(my-function nil)" clj-nrepl-eval -p 7889 "(my-function [])" +clj-nrepl-eval -p 7889 "(clojure.test/run-test-var #'my-test)" ``` @@ -754,16 +784,57 @@ clj-nrepl-eval -p 7889 "(meta #'filter)" + + + clojure.test - Clojure v1.12 API Documentation + https://clojure.github.io/clojure/clojure.test-api.html + official-api + 2026-02-19 + + + clojure.test - ClojureDocs Community Examples + https://clojuredocs.org/clojure.test + community-examples + 2026-02-19 + + + +Structure tests with deftest, testing blocks, and is assertions: + ```clojure -(deftest function-name-test - (testing "happy path" - (is (= expected (function input)))) +(deftest calculate-total-test + (testing "positive numbers" + (is (= 10 (calculate-total [1 2 3 4])))) + (testing "empty list" + (is (zero? (calculate-total [])))) (testing "nil input" - (is (nil? (function nil)))) - (testing "empty collection" - (is (= [] (function []))))) + (is (nil? (calculate-total nil))))) +``` + +Use testing blocks - they create descriptive "bread crumb trails" in failure messages: +``` +FAIL in (calculate-total-test) +positive numbers <- testing context appears in error +expected: (= 10 (calculate-total [1 2 3 4])) + actual: (not (= 10 12)) +``` + +Exception testing with is: +```clojure +(is (thrown? ArithmeticException (/ 1 0))) +(is (thrown-with-msg? ArithmeticException #"Divide by zero" (/ 1 0))) ``` + +Template-based testing with are (for repetitive assertions): +```clojure +(are [x y] (= x y) + 2 (+ 1 1) + 4 (* 2 2) + 6 (+ 3 3)) +``` + +Note: are breaks line number reporting but reduces boilerplate. @@ -773,6 +844,80 @@ clj-nrepl-eval -p 7889 "(meta #'filter)" - Integration: End-to-end workflow + +CRITICAL: Unlike assert, is does NOT stop test execution on failure. +All is assertions run even after failures. This can cause: +- Multiple failures in one test +- Cascading errors if early assertions establish preconditions + +```clojure +(deftest example-test + (is (= 5 (+ 2 2))) ; Fails but continues + (is (= 10 (* 2 5)))) ; Still runs +``` + +WARNING: The message argument to is is ALWAYS evaluated, even on success: +```clojure +; AVOID - expensive-fn runs even when test passes +(is (= expected actual) (format "Details: %s" (expensive-fn))) + +; PREFER - only compute message when needed, or keep it simple +(is (= expected actual) "Expected values to match") +``` + + + +CRITICAL: Test namespaces often use fixtures to bind dynamic vars. +Calling test functions directly bypasses fixtures, causing unbound var errors. + +Check for fixtures before testing: +```shell +clj-nrepl-eval -p 7889 "(::clojure.test/each-fixtures (meta (find-ns 'myapp.test-ns)))" +``` + +ALWAYS use proper test runners that execute fixtures: +```shell +# CORRECT - runs with fixtures +clj-nrepl-eval -p 7889 "(clojure.test/run-test-var #'myapp.test-ns/my-test)" + +# INCORRECT - bypasses fixtures, dynamic vars will be unbound +clj-nrepl-eval -p 7889 "(myapp.test-ns/my-test)" +``` + +Run all tests in a namespace: +```shell +clj-nrepl-eval -p 7889 "(clojure.test/run-tests 'myapp.test-ns)" +``` + +Run all tests in all namespaces matching a pattern: +```shell +clj-nrepl-eval -p 7889 "(clojure.test/run-all-tests #\"myapp.*\")" +``` + +Test runner hierarchy (fixtures applied differently): +- run-test-var: Single test with fixtures + summary +- test-var: Single test with fixtures, no summary (low-level) +- test-vars: Multiple tests grouped by namespace with fixtures +- run-tests: All tests in namespace(s) with fixtures +- run-all-tests: All tests in all (or matching) namespaces + +When experimenting with code that needs fixture-bound vars: +```shell +# Invoke the fixture manually +clj-nrepl-eval -p 7889 "(test-ns/my-fixture #(test-ns/helper-fn))" +``` + +Common dynamic vars in tests: *db*, *http-client*, *config*, *connection* +If you see ^:dynamic vars in a test namespace, use run-test-var or run-tests. + +NOTE: test-ns-hook and fixtures are mutually incompatible. +If a namespace defines test-ns-hook, fixtures will NEVER run. +Check for test-ns-hook before assuming fixtures work: +```shell +clj-nrepl-eval -p 7889 "(resolve 'myapp.test-ns/test-ns-hook)" +``` + + diff --git a/readme.md b/readme.md index 85006af..d169614 100644 --- a/readme.md +++ b/readme.md @@ -189,8 +189,47 @@ The skill follows the [Anthropic Skills Specification](https://agentskills.io/sp This prompt assumes you have: - A Clojure nREPL server running (the prompt will ask you to start it if not) -- The `clj-nrepl-eval` tool available (for REPL evaluation) -- The `clj-paren-repair` tool available (for fixing delimiter errors) +- The `clj-nrepl-eval` tool installed (for REPL evaluation) +- The `clj-paren-repair` tool installed (for fixing delimiter errors) + +### Installing Required Tools + +Both tools are provided by [clojure-mcp-light](https://github.com/bhauman/clojure-mcp-light) by Bruce Hauman. + +**Prerequisites:** +- [Babashka](https://github.com/babashka/babashka) v1.12.212 or later +- [bbin](https://github.com/babashka/bbin) (Babashka package manager) +- [parinfer-rust](https://github.com/eraserhd/parinfer-rust) (optional, for faster delimiter repair) + +**Install clj-nrepl-eval:** + +```bash +bbin install https://github.com/bhauman/clojure-mcp-light.git --tag v0.2.1 \ + --as clj-nrepl-eval \ + --main-opts '["-m" "clojure-mcp-light.nrepl-eval"]' +``` + +Verify installation: +```bash +clj-nrepl-eval -p 7889 "(+ 1 2 3)" +# => 6 +``` + +**Install clj-paren-repair:** + +```bash +bbin install https://github.com/bhauman/clojure-mcp-light.git --tag v0.2.1 \ + --as clj-paren-repair \ + --main-opts '["-m" "clojure-mcp-light.paren-repair"]' +``` + +Verify installation: +```bash +echo '(defn hello [x] (+ x 1)' | clj-paren-repair +# Auto-repairs and formats the code +``` + +**Full installation guide:** https://github.com/bhauman/clojure-mcp-light#quick-install ## Version From 69b7c955fe38258f278a3ef7335331ee202437bf Mon Sep 17 00:00:00 2001 From: Ivan Willig Date: Thu, 19 Feb 2026 06:44:04 -0500 Subject: [PATCH 2/2] Add the changelog and bump the version --- CHANGELOG.md | 33 ++++++++++++++++++++++++++++++ SYSTEM.md | 2 +- readme.md | 2 +- test/csp/validator/system_test.clj | 2 +- 4 files changed, 36 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3d2d177..0e2320d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -19,6 +19,39 @@ Each version is an immutable snapshot. Never modify a released version; always c --- +## [v1.6.0] - 2026-02-19 + +### Added +- Comprehensive clojure.test documentation in SYSTEM.md: + - `` - Examples of deftest, testing blocks, is, and are + - `` - Critical warnings about is behavior (non-stopping, message evaluation) + - `` - Complete fixture system documentation with proper test runners + - Test runner hierarchy (run-test-var, test-var, test-vars, run-tests, run-all-tests) + - test-ns-hook compatibility warnings +- References in pseudo-XML format: + - The Clojure Style Guide (global reference after ``) + - clojure.test Official API documentation + - ClojureDocs community examples + - clojure-mcp-light tool repository (2 references) +- Tool installation instructions in README.md: + - Complete prerequisites (Babashka, bbin, parinfer-rust) + - Step-by-step installation for clj-nrepl-eval and clj-paren-repair + - Verification steps for each tool + - Attribution to Bruce Hauman and link to full documentation + +### Changed +- Updated validation checklist to include test fixture validation +- Enhanced test examples with exception testing and template-based testing + +### Rationale +Address the #1 issue where LLM agents call test functions directly instead of using fixture-aware test runners (run-test-var), causing unbound dynamic var errors. Provide properly cited documentation for all major guidance areas. Move installation instructions to README.md where they belong, keeping SYSTEM.md focused on operational guidance. + +### References +- Official Clojure API: https://clojure.github.io/clojure/clojure.test-api.html +- ClojureDocs: https://clojuredocs.org/clojure.test +- The Clojure Style Guide: https://guide.clojure.style/ +- clojure-mcp-light: https://github.com/bhauman/clojure-mcp-light + ## [v1.5.0] - 2025-02-09 ### Added diff --git a/SYSTEM.md b/SYSTEM.md index 8f73482..ae06ae0 100644 --- a/SYSTEM.md +++ b/SYSTEM.md @@ -996,7 +996,7 @@ clojure-skills skill show "skill-name" -v1.5.0 +v1.6.0 Write tested, idiomatic Clojure through REPL-driven development. diff --git a/readme.md b/readme.md index d169614..f501947 100644 --- a/readme.md +++ b/readme.md @@ -233,7 +233,7 @@ echo '(defn hello [x] (+ x 1)' | clj-paren-repair ## Version -Current version: v1.5.0 (see CHANGELOG.md for details) +Current version: v1.6.0 (see CHANGELOG.md for details) ## License diff --git a/test/csp/validator/system_test.clj b/test/csp/validator/system_test.clj index 08dda9c..b996df8 100644 --- a/test/csp/validator/system_test.clj +++ b/test/csp/validator/system_test.clj @@ -7,7 +7,7 @@ (let [result (system/validate-system "SYSTEM.md")] (is (:valid? result)) (is (empty? (:errors result))) - (is (= "v1.5.0" (:version result))) + (is (= "v1.6.0" (:version result))) (is (contains? (:tags result) :system-prompt)) (is (contains? (:tags result) :identity)) (is (contains? (:tags result) :summary))