announcements

Ovi Stoica 2026-02-15T14:59:40.076569Z

Introducing leinpad πŸš€ The Problem: Your team uses Leiningen, but onboarding new devs is painful. Everyone has a different REPL setup, dev dependencies are inconsistent, and getting the local environment running is a multi-step manual process. You wish you could use https://github.com/lambdaisland/launchpad but it doesn't support Leiningen projects The Solution: leinpad brings the launchpad experience to Leiningen projects. One command to: β€’ Start your services (databases, queues, etc.) β€’ Configure nREPL middleware (CIDER, refactor-nrepl) β€’ Inject dev dependencies (no more "works on my machine") β€’ Connect your editor automatically β€’ Call your system's go function No more wiki pages explaining how to start the dev environment. Just bb leinpad and you're coding. Leinpad was dogfooded in my workplace before made public. Built with Babashka for fast startup. Inspired by @plexus's excellent launchpad. Try it: https://github.com/shipclojure/leinpad Feedback welcome! πŸ™

❀️ 4
πŸš€ 3
πŸŽ‰ 17
amiorin 2026-02-16T08:13:02.267699Z

My development is JVM-centric. I use Babashka to run BigConfig from the shell. The bb.edn is always {:deps {org/name {:local/root "."}}}. While starting the REPL wasn't originally in BigConfig’s scope, I see your point. I would proceed as follows: In an existing Clojure project looking to embrace these ideas, I would use neil to add the BigConfig dependency and then jack-in to the REPL. Within that session, I’d create a BigConfig workflow to launch the REPL using a specialized library, one that provides functionality similar to leinpad or launchpad (though this is yet to be developed). Finally, I would create a template bin/launchpad or a bb.edn task. In my projects, the bb.edn is committed, and invoking bb build generates all necessary files, including the bb.edn itself. If you want to remove Babashka from the bootstrap requirements and rely solely on Nix, you could use something like nix run nixpkgs#babashka -- scripts/build.bb to generate the bb.edn and the devenv environment. The workflow can look something like this:

(ns bigpad
  (:require
   [big-config :as bc]
   [big-config.core :refer [->workflow ok]]
   [big-config.system :refer [stop]]
   [big-config.step-fns :refer [log-step-fn]]))

(defn prepare [opts]
  (merge opts (ok) {::gst-module ["glib-2.0"
                                  "gobject-2.0"
                                  "gstreamer-1.0"
                                  "gstreamer-plugins-base-1.0"
                                  "gstreamer-plugins-good-1.0"
                                  "gstreamer-plugins-bad-1.0"]}))

(defn start-repl
  "to be implemented using a library `big-config.pad` that doesn't exist yet"
  [opts]
  (ok opts))

(def repl (->workflow {:first-step ::start
                       :wire-fn (fn [step _]
                                  (case step
                                    ::start [prepare ::start-repl]
                                    ::start-repl [start-repl ::end]
                                    ::end [stop]))}))

(repl [log-step-fn] {::bc/env :repl
                     ::async true})

teodorlu 2026-02-16T12:35:33.693239Z

@plexus / @ovidiu.stoica1094 I finally understand why it's bin/launchpad now! It never crossed my mind to use it to install things, or to use it's script-nature to set the Babashka version. Or to use it to ensure other tools were installed / are running. We currently have separate instructions for installing things, and a Babashka Tmux script to run processes. There's definitely tradeoffs with both approaches (explicit/implicit behavior, number of steps involved), but it was very helpful to understand your practice. Thanks!

πŸŽ‰ 1
plexus 2026-02-16T12:48:57.255969Z

Same for bin/kaocha btw, you can do extra setup in there, adjust it to work with lein/clojure-cli/boot/etc. So that, no matter the particulars of your project, someone can arrive cold and assume that bin/kaocha will run the tests

πŸ‘ 2
πŸ™ 1
plexus 2026-02-16T12:50:10.150959Z

I context switch so much between different projects, open source/client work/personal projects, that I care a lot about these well known entry points, see also https://gaiwan.co/wiki/WellKnownIdentifier.md

πŸ‘ 1
amiorin 2026-02-16T13:20:55.113279Z

I am facing the following challenge: I want to use borkdude/quickdoc on the BigConfig project to generate multiple MDX files for a separate project containing the http://bigconfig.it website. The markdown requires transformation because MDX uses a specific frontmatter format required by Astro. How would you automate this workflow so that whenever I save a docstring in the source code, the local Astro website automatically reloads with the updated content? The same applies to CI: commits to the source code should trigger a documentation refresh and a new commit in the http://bigconfig.it repo. How would you develop this CI logic inside a REPL? I want to avoid the typical 'operations hell' where you have to commit and push every tiny change just to see if the pipeline works.

plexus 2026-02-16T13:27:32.068249Z

This seems increasingly off-topic @alberto.miorin... seems like there's a #bigconfig channel, maybe ask there?

βž• 1
amiorin 2026-02-16T14:28:28.357349Z

I’ll try Launchpad and Leinpad as soon as I have the opportunity; therefore, my current analysis might be slightly off. My goal in my last message was to highlight why I believe the BigConfig solution works better for my needs. In this approach, every automation is in scope and can be addressed with a workflow; every side effect lives within a function (a 'step'), and everything is either a library or transformed into one (e.g., Terraform, Ansible, Integrant, deps-new, Selmer). Composing these 'bricks' enables you to solve any automation problem, including reproducible development environments, dotfiles, or cloud environments. Do I understand correctly that you think the quickdoc automation is outside the scope of Launchpad?

