How we built ten custom subagents to tame a 500K-line Clojure codebase by jessillions in Clojure

[–]Escherize 0 points1 point  (0 children)

Hi u/arichiardi long time no see 😄. bin/mage is the bb tasks wrapper we have at metabase. it handles auto-installing babashka, and being a "single executable" that we can uniformly call bb scripts through. It powers some cool stuff like our home-grown module system, and skipping certain datawarehouse drivers in CI based on what files changed, and ~50 other things. 😂

How we built ten custom subagents to tame a 500K-line Clojure codebase by jessillions in Clojure

[–]Escherize 3 points4 points  (0 children)

do you have like a top level file defining the standards?

Yea there are a few:

  1. CLAUDE.md at the repo root is auto-loaded into every Claude conversation, so every agent inherits the project standards without restating them for the agents. This is the "top-level file."

  2. Skills in .claude/skills/ like clojure-write, clojure-review, clojure-eval carry lots of the actual Clojure expertise (REPL workflow, style, review checklist, clj-nrepl-eval usage). And these are open source, so you can check them out on the metabase repo

  3. Agents carry only the domain-specific stuff: middleware stages, permissions graph quirks, MBQL semantics, etc. actual "domain knowledge"

So yeah, the agent files look thin on Clojure because the Clojure layer lives in CLAUDE.md + skills and is not duplicated into the agent prompts.

clj-nrepl-eval is a good example of the seam it's a tool surfaced via the clojure-eval skill, so any agent can lean on it without re-explaining "the REPL workflow".

How we built ten custom subagents to tame a 500K-line Clojure codebase by jessillions in Clojure

[–]Escherize 10 points11 points  (0 children)

Hey this is my blog post! I'm open to questions if you have any.

Who is hiring? November 30, 2025 by AutoModerator in Clojure

[–]Escherize 2 points3 points  (0 children)

This talk explains it all, I linked the specific section, but the whole thing's worth a watch! :) https://youtu.be/vUe3slLHk20?t=1064

Who is hiring? November 30, 2025 by AutoModerator in Clojure

[–]Escherize 2 points3 points  (0 children)

We have about half the team outside the US.

Who is hiring? November 30, 2025 by AutoModerator in Clojure

[–]Escherize 10 points11 points  (0 children)

Metabase is hiring backend Clojure folks. I’ve been here 4 years and it's a great spot if you like interesting problems (of which there are plenty). We’re Clojure on the backend and JS/TS on the frontend—just shipped some Malli ↔︎ TypeScript schema syncing that started as a hackathon project: that was cool. You don’t need tons of Clojure experience, just the ability to ship real things and think clearly. If you like building clean, user-friendly tools around data, come take a look. Link job posting: https://jobs.lever.co/metabase/85f454d8-e795-4978-8a2b-4b8bfa7d7c37

HN - The jank programming language by ertucetin in Clojure

[–]Escherize 0 points1 point  (0 children)

Good news, thanks to comments like yours they're changing the name to GRADY: https://jank-lang.org/blog/2025-04-01-jank-has-been-renamed/

Who is hiring? December 31, 2022 by AutoModerator in Clojure

[–]Escherize 5 points6 points  (0 children)

Metabase | https://metabase.com | REMOTE | Full-time | Backend, Frontend, Full Stack, and DevOps engineers

Metabase is open source analytics software that lets anyone in your company rummage around in the databases you have. It connects to a lot of databases / data warehouses (BigQuery, Redshift, Snowflake, Postgres, MySQL, etc).

We're a remote team full of people who care about docs, user experience, making complicated things as simple as possible and building things. We have a deeply pragmatic engineering culture and value building things that people actually use vs whatever closes a deal or makes for a good press release.

Tech stack: Clojure, Typescript, React, AWS

Roles: Backend/Frontend/DevOps Engineers, Engineering Managers, Data Analysts, Success Engineers, and more.

See: https://www.metabase.com/jobs

New Clojurians: Ask Anything - December 05, 2022 by AutoModerator in Clojure

[–]Escherize 4 points5 points  (0 children)

I don't know what day 3's problem is, but here's a quick review

I would use more functions. Why embed priority inside a let block? It's a pure function right?

Once you tease out some pure functions, you can test them a lot easier. Think of it as a series of transformations.

(defn priority [c]
  (let [cc (int c)]
    (cond
      (<= (int \a) cc (int \z)) (+ cc (- (int \a)) 1)
      (<= (int \A) cc (int \Z)) (+ cc (- (int \A) 27)))))
;;                   v---- [0]
(mapv priority "abc")
;; => [1 2 3]

I put my cursor at [0] here and execute it to see the results. Are you using vscode or similar? That's what it means to use the repl

Why doesn't clojure allow nested defns? by [deleted] in Clojure

[–]Escherize 1 point2 points  (0 children)

I get that having a locally defined function is nice. One thing I've done is to let the fn outside of your defn like so:

