clojure

maxweber 2026-02-02T12:04:59.557219Z

Hi πŸ™‚ Is there anyway to use clojure.core/evalwithout leaking memory (due to the Class metadata ending up in the Metaspace leading to a java.lang.OutOfMemoryError: Metaspace at some point)? At the moment I'm using https://github.com/babashka/sci for that reason, but the generated Clojure Code is trusted (our code generates it) so using SCI feels like an unnecessary step for my use case.

maxweber 2026-02-13T13:19:51.254929Z

Yes

maxweber 2026-02-11T10:14:59.433099Z

Hi Steven, I never tried using clojure.core/eval in production, since a conversation with Claude Code informed me that this problem exists.

Steven Lombardi 2026-02-11T16:22:55.500549Z

Okay so you've never actually hit the issue yourself or witnessed/reproduced it?

Steven Lombardi 2026-02-11T04:17:56.877089Z

Hi Max. I'm curious, before you switched to babashka, how long was your JVM running and handling eval jobs before this error happens?

exitsandman 2026-02-02T12:12:31.979229Z

I'm really curious as to how do you even end up using eval enough for this to be a problem. Leaving that aside, to my understanding eval always compiles a fn and loads it via its classloader, but potentially (IDK) it may get GC'd.

maxweber 2026-02-02T12:42:11.133449Z

Over the years I noticed that you can make some complex processes simpler by generating a little piece of code that performs it. Thereby you turn a bunch of side-effects into a read (returns the generated code). Our video rendering process for example needs to: β€’ take a screenshot with transparent background of each layer. β€’ Then it invokes https://www.mltframework.org/ to generate the video. β€’ Then ffmpeg to extract a preview picture. β€’ It uploads the video to Google Cloud Storage β€’ And does a Datomic transaction so that the video shows up in our UI In the old version, it would probably take a couple of hours to extract and understand this workflow out of our large code base. The new solution generates the script and it is pretty straight-forward to read, even if you see it for the first time.

borkdude 2026-02-02T12:49:22.414939Z

I don't expect SCi to add much overhead in this scenario. The function calls that call external processes dominate the time that interpretation time adds. It’s nice to be able to ditch a dependency or course. You could build your own interpreter to bypass eval.

maxweber 2026-02-02T13:00:01.575809Z

@borkdude thanks a lot for creating SCI and babashka, they are awesome 🀩 I'm fine with keeping the dependency. And as you mentioned stuff like ffmpeg make the compiled vs. interpreted detail completely irrelevant. However, if the (trusted) scripts have access to "dangerous" things anyway, is there a yolo mode? πŸ˜„ Meaning something in SCI to just whitelist everything?

borkdude 2026-02-02T13:41:22.733829Z

Hmm, not currently.

borkdude 2026-02-02T18:59:08.935789Z

Are you aware of sci/copy-ns?

maxweber 2026-02-02T19:09:27.485939Z

No, I just have looked at sci/copy-ns source code the first time. I'm not entirely sure how to use it? Currently, I'm doing:

(defn eval!
  [form]
  (let [ctx (sci/init
              {:namespaces
               (into {}
                     (map (fn [ns]
                            [ns (ns-publics ns)]))
                     ['clojure.core
                      'clojure.string
                      '
                      'babashka.process
                      'app.effect
                      'app.blob.store
                      'storrito.effect])
               :classes {'java.lang.Throwable Throwable
                         'java.io.File java.io.File}})]
    (sci/eval-form ctx
                   form)))

borkdude 2026-02-02T19:10:40.603559Z

copy-ns is a bit like this but more advanced, it also copied macros properly

maxweber 2026-02-02T19:11:07.005759Z

Ah okay, cool

borkdude 2026-02-02T19:11:19.988699Z

clojure.core and clojure.sring should probably not be necessary since they come with SCI

πŸ‘ 1
borkdude 2026-02-02T19:16:32.656089Z

unless you're missing some core functions

borkdude 2026-02-02T19:16:37.498619Z

that are new

borkdude 2026-02-02T19:16:52.758519Z

anyway, if this works, it seems like a minimal amount of work to maintain :)

maxweber 2026-02-02T19:20:10.814029Z

Yeah, totally fine πŸ™‚ I just thought about using clojure.core/eval since is yet another detail you have to explain your colleagues or the agent. Claude Code for example today just used clojure.core/eval since it wasn't aware of my SCI helper namespace, but I will add it to the claude.md

maxweber 2026-02-02T19:20:49.363219Z

For other use cases: how secure is it to rely on SCI as a sandbox? Looking at things like meltdown and spectre. Could they be mitigated by not providing a way to receive an exact timestamp. Should it be wrapped into something like gvisor or a microvm?

borkdude 2026-02-02T19:26:47.311399Z

SCI sandboxing should be safe in the sense that it doesn't let you execute code you don't give it access to. But there is one main caveat: it doesn't give you any control over how long your code is running

borkdude 2026-02-02T19:28:58.387129Z

SCI runs directly in your host and doesn't do anything special with regards to system resources, it doesn't limit RAM or the time it's running

maxweber 2026-02-02T19:44:39.677019Z

Okay, so an endless loop, adding objects to an array to fill the heap would be a problem. Sorry, for hijacking this thread for further questions πŸ˜… As the creator of all these great projects like Squint, Cherry, SCI, babashka, nbb, ... what would you use as a sandbox to execute Clojure code that has been generated by an AI agent in response to a user prompt? I'm considering to rely on something like https://e2b.dev/ but having something more lightweight would of course be preferable. Especially if the Clojure Code for example only assembles a few Hiccup pages or so.

borkdude 2026-02-02T19:45:47.119079Z

Currently I'm just reviewing the code and confirming it by hand

borkdude 2026-02-02T19:46:25.556239Z

claude also has a --sandbox flag which will use macOS's sandboxing feature

maxweber 2026-02-02T19:50:47.546899Z

Yeah, I allow Claude Code to even eval code via nrepl without asking anymore πŸ˜… But if you build an AI feature into your web app, then any user could prompt the AI to write malicious code.

borkdude 2026-02-02T19:50:51.652149Z

or you could use a webbrowser as a sandbox if it's just pure clojure functions

borkdude 2026-02-02T19:51:24.793579Z

yeah, that sounds like something you want to run in a container

maxweber 2026-02-02T19:52:26.523119Z

Yes, but the container would also only be kind of safe with something like https://gvisor.dev/

maxweber 2026-02-02T19:53:25.044499Z

But I also already thought about using a web browser as sandbox, like a headless chrome on the server. Probably, one of the most secure sandboxes that are available for free.

maxweber 2026-02-02T19:56:52.677759Z

However, I would love to see AI generate more Clojure code instead of JS clojure-spin I think it would even be beneficial for our customers, since Clojure is faster to learn than JS, if someone like to go down this rabbit hole.