Move all development tools from tools/ to scripts/ for consistency. Rename lint/fmt/check-fmt to lint-clj/fmt-clj/check-fmt-clj to clarify they target Clojure specifically. Remove unused scripts (attach-opencode, start-opencode, start-opencode-server) and the backport-commit skill. Update all internal references across .serena/, AGENTS.md, and CONTRIBUTING.md to point to the new script locations. Simplify CONTRIBUTING.md by delegating module-specific fmt/lint instructions to the respective serena memories. AI-assisted-by: deepseek-v4-flash
4.1 KiB
nREPL Eval
Evaluate Clojure (or ClojureScript) code via a running nREPL server using
scripts/nrepl-eval.mjs — a standalone CLI application.
Session state (defs, in-ns, etc.) persists across invocations via a stored session ID, so you can build up state incrementally.
Usage
node scripts/nrepl-eval.mjs [options] [<code>]
# or
./scripts/nrepl-eval.mjs [options] [<code>]
Options
| Flag | Description | Default |
|---|---|---|
--backend |
Connect to backend nREPL (port 6064) | — |
--frontend |
Connect to frontend nREPL (port 3447) | — |
-p, --port PORT |
nREPL server port | 6064 |
-H, --host HOST |
nREPL server host | 127.0.0.1 |
-t, --timeout MS |
Timeout in milliseconds | 120000 |
--reset-session |
Discard stored session and start fresh | — |
-e, --last-error |
Evaluate *e to retrieve the last exception |
— |
-h, --help |
Show help message | — |
--backendand--frontendare mutually exclusive.- Explicit
--portis overridden when--backend/--frontendis used.
When to Use
- Evaluate Clojure code during development — test functions, inspect state, or run experiments against a running Clojure process.
- Verify that edited files compile — require namespaces with
:reloadto pick up changes. - Inspect the last exception after a failed evaluation — use
-eto print the error stored in*e.
Workflow
Session management
Sessions are persisted to /tmp/penpot-nrepl-session-<host>-<port>. State
carries across calls automatically:
./scripts/nrepl-eval.mjs '(def x 42)'
./scripts/nrepl-eval.mjs 'x'
# => 42
Reset the session to start fresh:
./scripts/nrepl-eval.mjs --reset-session '(def x 0)'
Evaluate code
Single expression (inline) — uses default port 6064:
./scripts/nrepl-eval.mjs '(+ 1 2 3)'
Backend nREPL (explicit):
./scripts/nrepl-eval.mjs --backend '(+ 1 2 3)'
Frontend nREPL:
./scripts/nrepl-eval.mjs --frontend '(js/alert "hi")'
Multiple expressions via heredoc (recommended — avoids escaping issues):
./scripts/nrepl-eval.mjs <<'EOF'
(def x 10)
(+ x 20)
EOF
Override with a different port:
./scripts/nrepl-eval.mjs -p 7888 '(+ 1 2 3)'
Inspect last exception
After code throws an error, retrieve the full exception details:
./scripts/nrepl-eval.mjs -e
Common Patterns
Require a namespace with reload:
./scripts/nrepl-eval.mjs "(require '[my.namespace :as ns] :reload)"
Test a function:
./scripts/nrepl-eval.mjs "(ns/my-function arg1 arg2)"
Long-running operation with custom timeout:
./scripts/nrepl-eval.mjs -t 300000 "(long-running-fn)"
Accessing Private Functions
Private functions (declared with ^:private or defn-) cannot be called
directly from outside their namespace. Use the var quote syntax #' to
access the underlying var:
This fails:
./scripts/nrepl-eval.mjs "(app.rpc.commands.error-reports/build-list-query {})"
# => Syntax error: app.rpc.commands.error-reports/build-list-query is not public
This works:
./scripts/nrepl-eval.mjs "(#'app.rpc.commands.error-reports/build-list-query {})"
# => Returns the result
The #' reader macro resolves to (var ...), giving you direct access to
the var regardless of its visibility modifier. The syntax is #' followed
by the fully qualified symbol.
Key Principles
- Default port is 6064 — just pass code directly, no
-pneeded when your nREPL server is on 6064. Use--backend(6064) or--frontend(3447) as quick aliases. Use-p <PORT>for any other port. - Always use
:reloadwhen requiring namespaces to pick up file changes. - Session is reused across invocations — defs, in-ns, and var bindings
persist. Use
--reset-sessionto clear. - Do not start any server — the tool connects to an existing nREPL server, it is not the agent's responsibility to start the nREPL server (assume the server is already running on the specified port).