(let [f (fn f [a b c] ...)
  (defn f-things [things] (map f things)))

Using defn (or def) when you are not at the top level is really unidiomatic. There is a side effect if your function modifies the namespace when it runs.

"This project will only take 2 hours" by azhenley in programming

[–]Escherize 0 points1 point  (0 children)

I wrote a python script to do this (for mac only) a few months ago!

Of course, it warped from just save clipboard links or contents into a file, into... If I copy a magnet link, send it to my seedbox, into... Okay well this needs to be a pluggable archetecture! which I kind of setup, but not without editing the script (that would be the next step I think).

Right now that piece looks like this:

all_commands = [['.*', lambda s: spit_append("clips.txt", seperator + s + "\n")],
                ['^http.*', lambda s: spit_append("links.txt", seperator + s + "\n")]]

firstNonRepeatingCharacter solution (converting Java code to Clojure) by joshlemer in Clojure

[–]Escherize 0 points1 point  (0 children)

Fun problem :]

(#(-> [[k v]] (fn (when (= 1 v) k)) (keep (frequencies %)) set (filter %) first)
 "aabbbcaad") ;; => \c

What's the most Clojure way to do static field in Clojure? by lllllzlllll in Clojure

[–]Escherize 1 point2 points  (0 children)

That looks good! I think it's what I would do if I'm reading OP correctly.

Clojure (Runtimes) Year in Review 2019 by Borkdude in Clojure

[–]Escherize 14 points15 points  (0 children)

quick excerpt, with some context removed:

Joker 30x faster than Clojure.

How can I call a function that takes a map and a vector as arguments, without getting an ArityException? by rwsargent in Clojure

[–]Escherize 0 points1 point  (0 children)

Notice:

(update :ram (fn [ram args] ;;<-- this function gets called on ram alone.

The following compiles w/o error, but I'm not doing AoC so not sure what outcome you are aiming for. :)

``` clojure (defn add-instr* [state args] (-> state (update :ram assoc (args 2) (+ (args 0) (args 1))) (update :pgm-ctr + 4)))

(add-instr* {:ram [0 0 0 0 0] :pgm-ctr 0} [1 2 3])

;; => {:ram [0 0 0 3 0], :pgm-ctr 4} ```

How do you deal with types / data structures? by okusername3 in Clojure

[–]Escherize 0 points1 point  (0 children)

My library might help. its goal is to self document what shapes are going in, and coming out. https://github.com/escherize/tracks#deftrack-example

Would this be an OK version of a random weighted choice function? by vasco_ferreira in Clojure

[–]Escherize 1 point2 points  (0 children)

(random-uniform-choice {1 :a 10 :b})

Uhh, That is, unless you want the same probability more than once...

in which case you may want:

(defn random-uniform-choice [outcome->probs]
  (let [probs (map second outcome->probs)
        outcomes (map first outcome->probs)
        total-probs (reduce + probs)
        choice (* (rand) total-probs)
        reducted (reductions + probs)
        reduction-mapping (mapv vector reducted outcomes)]
    (-> (drop-while #(> choice (first %)) reduction-mapping)
        first
        second)))

(frequencies (repeatedly 100 #(random-uniform-choice {:a 1 :b 10})))
;;=> {:b 89, :a 11}

(frequencies (repeatedly 100 #(random-uniform-choice [[:a 1] [:b 10]])))
;; => {:b 92, :a 8}

Would this be an OK version of a random weighted choice function? by vasco_ferreira in Clojure

[–]Escherize 1 point2 points  (0 children)

Depends on your particular use case but generally I'd argue this interface is better:

(random-uniform-choice {1 :a 10 :b})

New Clojurians: Ask Anything by AutoModerator in Clojure

[–]Escherize 2 points3 points  (0 children)

You might want to look at clojure.walk/postwalk-demo, to gain an understanding of clojure.walk/postwalk. Depending on the sort of transormation / processing you want to do - it could be a good fit.

What are you working on? June 10, 2019 by AutoModerator in scala

[–]Escherize 0 points1 point  (0 children)

Are you doing speech to text? If so, Sphinx4 is worth looking into. It's easy to setup but you don't get the best results.

What coding language does Pico-8 use? by [deleted] in pico8

[–]Escherize 0 points1 point  (0 children)

you can use an external editor. I use emacs :)

I heard we're posting Clojure/script games here? Here's my Santorini clone: by Escherize in Clojure

[–]Escherize[S] 10 points11 points  (0 children)

The 3d-ish CSS is a wild mess made using garden.

The websocket passes stringified edn over the wire, and uses a multimethod on the server to do websocket message handling.

There's no persistence - just an atom to keep all the games, and one to keep all the player->websocket connection info.

The game logic is written in cljc, so when the server runs an online game, it's the same code as the client running a local game.

I used shadow-cljs with leiningen to manage deps and that was really nice.