#_ as a semantic block-closing marker for LLM-friendly Clojure

As I use LLMs more in my daily Clojure work, I keep running into the same issue - models often miscount closing parens and produce broken code. And I find long ))))) chains confusing myself too.

For humans there are great tools - paredit (structure editing), rainbow brackets, block highlighting in IDE - that mostly solve this. But for LLMs none of that applies.

I know there’s an existing practice of leaving comments after closing parens:

(defn process-user [user]
  (when (:active? user)
    (update user :name str/upper-case))) ;; when ;; defn

This does help LLMs track context, but it breaks paredit (it doesn’t move comments with parens), and the marker ends up after the closing paren - when the model has already closed the form and moved on.


I’ve been thinking about using #_ instead:

(defn process-users [users]
  (filter
    (fn [user]
      (and (:active? user)
           (> (:age user) 18) #_and) #_fn)
    users #_filter) #_defn)

#_ discards the next form at the reader level, this is valid Clojure - no preprocessor, no changes to the compiler. The marker sits inside the form before the closing paren, so the structure of the code is preserved.


The pattern is specific enough that tooling could do interesting things with it:

  • paredit could treat #_token) as a unit and move them together

  • rainbow-delimiters could color #_token the same as its opening paren - no name matching needed, just depth counter at that position

  • IDEs could hide or de-emphasize these markers if you want cleaner visuals


Obviously this adds verbosity, but it’s purely opt-in - useful in deeply nested code, skip it elsewhere.

Has anyone tried something like this?

1 Like

You write that you are using an LLM, but if you are using the LLM through an agent tool like claude code or others you could register a post tool hook that corrects parenthesis in the changed code based on the indentation. Because LLMs are quite good at keeping the indentation correct. brepl contains such a hook implementation for claude-code and eca.

1 Like

Which model are you using? I’m using Opus 4.6 (and 4.5 beforehand) with Claude Code (no additional tooling) and it almost never struggles with the parentheses and if it does, it is able to fix it on its own.

2 Likes

Maybe you know about Bruce Hauman’s Clojure MCP Light, which despite its name is a way to help LLMs untangle delimiter problems?

Myself, whenever I’ve had delimiter issues I’ve simply asked the agent to refactor the function into smaller composable functions and that’s solved the problem. I personally favor really short functions especially for LLMs. Strong opinion lightly held…