plexus 2026-02-16T14:31:17.917249Z

yes, launchpad is a dev env launcher, period. But if there's any shared setup you should be able to pull that into your launchpad setup.

plexus 2026-02-16T14:31:45.383649Z

it's not a build tool

amiorin 2026-02-16T14:38:02.466359Z

The dev env launcher is a cool idea. I like it a lot. I need some time to play around with it to get familiar.

plexus 2026-02-16T14:57:08.838249Z

https://gaiwan.co/wiki/DevEnvironmentLauncher.md

πŸ‘ 2
teodorlu 2026-02-15T16:45:55.338479Z

Awesome! Out of curiosity, why did you go for bin/leinpad in addition to bb leinpad?

Ovi Stoica 2026-02-15T17:22:06.848279Z

Just to respect the convention of launchpad and other lambdaisland utilities like kaocha

πŸ‘ 1
amiorin 2026-02-15T21:27:19.001869Z

My feedback. The comparison to lambdaisland/launchpad in the README is a huge help. It took me a while to "get" what Launchpad was doing initially, but seeing the parallel for Leiningen makes the intent much clearer. I fully agree with your problem definition. While I agree with the goal of automation, I’m not fully sold on a "Clojure-only" solution. In my experience, Nix, devenv, and direnv are the gold standard for creating truly reproducible environments. The key metric for me is: How many steps must I take before I can change code and evaluate it? Ideally, if Babashka is installed, a single command should set up everything:

bb build
From there, I "jack-in" from Emacs and only want to use cider-eval-defun-at-point and cider-inspect-last-result. I previously used Integrant to manage services like DynamoDB, Redis, and Postgres, but I have since https://bigconfig.it/blog/replacing-integrant-and-docker-compose-with-bigconfig-system/ that entire stack with Babashka and BigConfig. From a first-principles perspective, what is actually needed is a workflow and template engine. I believe it is a better design decision to offer a library rather than a CLI tool like bin/leinpad in the long run. My concern is that a CLI tool adds another layer of 'magic' that eventually needs to be unpicked when the project grows. By providing a library and a template engine, you empower the user to compose their own workflow. This aligns better with the Clojure philosophy of 'small pieces loosely joined' rather than a monolithic wrapper. Consequently, the Babashka tasks should be written by the user, not generated or hidden by the tool. I have compiled a comparison between the two approaches.

Ovi Stoica 2026-02-16T05:11:18.790569Z

> The key metric for me is: How many steps must I take before I can change code and evaluate it? Yes that's the general metric here. At work, for example we have 2 steps. 1. mise install 2. bb dev (leinpad) and you can eval code and get working. I am using launchpad for shipclojure, so I missed that instant setup experience at work, and that's why I made leinpad.

Ovi Stoica 2026-02-16T05:13:20.812699Z

Not sure how to address the cli vs library concern. It is still a library but you configure it and call it through the cli, Similar to kaocha, for example.

plexus 2026-02-16T07:12:48.856359Z

The point of launchpad insisting you make a bin/launchpad, is that that is general enough to adapt and extend for other needs. It can start out as a bb script, and evolve to a more general shell script that does other stuff and stull launches launchpad in the end. On a project I'm working on now we turned it into a nix-shell script so we can add system dependencies, while also ensuring everyone runs on the same bb version.

#!/usr/bin/env nix-shell
#! nix-shell -i bb -p babashka glib gst_all_1.gstreamer gst_all_1.gst-plugins-base gst_all_1.gst-plugins-good gst_all_1.gst-plugins-bad gst_all_1.gst-libav pkg-config
#! nix-shell -I nixpkgs=

(require
 '[lambdaisland.launchpad :as launchpad]
 '[clojure.java.shell :refer [sh]]
 '[clojure.string :as str])

(def gst-modules
  ["glib-2.0"
   "gobject-2.0"
   "gstreamer-1.0"
   "gstreamer-plugins-base-1.0"
   "gstreamer-plugins-good-1.0"
   "gstreamer-plugins-bad-1.0"])

(defn get-gst-info [var-name module]
  (-> (sh "pkg-config" (str "--variable=" var-name) module) :out str/trim))

(def plugin-paths (->> gst-modules (map #(get-gst-info "pluginsdir" %)) distinct (str/join ":")))
(def lib-paths    (->> gst-modules (map #(get-gst-info "libdir" %))     distinct (str/join ":")))

(launchpad/main
 {:java-args
  ["-Dawt.useSystemAAFontSettings=on"
   "-Dswing.aatext=true"
   (str "-Djna.library.path=" lib-paths)]

  :env
  {"GST_PLUGIN_SYSTEM_PATH"     plugin-paths
   "LD_LIBRARY_PATH"            lib-paths
   "DYLD_FALLBACK_LIBRARY_PATH" lib-paths}})

;; Local Variables:
;; mode:clojure
;; End:
On Gaiwan projects we also tend to run npm install, docker compose up, etc in there. Or you can call out to leinpad instead of launchpad in there, maintaining the convention that in any project, bin/launchpad is your one-stop-shop for a dev env.

πŸ’‘ 1
πŸ™ 1
πŸš€ 1
Ovi Stoica 2026-02-16T07:43:32.934279Z

Yes we tend to do the same. We have a scripts/leinpad that, through custom leinpad steps: 1. Starts docker compose 2. Starts storybook 3. Sets some specific env 4. does a small check All of this so you don't have to manage multiple services on your own

πŸ‘ 1