{"slug": "evaluate-clojure-code-in-the-running-app-written-by-claude", "title": "Evaluate Clojure code in the running app (written by Claude)", "summary": "A developer has created eval-app, a tool that connects to a running Clojure application's nREPL to evaluate code for inspecting app state, querying databases, or debugging issues. The tool accepts Clojure code via stdin and returns pretty-printed results, with configurable host, port, and timeout options.", "body_md": "| #!/usr/bin/env bb | |\n| ;; ============================================================================= | |\n| ;; eval-app - Evaluate Clojure code in the running app | |\n| ;; ============================================================================= | |\n| ;; | |\n| ;; This tool connects to the nREPL of the app running evaluates Clojure code. | |\n| ;; Useful for inspecting app state, querying the database, or debugging issues | |\n| ;; in the running system. | |\n| ;; | |\n| ;; USAGE: | |\n| ;; cat <<'EOF' | agent-tools/eval-app | |\n| ;; (your-code-here) | |\n| ;; EOF | |\n| ;; | |\n| ;; cat code.clj | agent-tools/eval-app | |\n| ;; | |\n| ;; OPTIONS: | |\n| ;; --host HOST nREPL host (default: localhost) | |\n| ;; --port PORT nREPL port (default: 4000) | |\n| ;; --timeout MS Timeout in milliseconds (default: 30000) | |\n| ;; --help, -h Show help | |\n| ;; | |\n| ;; EXAMPLES: | |\n| ;; | |\n| ;; # Get the current database value | |\n| ;; cat <<'EOF' | agent-tools/eval-app | |\n| ;; (dev/db) | |\n| ;; EOF | |\n| ;; | |\n| ;; # Query an entity | |\n| ;; cat <<'EOF' | agent-tools/eval-app | |\n| ;; (dev/show-entity 12345) | |\n| ;; EOF | |\n| ;; | |\n| ;; # Check system state | |\n| ;; cat <<'EOF' | agent-tools/eval-app | |\n| ;; (keys @app.system/state) | |\n| ;; EOF | |\n| ;; | |\n| ;; # Multi-line code | |\n| ;; cat <<'EOF' | agent-tools/eval-app | |\n| ;; (d/q '[:find ?e :where [?e :user/email]] (dev/db)) | |\n| ;; EOF | |\n| ;; | |\n| ;; OUTPUT: | |\n| ;; Returns the result of evaluating the Clojure code, pretty-printed. | |\n| ;; Errors are printed to stderr. | |\n| ;; | |\n| ;; ============================================================================= | |\n| (require '[babashka.cli :as cli] | |\n| '[clojure.string :as str] | |\n| '[bencode.core :as bencode]) | |\n| (import '[java.net Socket] | |\n| '[java.io PushbackInputStream]) | |\n| (def cli-spec | |\n| {:host {:desc \"nREPL host\" | |\n| :default \"localhost\"} | |\n| :port {:desc \"nREPL port\" | |\n| :default 4000 | |\n| :coerce :int} | |\n| :timeout {:desc \"Timeout in milliseconds\" | |\n| :default 30000 | |\n| :coerce :int} | |\n| :help {:desc \"Show help\" | |\n| :alias :h}}) | |\n| (defn print-help [] | |\n| (println \"eval-app - Evaluate Clojure code in the running app\") | |\n| (println) | |\n| (println \"Usage: cat <<'EOF' | agent-tools/eval-app [OPTIONS]\") | |\n| (println \" (your-code-here)\") | |\n| (println \" EOF\") | |\n| (println) | |\n| (println \" cat code.clj | agent-tools/eval-app [OPTIONS]\") | |\n| (println) | |\n| (println \"Options:\") | |\n| (println \" --host HOST nREPL host (default: localhost)\") | |\n| (println \" --port PORT nREPL port (default: 4000)\") | |\n| (println \" --timeout MS Timeout in milliseconds (default: 30000)\") | |\n| (println \" --help, -h Show this help\") | |\n| (println) | |\n| (println \"Examples:\") | |\n| (println \" cat <<'EOF' | agent-tools/eval-app\") | |\n| (println \" (dev/db)\") | |\n| (println \" EOF\")) | |\n| (defn bytes->str [x] | |\n| (if (bytes? x) | |\n| (String. ^bytes x \"UTF-8\") | |\n| x)) | |\n| (defn parse-response [response] | |\n| (into {} | |\n| (map (fn [[k v]] | |\n| [(keyword (bytes->str k)) | |\n| (if (sequential? v) | |\n| (mapv bytes->str v) | |\n| (bytes->str v))]) | |\n| response))) | |\n| (defn nrepl-eval [{:keys [host port timeout]} code] | |\n| (let [socket (Socket. ^String host ^int port) | |\n| _ (.setSoTimeout socket timeout) | |\n| out (.getOutputStream socket) | |\n| in (PushbackInputStream. (.getInputStream socket)) | |\n| session-id (str (random-uuid)) | |\n| msg {\"op\" \"eval\" | |\n| \"code\" code | |\n| \"id\" session-id}] | |\n| (try | |\n| (bencode/write-bencode out msg) | |\n| (loop [has-error false] | |\n| (let [response (parse-response (bencode/read-bencode in))] | |\n| (when-let [out-str (:out response)] | |\n| (print out-str) | |\n| (flush)) | |\n| (when-let [err-str (:err response)] | |\n| (binding [*out* *err*] | |\n| (print err-str) | |\n| (flush))) | |\n| (when-let [value (:value response)] | |\n| (println value)) | |\n| (when-let [ex (:ex response)] | |\n| (binding [*out* *err*] | |\n| (println \"Exception:\" ex))) | |\n| (let [status (set (:status response)) | |\n| has-error (or has-error | |\n| (contains? status \"error\") | |\n| (contains? status \"eval-error\"))] | |\n| (if (contains? status \"done\") | |\n| (if has-error 1 0) | |\n| (recur has-error))))) | |\n| (finally | |\n| (.close socket))))) | |\n| (defn eval-code [opts code] | |\n| (try | |\n| (nrepl-eval opts code) | |\n| (catch java.net.ConnectException e | |\n| (binding [*out* *err*] | |\n| (println \"Error: Cannot connect to nREPL at\" (str (:host opts) \":\" (:port opts))) | |\n| (println \"Make sure the app is running (bin/dev up)\")) | |\n| 1) | |\n| (catch java.net.SocketTimeoutException e | |\n| (binding [*out* *err*] | |\n| (println \"Error: nREPL request timed out\")) | |\n| 1) | |\n| (catch Exception e | |\n| (binding [*out* *err*] | |\n| (println \"Error:\" (.getMessage e))) | |\n| 1))) | |\n| (let [{:keys [opts]} (cli/parse-args *command-line-args* {:spec cli-spec}) | |\n| opts-with-defaults (merge {:host \"localhost\" :port 4000 :timeout 30000} opts)] | |\n| (if (:help opts) | |\n| (print-help) | |\n| (let [code (slurp *in*)] | |\n| (if (str/blank? code) | |\n| (do (binding [*out* *err*] | |\n| (println \"Error: No code provided on stdin\") | |\n| (println \"Usage: cat <<'EOF' | agent-tools/eval-app\") | |\n| (println \" (dev/db)\") | |\n| (println \" EOF\") | |\n| (println \"Run with --help for more information\")) | |\n| (System/exit 1)) | |\n| (System/exit (eval-code opts-with-defaults code)))))) |", "url": "https://wpnews.pro/news/evaluate-clojure-code-in-the-running-app-written-by-claude", "canonical_source": "https://gist.github.com/maxweber/4b03dff8b3ab3fed7f42891e60faada6", "published_at": "2026-05-27 12:41:05+00:00", "updated_at": "2026-05-28 13:55:31.748546+00:00", "lang": "en", "topics": ["ai-tools"], "entities": ["Clojure", "nREPL"], "alternates": {"html": "https://wpnews.pro/news/evaluate-clojure-code-in-the-running-app-written-by-claude", "markdown": "https://wpnews.pro/news/evaluate-clojure-code-in-the-running-app-written-by-claude.md", "text": "https://wpnews.pro/news/evaluate-clojure-code-in-the-running-app-written-by-claude.txt", "jsonld": "https://wpnews.pro/news/evaluate-clojure-code-in-the-running-app-written-by-claude.jsonld"}}