clojure 2026-05-06

when starting a repl or running a script or calling -main or any other entrypoint into clojure, they all call clojure.main/initialize which starts the session with (in-ns 'user) so that any requires or loading happens in that context (meaning that all of clojure.core and default imports exist). i'm interested in setting up an alternative to clojure.core . is there a means of sidestepping this or ensuring that a specific library is the source of a custom ns macro or something?

this feels a bit dirty but what about just ns-unmaping stuff right after the entry point and requireing your own?

yeah i was thinking of doing something like ((requiring-resolve 'noah.custom-ns) ...) but that felt messy

if i could guarantee a single entrypoint, then having one place that does the replace/swap would be fine, but folks like to load code at the repl from any namespace, and they all assume user as the initial location

clojure.main and the socket servers all provide the :init option for this. Totally configurable.

I have a custom repl that grabs all locals and throws them intoa temp namespace and puts me into the current ns i think:

(defmacro nocommit-repl []
  `(clojure.main/repl
    :init   (fn []
              (remove-ns '~'temp)
              (create-ns '~'temp)
              (doseq [[binding# value#] (the-env)]
                (intern '~'temp (symbol binding#) value#)))
    :prompt (fn [] (printf "paused.%s=> " (peek (clojure.string/split (str *ns*) #"\."))))
    :eval (fn [f#] (binding [clojure.test/*test-out* *out*] (eval f#)))
    :read clojure.core.server/repl-read
    :print clojure.pprint/pprint))

some-namespace=> (require 'llm-repl.human-repl)
nil
some-namespace=> (let [x 1 y {:some :stuff}](llm-repl.human-repl/nocommit-repl))
paused.some-namespace=> temp/x
1
paused.some-namespace=> temp/y
{:some :stuff}
paused.some-namespace=> (ns-name *ns*)
some-namespace

i'll have to think about this, but that's very intruiging

i also have a keycommand to send the repl requires so it’s less important for me that they are loaded automatically

(defun personal/repl-requires ()
  "Send repl requires."
  (interactive)
  (when-let ((inf-proc (inf-clojure-proc 'no-error)))
    (inf-clojure--send-string inf-proc "(apply require clojure.main/repl-requires)")))
i hit c-c h and it makes sure i have doc, apropos and friends

yeah that's really cool

ah. and you exit the subrepl with:

paused.some-namespace=> (ns-name *ns*)
some-namespace
paused.some-namespace=> :repl/quit
nil

note these subrepls don’t play nice with nrepl

but perhaps hooking up transports with nrepl can make it work? they definitely use one instance of clojure.main. maybe with the right inputs/outputs hooked up it can work. i’m not sure

yeah my goal isn't a subrepl so much as a way to say "do not refer clojure.core, refer my thing" and then the namespace would be in a strange alternate world

but having a repl that sets the :init to require and set my own custom initial namespace would do that for me

ah. that would have a lot of work to do. but sounds interesting:

(macroexpand '(ns foo))
(do
 (clojure.core/in-ns (quote foo))
 (clojure.core/with-loading-context
  (clojure.core/refer (quote clojure.core)))
 (if
  (.equals (quote foo) (quote clojure.core))
  nil
  (do
   (clojure.core/dosync
    (clojure.core/commute
     (clojure.core/deref (var clojure.core/*loaded-libs*))
     clojure.core/conj
     (quote foo)))
   nil)))
it’s not a ton of stuff mechanically, just a lot of stuff breaks without clojure.core around. sounds like a very interesting project

"why do you want this, noah?" because i love to be naughty, that's why

oh i don’t question it. i love to see it 🙂

❤️ 1

right, ns is a cool namespace and referring clojure.core by default is really good, but i kind of wanted to see what would happen if i started from "scratch"

my own version of racket's #lang system