<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom"><title>Planet Scheme</title><link href="https://planet.scheme.org/" rel="alternate"/><link href="https://planet.scheme.org/atom.xml" rel="self" type="application/atom+xml"/><id>https://planet.scheme.org/</id><updated>2026-08-17T04:02:02Z</updated><entry><title>The Racket Blog: Rhombus v1.1</title><link href="http://blog.racket-lang.org/2026/08/rhombus-v1.1.html?utm_source=all&amp;utm_medium=Atom" rel="alternate"/><id>http://blog.racket-lang.org/2026/08/rhombus-v1.1.html?utm_source=all&amp;utm_medium=Atom</id><updated>2026-08-17T13:00:00Z</updated><author><name>Matthew Flatt</name></author><content type="html">
&lt;p&gt;Rhombus version 1.1 is now available!&lt;/p&gt;

&lt;p&gt;We are pleased to announce Rhombus 1.1 is now available from &lt;a href=&quot;https://rhombus-lang.org/&quot;&gt;https://rhombus-lang.org/&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;&lt;a href=&quot;https://rhombus-lang.org/&quot;&gt;Rhombus&lt;/a&gt; is a general-purpose programming language that is easy to use and uniquely customizable.&lt;/em&gt;&lt;/p&gt;

&lt;h2 id=&quot;as-of-this-release&quot;&gt;As of this release:&lt;/h2&gt;

&lt;ul&gt;
 &lt;li&gt;
  &lt;p&gt;Add &lt;a href=&quot;https://docs.racket-lang.org/rhombus-reference/Annotations.html?fam=Rhombus&amp;amp;famroot=rhombus#%28def._%28%28submod._%28lib._rhombus%2Fprivate%2Famalgam..rkt%29._core%29._annot._rhombus%2Fdefn%29%29&quot;&gt;&lt;code&gt;annot&lt;/code&gt;&lt;/a&gt; and &lt;a href=&quot;https://docs.racket-lang.org/rhombus-meta/Annotation_Macros.html?fam=Rhombus&amp;amp;famroot=rhombus#%28def._%28%28submod._%28lib._rhombus%2Fprivate%2Famalgam..rkt%29._core-meta%29._annot._%28annot..def._rhombus%2Fdefn%29%29%29&quot;&gt;&lt;code&gt;annot.def&lt;/code&gt;&lt;/a&gt; as ways to define an annotation without  directly writing meta-time (i.e., macro) code.&lt;/p&gt;&lt;/li&gt;
 &lt;li&gt;
  &lt;p&gt;Add &lt;a href=&quot;https://docs.racket-lang.org/rhombus-reference/Definitions.html?fam=Rhombus&amp;amp;famroot=rhombus#%28def._%28%28submod._%28lib._rhombus%2Fprivate%2Famalgam..rkt%29._core%29._as._rhombus%2Fbind%29%29&quot;&gt;&lt;code&gt;as&lt;/code&gt;&lt;/a&gt; as a binding form, which is sometimes more readable for  naming than using &lt;code&gt;&amp;&amp;&lt;/code&gt; and provides a way to shadow an identifier  that is bound as a binding form.&lt;/p&gt;&lt;/li&gt;
 &lt;li&gt;
  &lt;p&gt;Change &lt;a href=&quot;https://docs.racket-lang.org/rhombus-reference/class.html?fam=Rhombus&amp;amp;famroot=rhombus&quot;&gt;&lt;code&gt;class&lt;/code&gt;&lt;/a&gt; to bind inherited names using the corresponding  superclass or interface reference.&lt;/p&gt;&lt;/li&gt;
 &lt;li&gt;
  &lt;p&gt;Change &lt;a href=&quot;https://docs.racket-lang.org/rhombus-meta/ref-space.html?fam=Rhombus&amp;amp;famroot=rhombus#%28def._%28%28submod._%28lib._rhombus%2Fprivate%2Famalgam..rkt%29._core-meta%29._space._%28space..enforest._rhombus%2Fdecl%29%29%29&quot;&gt;&lt;code&gt;space.enforest&lt;/code&gt;&lt;/a&gt; to adjust scopes in the same way as for a  macro transformer when applying an identifier handler.&lt;/p&gt;&lt;/li&gt;
 &lt;li&gt;
  &lt;p&gt;ffi: Add an initialized-array variant of &lt;a href=&quot;https://docs.racket-lang.org/rhombus-ffi/pointer.html?fam=Rhombus&amp;amp;famroot=rhombus#%28def._%28%28lib._ffi%2Fmain..rhm%29._new%29%29&quot;&gt;&lt;code&gt;new&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;&lt;/li&gt;
 &lt;li&gt;
  &lt;p&gt;&lt;a href=&quot;https://docs.racket-lang.org/rhombus-pict/index.html?fam=Rhombus&amp;amp;famroot=rhombus&quot;&gt;pict&lt;/a&gt;: Change &lt;code&gt;explain_anim&lt;/code&gt; to add a &lt;code&gt;~label_as&lt;/code&gt; argument. Change  &lt;code&gt;Pict.rebuilt&lt;/code&gt; to replace as rebuilt, and also add a &lt;code&gt;~as_rebuilt&lt;/code&gt;  argument to select the old or new bevavior. The &lt;code&gt;Pict.rebuild&lt;/code&gt;  method also supports &lt;code&gt;~as_rebuilt&lt;/code&gt;. Improve &lt;code&gt;magic_move&lt;/code&gt; and  &lt;code&gt;cross_fade&lt;/code&gt; to better handle paragraph points and multiple  instances of a child pict.&lt;/p&gt;&lt;/li&gt;
 &lt;li&gt;
  &lt;p&gt;&lt;a href=&quot;https://docs.racket-lang.org/rhombus-slideshow/index.html?fam=Rhombus&amp;amp;famroot=rhombus&quot;&gt;slideshow&lt;/a&gt;: Add &lt;code&gt;slide_transition&lt;/code&gt; and &lt;code&gt;continued&lt;/code&gt; page numbering.&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;

&lt;p&gt;Thank you to community members who contributed this release.&lt;/p&gt;

&lt;h2 id=&quot;feedback-welcome&quot;&gt;Feedback Welcome&lt;/h2&gt;

&lt;p&gt;Questions and discussion welcome at the Racket community on &lt;a href=&quot;https://racket.discourse.group/invites/VxkBcXY7yL&quot;&gt;Discourse&lt;/a&gt; or &lt;a href=&quot;https://discord.gg/6Zq8sH5&quot;&gt;Discord&lt;/a&gt; (&lt;code&gt;#rhombus&lt;/code&gt; channel)&lt;/p&gt;

&lt;p&gt;Anyone can participate in Rhombus design discussions. The Racket team&amp;rsquo;s unofficial motto is &lt;em&gt;anything we can do, you can do:&lt;/em&gt; programmers should feel empowered to participate in the creation of the languages they use. Discussions, pull requests, and issues are open to all, and a wide variety of perspectives is especially beneficial.&lt;/p&gt;</content><source><title>The Racket Blog</title></source></entry><entry><title>The Racket Blog: Racket v9.3</title><link href="http://blog.racket-lang.org/2026/08/racket-v9-3.html?utm_source=all&amp;utm_medium=Atom" rel="alternate"/><id>http://blog.racket-lang.org/2026/08/racket-v9-3.html?utm_source=all&amp;utm_medium=Atom</id><updated>2026-08-13T09:27:32Z</updated><content type="html">
&lt;p&gt;&lt;em&gt;posted by Stephen De Gabrielle and John Clements&lt;/em&gt;&lt;/p&gt;

&lt;hr/&gt;

&lt;p&gt;We are pleased to announce Racket v9.3 is now available from &lt;a href=&quot;https://download.racket-lang.org&quot;&gt;https://download.racket-lang.org/&lt;/a&gt;.&lt;/p&gt;

&lt;h2 id=&quot;as-of-this-release&quot;&gt;As of this release:&lt;/h2&gt;

&lt;ul&gt;
 &lt;li&gt;The &lt;a href=&quot;https://docs.racket-lang.org/raco/running.html&quot;&gt;&lt;code&gt;raco setup&lt;/code&gt;&lt;/a&gt; command can generate markdown documentation, using the &lt;code&gt;--doc-markdown&lt;/code&gt; option.&lt;/li&gt;
 &lt;li&gt;The &quot;#lang&quot; &lt;a href=&quot;https://docs.racket-lang.org/htdp-langs/index.html&quot;&gt;teaching languages&lt;/a&gt; (BSL, &amp;hellip;, ISL+; plus DeinProgram) have reached parity with the ones chosen using the Language dialog, and are the recommended choice.&lt;/li&gt;
 &lt;li&gt;DrRacket&amp;rsquo;s background expansion disables errortrace annotations, for faster &lt;a href=&quot;https://docs.racket-lang.org/drracket/buttons.html#%28idx._%28gentag._8._%28lib._scribblings%2Fdrracket%2Fdrracket..scrbl%29%29%29&quot;&gt;syntax checking&lt;/a&gt;.&lt;/li&gt;
 &lt;li&gt;The &lt;a href=&quot;https://docs.racket-lang.org/pkg/cmdline.html#%28part._raco-pkg-install%29&quot;&gt;&lt;code&gt;raco pkg install&lt;/code&gt;&lt;/a&gt; command includes new options that provide more install-time configuration flexibility: &lt;code&gt;--adjacent-deps&lt;/code&gt;, &lt;code&gt;--destdir&lt;/code&gt;, and &lt;code&gt;--attach&lt;/code&gt;, and a refined &lt;code&gt;--skip-installed&lt;/code&gt;.&lt;/li&gt;
 &lt;li&gt;The &lt;code&gt;ffi/unsafe/runtime-lib&lt;/code&gt; library provides a &lt;a href=&quot;https://docs.racket-lang.org/foreign/runtime-lib.html#%28form._%28%28lib._ffi%2Funsafe%2Fruntime-lib..rkt%29._define-runtime-lib%29%29&quot;&gt;&lt;code&gt;define-runtime-lib&lt;/code&gt;&lt;/a&gt; mechanism similar to &lt;code&gt;define-runtime-path&lt;/code&gt;, allowing location of libraries located relative to a source file.&lt;/li&gt;
 &lt;li&gt;The &lt;a href=&quot;https://docs.racket-lang.org/reference/data-structure-contracts.html#%28form._%28%28lib._racket%2Fcontract%2Fprivate%2Fmisc..rkt%29._prompt-tag%2Fc%29%29&quot;&gt;&lt;code&gt;prompt-tag/c&lt;/code&gt;&lt;/a&gt; contract generator no longer performs checking on &lt;code&gt;call/cc&lt;/code&gt; when the &lt;code&gt;#:call/cc&lt;/code&gt; option is not present.&lt;/li&gt;
 &lt;li&gt;The &lt;a href=&quot;https://docs.racket-lang.org/reference/chaperones.html#%28def._%28%28quote._~23~25kernel%29._impersonate-prompt-tag%29%29&quot;&gt;&lt;code&gt;impersonate-prompt-tag&lt;/code&gt;&lt;/a&gt; function takes an additional argument that allows checking and update of results for composable continuations.&lt;/li&gt;
 &lt;li&gt;The &lt;a href=&quot;https://docs.racket-lang.org/reference/exns.html#%28def._%28%28quote._~23~25kernel%29._error-syntax-~3esrcloc-handler%29%29&quot;&gt;&lt;code&gt;error-syntax-&gt;srcloc-handler&lt;/code&gt;&lt;/a&gt; parameter provides control over the mapping from syntactic forms to source locations for error handling.&lt;/li&gt;
 &lt;li&gt;Uses of &lt;a href=&quot;https://docs.racket-lang.org/reference/tcp.html#%28def._%28%28lib._racket%2Ftcp..rkt%29._tcp-listen%29%29&quot;&gt;&lt;code&gt;(tcp-listen 0)&lt;/code&gt;&lt;/a&gt; will retry when it fails with &amp;ldquo;address in use&amp;rdquo;.&lt;/li&gt;
 &lt;li&gt;The &lt;a href=&quot;https://docs.racket-lang.org/reference/index.html&quot;&gt;&lt;code&gt;racket/base&lt;/code&gt;&lt;/a&gt; module requires fewer internal modules and instantiations.&lt;/li&gt;
 &lt;li&gt;The &lt;code&gt;file/zip&lt;/code&gt; package provides a &lt;a href=&quot;https://docs.racket-lang.org/file/zip.html#%28def._%28%28lib._file%2Fzip..rkt%29._zip-entry~3f%29%29&quot;&gt;new mechanism&lt;/a&gt; for greatly increased control over zip file generation, allowing in-memory file sources and per-file compression control.&lt;/li&gt;&lt;/ul&gt;

&lt;h2 id=&quot;thank-you&quot;&gt;Thank you&lt;/h2&gt;

&lt;p&gt;The following people contributed to this release:&lt;/p&gt;

&lt;p&gt;Alex Knauth, Alexander Shopov, Aris Spathis, Bert De Ketelaere, Bob Burger, Caleb Mazalevskis, Cameron Moy, Geoffrey J. Teale, Gustavo Massaccesi, Hannes Braun, Jade Sailor, Jason Hemann, Jens Axel Søgaard, John Clements, Jordan Johnson, Matthew Flatt, Matthias Felleisen, Mike Sperber, Nathan Dykman, Noah Ma, Philip McGrath, Robby Findler, Romeo Ahmed, Sam Tobin-Hochstadt, Shu-Hung You, Stefan Schwarzer, Stephen De Gabrielle, and Wing Hei Chan.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Racket&lt;/strong&gt; is a community developed open source project and we welcome new contributors. See &lt;a href=&quot;https://github.com/racket/racket/blob/master/README.md#contributing&quot;&gt;racket/README.md&lt;/a&gt; to learn how you can be a part of this amazing project.&lt;/p&gt;

&lt;h2 id=&quot;feedback-welcome&quot;&gt;Feedback Welcome&lt;/h2&gt;

&lt;p&gt;Questions and discussion welcome at the Racket community on &lt;a href=&quot;https://racket.discourse.group/invites/VxkBcXY7yL&quot;&gt;Discourse&lt;/a&gt; or &lt;a href=&quot;https://discord.gg/6Zq8sH5&quot;&gt;Discord&lt;/a&gt;.&lt;/p&gt;

&lt;h2 id=&quot;please-share&quot;&gt;Please share&lt;/h2&gt;

&lt;p&gt;If you can - please help get the word out to users and platform specific repo packagers&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;Racket - the Language-Oriented Programming Language - version 9.3 is now available from https://download.racket-lang.org

See https://blog.racket-lang.org/2026/08/racket-v9-3.html for the release announcement and highlights.&lt;/code&gt;&lt;/pre&gt;</content><source><title>The Racket Blog</title></source></entry><entry><title>Scheme Requests for Implementation: SRFI 279: In(tro)spection Protocol</title><link href="https://srfi.schemers.org/srfi-279/" rel="alternate"/><id>https://srfi.schemers.org/srfi-279/</id><updated>2026-08-11T12:00:00-08:00</updated><author><name>Artyom Bologov</name></author><content type="html">SRFI 279 is now in &lt;em&gt;draft&lt;/em&gt; status.&lt;blockquote&gt;&lt;p&gt;
  Interactive REPL-driven systems (that most Schemes are) need a way to get detailed information on a given piece of data.
  Inspectors, as these are conventionally called.
  This SRFI defines a basic protocol for inspectors, consisting of two procedures:
  &lt;code&gt;inspect-properties&lt;/code&gt; and &lt;code&gt;inspect-describe&lt;/code&gt;.
  Some suggestions for standard and popular types’ inspection are also provided.
&lt;/p&gt;&lt;/blockquote&gt;</content><source><title>Scheme Requests for Implementation</title></source></entry><entry><title>Scheme Requests for Implementation: SRFI 273: Extensions to Data (Type-)Checking</title><link href="https://srfi.schemers.org/srfi-273/" rel="alternate"/><id>https://srfi.schemers.org/srfi-273/</id><updated>2026-08-03T12:00:00-08:00</updated><author><name>Artyom Bologov</name></author><content type="html">SRFI 273 is now in &lt;em&gt;final&lt;/em&gt; status.&lt;blockquote&gt;&lt;p&gt;
  The original &lt;a href=&quot;https://srfi.schemers.org/srfi-253/&quot;&gt;SRFI 253&lt;/a&gt; established a basis for type-checked (or otherwise checked) data handling.
  But it lacked some quality-of-life features.
  This SRFI extends SRFI 253 to match existing implementation practice and common sense.
  Provided extensions are:
  check aliasing with &lt;code&gt;define-check&lt;/code&gt;;
  pre- and post-declaration of type / check with &lt;code&gt;declare-checked&lt;/code&gt;;
  return value checks
  in &lt;code&gt;lambda-checked&lt;/code&gt;, &lt;code&gt;case-lambda-checked&lt;/code&gt;, and &lt;code&gt;define-checked&lt;/code&gt;;
  and some optimizable, supported, and explicitly unsupported patterns suggested to implementors.
&lt;/p&gt;&lt;/blockquote&gt;</content><source><title>Scheme Requests for Implementation</title></source></entry><entry><title>Gwen Weinholt: The State of Chez Scheme in Debian</title><link href="https://weinholt.se/articles/state-of-chezscheme-in-debian/" rel="alternate"/><id>https://weinholt.se/articles/state-of-chezscheme-in-debian/</id><updated>2026-07-31T02:00:00+02:00</updated><author><name>weinholt</name></author><content type="html">&lt;p&gt;I have uploaded Chez Scheme 10.4.0 to Debian unstable. It has been a
few years since there was a new Chez Scheme version in Debian, and
that is all on me. 😅&lt;/p&gt;
&lt;p&gt;&lt;span class=&quot;more&quot;/&gt;&lt;/p&gt;
&lt;p&gt;The new release builds fine on all architectures according to
the &lt;a href=&quot;https://buildd.debian.org/status/logs.php?pkg=chezscheme&quot;&gt;build logs&lt;/a&gt;. In case you missed it, Chez Scheme got an
infusion of energy from the Racket people and gained portable bytecode
support a few years ago. So for those architectures where there is no
native backend, Chez instead generates portable bytecode.&lt;/p&gt;
&lt;p&gt;There was a problem with m68k and hppa where they would sometimes get
the wrong endianness for the portable bytecode, possibly depending on
which buildd picked them up. But that should be fixed now as
&lt;code&gt;debian/rules&lt;/code&gt; constructs the machine type from Debian’s build
variables.&lt;/p&gt;
&lt;h1 id=&quot;debian-scheme-dream-team&quot;&gt;Debian Scheme Dream Team&lt;/h1&gt;
&lt;p&gt;I moved the package to the Debian Scheme Dream Team! So now there are
more people who can help maintain it. The team has been gathering some
mass recently, which is really nice to see. I hope that together we
can make Scheme a stronger language in Debian.&lt;/p&gt;
&lt;h1 id=&quot;cross-compilation-was-broken&quot;&gt;Cross-compilation was broken&lt;/h1&gt;
&lt;p&gt;I enabled cross-compilation from amd64 to arm64 in
the &lt;a href=&quot;https://salsa.debian.org/scheme-team/chezscheme/-/pipelines&quot;&gt;Salsa pipelines&lt;/a&gt; and found that it was actually broken!
The problem was that cross-compilation kicks off a secondary build
where several of our build parameters were missing. So the secondary
build couldn’t find zuo and also got the wrong C compiler.&lt;/p&gt;
&lt;p&gt;This has been fixed by &lt;a href=&quot;https://salsa.debian.org/scheme-team/chezscheme/-/blob/50b2d295360850430ae8124b5ff464f73b98c010/debian/patches/0003-build.zuo-passes-through-ZUO-ZLIB-etc-for-cross-comp.patch&quot;&gt;patching build.zuo&lt;/a&gt;. This patch should
be upstreamed.&lt;/p&gt;
&lt;h1 id=&quot;future-work&quot;&gt;Future work&lt;/h1&gt;
&lt;p&gt;The &lt;code&gt;chezscheme-dev&lt;/code&gt; package is not something I have actually tested
myself. It ships &lt;code&gt;libkernel.a&lt;/code&gt;, &lt;code&gt;main.o&lt;/code&gt; and &lt;code&gt;scheme.h&lt;/code&gt;. Could be
working, nobody has ever said otherwise. :)&lt;/p&gt;
&lt;p&gt;Then there are the portable bytecodes! It would be possible to de-dupe
those in the archive. They could be built as &lt;code&gt;Architecture: all&lt;/code&gt;
packages and be reused. Now, e.g., sparc64 and ppc64 both build
threaded 64-bit big endian bytecode, so those exist at least twice in
the archive.&lt;/p&gt;
&lt;h1 id=&quot;reproducible-builds&quot;&gt;Reproducible builds&lt;/h1&gt;
&lt;p&gt;Last, but not
least, &lt;a href=&quot;https://github.com/cisco/ChezScheme/issues/585&quot;&gt;Chez Scheme builds are not reproducible&lt;/a&gt;. This is
becoming a real problem now
because
&lt;a href=&quot;https://weinholt.se/articles/state-of-chezscheme-in-debian/_https://lists.debian.org/debian-devel-announce/2026/05/msg00001.html&quot;&gt;Debian’s release team has made reproducible builds mandatory&lt;/a&gt;.
Chez Scheme will not be part of future Debian releases unless this
gets fixed.&lt;/p&gt;
&lt;p&gt;Thankfully it does seem to be fixable. The root of the problem is that
unique identifiers are used to support separate compilation. If
anyone’s interested in the background then they can check
out &lt;a href=&quot;https://web.archive.org/web/20010615153947/http://www.cs.indiana.edu/~owaddell/papers/thesis.ps.gz&quot;&gt;Oscar Waddell’s Ph.D. thesis&lt;/a&gt; (&lt;em&gt;warning&lt;/em&gt;: .ps.gz file).&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;The implementation described in Section 3.5 supports both internal
and top-level modules. For internal modules, the new names
generated by the expander must be locally unique, i.e., not
otherwise visible within the same top-level expression. For
top-level modules within a single compilation unit, the names must
be unique within the compilation unit. When multiple compilation
units may be linked together, the names must be unique across
compilation units.&lt;/p&gt;
&lt;p&gt;– Oscar Waddell, &lt;em&gt;Extending the Scope of Syntactic Abstraction&lt;/em&gt;, §3.6.1&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Chez Scheme generates a UUID for each session that gets embedded into
gensyms and that then gets embedded into the code. This satisfies the
need for unique identifiers that are different between separate
compilations. It ensures that things work smoothly when you are using
the compiler yourself. But we want reproducible builds, meaning
byte-for-byte identical builds, so the UUID is a problem.&lt;/p&gt;
&lt;p&gt;When building packages for Linux distributions, things are a bit
different than when you’re using the compiler yourself. Our build
system can tell us what code went into the build, including the
dependencies that brought in Scheme code, and if those stay the same
then there is no need to use different identifiers compared to the
previous time we built the same code.&lt;/p&gt;
&lt;p&gt;I’m toying with the idea of generating a session key from the package
version numbers and passing it to &lt;code&gt;configure&lt;/code&gt;. I think it can be done
without changing anything outside of the build system (the Zuo code).
Conceptually we would be doing this:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;lang-scheme&quot;&gt;(#%$set-top-level-value! &lt;span class=&quot;symbol&quot;&gt;'$session-key&lt;/span&gt; &lt;span class=&quot;string&quot;&gt;&quot;k&lt;hashed versions&gt;-&quot;&lt;/span&gt;)
(&lt;span class=&quot;name&quot;&gt;compile-file&lt;/span&gt; &lt;span class=&quot;string&quot;&gt;&quot;s/foo.ss&quot;&lt;/span&gt;)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;It remains to be seen if this is enough or if there are other sources
of non-determinism.&lt;/p&gt;
</content><source><title>Gwen Weinholt</title></source></entry><entry><title>jointhefreeworld: Emacs Eglot for Scala and Kotlin (JVM)</title><link href="https://jointhefreeworld.org/blog/articles/emacs/emacs-eglot-scala-kotlin/index.html" rel="alternate"/><id>https://jointhefreeworld.org/blog/articles/emacs/emacs-eglot-scala-kotlin/index.html</id><updated>2026-07-21T01:00:00+02:00</updated><content type="html">&lt;div id=&quot;content&quot; class=&quot;content max-w-full&quot;&gt; &lt;p&gt;
When Emacs 29 made  &lt;code&gt;eglot&lt;/code&gt; the built-in, default Language Server Protocol (LSP) client, many of us rejoiced.
&lt;/p&gt;

 &lt;p&gt;
It is lightweight, fast, adheres strictly to Emacs philosophy, and doesn’t try to reinvent the wheel.
&lt;/p&gt;

 &lt;p&gt;
However, being minimal means that when an LSP server steps out of line or acts quirky,  &lt;code&gt;eglot&lt;/code&gt; doesn’t provide a million customizable toggles to fix it out-of-the-box. Instead, it expects you to leverage the power of Emacs Lisp.
&lt;/p&gt;

 &lt;p&gt;
In this post, I will dissect my production-ready  &lt;code&gt;eglot&lt;/code&gt; setup (part of my  &lt;code&gt;heks-emacs&lt;/code&gt; configuration) which I use in my day-to-day work, with Scala and Kotlin (and some Java).
&lt;/p&gt;

 &lt;p&gt;
For reference, find my  full Eglot config here:  &lt;a href=&quot;https://codeberg.org/jjba23/heks-emacs/src/branch/trunk/src/modules/eglot.el&quot;&gt;https://codeberg.org/jjba23/heks-emacs/src/branch/trunk/src/modules/eglot.el&lt;/a&gt;
&lt;/p&gt;

 &lt;p&gt;
We will walk through basic language setups, specialized workspace configuration handling, and dive deep into some advanced JSON-RPC and advice-based workarounds for  &lt;b&gt;Scala (Metals)&lt;/b&gt; and  &lt;b&gt;Kotlin&lt;/b&gt; that make development truly seamless from Emacs and liberate you from IntelliJ ☺️.
&lt;/p&gt;

 &lt;p&gt;
It’s not perfect, but it’s pretty darn close to perfection if you ask me, and the developer experience and speed that it enables is just wild. Thank you Emacs, thank you GNU, thank you Eglot! 🐂
&lt;/p&gt;

 &lt;hr/&gt;&lt;hr/&gt; &lt;p&gt;
Before looking at the code, let’s talk about why we are doing this. For years, the conventional wisdom stated that if you write JVM languages, especially Scala or Kotlin, you must use  &lt;a href=&quot;https://www.jetbrains.com/idea/&quot;&gt;IntelliJ IDEA&lt;/a&gt;. The narrative claimed that these languages are too complex for a standard text editor.
&lt;/p&gt;

 &lt;p&gt;
But what do you actually get with IntelliJ? A massive, monolithic Java application that frequently hogs 8GB+ of RAM, locks up your system while “indexing pre-built binaries,” and forces you into a closed proprietary ecosystem.
&lt;/p&gt;

 &lt;p&gt;
Emacs turns this paradigm on its head through three core strengths:
&lt;/p&gt;

 &lt;ul class=&quot;org-ul&quot;&gt; &lt;li&gt;The Unix Philosophy of LSP: Instead of a single IDE trying to compile, index, and render your code simultaneously, Emacs splits these duties.  &lt;a href=&quot;https://www.gnu.org/software/emacs/manual/html_node/eglot/&quot;&gt;Eglot&lt;/a&gt; acts as a lean, protocol-first transport layer that talks to dedicated language servers via JSON-RPC.&lt;/li&gt;
 &lt;li&gt;Infinite Hackability: If IntelliJ has a bug in how it auto-completes Kotlin code, you are stuck waiting for JetBrains to issue a patch. In Emacs, you can write a 10-line Lisp advice function to intercept the network payload and patch the bug live in your editor buffer.&lt;/li&gt;
 &lt;li&gt;Unified Interface: You use the same text-manipulation utilities, text-jumping tools ( &lt;code&gt;xref&lt;/code&gt;), and completion frameworks ( &lt;code&gt;corfu&lt;/code&gt;,  &lt;code&gt;company&lt;/code&gt;, etc.) whether you are adjusting a Nix expression, editing a Markdown file, or refactoring a massive Scala service.&lt;/li&gt;
&lt;/ul&gt; &lt;hr/&gt;&lt;hr/&gt; &lt;h2&gt;Hooks, Keybindings, and Initial Configurations  &lt;a id=&quot;hooks-keybindings-and-initial-configurations&quot; class=&quot;anchor&quot; href=&quot;#hooks-keybindings-and-initial-configurations&quot;&gt;#&lt;/a&gt;&lt;/h2&gt; &lt;div class=&quot;outline-text-2&quot; id=&quot;text-org11a2793&quot;&gt;
 &lt;p&gt;
Let’s start with how  &lt;code&gt;eglot&lt;/code&gt; is initialized. I use Elpaca and  &lt;code&gt;use-package&lt;/code&gt; to manage the configuration, ensuring it doesn’t download an external package since it is built-in ( &lt;code&gt;:ensure nil&lt;/code&gt;). Then I add some hooks to automatically start the language server for certain modes.
&lt;/p&gt;

 &lt;pre&gt;( &lt;span class=&quot;org-keyword&quot;&gt;use-package&lt;/span&gt; eglot
   &lt;span class=&quot;org-builtin&quot;&gt;:ensure&lt;/span&gt; nil
   &lt;span class=&quot;org-builtin&quot;&gt;:hook&lt;/span&gt; ((scala-ts-mode . eglot-ensure)
         (sh-mode . eglot-ensure)
         (markdown-mode . eglot-ensure)
         (markdown-ts-mode . eglot-ensure)
         (nix-ts-mode . eglot-ensure)
         (html-mode . eglot-ensure)
         (css-mode . eglot-ensure)
         (css-ts-mode . eglot-ensure)
         (html-ts-mode . eglot-ensure)
         (js-mode . eglot-ensure)
         (js-ts-mode . eglot-ensure)
         (kotlin-ts-mode . eglot-ensure)
         (yaml-mode . eglot-ensure)
         (yaml-ts-mode . eglot-ensure)
          &lt;span class=&quot;org-comment-delimiter&quot;&gt;;; &lt;/span&gt; &lt;span class=&quot;org-comment&quot;&gt;formatting
&lt;/span&gt;         (before-save . eglot-format-buffer))
   &lt;span class=&quot;org-comment-delimiter&quot;&gt;;; &lt;/span&gt; &lt;span class=&quot;org-comment&quot;&gt;..................
&lt;/span&gt;   &lt;span class=&quot;org-comment-delimiter&quot;&gt;;; &lt;/span&gt; &lt;span class=&quot;org-comment&quot;&gt;more config
&lt;/span&gt;  )&lt;/pre&gt;

 &lt;ul class=&quot;org-ul&quot;&gt; &lt;li&gt; &lt;b&gt;Eglot-Ensure Everywhere:&lt;/b&gt; I hook  &lt;code&gt;eglot-ensure&lt;/code&gt; into almost every programming mode I use, adapting both classic modes and modern Tree-sitter ( &lt;code&gt;*-ts-mode&lt;/code&gt;) alternatives.&lt;/li&gt;
 &lt;li&gt; &lt;b&gt;Auto-Formatting:&lt;/b&gt; Adding  &lt;code&gt;eglot-format-buffer&lt;/code&gt; to  &lt;code&gt;before-save&lt;/code&gt; guarantees code style compliance automatically every time a file hits the disk.&lt;/li&gt;
&lt;/ul&gt; &lt;p&gt;
My keybindings are nested under the  &lt;code&gt;C-c i&lt;/code&gt; prefix, keeping them memorable and consistent across languages. The mnemonic keyword is “IDE” .
&lt;/p&gt;

 &lt;pre&gt; &lt;span class=&quot;org-builtin&quot;&gt;:bind&lt;/span&gt; (( &lt;span class=&quot;org-string&quot;&gt;&quot;C-c i i&quot;&lt;/span&gt; . eglot-find-implementation)
       ( &lt;span class=&quot;org-string&quot;&gt;&quot;C-c i e&quot;&lt;/span&gt; . eglot)
       ( &lt;span class=&quot;org-string&quot;&gt;&quot;C-c i k&quot;&lt;/span&gt; . eglot-shutdown-all)
       ( &lt;span class=&quot;org-string&quot;&gt;&quot;C-c i r&quot;&lt;/span&gt; . eglot-rename)
       ( &lt;span class=&quot;org-string&quot;&gt;&quot;C-c i x&quot;&lt;/span&gt; . eglot-reconnect)
       ( &lt;span class=&quot;org-string&quot;&gt;&quot;C-c i a&quot;&lt;/span&gt; . eglot-code-actions)
       ( &lt;span class=&quot;org-string&quot;&gt;&quot;C-c i m&quot;&lt;/span&gt; . eglot-menu)
       ( &lt;span class=&quot;org-string&quot;&gt;&quot;C-c i f&quot;&lt;/span&gt; . eglot-format-buffer)
       ( &lt;span class=&quot;org-string&quot;&gt;&quot;C-c i h&quot;&lt;/span&gt; . eglot-inlay-hints-mode))
 &lt;span class=&quot;org-builtin&quot;&gt;:init&lt;/span&gt;
( &lt;span class=&quot;org-keyword&quot;&gt;setq&lt;/span&gt; eglot-autoshutdown t
      eglot-confirm-server-edits nil
      eglot-report-progress t
      eglot-extend-to-xref t
      eglot-sync-connect 1
      eglot-connect-timeout 60
      eglot-autoreconnect t)&lt;/pre&gt;

 &lt;p&gt;
Then with these  &lt;code&gt;:init&lt;/code&gt; settings:
&lt;/p&gt;

 &lt;ul class=&quot;org-ul&quot;&gt; &lt;li&gt; &lt;code&gt;eglot-autoshutdown&lt;/code&gt; cleans up language server processes as soon as the last buffer managed by them is killed.&lt;/li&gt;
 &lt;li&gt; &lt;code&gt;eglot-extend-to-xref&lt;/code&gt; allows Emacs’ cross-referencing commands to smoothly transition into external library files outside your workspace directory.&lt;/li&gt;
&lt;/ul&gt; &lt;hr/&gt;&lt;/div&gt;&lt;/div&gt;
 &lt;h2&gt;Fine-Tuning Server Definitions and Workspaces  &lt;a id=&quot;fine-tuning-server-definitions-and-workspaces&quot; class=&quot;anchor&quot; href=&quot;#fine-tuning-server-definitions-and-workspaces&quot;&gt;#&lt;/a&gt;&lt;/h2&gt; &lt;div class=&quot;outline-text-2&quot; id=&quot;text-orgd3f74be&quot;&gt;
 &lt;p&gt;
Under the  &lt;code&gt;:config&lt;/code&gt; block, we begin optimizing specific language servers. For instance, removing default configurations before re-adding custom entries prevents collisions.
&lt;/p&gt;

 &lt;pre&gt; &lt;span class=&quot;org-builtin&quot;&gt;:config&lt;/span&gt;
( &lt;span class=&quot;org-keyword&quot;&gt;setopt&lt;/span&gt; eglot-code-action-indications nil)  &lt;span class=&quot;org-comment-delimiter&quot;&gt;;; &lt;/span&gt; &lt;span class=&quot;org-comment&quot;&gt;Cleans up Emacs 31 visual noise
&lt;/span&gt;
 &lt;span class=&quot;org-comment-delimiter&quot;&gt;;; &lt;/span&gt; &lt;span class=&quot;org-comment&quot;&gt;Clean slate for Scala and Kotlin
&lt;/span&gt;( &lt;span class=&quot;org-keyword&quot;&gt;setq&lt;/span&gt; eglot-server-programs (assq-delete-all 'scala-mode eglot-server-programs))
( &lt;span class=&quot;org-keyword&quot;&gt;setq&lt;/span&gt; eglot-server-programs (assq-delete-all 'scala-ts-mode eglot-server-programs))
( &lt;span class=&quot;org-keyword&quot;&gt;setq&lt;/span&gt; eglot-server-programs (assoc-delete-all 'scala-ts-mode eglot-server-programs))

(add-to-list 'eglot-server-programs `(scala-ts-mode . ( &lt;span class=&quot;org-string&quot;&gt;&quot;metals&quot;&lt;/span&gt;
                                                        &lt;span class=&quot;org-string&quot;&gt;&quot;-Xmx4G&quot;&lt;/span&gt;
                                                        &lt;span class=&quot;org-string&quot;&gt;&quot;-XX:+UseZGC&quot;&lt;/span&gt;
                                                        &lt;span class=&quot;org-string&quot;&gt;&quot;-Dmetals.http=true&quot;&lt;/span&gt;
                                                        &lt;span class=&quot;org-builtin&quot;&gt;:initializationOptions&lt;/span&gt; ( &lt;span class=&quot;org-builtin&quot;&gt;:isHttpEnabled&lt;/span&gt; t))))

( &lt;span class=&quot;org-keyword&quot;&gt;setq&lt;/span&gt; eglot-server-programs (assoc-delete-all 'kotlin-ts-mode eglot-server-programs))
(add-to-list 'eglot-server-programs '(kotlin-ts-mode . ( &lt;span class=&quot;org-string&quot;&gt;&quot;intellij-server&quot;&lt;/span&gt;  &lt;span class=&quot;org-string&quot;&gt;&quot;--stdio&quot;&lt;/span&gt;)))&lt;/pre&gt;

 &lt;p&gt;
 &lt;b&gt;Why these changes?&lt;/b&gt;
&lt;/p&gt;

 &lt;ul class=&quot;org-ul&quot;&gt; &lt;li&gt; &lt;b&gt;Scala (Metals):&lt;/b&gt; I pass specific JVM tuning flags directly to Metals (allocating a comfortable 4GB heap and utilizing the Z Garbage Collector for minimal latency). Also, enabling Metals HTTP communication via initialization options lets us hook into specialized UI features if needed.&lt;/li&gt;
 &lt;li&gt; &lt;b&gt;Kotlin:&lt;/b&gt; I swap out standard options for the IntelliJ-backed Kotlin Language Server ( &lt;code&gt;intellij-server --stdio&lt;/code&gt;).&lt;/li&gt;
&lt;/ul&gt;&lt;/div&gt;
 &lt;h2&gt;Global Workspace Configurations  &lt;a id=&quot;global-workspace-configurations&quot; class=&quot;anchor&quot; href=&quot;#global-workspace-configurations&quot;&gt;#&lt;/a&gt;&lt;/h2&gt; &lt;div class=&quot;outline-text-2&quot; id=&quot;text-org2961531&quot;&gt;
 &lt;p&gt;
 &lt;code&gt;eglot-workspace-configuration&lt;/code&gt; lets you pass customized variables downstream to your language servers. This section of my configuration acts like a universal  &lt;code&gt;settings.json&lt;/code&gt;:
&lt;/p&gt;

 &lt;pre&gt;( &lt;span class=&quot;org-keyword&quot;&gt;setq-default&lt;/span&gt; eglot-workspace-configuration
              '(
                 &lt;span class=&quot;org-builtin&quot;&gt;:metals&lt;/span&gt; (  &lt;span class=&quot;org-builtin&quot;&gt;:autoImportBuild&lt;/span&gt;  &lt;span class=&quot;org-string&quot;&gt;&quot;all&quot;&lt;/span&gt;
                           &lt;span class=&quot;org-builtin&quot;&gt;:isHttpEnabled&lt;/span&gt; t
                           &lt;span class=&quot;org-builtin&quot;&gt;:superMethodLensesEnabled&lt;/span&gt; t
                           &lt;span class=&quot;org-builtin&quot;&gt;:showInferredType&lt;/span&gt; t
                           &lt;span class=&quot;org-builtin&quot;&gt;:enableSemanticHighlighting&lt;/span&gt; t
                           &lt;span class=&quot;org-builtin&quot;&gt;:inlayHints&lt;/span&gt; (  &lt;span class=&quot;org-builtin&quot;&gt;:inferredTypes&lt;/span&gt; ( &lt;span class=&quot;org-builtin&quot;&gt;:enable&lt;/span&gt; t )
                                         &lt;span class=&quot;org-builtin&quot;&gt;:implicitArguments&lt;/span&gt; ( &lt;span class=&quot;org-builtin&quot;&gt;:enable&lt;/span&gt; nil)
                                         &lt;span class=&quot;org-builtin&quot;&gt;:implicitConversions&lt;/span&gt; ( &lt;span class=&quot;org-builtin&quot;&gt;:enable&lt;/span&gt; nil )
                                         &lt;span class=&quot;org-builtin&quot;&gt;:typeParameters&lt;/span&gt; ( &lt;span class=&quot;org-builtin&quot;&gt;:enable&lt;/span&gt; t )
                                         &lt;span class=&quot;org-builtin&quot;&gt;:hintsInPatternMatch&lt;/span&gt; ( &lt;span class=&quot;org-builtin&quot;&gt;:enable&lt;/span&gt; nil ))
                           &lt;span class=&quot;org-builtin&quot;&gt;:bloopJvmProperties&lt;/span&gt; [ &lt;span class=&quot;org-string&quot;&gt;&quot;-Xmx4G&quot;&lt;/span&gt;])
                 &lt;span class=&quot;org-builtin&quot;&gt;:haskell&lt;/span&gt; ( &lt;span class=&quot;org-builtin&quot;&gt;:formattingProvider&lt;/span&gt;  &lt;span class=&quot;org-string&quot;&gt;&quot;ormolu&quot;&lt;/span&gt;)
                 &lt;span class=&quot;org-builtin&quot;&gt;:typescript&lt;/span&gt; ( &lt;span class=&quot;org-builtin&quot;&gt;:format&lt;/span&gt; ( &lt;span class=&quot;org-builtin&quot;&gt;:baseIndentSize&lt;/span&gt; 0
                                                       &lt;span class=&quot;org-builtin&quot;&gt;:convertTabsToSpaces&lt;/span&gt; t
                                                       &lt;span class=&quot;org-builtin&quot;&gt;:indentSize&lt;/span&gt; 2
                                                       &lt;span class=&quot;org-builtin&quot;&gt;:semicolons&lt;/span&gt;  &lt;span class=&quot;org-string&quot;&gt;&quot;remove&quot;&lt;/span&gt;
                                                       &lt;span class=&quot;org-builtin&quot;&gt;:tabSize&lt;/span&gt; 2))
                 &lt;span class=&quot;org-builtin&quot;&gt;:javascript&lt;/span&gt; ( &lt;span class=&quot;org-builtin&quot;&gt;:format&lt;/span&gt; ( &lt;span class=&quot;org-builtin&quot;&gt;:baseIndentSize&lt;/span&gt; 0
                                                       &lt;span class=&quot;org-builtin&quot;&gt;:convertTabsToSpaces&lt;/span&gt; t
                                                       &lt;span class=&quot;org-builtin&quot;&gt;:indentSize&lt;/span&gt; 2
                                                       &lt;span class=&quot;org-builtin&quot;&gt;:semicolons&lt;/span&gt;  &lt;span class=&quot;org-string&quot;&gt;&quot;remove&quot;&lt;/span&gt;
                                                       &lt;span class=&quot;org-builtin&quot;&gt;:tabSize&lt;/span&gt; 2))
                 &lt;span class=&quot;org-builtin&quot;&gt;:rust-analyzer&lt;/span&gt; ( &lt;span class=&quot;org-builtin&quot;&gt;:check&lt;/span&gt; ( &lt;span class=&quot;org-builtin&quot;&gt;:command&lt;/span&gt;  &lt;span class=&quot;org-string&quot;&gt;&quot;clippy&quot;&lt;/span&gt;)
                                        &lt;span class=&quot;org-builtin&quot;&gt;:cargo&lt;/span&gt; ( &lt;span class=&quot;org-builtin&quot;&gt;:sysroot&lt;/span&gt;  &lt;span class=&quot;org-string&quot;&gt;&quot;discover&quot;&lt;/span&gt;
                                                         &lt;span class=&quot;org-builtin&quot;&gt;:features&lt;/span&gt;  &lt;span class=&quot;org-string&quot;&gt;&quot;all&quot;&lt;/span&gt;
                                                         &lt;span class=&quot;org-builtin&quot;&gt;:buildScripts&lt;/span&gt; ( &lt;span class=&quot;org-builtin&quot;&gt;:enable&lt;/span&gt; t))
                                        &lt;span class=&quot;org-builtin&quot;&gt;:diagnostics&lt;/span&gt; ( &lt;span class=&quot;org-builtin&quot;&gt;:disabled&lt;/span&gt; [ &lt;span class=&quot;org-string&quot;&gt;&quot;macro-error&quot;&lt;/span&gt;])
                                        &lt;span class=&quot;org-builtin&quot;&gt;:procMacro&lt;/span&gt; ( &lt;span class=&quot;org-builtin&quot;&gt;:enable&lt;/span&gt; t))

                 &lt;span class=&quot;org-builtin&quot;&gt;:yaml&lt;/span&gt; (  &lt;span class=&quot;org-builtin&quot;&gt;:format&lt;/span&gt; ( &lt;span class=&quot;org-builtin&quot;&gt;:enable&lt;/span&gt; t)
                         &lt;span class=&quot;org-builtin&quot;&gt;:validate&lt;/span&gt; t
                         &lt;span class=&quot;org-builtin&quot;&gt;:hover&lt;/span&gt; t
                         &lt;span class=&quot;org-builtin&quot;&gt;:completion&lt;/span&gt; t
                         &lt;span class=&quot;org-builtin&quot;&gt;:schemas&lt;/span&gt; (
                                  https://codeberg.org/jjba23/pop-test/raw/branch/trunk/resources/json-schema/pop-test.json [ &lt;span class=&quot;org-string&quot;&gt;&quot;golden-test.yaml&quot;&lt;/span&gt;  &lt;span class=&quot;org-string&quot;&gt;&quot;golden-test.yml&quot;&lt;/span&gt;  &lt;span class=&quot;org-string&quot;&gt;&quot;pop-test.yaml&quot;&lt;/span&gt;  &lt;span class=&quot;org-string&quot;&gt;&quot;pop-test.yml&quot;&lt;/span&gt;]
                                  https://raw.githubusercontent.com/Vandebron/gh-mpyl/refs/heads/main/src/mpyl/schema/project.schema.yml [ &lt;span class=&quot;org-string&quot;&gt;&quot;project.yml&quot;&lt;/span&gt;]
                                  https://json.schemastore.org/yamllint.json [ &lt;span class=&quot;org-string&quot;&gt;&quot;/*.yml&quot;&lt;/span&gt;])
                         &lt;span class=&quot;org-builtin&quot;&gt;:schemaStore&lt;/span&gt; ( &lt;span class=&quot;org-builtin&quot;&gt;:enable&lt;/span&gt; t))
                 &lt;span class=&quot;org-builtin&quot;&gt;:nil&lt;/span&gt; ( &lt;span class=&quot;org-builtin&quot;&gt;:formatting&lt;/span&gt; ( &lt;span class=&quot;org-builtin&quot;&gt;:command&lt;/span&gt; [ &lt;span class=&quot;org-string&quot;&gt;&quot;nixfmt&quot;&lt;/span&gt;]))))&lt;/pre&gt;

 &lt;p&gt;
Notable Configurations here:
&lt;/p&gt;

 &lt;ul class=&quot;org-ul&quot;&gt; &lt;li&gt; &lt;b&gt;Metals:&lt;/b&gt; Granular inlay hints are activated specifically for inferred types and type parameters while muting implicit conversions to keep buffers readable. (more options here:  &lt;a href=&quot;https://scalameta.org/metals/docs/editors/user-configuration/&quot;&gt;https://scalameta.org/metals/docs/editors/user-configuration/&lt;/a&gt;)&lt;/li&gt;
 &lt;li&gt; &lt;b&gt;YAML Schema Mapping:&lt;/b&gt; Maps distinct internet-hosted JSON schemas straight to patterns of YAML files automatically.&lt;/li&gt;
&lt;/ul&gt; &lt;hr/&gt;&lt;hr/&gt;&lt;/div&gt;
 &lt;h2&gt;Deep Dive: The Workarounds  &lt;a id=&quot;deep-dive-the-workarounds&quot; class=&quot;anchor&quot; href=&quot;#deep-dive-the-workarounds&quot;&gt;#&lt;/a&gt;&lt;/h2&gt; &lt;div class=&quot;outline-text-2&quot; id=&quot;text-orgf81346f&quot;&gt;
 &lt;p&gt;
This is where things get interesting. Sometimes servers violate standard LSP expectations, requiring custom Emacs Lisp logic to bridge the gap.
&lt;/p&gt;
&lt;/div&gt;
 &lt;h3&gt;Fixing Eldoc Overload  &lt;a id=&quot;fixing-eldoc-overload&quot; class=&quot;anchor&quot; href=&quot;#fixing-eldoc-overload&quot;&gt;#&lt;/a&gt;&lt;/h3&gt; &lt;div class=&quot;outline-text-3&quot; id=&quot;text-org7eabcea&quot;&gt;
 &lt;p&gt;
By default,  &lt;code&gt;eldoc&lt;/code&gt; can easily get flooded by different feedback mechanisms. This block prioritizes structural code diagnostics over generic hover data:
&lt;/p&gt;

 &lt;pre&gt;(add-hook 'eglot-managed-mode-hook
          ( &lt;span class=&quot;org-keyword&quot;&gt;lambda&lt;/span&gt; ()
             &lt;span class=&quot;org-comment-delimiter&quot;&gt;;; &lt;/span&gt; &lt;span class=&quot;org-comment&quot;&gt;Show flymake diagnostics first.
&lt;/span&gt;            ( &lt;span class=&quot;org-keyword&quot;&gt;setq&lt;/span&gt; eldoc-documentation-functions
                  (cons #'flymake-eldoc-function
                        (remove #'flymake-eldoc-function eldoc-documentation-functions)))
             &lt;span class=&quot;org-comment-delimiter&quot;&gt;;; &lt;/span&gt; &lt;span class=&quot;org-comment&quot;&gt;Show all eldoc feedback.
&lt;/span&gt;            ( &lt;span class=&quot;org-keyword&quot;&gt;setq&lt;/span&gt; eldoc-documentation-strategy #'eldoc-documentation-compose)))&lt;/pre&gt;
&lt;/div&gt;
 &lt;h3&gt;Kotlin Source Navigation (Jar URI Translation)  &lt;a id=&quot;kotlin-source-navigation-jar-uri-translation&quot; class=&quot;anchor&quot; href=&quot;#kotlin-source-navigation-jar-uri-translation&quot;&gt;#&lt;/a&gt;&lt;/h3&gt; &lt;div class=&quot;outline-text-3&quot; id=&quot;text-org79f72ee&quot;&gt;
 &lt;p&gt;
When traversing into a dependency library using Kotlin, the server returns file references formatted as  &lt;code&gt;jar:///path/to/library.jar!/File.kt&lt;/code&gt;. Emacs can’t resolve this scheme directly out of the box, throwing errors when you try to jump to definition.
&lt;/p&gt;

 &lt;p&gt;
By wrapping Eglot’s URI translators with advice, we can map this custom scheme into something Emacs understands (especially alongside companion extensions like  &lt;code&gt;jarchive&lt;/code&gt;):
&lt;/p&gt;

 &lt;pre&gt;( &lt;span class=&quot;org-keyword&quot;&gt;defun&lt;/span&gt;  &lt;span class=&quot;org-function-name&quot;&gt;heks/eglot-uri-to-path-kotlin&lt;/span&gt; (orig-fn uri  &lt;span class=&quot;org-type&quot;&gt;&amp;rest;&lt;/span&gt; args)
  ( &lt;span class=&quot;org-keyword&quot;&gt;if&lt;/span&gt; ( &lt;span class=&quot;org-keyword&quot;&gt;and&lt;/span&gt; (stringp uri) (string-prefix-p  &lt;span class=&quot;org-string&quot;&gt;&quot;jar:///&quot;&lt;/span&gt; uri))
      (apply orig-fn (replace-regexp-in-string  &lt;span class=&quot;org-string&quot;&gt;&quot;^jar:///&quot;&lt;/span&gt;  &lt;span class=&quot;org-string&quot;&gt;&quot;jar:file:///&quot;&lt;/span&gt; uri) args)
    (apply orig-fn uri args)))

( &lt;span class=&quot;org-keyword&quot;&gt;defun&lt;/span&gt;  &lt;span class=&quot;org-function-name&quot;&gt;heks/eglot-path-to-uri-kotlin&lt;/span&gt; (orig-fn path  &lt;span class=&quot;org-type&quot;&gt;&amp;rest;&lt;/span&gt; args)
  ( &lt;span class=&quot;org-keyword&quot;&gt;if&lt;/span&gt; ( &lt;span class=&quot;org-keyword&quot;&gt;and&lt;/span&gt; (stringp path) (string-prefix-p  &lt;span class=&quot;org-string&quot;&gt;&quot;jar:file:///&quot;&lt;/span&gt; path))
      (replace-regexp-in-string  &lt;span class=&quot;org-string&quot;&gt;&quot;^jar:file:///&quot;&lt;/span&gt;  &lt;span class=&quot;org-string&quot;&gt;&quot;jar:///&quot;&lt;/span&gt; path)
    (apply orig-fn path args)))

( &lt;span class=&quot;org-keyword&quot;&gt;if&lt;/span&gt; (fboundp 'eglot-uri-to-path)
    ( &lt;span class=&quot;org-keyword&quot;&gt;progn&lt;/span&gt;
      (advice-add 'eglot-uri-to-path  &lt;span class=&quot;org-builtin&quot;&gt;:around&lt;/span&gt; #'heks/eglot-uri-to-path-kotlin)
      (advice-add 'eglot-path-to-uri  &lt;span class=&quot;org-builtin&quot;&gt;:around&lt;/span&gt; #'heks/eglot-path-to-uri-kotlin))
  ( &lt;span class=&quot;org-keyword&quot;&gt;progn&lt;/span&gt;
    (advice-add 'eglot--uri-to-path  &lt;span class=&quot;org-builtin&quot;&gt;:around&lt;/span&gt; #'heks/eglot-uri-to-path-kotlin)
    (advice-add 'eglot--path-to-uri  &lt;span class=&quot;org-builtin&quot;&gt;:around&lt;/span&gt; #'heks/eglot-path-to-uri-kotlin)))&lt;/pre&gt;
&lt;/div&gt;
 &lt;h3&gt;Intercepting the Kotlin Empty  &lt;code&gt;newText&lt;/code&gt; Auto-Completion Bug  &lt;a id=&quot;intercepting-the-kotlin-empty-codenewtextcode-auto-completion-bug&quot; class=&quot;anchor&quot; href=&quot;#intercepting-the-kotlin-empty-codenewtextcode-auto-completion-bug&quot;&gt;#&lt;/a&gt;&lt;/h3&gt; &lt;div class=&quot;outline-text-3&quot; id=&quot;text-org31df172&quot;&gt;
 &lt;p&gt;
A notorious issue in certain Kotlin LSP releases occurs during auto-completion. The server reports matching candidates, but mistakenly attaches a  &lt;code&gt;textEdit&lt;/code&gt; field containing an empty string ( &lt;code&gt;newText: &quot;&quot;&lt;/code&gt;). This causes Eglot to wipe out the word you are completing entirely.
&lt;/p&gt;

 &lt;p&gt;
To solve this, I intercept the incoming JSON-RPC response payloads, both synchronous and asynchronous. If a Kotlin completion candidate returns an empty string edit, we strip the `textEdit` attribute completely, forcing Eglot to fall back gracefully to standard prefix matching.
&lt;/p&gt;

 &lt;pre&gt;( &lt;span class=&quot;org-keyword&quot;&gt;defun&lt;/span&gt;  &lt;span class=&quot;org-function-name&quot;&gt;my-jsonrpc-request-kotlin-fix&lt;/span&gt; (orig-fn connection method params  &lt;span class=&quot;org-type&quot;&gt;&amp;rest;&lt;/span&gt; args)
   &lt;span class=&quot;org-doc&quot;&gt;&quot;Fix kotlin-lsp empty newText bug by removing textEdit to trigger Eglot fallback.&quot;&lt;/span&gt;
  ( &lt;span class=&quot;org-keyword&quot;&gt;let&lt;/span&gt; ((result (apply orig-fn connection method params args)))
    ( &lt;span class=&quot;org-keyword&quot;&gt;when&lt;/span&gt; ( &lt;span class=&quot;org-keyword&quot;&gt;and&lt;/span&gt; (eq method  &lt;span class=&quot;org-builtin&quot;&gt;:textDocument/completion&lt;/span&gt;)
               (derived-mode-p 'kotlin-mode 'kotlin-ts-mode)
               result)
      ( &lt;span class=&quot;org-keyword&quot;&gt;let&lt;/span&gt; ((items ( &lt;span class=&quot;org-keyword&quot;&gt;if&lt;/span&gt; (vectorp result) result (plist-get result  &lt;span class=&quot;org-builtin&quot;&gt;:items&lt;/span&gt;))))
        (seq-do ( &lt;span class=&quot;org-keyword&quot;&gt;lambda&lt;/span&gt; (item)
                  ( &lt;span class=&quot;org-keyword&quot;&gt;let&lt;/span&gt; ((text-edit (plist-get item  &lt;span class=&quot;org-builtin&quot;&gt;:textEdit&lt;/span&gt;)))
                     &lt;span class=&quot;org-comment-delimiter&quot;&gt;;; &lt;/span&gt; &lt;span class=&quot;org-comment&quot;&gt;If the server sent an empty newText, strip textEdit completely
&lt;/span&gt;                     &lt;span class=&quot;org-comment-delimiter&quot;&gt;;; &lt;/span&gt; &lt;span class=&quot;org-comment&quot;&gt;so Eglot falls back to replacing the actual prefix.
&lt;/span&gt;                    ( &lt;span class=&quot;org-keyword&quot;&gt;when&lt;/span&gt; ( &lt;span class=&quot;org-keyword&quot;&gt;and&lt;/span&gt; text-edit (equal (plist-get text-edit  &lt;span class=&quot;org-builtin&quot;&gt;:newText&lt;/span&gt;)  &lt;span class=&quot;org-string&quot;&gt;&quot;&quot;&lt;/span&gt;))
                      (plist-put item  &lt;span class=&quot;org-builtin&quot;&gt;:textEdit&lt;/span&gt; nil))))
                items)))
    result))

( &lt;span class=&quot;org-keyword&quot;&gt;defun&lt;/span&gt;  &lt;span class=&quot;org-function-name&quot;&gt;my-jsonrpc-async-request-kotlin-fix&lt;/span&gt; (orig-fn connection method params  &lt;span class=&quot;org-type&quot;&gt;&amp;rest;&lt;/span&gt; args)
   &lt;span class=&quot;org-doc&quot;&gt;&quot;Fix kotlin-lsp empty newText bug in asynchronous Eglot requests.&quot;&lt;/span&gt;
  ( &lt;span class=&quot;org-keyword&quot;&gt;if&lt;/span&gt; ( &lt;span class=&quot;org-keyword&quot;&gt;and&lt;/span&gt; (eq method  &lt;span class=&quot;org-builtin&quot;&gt;:textDocument/completion&lt;/span&gt;)
           (derived-mode-p 'kotlin-mode 'kotlin-ts-mode))
      ( &lt;span class=&quot;org-keyword&quot;&gt;let*&lt;/span&gt; ((orig-success (plist-get args  &lt;span class=&quot;org-builtin&quot;&gt;:success-fn&lt;/span&gt;))
             (new-success ( &lt;span class=&quot;org-keyword&quot;&gt;lambda&lt;/span&gt; (result)
                            ( &lt;span class=&quot;org-keyword&quot;&gt;let&lt;/span&gt; ((items ( &lt;span class=&quot;org-keyword&quot;&gt;if&lt;/span&gt; (vectorp result) result (plist-get result  &lt;span class=&quot;org-builtin&quot;&gt;:items&lt;/span&gt;))))
                              (seq-do ( &lt;span class=&quot;org-keyword&quot;&gt;lambda&lt;/span&gt; (item)
                                        ( &lt;span class=&quot;org-keyword&quot;&gt;let&lt;/span&gt; ((text-edit (plist-get item  &lt;span class=&quot;org-builtin&quot;&gt;:textEdit&lt;/span&gt;)))
                                          ( &lt;span class=&quot;org-keyword&quot;&gt;when&lt;/span&gt; ( &lt;span class=&quot;org-keyword&quot;&gt;and&lt;/span&gt; text-edit (equal (plist-get text-edit  &lt;span class=&quot;org-builtin&quot;&gt;:newText&lt;/span&gt;)  &lt;span class=&quot;org-string&quot;&gt;&quot;&quot;&lt;/span&gt;))
                                            (plist-put item  &lt;span class=&quot;org-builtin&quot;&gt;:textEdit&lt;/span&gt; nil))))
                                      items))
                            (funcall orig-success result)))
             (new-args (plist-put (copy-sequence args)  &lt;span class=&quot;org-builtin&quot;&gt;:success-fn&lt;/span&gt; new-success)))
        (apply orig-fn connection method params new-args))
    (apply orig-fn connection method params args)))

(advice-add 'jsonrpc-request  &lt;span class=&quot;org-builtin&quot;&gt;:around&lt;/span&gt; #'my-jsonrpc-request-kotlin-fix)
(advice-add 'jsonrpc-async-request  &lt;span class=&quot;org-builtin&quot;&gt;:around&lt;/span&gt; #'my-jsonrpc-async-request-kotlin-fix)&lt;/pre&gt;
&lt;/div&gt;
 &lt;h3&gt;Silencing Metals Semantic Refresh Flickering  &lt;a id=&quot;silencing-metals-semantic-refresh-flickering&quot; class=&quot;anchor&quot; href=&quot;#silencing-metals-semantic-refresh-flickering&quot;&gt;#&lt;/a&gt;&lt;/h3&gt; &lt;div class=&quot;outline-text-3&quot; id=&quot;text-org3a31301&quot;&gt;
 &lt;p&gt;
Scala Metals aggressively forces full buffer semantic token refreshes. In large projects, this results in visual layout flickering and unnecessary CPU strain. Disabling this also can solve some startup issues for Metals.
&lt;/p&gt;

 &lt;pre&gt;( &lt;span class=&quot;org-keyword&quot;&gt;defun&lt;/span&gt;  &lt;span class=&quot;org-function-name&quot;&gt;my/eglot-disable-metals-semantic-refresh&lt;/span&gt; (orig-fn server)
  ( &lt;span class=&quot;org-keyword&quot;&gt;let*&lt;/span&gt; ((caps (funcall orig-fn server))
         (workspace (plist-get caps  &lt;span class=&quot;org-builtin&quot;&gt;:workspace&lt;/span&gt;))
         (tokens (plist-get workspace  &lt;span class=&quot;org-builtin&quot;&gt;:semanticTokens&lt;/span&gt;)))
    ( &lt;span class=&quot;org-keyword&quot;&gt;when&lt;/span&gt; tokens
      (plist-put tokens  &lt;span class=&quot;org-builtin&quot;&gt;:refreshSupport&lt;/span&gt;  &lt;span class=&quot;org-builtin&quot;&gt;:json-false&lt;/span&gt;))
    caps))

(advice-add 'eglot-client-capabilities  &lt;span class=&quot;org-builtin&quot;&gt;:around&lt;/span&gt; #'my/eglot-disable-metals-semantic-refresh)&lt;/pre&gt;

 &lt;hr/&gt;&lt;hr/&gt;&lt;/div&gt;
 &lt;h2&gt;Companion Packages: Java and Compressed Archives  &lt;a id=&quot;companion-packages-java-and-compressed-archives&quot; class=&quot;anchor&quot; href=&quot;#companion-packages-java-and-compressed-archives&quot;&gt;#&lt;/a&gt;&lt;/h2&gt; &lt;div class=&quot;outline-text-2&quot; id=&quot;text-org5e99d3a&quot;&gt;
 &lt;p&gt;
To complete the setup, I load complementary minor modes outside of Eglot’s core file, ensuring smooth operations for Java and deep navigation for packed jars:
&lt;/p&gt;

 &lt;pre&gt;( &lt;span class=&quot;org-keyword&quot;&gt;use-package&lt;/span&gt; eglot-java
   &lt;span class=&quot;org-builtin&quot;&gt;:ensure&lt;/span&gt; t
   &lt;span class=&quot;org-builtin&quot;&gt;:after&lt;/span&gt; (eglot)
   &lt;span class=&quot;org-builtin&quot;&gt;:hook&lt;/span&gt; ((java-mode . eglot-java-mode)
         (java-ts-mode . eglot-java-mode)))

( &lt;span class=&quot;org-keyword&quot;&gt;use-package&lt;/span&gt; jarchive
   &lt;span class=&quot;org-builtin&quot;&gt;:ensure&lt;/span&gt; t
   &lt;span class=&quot;org-builtin&quot;&gt;:config&lt;/span&gt;
  (jarchive-mode))&lt;/pre&gt;

 &lt;ul class=&quot;org-ul&quot;&gt; &lt;li&gt; &lt;code&gt;eglot-java&lt;/code&gt;: Provisions proper workspace configurations specifically for Eclipse JDT LS seamlessly.&lt;/li&gt;
 &lt;li&gt; &lt;code&gt;jarchive&lt;/code&gt;: Works harmoniously alongside the Kotlin JAR-URI translation hack, opening zipped up source containers into regular, viewable Emacs buffers.&lt;/li&gt;
&lt;/ul&gt;&lt;/div&gt;
 &lt;h2&gt;The way I like it on reproducibility  &lt;a id=&quot;the-way-i-like-it-on-reproducibility&quot; class=&quot;anchor&quot; href=&quot;#the-way-i-like-it-on-reproducibility&quot;&gt;#&lt;/a&gt;&lt;/h2&gt; &lt;div class=&quot;outline-text-2&quot; id=&quot;text-org87c0af6&quot;&gt;
 &lt;p&gt;
I generally don’t use the “global” system wide JDK installation, but I use isolated development reproducible shells with Nix flakes.
&lt;/p&gt;

 &lt;p&gt;
I’ll eventually probably move to using Guix, but for now package availability isn’t quite there for JVM world so Nix it is.
&lt;/p&gt;

 &lt;p&gt;
This way you can easily work on the same machine with many environments and projects (e.g. different Java versions) and no need for SDKMan or version managers, but clean isolated per-project reproducible builds.
&lt;/p&gt;

 &lt;p&gt;
So I create a  &lt;code&gt;flake.nix&lt;/code&gt; and add it to Git.
&lt;/p&gt;

 &lt;p&gt;
Kotlin development flake (TODO intellij-server via Nix):
&lt;/p&gt;
 &lt;pre&gt;{
  inputs = {
    nixpkgs.url = &quot;github:NixOS/nixpkgs/nixos-unstable&quot;;
    systems.url = &quot;github:nix-systems/default&quot;;
  };
  outputs = { systems, nixpkgs, ... }:
    let
      eachSystem = f:
        nixpkgs.lib.genAttrs (import systems)
        (system: f nixpkgs.legacyPackages.${system});
    in {
      devShells = eachSystem (pkgs: {
        default = pkgs.mkShell {
          buildInputs = with pkgs; [
            ktfmt
            ktlint
            kotlin
            jdk25
            nil
            just
            yaml-language-server
          ];
        };
      });
    };
}&lt;/pre&gt;

 &lt;p&gt;
Scala development flake.
&lt;/p&gt;
 &lt;pre&gt;{
  inputs = {
    nixpkgs.url = &quot;github:NixOS/nixpkgs/nixos-unstable&quot;;
    systems.url = &quot;github:nix-systems/default&quot;;
  };
  outputs = { systems, nixpkgs, ... }:
    let
      eachSystem = f:
        nixpkgs.lib.genAttrs (import systems)
        (system: f nixpkgs.legacyPackages.${system});
    in {
      devShells = eachSystem (pkgs: {
        default = pkgs.mkShell {
          buildInputs = with pkgs; [
            scala_2_13
            jdk25
            metals
            sbt
            scalafmt
            scalafix
            scala-cli
            yaml-language-server
            coursier
          ];
        };
      });
    };
}&lt;/pre&gt;

 &lt;p&gt;
Then I load the flake with  &lt;a href=&quot;https://direnv.net/&quot;&gt;direnv&lt;/a&gt; so I create a  &lt;code&gt;.envrc&lt;/code&gt; file .
&lt;/p&gt;
 &lt;pre&gt;use flake&lt;/pre&gt;

 &lt;p&gt;
This way and inside Emacs I can use  &lt;a href=&quot;https://github.com/wbolster/emacs-direnv&quot;&gt;emacs-direnv&lt;/a&gt; to dynamically switch contexts inside Emacs LSPs and have even multiple running.
&lt;/p&gt;

 &lt;p&gt;
I also plug direnv into my Bash shell configurations and thus complete the development environment.
&lt;/p&gt;
&lt;/div&gt;
 &lt;h2&gt;Conclusion  &lt;a id=&quot;conclusion&quot; class=&quot;anchor&quot; href=&quot;#conclusion&quot;&gt;#&lt;/a&gt;&lt;/h2&gt; &lt;div class=&quot;outline-text-2&quot; id=&quot;text-orgab1aafa&quot;&gt;
 &lt;p&gt;
Eglot’s minimal, built-in design doesn’t mean you have to settle for sub-par language server behavior. After all, you are using Emacs, so the power is infinite!
&lt;/p&gt;

 &lt;p&gt;
By intercepting communication at the JSON-RPC level via  &lt;code&gt;advice-add&lt;/code&gt;, you can tailor client-server behaviors exactly to your liking.
&lt;/p&gt;

 &lt;p&gt;
Happy hacking! ✨
&lt;/p&gt;
&lt;/div&gt;
&lt;div/&gt;</content><source><title>jointhefreeworld</title></source></entry><entry><title>Scheme Requests for Implementation: SRFI 270: Hexadecimal Floating-Point Constants</title><link href="https://srfi.schemers.org/srfi-270/" rel="alternate"/><id>https://srfi.schemers.org/srfi-270/</id><updated>2026-07-18T12:00:00-08:00</updated><author><name>Peter McGoron</name></author><content type="html">SRFI 270 is now in &lt;em&gt;final&lt;/em&gt; status.&lt;blockquote&gt;&lt;p&gt;
 Floating-point numbers are usually stored in radix 2, but are written by
 users in radix 10. This SRFI introduces Scheme syntax for hexadecimal floating
 point constants based on C99’s syntax. They use radix 16 for writing
 the integer and fractional part, and a radix 10 exponent part that raises
 the whole value to a power of 2.
&lt;/p&gt;&lt;/blockquote&gt;</content><source><title>Scheme Requests for Implementation</title></source></entry><entry><title>Scheme Requests for Implementation: SRFI 271: Random port libraries</title><link href="https://srfi.schemers.org/srfi-271/" rel="alternate"/><id>https://srfi.schemers.org/srfi-271/</id><updated>2026-07-18T12:00:00-08:00</updated><author><name>Wolfgang Corcoran-Mathe</name></author><content type="html">SRFI 271 is now in &lt;em&gt;final&lt;/em&gt; status.&lt;blockquote&gt;&lt;p&gt;This SRFI proposes a pattern of libraries for binary input ports
  that produce random bytes. Libraries are divided into
  “randomized” and “determinized” categories to address different
  uses of random data. The design leaves the details of random
  number generation to the implementer and the transformation of
  bytes to other types (floats, etc.) to higher-level libraries.
  A mechanism for saving random-port states and
  propagating them to new ports is also provided.&lt;/p&gt;&lt;/blockquote&gt;</content><source><title>Scheme Requests for Implementation</title></source></entry><entry><title>Scheme Requests for Implementation: SRFI 278: Supplemental Numerics</title><link href="https://srfi.schemers.org/srfi-278/" rel="alternate"/><id>https://srfi.schemers.org/srfi-278/</id><updated>2026-07-18T12:00:00-08:00</updated><author><name>Peter McGoron</name></author><content type="html">SRFI 278 is now in &lt;em&gt;draft&lt;/em&gt; status.&lt;blockquote&gt;&lt;p&gt;
  This SRFI defines procedures on Scheme numbers that aim to improve the
  portability and usefulness of Scheme arithmetic. These procedures include
  predicates with extended domains, hyperbolic and inverse hyperbolic
  functions, the &lt;span class=&quot;report-name&quot;&gt;R&lt;sup&gt;6&lt;/sup&gt;RS&lt;/span&gt; numeric
  tower, and additional procedures for rounding. Also included are
  recommendations and justifications for mixed inexact/exact arithmetic
  to make complex number arithmetic more predictable.
&lt;/p&gt;&lt;/blockquote&gt;</content><source><title>Scheme Requests for Implementation</title></source></entry><entry><title>jointhefreeworld: Maak: The power of Lisp that powers your trusty command runner and the enlightments</title><link href="https://jointhefreeworld.org/blog/articles/lisps/maak/index.html" rel="alternate"/><id>https://jointhefreeworld.org/blog/articles/lisps/maak/index.html</id><updated>2026-07-15T01:00:00+02:00</updated><content type="html">&lt;div id=&quot;content&quot; class=&quot;content max-w-full&quot;&gt; &lt;p&gt;
 &lt;i&gt;The infinitely extensible command runner, control plane and project automator à la Make (Guile Scheme - Lisp)&lt;/i&gt;
&lt;/p&gt;

 &lt;p&gt;
Find the project at  &lt;a href=&quot;https://codeberg.org/jjba23/maak&quot;&gt;https://codeberg.org/jjba23/maak&lt;/a&gt;
&lt;/p&gt;

 &lt;p&gt;
Most build tools invent their own limited domain-specific language.  Maak embraces the powerful  &lt;b&gt;λ Lisp&lt;/b&gt;.
&lt;/p&gt;

 &lt;p&gt;
This also means your code is solid, reliable and robust for the next 50 years at least.
&lt;/p&gt;

 &lt;p&gt;
If you like my work, please support me by  &lt;a href=&quot;https://bmc.link/jjbigorra&quot;&gt;buying me a cup of coffee ☕&lt;/a&gt; so I can continue with a lot of motivation.
&lt;/p&gt;

 &lt;div&gt;
   &lt;img src=&quot;https://jointhefreeworld.org/ggg/dist/scheme-guile.svg&quot; alt=&quot;Scheme Guile&quot;/&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt; &lt;img src=&quot;https://jointhefreeworld.org/ggg/dist/gnu-guix.svg&quot; alt=&quot;GNU Guix&quot;/&gt;&lt;img/&gt; &lt;img src=&quot;https://jointhefreeworld.org/ggg/dist/maak.svg&quot; alt=&quot;Maak&quot;/&gt;&lt;img/&gt; &lt;img src=&quot;https://jointhefreeworld.org/ggg/dist/license-gpl3+.svg&quot; alt=&quot;GPLv3+&quot;/&gt;&lt;img/&gt; &lt;img src=&quot;https://jointhefreeworld.org/ggg/dist/license-fdl13+.svg&quot; alt=&quot;FDLv1.3+&quot;/&gt;&lt;img/&gt; &lt;img src=&quot;https://jointhefreeworld.org/ggg/dist/jointhefreeworld-org.svg&quot; alt=&quot;Join The Free World&quot;/&gt;&lt;img/&gt;&lt;/div&gt;

 &lt;hr/&gt;&lt;hr/&gt; &lt;h2&gt;Core features  &lt;a id=&quot;core-features&quot; class=&quot;anchor&quot; href=&quot;#core-features&quot;&gt;#&lt;/a&gt;&lt;/h2&gt; &lt;div class=&quot;outline-text-2&quot; id=&quot;text-orge3e2d9c&quot;&gt;
 &lt;p&gt;
Instead of learning a limited DSL, you can leverage your existing Lisp skills to define tasks, manage data, and automate your workflows with ease. Define functions, manipulate lists, use conditional, create macros—the entire language is at your disposal.
&lt;/p&gt;

 &lt;p&gt;
You can also easily call external shell commands and integrate with your existing scripts and tools.
&lt;/p&gt;

 &lt;p&gt;
All you will need to do to use Maak is to write a file (by default  &lt;code&gt;./maak.scm&lt;/code&gt;) where you define your Maak file module and import Maak library:
&lt;/p&gt;

 &lt;pre&gt;( &lt;span class=&quot;org-keyword&quot;&gt;define-module&lt;/span&gt; ( &lt;span class=&quot;org-type&quot;&gt;maak&lt;/span&gt;)
   &lt;span class=&quot;org-builtin&quot;&gt;#:declarative?&lt;/span&gt; #t
   &lt;span class=&quot;org-builtin&quot;&gt;#:use-module&lt;/span&gt; (maak maak))&lt;/pre&gt;

 &lt;hr/&gt;&lt;hr/&gt;&lt;/div&gt;
 &lt;h2&gt;Defining tasks  &lt;a id=&quot;defining-tasks&quot; class=&quot;anchor&quot; href=&quot;#defining-tasks&quot;&gt;#&lt;/a&gt;&lt;/h2&gt; &lt;div class=&quot;outline-text-2&quot; id=&quot;text-org4b9934e&quot;&gt;
 &lt;p&gt;
Any function (with or without arguments) you define in this file becomes a runnable task.
&lt;/p&gt;
&lt;/div&gt;
 &lt;h3&gt;Task Export &amp; Visibility Rule  &lt;a id=&quot;task-export-amp-visibility-rule&quot; class=&quot;anchor&quot; href=&quot;#task-export-amp-visibility-rule&quot;&gt;#&lt;/a&gt;&lt;/h3&gt; &lt;div class=&quot;outline-text-3&quot; id=&quot;text-orgbf7f26c&quot;&gt;
 &lt;ul class=&quot;org-ul&quot;&gt; &lt;li&gt; &lt;b&gt;Open Fallback (No Exports)&lt;/b&gt;: If you do not write an  &lt;code&gt;#:export&lt;/code&gt; directive in your module (or leave it empty), Maak is completely “open season”: all procedures in the file are treated as runnable tasks.&lt;/li&gt;
 &lt;li&gt; &lt;b&gt;Strict Lock (With Exports)&lt;/b&gt;: If you define anything in your  &lt;code&gt;#:export&lt;/code&gt; directive (e.g.,  &lt;code&gt;#:export (quick-math)&lt;/code&gt;), then only the explicitly exported procedures will be treated as tasks. Any other functions become private helper procedures and are completely hidden from the CLI and  &lt;code&gt;--list&lt;/code&gt; command.&lt;/li&gt;
&lt;/ul&gt; &lt;p&gt;
If no task is passed via command-line, Maak will run the  &lt;code&gt;default&lt;/code&gt; task.
&lt;/p&gt;

 &lt;p&gt;
Tasks can:
&lt;/p&gt;
 &lt;ul class=&quot;org-ul&quot;&gt; &lt;li&gt;Run shell commands with the  &lt;code&gt;$&lt;/code&gt; helper.&lt;/li&gt;
 &lt;li&gt;Print logs with  &lt;code&gt;log-info&lt;/code&gt;.&lt;/li&gt;
 &lt;li&gt;Call other Maak tasks.&lt;/li&gt;
 &lt;li&gt;Use any Guile Scheme function you define (or import from a library).&lt;/li&gt;
 &lt;li&gt;Some syntactic sugar for working with Guix dev shells and time-machine, e.g.   &lt;code&gt;manifest-shell&lt;/code&gt; and  &lt;code&gt;program-shell&lt;/code&gt; as well as  &lt;code&gt;time-machine-manifest-shell&lt;/code&gt; and more&lt;/li&gt;
&lt;/ul&gt; &lt;p&gt;
⚠️ Beware not to use names for tasks that conflict with names of built-in Scheme functions as this can cause some problems. For example, avoid calling something  &lt;code&gt;format&lt;/code&gt; or  &lt;code&gt;display&lt;/code&gt;, choose something else instead.
&lt;/p&gt;

 &lt;p&gt;
You can extend Maak by defining new tasks — just like writing functions in Scheme.
&lt;/p&gt;

 &lt;p&gt;
Here’s an example:
&lt;/p&gt;

 &lt;pre&gt;( &lt;span class=&quot;org-keyword&quot;&gt;define&lt;/span&gt; ( &lt;span class=&quot;org-function-name&quot;&gt;hello&lt;/span&gt;)
   &lt;span class=&quot;org-string&quot;&gt;&quot;Say hello from Maak!&quot;&lt;/span&gt;
  (display  &lt;span class=&quot;org-string&quot;&gt;&quot;Hello from Maak!&quot;&lt;/span&gt;)
  (display (format #f  &lt;span class=&quot;org-string&quot;&gt;&quot;~a + ~a = ~a&quot;&lt;/span&gt; 3 4 (+ 3 4))))

( &lt;span class=&quot;org-keyword&quot;&gt;define&lt;/span&gt; ( &lt;span class=&quot;org-function-name&quot;&gt;quick-math&lt;/span&gt; x-arg y-arg)
   &lt;span class=&quot;org-comment-delimiter&quot;&gt;;; &lt;/span&gt; &lt;span class=&quot;org-comment&quot;&gt;beware task args come always as strings due to CLI parse
&lt;/span&gt;  ( &lt;span class=&quot;org-keyword&quot;&gt;let*&lt;/span&gt; ((x (string-&gt;number x-arg))
         (y (string-&gt;number y-arg)))
    (format #t  &lt;span class=&quot;org-string&quot;&gt;&quot;~a + ~a = ~a&quot;&lt;/span&gt; x y
            (+ x y))))&lt;/pre&gt;

 &lt;p&gt;
You can now run it:
&lt;/p&gt;

 &lt;pre&gt;maak hello
maak quick-math 23 42&lt;/pre&gt;

 &lt;p&gt;
You can also run multiple tasks easily (sequentially) via a comma-separated list :
&lt;/p&gt;

 &lt;pre&gt;maak fmt,compile,test&lt;/pre&gt;

 &lt;p&gt;
Often it’s just cleaner to do it directly in Lisp (Scheme code ) in your Maakfile (where it’s also trivial to add concurrent computations)
&lt;/p&gt;

 &lt;p&gt;
More advanced examples here and below:
&lt;/p&gt;

 &lt;pre&gt; &lt;span class=&quot;org-comment-delimiter&quot;&gt;;; &lt;/span&gt; &lt;span class=&quot;org-comment&quot;&gt;Format Scheme source code files according to the Guix style guide.
&lt;/span&gt;( &lt;span class=&quot;org-keyword&quot;&gt;define&lt;/span&gt; ( &lt;span class=&quot;org-function-name&quot;&gt;fmt&lt;/span&gt;)
  (log-info  &lt;span class=&quot;org-string&quot;&gt;&quot;Format Scheme files using Guix Style&quot;&lt;/span&gt;)
  ($ '( &lt;span class=&quot;org-string&quot;&gt;&quot;find . -maxdepth 8 -name '*.scm'&quot;&lt;/span&gt;
        &lt;span class=&quot;org-string&quot;&gt;&quot;-type f -exec guix style -f {} \\;&quot;&lt;/span&gt;)
      &lt;span class=&quot;org-builtin&quot;&gt;#:verbose?&lt;/span&gt; #t))

 &lt;span class=&quot;org-comment-delimiter&quot;&gt;;; &lt;/span&gt; &lt;span class=&quot;org-comment&quot;&gt;Display program help screen.
&lt;/span&gt;( &lt;span class=&quot;org-keyword&quot;&gt;define&lt;/span&gt; ( &lt;span class=&quot;org-function-name&quot;&gt;help&lt;/span&gt;)
  ($ '( &lt;span class=&quot;org-string&quot;&gt;&quot;guix shell -f guix.scm -- maak --help&quot;&lt;/span&gt;)))

 &lt;span class=&quot;org-comment-delimiter&quot;&gt;;; &lt;/span&gt; &lt;span class=&quot;org-comment&quot;&gt;By default (no task given) run help.
&lt;/span&gt;( &lt;span class=&quot;org-keyword&quot;&gt;define&lt;/span&gt; ( &lt;span class=&quot;org-function-name&quot;&gt;default&lt;/span&gt;)
  ($ '( &lt;span class=&quot;org-string&quot;&gt;&quot;maak --list&quot;&lt;/span&gt;))

 &lt;span class=&quot;org-comment-delimiter&quot;&gt;;; &lt;/span&gt; &lt;span class=&quot;org-comment&quot;&gt;Do some quick math
&lt;/span&gt;( &lt;span class=&quot;org-keyword&quot;&gt;define&lt;/span&gt; ( &lt;span class=&quot;org-function-name&quot;&gt;arithmetics&lt;/span&gt;)
  (fmt)  &lt;span class=&quot;org-comment-delimiter&quot;&gt;;; &lt;/span&gt; &lt;span class=&quot;org-comment&quot;&gt;call another task first
&lt;/span&gt;  ( &lt;span class=&quot;org-keyword&quot;&gt;let*&lt;/span&gt; ((entries '(1 3 5 7 9))
         (arithmetics ( &lt;span class=&quot;org-keyword&quot;&gt;lambda&lt;/span&gt;(x) (* x x 3)))
         (some-data ( &lt;span class=&quot;org-keyword&quot;&gt;map&lt;/span&gt; arithmetics entries)))
    (log-info  &lt;span class=&quot;org-string&quot;&gt;&quot;Running default task&quot;&lt;/span&gt;)
    (log-info  &lt;span class=&quot;org-string&quot;&gt;&quot;Performed some fun arithmetics:\nResult: ~a&quot;&lt;/span&gt; some-data)))&lt;/pre&gt;

 &lt;hr/&gt;&lt;hr/&gt; &lt;div id=&quot;org98e91d2&quot; class=&quot;figure&quot;&gt;
 &lt;p&gt; &lt;img loading=&quot;lazy&quot; src=&quot;https://jointhefreeworld.org/static-assets/maak/new-maak-small.png&quot;/&gt;&lt;img/&gt;&lt;/p&gt;
&lt;/div&gt;

 &lt;p&gt;
The project logo of maak was generated by the ChatGPT Dall-E LLM when fed this very document
&lt;/p&gt;

 &lt;hr/&gt;&lt;hr/&gt;&lt;/div&gt;
 &lt;h2&gt;Command Line Interface Options  &lt;a id=&quot;command-line-interface-options&quot; class=&quot;anchor&quot; href=&quot;#command-line-interface-options&quot;&gt;#&lt;/a&gt;&lt;/h2&gt; &lt;div class=&quot;outline-text-2&quot; id=&quot;text-org7c3577a&quot;&gt;
 &lt;p&gt;
Maak provides standard CLI options to manage your execution pipeline:
&lt;/p&gt;

 &lt;table border=&quot;2&quot; cellspacing=&quot;0&quot; cellpadding=&quot;6&quot;&gt; &lt;colgroup&gt; &lt;col class=&quot;org-left&quot;/&gt; &lt;col class=&quot;org-left&quot;/&gt; &lt;col class=&quot;org-left&quot;/&gt; &lt;col class=&quot;org-left&quot;/&gt;&lt;/colgroup&gt; &lt;thead&gt; &lt;tr&gt; &lt;th scope=&quot;col&quot; class=&quot;org-left&quot;&gt;Short Flag&lt;/th&gt;
 &lt;th scope=&quot;col&quot; class=&quot;org-left&quot;&gt;Long Flag&lt;/th&gt;
 &lt;th scope=&quot;col&quot; class=&quot;org-left&quot;&gt;Argument&lt;/th&gt;
 &lt;th scope=&quot;col&quot; class=&quot;org-left&quot;&gt;Description&lt;/th&gt;
&lt;/tr&gt;&lt;/thead&gt; &lt;tbody&gt; &lt;tr&gt; &lt;td class=&quot;org-left&quot;&gt; &lt;code&gt;-f&lt;/code&gt;&lt;/td&gt;
 &lt;td class=&quot;org-left&quot;&gt; &lt;code&gt;--file&lt;/code&gt;&lt;/td&gt;
 &lt;td class=&quot;org-left&quot;&gt; &lt;code&gt;FILE&lt;/code&gt;&lt;/td&gt;
 &lt;td class=&quot;org-left&quot;&gt;Specify the path to the Maak file (defaults to  &lt;code&gt;./maak.scm&lt;/code&gt;).&lt;/td&gt;
&lt;/tr&gt; &lt;tr&gt; &lt;td class=&quot;org-left&quot;&gt; &lt;code&gt;-h&lt;/code&gt;&lt;/td&gt;
 &lt;td class=&quot;org-left&quot;&gt; &lt;code&gt;--help&lt;/code&gt;&lt;/td&gt;
 &lt;td class=&quot;org-left&quot;&gt;None&lt;/td&gt;
 &lt;td class=&quot;org-left&quot;&gt;Display the help screen and exit.&lt;/td&gt;
&lt;/tr&gt; &lt;tr&gt; &lt;td class=&quot;org-left&quot;&gt; &lt;code&gt;-l&lt;/code&gt;&lt;/td&gt;
 &lt;td class=&quot;org-left&quot;&gt; &lt;code&gt;--list&lt;/code&gt;&lt;/td&gt;
 &lt;td class=&quot;org-left&quot;&gt;None&lt;/td&gt;
 &lt;td class=&quot;org-left&quot;&gt;List all available tasks in the currently loaded Maak file.&lt;/td&gt;
&lt;/tr&gt; &lt;tr&gt; &lt;td class=&quot;org-left&quot;&gt; &lt;code&gt;-n&lt;/code&gt;&lt;/td&gt;
 &lt;td class=&quot;org-left&quot;&gt; &lt;code&gt;--dry-run&lt;/code&gt;&lt;/td&gt;
 &lt;td class=&quot;org-left&quot;&gt;None&lt;/td&gt;
 &lt;td class=&quot;org-left&quot;&gt;Dry-run mode. Print shell commands instead of executing them.&lt;/td&gt;
&lt;/tr&gt; &lt;tr&gt; &lt;td class=&quot;org-left&quot;&gt; &lt;code&gt;-q&lt;/code&gt;&lt;/td&gt;
 &lt;td class=&quot;org-left&quot;&gt; &lt;code&gt;--quiet&lt;/code&gt;&lt;/td&gt;
 &lt;td class=&quot;org-left&quot;&gt;None&lt;/td&gt;
 &lt;td class=&quot;org-left&quot;&gt;Quiet mode. Suppress standard logging, banners, and header outputs.&lt;/td&gt;
&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt; &lt;p&gt;
To pass arguments directly to a task, it’s recommended to separate options from tasks with a double-dash ( &lt;code&gt;--&lt;/code&gt;):
&lt;/p&gt;

 &lt;pre&gt; &lt;span class=&quot;org-comment-delimiter&quot;&gt;# &lt;/span&gt; &lt;span class=&quot;org-comment&quot;&gt;Run clean and build in dry-run mode, quietly
&lt;/span&gt;maak -n -q -- clean,build

 &lt;span class=&quot;org-comment-delimiter&quot;&gt;# &lt;/span&gt; &lt;span class=&quot;org-comment&quot;&gt;Run a custom task with arguments
&lt;/span&gt;maak -f ./my-tasks.scm -- deploy production&lt;/pre&gt;


 &lt;hr/&gt;&lt;hr/&gt;&lt;/div&gt;
 &lt;h2&gt;Examples of maak files  &lt;a id=&quot;examples-of-maak-files&quot; class=&quot;anchor&quot; href=&quot;#examples-of-maak-files&quot;&gt;#&lt;/a&gt;&lt;/h2&gt; &lt;div class=&quot;outline-text-2&quot; id=&quot;text-org72094af&quot;&gt;
 &lt;p&gt;
Find below a list of some projects using maak for their automation. Reminder:  &lt;code&gt;maak.scm&lt;/code&gt; is the default name of a maak file, but you can choose to use a different one.
&lt;/p&gt;

 &lt;ul class=&quot;org-ul&quot;&gt; &lt;li&gt; &lt;a href=&quot;https://codeberg.org/jjba23/heks-linux&quot;&gt;Heks GNU/Linux&lt;/a&gt; - The witches’ GNU/Linux: modular, flexible, reproducible, powered by Lisp and Fedora / Debian + GNOME / Niri&lt;/li&gt;
 &lt;li&gt; &lt;a href=&quot;https://codeberg.org/jjba23/lucidplan&quot;&gt;LucidPlan&lt;/a&gt; - Project management (CMS) for everyone - free and open&lt;/li&gt;
 &lt;li&gt; &lt;a href=&quot;https://codeberg.org/jjba23/veritas&quot;&gt;Veritas&lt;/a&gt; - Unit, Integration and Black Box testing framework powered by Lisp (Guile Scheme)&lt;/li&gt;
 &lt;li&gt; &lt;a href=&quot;https://codeberg.org/jjba23/mutastructura&quot;&gt;Mutastructura&lt;/a&gt; -  Relational Schema and Database Migrations powered by Lisp (Guile Scheme)&lt;/li&gt;
 &lt;li&gt; &lt;a href=&quot;https://codeberg.org/jjba23/ggg&quot;&gt;GGG (Guile Glyph Generator)&lt;/a&gt; - Create SVG images, handy useful glyphs, org/markdown badges.&lt;/li&gt;
 &lt;li&gt; &lt;a href=&quot;https://codeberg.org/jjba23/hygguile&quot;&gt;Hygguile&lt;/a&gt; - UI framework for cozy and professional user-interfaces for everyone with the power of Scheme.&lt;/li&gt;
 &lt;li&gt; &lt;a href=&quot;https://codeberg.org/jjba23/sss&quot;&gt;SSS (Supreme Sexp System)&lt;/a&gt; - SSS is a Lisp machine adventure, where the hacking culture is celebrated. This custom GNU + Linux setup enhances customization to infinity, encourages the hacking spirit.&lt;/li&gt;
&lt;/ul&gt; &lt;hr/&gt;&lt;hr/&gt;&lt;/div&gt;
 &lt;h2&gt;Why write Maak ?  &lt;a id=&quot;why-write-maak-&quot; class=&quot;anchor&quot; href=&quot;#why-write-maak-&quot;&gt;#&lt;/a&gt;&lt;/h2&gt; &lt;div class=&quot;outline-text-2&quot; id=&quot;text-org3a13851&quot;&gt;
 &lt;p&gt;
Have you ever found Makefile to be repetitive, lacking expressiveness and having a weird, limited syntax and unexpected arcane behavior?
&lt;/p&gt;

 &lt;p&gt;
No fear,  &lt;b&gt;Maak&lt;/b&gt; is here. With the full power of Lisp directly in your command runner/control plane,  easily define functions, data, lists, loop through them, macros, etc. Maak replaces the arcane syntax of Make with the power and elegance of a full-featured functional programming language: GNU Guile Scheme λ.
&lt;/p&gt;

 &lt;p&gt;
Maak replaces Make’s runes and mystery with the power and clarity of GNU Guile Scheme λ.
&lt;/p&gt;
&lt;/div&gt;
 &lt;h2&gt;The Problems with Make  &lt;a id=&quot;the-problems-with-make&quot; class=&quot;anchor&quot; href=&quot;#the-problems-with-make&quot;&gt;#&lt;/a&gt;&lt;/h2&gt; &lt;div class=&quot;outline-text-2&quot; id=&quot;text-orgbade776&quot;&gt;
 &lt;p&gt;
Many developers find GNU Make and related tooling to be at times frustrating and not intuitive, despite being so powerful.
&lt;/p&gt;

 &lt;p&gt;
Makefile often contains  &lt;i&gt;repetitive&lt;/i&gt; code, particularly when dealing with similar targets or file types. You might have to write a separate rule for every single output file, even if the process is exactly the same. The limited syntax makes it difficult to abstract this logic into reusable functions or macros, leading to a lot of copy-pasting.
&lt;/p&gt;

 &lt;p&gt;
Make’s syntax is a Domain-Specific Language (DSL), not a general-purpose programming language. While it’s powerful for its intended purpose of managing dependencies, it’s  &lt;i&gt;terrible for anything else&lt;/i&gt;.
&lt;/p&gt;

 &lt;p&gt;
Defining variables, using conditionals, or looping over a list of items can be surprisingly clunky and often requires arcane, non-standard constructs.
&lt;/p&gt;

 &lt;p&gt;
Make has many “gotchas” that can trip up even experienced users.
&lt;/p&gt;
&lt;/div&gt;
 &lt;h2&gt;How Maak Innovates  &lt;a id=&quot;how-maak-innovates&quot; class=&quot;anchor&quot; href=&quot;#how-maak-innovates&quot;&gt;#&lt;/a&gt;&lt;/h2&gt; &lt;div class=&quot;outline-text-2&quot; id=&quot;text-org6c06ebb&quot;&gt;
 &lt;p&gt;
Maak positions itself as a modern infinitely extensible task runner, using the functional programming language  GNU Guile Scheme (a dialect of Lisp). No need for .PHONY recipes here.
&lt;/p&gt;

 &lt;p&gt;
Maak gives you the power of Scheme. You’re not restricted to a limited, weird syntax. This means you can easily define functions to avoid repetition, create complex data structures (like lists and maps), and use control flow statements (like loops and conditionals) to write much cleaner and more expressive scripts.
&lt;/p&gt;

 &lt;p&gt;
Instead of having to learn a new, limited language, you can leverage your existing Lisp knowledge to define tasks, manage data, and automate your workflows. This leads to code that is much easier to read, write, and maintain. For example, you can write a simple loop to process all your source files instead of writing a separate rule for each one.
&lt;/p&gt;

 &lt;p&gt;
Maak is designed to be your central control plane. While Make is primarily focused on building software from source, Maak is a general-purpose command runner. This means you can use it for tasks like running tests, deploying applications, or managing your development environment. It’s meant to be a more flexible and powerful alternative for all your project’s automation needs.
&lt;/p&gt;

 &lt;hr/&gt;&lt;hr/&gt;&lt;/div&gt;
 &lt;h2&gt;Parameterize: customize the running of tasks and commands  &lt;a id=&quot;parameterize-customize-the-running-of-tasks-and-commands&quot; class=&quot;anchor&quot; href=&quot;#parameterize-customize-the-running-of-tasks-and-commands&quot;&gt;#&lt;/a&gt;&lt;/h2&gt; &lt;div class=&quot;outline-text-2&quot; id=&quot;text-org9b534d7&quot;&gt;
 &lt;p&gt;
Dry-run and quietness can be defined globally using the command-line options ( &lt;code&gt;-n&lt;/code&gt; /  &lt;code&gt;-q&lt;/code&gt;), but they are also easily controlled and overridden in lexical scope via Lisp (Scheme) parameters.
&lt;/p&gt;

 &lt;p&gt;
This gives you a highly precise control mechanism when testing. For example, you can write a test task that dynamically runs destructive file manipulations safely in a localized dry-run scope, without requiring the user to pass a CLI flag.
&lt;/p&gt;

 &lt;p&gt;
Dry-runs for example are  good for testing.
&lt;/p&gt;

 &lt;pre&gt;( &lt;span class=&quot;org-keyword&quot;&gt;define&lt;/span&gt; ( &lt;span class=&quot;org-function-name&quot;&gt;fmt&lt;/span&gt;)
   &lt;span class=&quot;org-string&quot;&gt;&quot;Format Scheme source code files according to the Guix style guide.&quot;&lt;/span&gt;
  (syscall  &lt;span class=&quot;org-string&quot;&gt;&quot;ls&quot;&lt;/span&gt;)  &lt;span class=&quot;org-comment-delimiter&quot;&gt;;; &lt;/span&gt; &lt;span class=&quot;org-comment&quot;&gt;this will run
&lt;/span&gt;   &lt;span class=&quot;org-comment-delimiter&quot;&gt;;; &lt;/span&gt; &lt;span class=&quot;org-comment&quot;&gt;this will not
&lt;/span&gt;  ( &lt;span class=&quot;org-keyword&quot;&gt;parameterize&lt;/span&gt; ((dry-run? #t)
                 (quiet? #f))
    (delete-file-recursively  &lt;span class=&quot;org-string&quot;&gt;&quot;tmp&quot;&lt;/span&gt;)
    ($ '( &lt;span class=&quot;org-string&quot;&gt;&quot;find . -maxdepth 8 -name '*.scm'&quot;&lt;/span&gt;
          &lt;span class=&quot;org-string&quot;&gt;&quot;-type f -exec guix style -f {} \\;&quot;&lt;/span&gt;)
        &lt;span class=&quot;org-builtin&quot;&gt;#:verbose?&lt;/span&gt; #t)))
 &lt;span class=&quot;org-comment-delimiter&quot;&gt;;; &lt;/span&gt; &lt;span class=&quot;org-comment&quot;&gt;it will print instead or unning
&lt;/span&gt; &lt;span class=&quot;org-comment-delimiter&quot;&gt;;; &lt;/span&gt; &lt;span class=&quot;org-comment&quot;&gt;[DRY-RUN]: rm -rfv tmp
&lt;/span&gt; &lt;span class=&quot;org-comment-delimiter&quot;&gt;;; &lt;/span&gt; &lt;span class=&quot;org-comment&quot;&gt;[DRY-RUN]: find . -maxdepth 8 -name '*.scm' -type f -exec guix style -f {} \;&lt;/span&gt;&lt;/pre&gt;

 &lt;hr/&gt;&lt;hr/&gt;&lt;/div&gt;
 &lt;h2&gt;Help  &lt;a id=&quot;help&quot; class=&quot;anchor&quot; href=&quot;#help&quot;&gt;#&lt;/a&gt;&lt;/h2&gt; &lt;div class=&quot;outline-text-2&quot; id=&quot;text-org9de141b&quot;&gt;
 &lt;p&gt;
The project’s automation is done using Maak itself, check the  &lt;code&gt;maak.scm&lt;/code&gt; file.
&lt;/p&gt;

 &lt;p&gt;
Also, find the technical Guile Scheme API documentation of Maak here:
&lt;/p&gt;

 &lt;p&gt;
 &lt;a href=&quot;https://jointhefreeworld.org/api-docs/maak/API.html&quot;&gt;https://jointhefreeworld.org/api-docs/maak/API.html&lt;/a&gt;
&lt;/p&gt;

 &lt;p&gt;
You can see the program’s help by invoking ggg with the  &lt;code&gt;--help&lt;/code&gt; argument or looking at  &lt;code&gt;resources/help.txt&lt;/code&gt;.
&lt;/p&gt;

 &lt;hr/&gt;&lt;hr/&gt;&lt;/div&gt;
 &lt;h2&gt;Installing  &lt;a id=&quot;installing&quot; class=&quot;anchor&quot; href=&quot;#installing&quot;&gt;#&lt;/a&gt;&lt;/h2&gt; &lt;div class=&quot;outline-text-2&quot; id=&quot;text-orga04d29e&quot;&gt;
 &lt;p&gt;
maak is officially distributed via:
&lt;/p&gt;
 &lt;ul class=&quot;org-ul&quot;&gt; &lt;li&gt;Guix package manager&lt;/li&gt;
 &lt;li&gt;Podman/Docker images&lt;/li&gt;
&lt;/ul&gt; &lt;p&gt;
 &lt;i&gt;That being said, feel free to use it as you wish, within the terms of the GNU General Public License v3 or newer.&lt;/i&gt;
&lt;/p&gt;
&lt;/div&gt;
 &lt;h3&gt;On Guix  &lt;a id=&quot;on-guix&quot; class=&quot;anchor&quot; href=&quot;#on-guix&quot;&gt;#&lt;/a&gt;&lt;/h3&gt; &lt;div class=&quot;outline-text-3&quot; id=&quot;text-orgcbee930&quot;&gt;
 &lt;p&gt;
Maak is Guix-first and caters to Guix as first-class citizen in favor of other package managers or build systems. Maak targets exclusively systems that can run Guile Scheme (and optionally Guix). Check the  &lt;code&gt;maak.scm&lt;/code&gt;, the  &lt;code&gt;guix.scm&lt;/code&gt; and  &lt;code&gt;manifest.scm&lt;/code&gt; for more details.
&lt;/p&gt;

 &lt;p&gt;
Requirements:
&lt;/p&gt;
 &lt;ul class=&quot;org-ul&quot;&gt; &lt;li&gt; &lt;b&gt;Guix&lt;/b&gt;: The Guix package manager will ensure a reproducible working software, and will manage all needed dependencies for you.&lt;/li&gt;
 &lt;li&gt; &lt;b&gt;Guile Scheme:&lt;/b&gt;  This entire program is written using the official GNU extension language, Guile Scheme.&lt;/li&gt;
&lt;/ul&gt; &lt;p&gt;
If you just want to quickly install it to your profile:
&lt;/p&gt;

 &lt;pre&gt;guix package --install-from-file=./guix.scm&lt;/pre&gt;

 &lt;p&gt;
For example, to enter an environment shell with maak temporarily you can use:
&lt;/p&gt;
 &lt;pre&gt;guix time-machine --channels=channels.scm -- shell -f guix.scm&lt;/pre&gt;

 &lt;p&gt;
You can also chain commands to it:
&lt;/p&gt;

 &lt;pre&gt;guix time-machine --channels=channels.scm --  &lt;span class=&quot;org-sh-escaped-newline&quot;&gt;\&lt;/span&gt;
     shell -f guix.scm --  &lt;span class=&quot;org-sh-escaped-newline&quot;&gt;\&lt;/span&gt;
     maak --help&lt;/pre&gt;

 &lt;p&gt;
You can also run a dev shell (with manifest)
&lt;/p&gt;
 &lt;pre&gt;guix time-machine --channels=channels.scm --  &lt;span class=&quot;org-sh-escaped-newline&quot;&gt;\&lt;/span&gt;
     shell -m manifest.scm -- guile -L ./src -c  &lt;span class=&quot;org-sh-escaped-newline&quot;&gt;\&lt;/span&gt;
      &lt;span class=&quot;org-string&quot;&gt;'((@(maak main) main))'&lt;/span&gt; --list&lt;/pre&gt;

 &lt;p&gt;
Maak is available in upstream Guix as  &lt;code&gt;maak&lt;/code&gt; in the module  &lt;code&gt;(gnu packages build-tools)&lt;/code&gt;
&lt;/p&gt;
&lt;/div&gt;
 &lt;h3&gt;On Podman/Docker  &lt;a id=&quot;on-podmandocker&quot; class=&quot;anchor&quot; href=&quot;#on-podmandocker&quot;&gt;#&lt;/a&gt;&lt;/h3&gt; &lt;div class=&quot;outline-text-3&quot; id=&quot;text-orgf5914f2&quot;&gt;
 &lt;p&gt;
Maak is also available as a Docker container, from DockerHub (also compatible with Podman).
&lt;/p&gt;

 &lt;p&gt;
 &lt;a href=&quot;https://hub.docker.com/repository/docker/jjba23/maak/general&quot;&gt;https://hub.docker.com/repository/docker/jjba23/maak/general&lt;/a&gt;
&lt;/p&gt;

 &lt;p&gt;
You can also build images of maak yourself, using  &lt;code&gt;guix pack&lt;/code&gt;. See the  &lt;code&gt;maak.scm&lt;/code&gt; file for more.
To load these tarball images, you can do  &lt;code&gt;podman load &lt; my.tar.gz&lt;/code&gt;
&lt;/p&gt;

 &lt;p&gt;
Then you can run Maak from the container, and bind your local filesystem to give access, for example:
&lt;/p&gt;

 &lt;pre&gt;docker container run -v /home/joe:/home/joe  &lt;span class=&quot;org-sh-escaped-newline&quot;&gt;\&lt;/span&gt;
    docker.io/jjba23/maak:latest  &lt;span class=&quot;org-sh-escaped-newline&quot;&gt;\&lt;/span&gt;
    maak -f /home/joe/hacking/maak/maak.scm --list&lt;/pre&gt;

 &lt;hr/&gt;&lt;hr/&gt;&lt;/div&gt;
 &lt;h2&gt;Shell completions: Bash, ZSH, Fish  &lt;a id=&quot;shell-completions-bash-zsh-fish&quot; class=&quot;anchor&quot; href=&quot;#shell-completions-bash-zsh-fish&quot;&gt;#&lt;/a&gt;&lt;/h2&gt; &lt;div class=&quot;outline-text-2&quot; id=&quot;text-orgd222764&quot;&gt;
 &lt;p&gt;
Maak offers a simple but powerful shell completion. When you are in a directory with  &lt;code&gt;maak.scm&lt;/code&gt; files, you can type  &lt;code&gt;maak&lt;/code&gt; followed by space, then hit TAB and you will see the names of maak tasks appear. This is done by reading the current file and extracting task names from it with some awk magic.
&lt;/p&gt;

 &lt;p&gt;
See the scripts at  &lt;code&gt;./scripts&lt;/code&gt; . You should “source” these script if you want these completions to be available for you.
&lt;/p&gt;

 &lt;p&gt;
You might find these variables useful (for your  &lt;code&gt;.bashrc&lt;/code&gt;,  &lt;code&gt;.zshrc&lt;/code&gt;  or  &lt;code&gt;fish&lt;/code&gt; config) specially if you run Guix, but feel free to download and load the scripts from  &lt;code&gt;./scripts&lt;/code&gt; at your will in your shell.
&lt;/p&gt;

 &lt;p&gt;
For ZSH and fish shell, scripts are also provided, and should be loaded in similar fashion. See  &lt;code&gt;./scripts&lt;/code&gt;
&lt;/p&gt;

 &lt;p&gt;
ZSH users will want to add the Maak completion script to  &lt;code&gt;$FPATH&lt;/code&gt;. Fish users will want to look at  &lt;code&gt;$fish_complete_path&lt;/code&gt;.
&lt;/p&gt;

 &lt;p&gt;
Bash example:
&lt;/p&gt;

 &lt;pre&gt; &lt;span class=&quot;org-variable-name&quot;&gt;maak_bin_install_dir&lt;/span&gt;=$( &lt;span class=&quot;org-sh-quoted-exec&quot;&gt;which maak&lt;/span&gt;)
 &lt;span class=&quot;org-variable-name&quot;&gt;maak_install_dir&lt;/span&gt;=$( &lt;span class=&quot;org-sh-quoted-exec&quot;&gt;realpath &quot;${maak_bin_install_dir}&quot;&lt;/span&gt;)
 &lt;span class=&quot;org-variable-name&quot;&gt;maak_bin&lt;/span&gt;=$( &lt;span class=&quot;org-sh-quoted-exec&quot;&gt;dirname &quot;${maak_install_dir}&quot;&lt;/span&gt;)
 &lt;span class=&quot;org-variable-name&quot;&gt;maak_store&lt;/span&gt;=$( &lt;span class=&quot;org-sh-quoted-exec&quot;&gt;dirname &quot;${maak_bin}&quot;&lt;/span&gt;)&lt;/pre&gt;


 &lt;pre&gt; &lt;span class=&quot;org-comment-delimiter&quot;&gt;#&lt;/span&gt; &lt;span class=&quot;org-comment&quot;&gt;!/usr/bin/&lt;/span&gt; &lt;span class=&quot;org-keyword&quot;&gt;env&lt;/span&gt; &lt;span class=&quot;org-comment&quot;&gt; bash
&lt;/span&gt; &lt;span class=&quot;org-variable-name&quot;&gt;maak_completions&lt;/span&gt;= &lt;span class=&quot;org-string&quot;&gt;&quot;${maak_store}/share/scripts/maak-completion.bash&quot;&lt;/span&gt;

 &lt;span class=&quot;org-comment-delimiter&quot;&gt;# &lt;/span&gt; &lt;span class=&quot;org-comment&quot;&gt;Load Maak auto-completions
&lt;/span&gt; &lt;span class=&quot;org-keyword&quot;&gt;if&lt;/span&gt; [[ -f  &lt;span class=&quot;org-string&quot;&gt;&quot;${maak_completions}&quot;&lt;/span&gt; ]];  &lt;span class=&quot;org-keyword&quot;&gt;then&lt;/span&gt;
   &lt;span class=&quot;org-builtin&quot;&gt;source&lt;/span&gt;  &lt;span class=&quot;org-string&quot;&gt;&quot;${maak_completions}&quot;&lt;/span&gt; || true
 &lt;span class=&quot;org-keyword&quot;&gt;fi&lt;/span&gt;&lt;/pre&gt;


 &lt;hr/&gt;&lt;hr/&gt;&lt;/div&gt;
 &lt;h2&gt;Maak integrations  &lt;a id=&quot;maak-integrations&quot; class=&quot;anchor&quot; href=&quot;#maak-integrations&quot;&gt;#&lt;/a&gt;&lt;/h2&gt; &lt;div class=&quot;outline-text-2&quot; id=&quot;text-org20005af&quot;&gt;
 &lt;p&gt;
Creating a connection to Maak from your favourite programmable environment should be simple.
&lt;/p&gt;

 &lt;p&gt;
You can see an Emacs integration here:  &lt;a href=&quot;https://codeberg.org/jjba23/maak.el&quot;&gt;maak.el&lt;/a&gt;
&lt;/p&gt;


 &lt;div id=&quot;org7645f58&quot; class=&quot;figure&quot;&gt;
 &lt;p&gt; &lt;img loading=&quot;lazy&quot; src=&quot;https://jointhefreeworld.org/static-assets/maak/maak-in-emacs.png&quot;/&gt;&lt;img/&gt;&lt;/p&gt;
&lt;/div&gt;

 &lt;hr/&gt;&lt;hr/&gt;&lt;/div&gt;
 &lt;h2&gt;Licensing  &lt;a id=&quot;licensing&quot; class=&quot;anchor&quot; href=&quot;#licensing&quot;&gt;#&lt;/a&gt;&lt;/h2&gt; &lt;div class=&quot;outline-text-2&quot; id=&quot;text-org80e5b94&quot;&gt;
 &lt;p&gt;
Maak and all of its source code are free software, licensed under the GNU General Public License v3 (or newer at your convenience).
&lt;/p&gt;

 &lt;p&gt;
 &lt;a href=&quot;https://www.gnu.org/licenses/gpl-3.0.html&quot;&gt;https://www.gnu.org/licenses/gpl-3.0.html&lt;/a&gt;
&lt;/p&gt;

 &lt;p&gt;
The documentation and examples, including this document, which are provided with Maak, are all licensed under the GNU Free Documentation License v1.3 (or newer at your convenience).
&lt;/p&gt;

 &lt;p&gt;
 &lt;a href=&quot;https://www.gnu.org/licenses/fdl-1.3.html&quot;&gt;https://www.gnu.org/licenses/fdl-1.3.html&lt;/a&gt;
&lt;/p&gt;

 &lt;hr/&gt;&lt;hr/&gt;&lt;/div&gt;
 &lt;h2&gt;REPL: Interactive workflow, developer power  &lt;a id=&quot;repl-interactive-workflow-developer-power&quot; class=&quot;anchor&quot; href=&quot;#repl-interactive-workflow-developer-power&quot;&gt;#&lt;/a&gt;&lt;/h2&gt; &lt;div class=&quot;outline-text-2&quot; id=&quot;text-org925016c&quot;&gt;
 &lt;p&gt;
A REPL (Read-Eval-Print Loop) is an interactive environment, which can be used connected to your console, running application, language compiler and more, which gives you superpowers as an engineer 🦸🏼.
&lt;/p&gt;

 &lt;p&gt;
Lisp dialects, more specifically Guile Scheme, have great support for this. I personally of course like to do this with  &lt;a href=&quot;https://guix.gnu.org/&quot;&gt;Guix&lt;/a&gt;,  &lt;a href=&quot;https://www.gnu.org/software/emacs/&quot;&gt;Emacs&lt;/a&gt;, ( &lt;a href=&quot;https://git.sr.ht/~abcdw/emacs-arei&quot;&gt;Arei/Ares&lt;/a&gt; +  &lt;a href=&quot;https://github.com/vspinu/sesman&quot;&gt;sesman&lt;/a&gt;) you can get an ultimate extensible powerful editor experience, miles ahead of traditional IDEs 🐂 .
&lt;/p&gt;

 &lt;p&gt;
It fundamentally changes the development workflow by eliminating the slow  &lt;i&gt;edit, save, compile, run&lt;/i&gt; cycle. Instead of writing a whole program and then running it to see what happens, you get a fast, conversational workflow. What does this mean for in practice?
&lt;/p&gt;

 &lt;ul class=&quot;org-ul&quot;&gt; &lt;li&gt; &lt;b&gt;Incremental Development:&lt;/b&gt; Write, test, inspect, evaluate one function or even one line at a time. Get immediate feedback without running the entire app.&lt;/li&gt;
 &lt;li&gt; &lt;b&gt;Powerful Debugging:&lt;/b&gt; Forget adding  &lt;code&gt;print&lt;/code&gt; statements and restarting. You can pause, inspect objects, change values, and even redefine a broken function on the fly to test a fix in any environment (yes even in production, while running).&lt;/li&gt;
 &lt;li&gt; &lt;b&gt;Fast Prototyping &amp; Learning:&lt;/b&gt; Instantly experiment with a new library or API. Just load it and start calling functions to see how they work, which is much faster than only reading documentation.&lt;/li&gt;
&lt;/ul&gt; &lt;p&gt;
When integrated into your code editor, you can execute any piece of code (a line, a selection, or a file) with a keyboard shortcut and see the result instantly, creating a seamless and powerful development experience.
&lt;/p&gt;

 &lt;hr/&gt;&lt;hr/&gt;&lt;/div&gt;
 &lt;h2&gt;AI Policy  &lt;a id=&quot;ai-policy&quot; class=&quot;anchor&quot; href=&quot;#ai-policy&quot;&gt;#&lt;/a&gt;&lt;/h2&gt; &lt;div class=&quot;outline-text-2&quot; id=&quot;text-orgcfb4017&quot;&gt;
 &lt;p&gt;
This project adheres to the  &lt;a href=&quot;https://jointhefreeworld.org/blog/articles/personal/jointhefreeworld-ai-policy/index.html&quot;&gt;jointhefreeworld AI (Artificial Intelligence) policy&lt;/a&gt;.
&lt;/p&gt;

 &lt;p&gt;
Our core principle is simple:  &lt;b&gt;AI should assist human creativity and problem-solving, never replace human reasoning.&lt;/b&gt;
&lt;/p&gt;

 &lt;p&gt;
While tools like Large Language Models (LLMs) and interactive chatbots can be beneficial for reviewing, refactoring small functions, or acting as a sounding board, they should be used with moderation.
&lt;/p&gt;

 &lt;p&gt;
We require a human in the loop for all contributions. The use of autonomous AI agents to automatically generate and submit pull requests to this project is strictly prohibited.
&lt;/p&gt;



 &lt;hr/&gt;&lt;hr/&gt;&lt;/div&gt;
 &lt;h2&gt;Code of conduct  &lt;a id=&quot;code-of-conduct&quot; class=&quot;anchor&quot; href=&quot;#code-of-conduct&quot;&gt;#&lt;/a&gt;&lt;/h2&gt; &lt;div class=&quot;outline-text-2&quot; id=&quot;text-org1104207&quot;&gt;
 &lt;p&gt;
This project adheres to the jointhefreeworld code of conduct. Find it here:
&lt;/p&gt;

 &lt;p&gt;
 &lt;a href=&quot;https://jointhefreeworld.org/blog/articles/personal/jointhefreeworld-code-of-conduct/index.html&quot;&gt;https://jointhefreeworld.org/blog/articles/personal/jointhefreeworld-code-of-conduct/index.html&lt;/a&gt;
&lt;/p&gt;

 &lt;p&gt;
In summary, we foster an inclusive, respectful, and cooperative environment for all contributors and users of this free software project. Inspired by the ideals of the GNU Project, we strive to uphold freedom, equality, and community as guiding principles. We believe that collaboration in a community of mutual respect is essential to creating excellent free software.
&lt;/p&gt;

 &lt;hr/&gt;&lt;hr/&gt;&lt;/div&gt;
 &lt;h2&gt;Maak Project  &lt;a id=&quot;maak-project&quot; class=&quot;anchor&quot; href=&quot;#maak-project&quot;&gt;#&lt;/a&gt;&lt;/h2&gt; &lt;div class=&quot;outline-text-2&quot; id=&quot;text-orgb282c94&quot;&gt;
 &lt;p&gt;
Contributing to free software is a uniquely beautiful act because it embodies principles of generosity, collaboration, and empowerment.
&lt;/p&gt;

 &lt;p&gt;
We welcome everyone to feel invited to the Maak Project, and encourage active contribution in all forms, to improve it and/or suggest improvements, brainstorm with me, make it more modular/flexible, etc, feel free to contact me @gmail.com&gt; to chat, discuss or report feedback.
&lt;/p&gt;

 &lt;p&gt;
Find here the Backlog and Kanban boards for Maak:  &lt;a href=&quot;https://lucidplan.jointhefreeworld.org/tickets/maak&quot;&gt;https://lucidplan.jointhefreeworld.org/tickets/maak&lt;/a&gt;
&lt;/p&gt;

 &lt;p&gt;
Maak embodies the spirit of GNU: simplicity, freedom, and curiosity.
It’s both a tool and a playground for learning Lisp-based automation.
&lt;/p&gt;

 &lt;p&gt;
As you grow comfortable, extend Maak — define your own DSLs, orchestrate builds, or automate your projects in elegant Scheme.
&lt;/p&gt;

 &lt;p&gt;
Happy hacking! ✨
&lt;/p&gt;

 &lt;hr/&gt;&lt;hr/&gt;&lt;/div&gt;
 &lt;h2&gt;The Philosophy of Maak  &lt;a id=&quot;the-philosophy-of-maak&quot; class=&quot;anchor&quot; href=&quot;#the-philosophy-of-maak&quot;&gt;#&lt;/a&gt;&lt;/h2&gt; &lt;div class=&quot;outline-text-2&quot; id=&quot;text-orgbf07c75&quot;&gt;
 &lt;p&gt;
Maak was designed with a few simple but powerful ideas in mind — ideas rooted in the GNU tradition and Lisp philosophy.
&lt;/p&gt;
&lt;/div&gt;
 &lt;h3&gt;Lisp as the Language of Tasks  &lt;a id=&quot;lisp-as-the-language-of-tasks&quot; class=&quot;anchor&quot; href=&quot;#lisp-as-the-language-of-tasks&quot;&gt;#&lt;/a&gt;&lt;/h3&gt; &lt;div class=&quot;outline-text-3&quot; id=&quot;text-org0a1d6b0&quot;&gt;
 &lt;p&gt;
Every build rule, every script, is a first-class Scheme function.
This means your automation scripts are  &lt;b&gt;composable&lt;/b&gt;,  &lt;b&gt;readable&lt;/b&gt;, and  &lt;b&gt;hackable&lt;/b&gt;.
&lt;/p&gt;
&lt;/div&gt;
 &lt;h3&gt;Purity and Reproducibility  &lt;a id=&quot;purity-and-reproducibility&quot; class=&quot;anchor&quot; href=&quot;#purity-and-reproducibility&quot;&gt;#&lt;/a&gt;&lt;/h3&gt; &lt;div class=&quot;outline-text-3&quot; id=&quot;text-org74a5955&quot;&gt;
 &lt;p&gt;
Maak believes in pure, deterministic environments, that’s why it integrates so well with GNU Guix 🐂.
&lt;/p&gt;
&lt;/div&gt;
 &lt;h3&gt;Small Is Beautiful  &lt;a id=&quot;small-is-beautiful&quot; class=&quot;anchor&quot; href=&quot;#small-is-beautiful&quot;&gt;#&lt;/a&gt;&lt;/h3&gt; &lt;div class=&quot;outline-text-3&quot; id=&quot;text-org8bf5155&quot;&gt;
 &lt;p&gt;
No YAML, HOCON, INI or configs, no hidden logic, no magic — just clean Scheme code.
&lt;/p&gt;

 &lt;p&gt;
Every part of Maak can be read, understood, and extended within a good afternoon of hacking ☕.
&lt;/p&gt;
&lt;/div&gt;
 &lt;h3&gt;Free as in Freedom  &lt;a id=&quot;free-as-in-freedom&quot; class=&quot;anchor&quot; href=&quot;#free-as-in-freedom&quot;&gt;#&lt;/a&gt;&lt;/h3&gt; &lt;div class=&quot;outline-text-3&quot; id=&quot;text-orgf82b589&quot;&gt;
 &lt;p&gt;
It’s free software under the GNU GPL, built to encourage curiosity, learning, and contribution.
&lt;/p&gt;

 &lt;p&gt;
You own your build logic, you can read it, change it, and share it freely.
&lt;/p&gt;

 &lt;hr/&gt;&lt;hr/&gt;&lt;/div&gt;
 &lt;h2&gt;Hacking on Maak  &lt;a id=&quot;hacking-on-maak&quot; class=&quot;anchor&quot; href=&quot;#hacking-on-maak&quot;&gt;#&lt;/a&gt;&lt;/h2&gt; &lt;div class=&quot;outline-text-2&quot; id=&quot;text-orgf0c36ce&quot;&gt;
 &lt;p&gt;
In systems where  &lt;code&gt;maak&lt;/code&gt; is already installed, a good way to compile from source and test all program functionalities is a pure shell:
&lt;/p&gt;

 &lt;pre&gt;guix shell --pure -f guix.scm  &lt;span class=&quot;org-sh-escaped-newline&quot;&gt;\&lt;/span&gt;
     bash coreutils util-linux-with-udev guile --  &lt;span class=&quot;org-sh-escaped-newline&quot;&gt;\&lt;/span&gt;
     maak --list

 &lt;span class=&quot;org-comment-delimiter&quot;&gt;# &lt;/span&gt; &lt;span class=&quot;org-comment&quot;&gt;run project tests
&lt;/span&gt;guix time-machine --channels=channels.scm --  &lt;span class=&quot;org-sh-escaped-newline&quot;&gt;\&lt;/span&gt;
     shell -f guix.scm --pure --  &lt;span class=&quot;org-sh-escaped-newline&quot;&gt;\&lt;/span&gt;
     maak test&lt;/pre&gt;
&lt;/div&gt;
&lt;div/&gt;</content><source><title>jointhefreeworld</title></source></entry><entry><title>Scheme Requests for Implementation: SRFI 277: Cyclic ports</title><link href="https://srfi.schemers.org/srfi-277/" rel="alternate"/><id>https://srfi.schemers.org/srfi-277/</id><updated>2026-07-07T12:00:00-08:00</updated><author><name>Wolfgang Corcoran-Mathe</name></author><content type="html">SRFI 277 is now in &lt;em&gt;draft&lt;/em&gt; status.&lt;blockquote&gt;    &lt;p&gt;Cyclic ports are like infinite string and bytevector input ports:
      they produce the elements of a given sequence repeatedly, forever.
      While their intended use is as reusable seeds for SRFI 271 random
      ports, they are also useful whenever a repeating sequence of one
      or more bytes or characters is needed.&lt;/p&gt;&lt;/blockquote&gt;</content><source><title>Scheme Requests for Implementation</title></source></entry><entry><title>jointhefreeworld: Hacking Freedom: Compiling GNU Emacs from Source</title><link href="https://jointhefreeworld.org/blog/articles/emacs/build-emacs-from-source/index.html" rel="alternate"/><id>https://jointhefreeworld.org/blog/articles/emacs/build-emacs-from-source/index.html</id><updated>2026-07-01T01:00:00+02:00</updated><content type="html">&lt;div id=&quot;content&quot; class=&quot;content max-w-full&quot;&gt; &lt;p&gt;
By compiling GNU Emacs directly from the upstream Savannah repositories, you unlock the absolute bleeding edge of the extensible, self-documenting operating system disguised as a text editor.
&lt;/p&gt;

 &lt;p&gt;
True autonomy over your computing environment sometimes involves building your own tools and customizing many programs.
&lt;/p&gt;

 &lt;p&gt;
We start by cloning the live development branch straight from the GNU project’s forge.
&lt;/p&gt;

 &lt;pre&gt; &lt;span class=&quot;org-comment-delimiter&quot;&gt;# &lt;/span&gt; &lt;span class=&quot;org-comment&quot;&gt;maker sure to have Git
&lt;/span&gt;sudo apt update
sudo apt upgrade

sudo apt install git

 &lt;span class=&quot;org-builtin&quot;&gt;cd&lt;/span&gt; ~/Fork  &lt;span class=&quot;org-comment-delimiter&quot;&gt;# &lt;/span&gt; &lt;span class=&quot;org-comment&quot;&gt;or wherever
&lt;/span&gt;git clone https://git.savannah.gnu.org/git/emacs.git emacs-build
 &lt;span class=&quot;org-builtin&quot;&gt;cd&lt;/span&gt; emacs-build&lt;/pre&gt;
 &lt;h2&gt;Dependencies  &lt;a id=&quot;dependencies&quot; class=&quot;anchor&quot; href=&quot;#dependencies&quot;&gt;#&lt;/a&gt;&lt;/h2&gt; &lt;div class=&quot;outline-text-2&quot; id=&quot;text-orgf940d61&quot;&gt;
 &lt;p&gt;
Depending on the compilation options we choose, we need some build and compile time dependencies. Before we can shape the metal, we need the furnace. For example in Debian we need things like:
&lt;/p&gt;

 &lt;pre&gt;sudo apt update
sudo apt install build-essential autoconf imagemagick libmagickwand-dev libgtk-3-dev librsvg2-dev libsqlite3-dev libgccjit0 libgccjit-15-dev libgnutls28-dev libtree-sitter-dev&lt;/pre&gt;

 &lt;div class=&quot;note&quot; id=&quot;orgb79ebef&quot;&gt;
 &lt;p&gt;
Pro-tip: If you want a quick shortcut to grab standard development headers for graphics and window management libraries, you can run  &lt;code&gt;sudo apt-get build-dep emacs&lt;/code&gt; before moving to the next step.
&lt;/p&gt;

&lt;/div&gt;
&lt;/div&gt;
 &lt;h2&gt;Autogen  &lt;a id=&quot;autogen&quot; class=&quot;anchor&quot; href=&quot;#autogen&quot;&gt;#&lt;/a&gt;&lt;/h2&gt; &lt;div class=&quot;outline-text-2&quot; id=&quot;text-org36d51bb&quot;&gt;
 &lt;p&gt;
Run the autogen.sh the first time
This script will generate the configuration scaffold. You only really need to do this once (and I always forget about it for this very reason). Simply do this on the command line:
&lt;/p&gt;

 &lt;p&gt;
 &lt;code&gt;./autogen.sh&lt;/code&gt;
It checks that you have all you need to get started and prints output like this:
&lt;/p&gt;

 &lt;pre class=&quot;example&quot; id=&quot;orgea01cad&quot;&gt;
Checking whether you have the necessary tools...
(Read INSTALL.REPO for more details on building Emacs)
Checking for autoconf (need at least version 2.65) ... ok
Your system has the required tools.
Building aclocal.m4 ...
Running 'autoreconf -fi -I m4' ...
Building 'aclocal.m4' in exec ...
Running 'autoreconf -fi' in exec ...
Configuring local git repository...
'.git/config' -&gt; '.git/config.~1~'
git config transfer.fsckObjects 'true'
git config diff.cpp.xfuncname '!^[ 	]*[A-Za-z_][A-Za-z_0-9]*:[[:space:]]*($|/[/*])
^((::[[:space:]]*)?[A-Za-z_][A-Za-z_0-9]*[[:space:]]*\(.*)$
^((#define[[:space:]]|DEFUN).*)$'
git config diff.elisp.xfuncname '^\([^[:space:]]*def[^[:space:]]+[[:space:]]+([^()[:space:]]+)'
git config diff.m4.xfuncname '^((m4_)?define|A._DEFUN(_ONCE)?)\([^),]*'
git config diff.make.xfuncname '^([$.[:alnum:]_].*:|[[:alnum:]_]+[[:space:]]*([*:+]?[:?]?|!?)=|define .*)'
git config diff.shell.xfuncname '^([[:space:]]*[[:alpha:]_][[:alnum:]_]*[[:space:]]*\(\)|[[:alpha:]_][[:alnum:]_]*=)'
git config diff.texinfo.xfuncname '^@node[[:space:]]+([^,[:space:]][^,]+)'
Installing git hooks...
'build-aux/git-hooks/commit-msg' -&gt; '.git/hooks/commit-msg'
'build-aux/git-hooks/pre-commit' -&gt; '.git/hooks/pre-commit'
'build-aux/git-hooks/prepare-commit-msg' -&gt; '.git/hooks/prepare-commit-msg'
'build-aux/git-hooks/post-commit' -&gt; '.git/hooks/post-commit'
'build-aux/git-hooks/pre-push' -&gt; '.git/hooks/pre-push'
'build-aux/git-hooks/commit-msg-files.awk' -&gt; '.git/hooks/commit-msg-files.awk'
'.git/hooks/applypatch-msg.sample' -&gt; '.git/hooks/applypatch-msg'
'.git/hooks/pre-applypatch.sample' -&gt; '.git/hooks/pre-applypatch'
&lt;/pre&gt;

 &lt;p&gt;
You can now run  &lt;code&gt;./configure&lt;/code&gt;
Do not be intimidated by it. Focus on the final line instead, which directs you to the configure directive.
&lt;/p&gt;
&lt;/div&gt;
 &lt;h2&gt;Configuration Flags  &lt;a id=&quot;configuration-flags&quot; class=&quot;anchor&quot; href=&quot;#configuration-flags&quot;&gt;#&lt;/a&gt;&lt;/h2&gt; &lt;div class=&quot;outline-text-2&quot; id=&quot;text-org728c4fb&quot;&gt;
 &lt;p&gt;
This is where you sculpt Emacs to your exact workflow. True hackers audit their build environment—you can inspect every configuration option available by running  &lt;code&gt;./configure --help&lt;/code&gt;.
&lt;/p&gt;

 &lt;p&gt;
For a modern, highly optimized, Wayland-native hacker workstation, these choices are optimal:
&lt;/p&gt;

 &lt;pre&gt;./configure --with-native-compilation=aot  &lt;span class=&quot;org-sh-escaped-newline&quot;&gt;\&lt;/span&gt;
            --with-tree-sitter  &lt;span class=&quot;org-sh-escaped-newline&quot;&gt;\&lt;/span&gt;
            --with-pgtk  &lt;span class=&quot;org-sh-escaped-newline&quot;&gt;\&lt;/span&gt;
            --with-dbus  &lt;span class=&quot;org-sh-escaped-newline&quot;&gt;\&lt;/span&gt;
            --with-imagemagick  &lt;span class=&quot;org-sh-escaped-newline&quot;&gt;\&lt;/span&gt;
            --with-mailutils&lt;/pre&gt;
&lt;/div&gt;
 &lt;h2&gt;Why these flags matter:  &lt;a id=&quot;why-these-flags-matter&quot; class=&quot;anchor&quot; href=&quot;#why-these-flags-matter&quot;&gt;#&lt;/a&gt;&lt;/h2&gt; &lt;div class=&quot;outline-text-2&quot; id=&quot;text-org946d1e5&quot;&gt;
 &lt;dl class=&quot;org-dl&quot;&gt; &lt;dt&gt; &lt;code&gt;--with-native-compilation=aot&lt;/code&gt;&lt;/dt&gt; &lt;dd&gt;Compiles Emacs Lisp directly into native machine code Ahead-Of-Time. Maximum performance, zero lag.&lt;/dd&gt;
 &lt;dt&gt; &lt;code&gt;--with-tree-sitter&lt;/code&gt;&lt;/dt&gt; &lt;dd&gt;Swaps out old regex parsing for high-performance, incremental AST parsing. Better structural navigation and syntax awareness.&lt;/dd&gt;
 &lt;dt&gt; &lt;code&gt;--with-pgtk&lt;/code&gt;&lt;/dt&gt; &lt;dd&gt;Pure GTK. Critical if you are running a modern Wayland compositor and want to bypass the legacy Xwayland translation layer completely.&lt;/dd&gt;
&lt;/dl&gt;&lt;/div&gt;
 &lt;h2&gt;Compile and Install  &lt;a id=&quot;compile-and-install&quot; class=&quot;anchor&quot; href=&quot;#compile-and-install&quot;&gt;#&lt;/a&gt;&lt;/h2&gt; &lt;div class=&quot;outline-text-2&quot; id=&quot;text-org1704cd4&quot;&gt;
 &lt;p&gt;
First, ensure you are starting from a completely pristine state. If you are rebuilding an older tree or updating a previous commit, wipe away old compilation artifacts:
&lt;/p&gt;

 &lt;pre&gt;make clean&lt;/pre&gt;

 &lt;p&gt;
Now, unleash the compiler. Instead of hardcoding an arbitrary job number, let’s query your machine to leverage every single parallel thread your processor has to offer:
&lt;/p&gt;

 &lt;pre&gt;make -j$( &lt;span class=&quot;org-sh-quoted-exec&quot;&gt;nproc&lt;/span&gt;)&lt;/pre&gt;

 &lt;p&gt;
Once the compilation wraps up successfully, verify your creation in-place before deploying it system-wide:
&lt;/p&gt;

 &lt;pre&gt;./src/emacs --version&lt;/pre&gt;

 &lt;p&gt;
You should be greeted by that glorious declaration of software liberty:
&lt;/p&gt;

 &lt;pre class=&quot;example&quot; id=&quot;org7793fa0&quot;&gt;
GNU Emacs 31.0.50
Copyright (C) 2026 Free Software Foundation, Inc.
GNU Emacs comes with ABSOLUTELY NO WARRANTY.
You may redistribute copies of GNU Emacs
under the terms of the GNU General Public License.
For more information about these matters, see the file named COPYING.
&lt;/pre&gt;

 &lt;p&gt;
If everything looks pristine, purge any pre-packaged, stale distro binaries and inject your custom-built system into the local environment:
&lt;/p&gt;

 &lt;pre&gt;sudo apt remove emacs emacs-pgtk
rm -rf ~/.emacs.d
sudo make install&lt;/pre&gt;

 &lt;p&gt;
Do a final check to confirm your shell path resolves directly to your new build:
&lt;/p&gt;

 &lt;pre&gt;which emacs
emacs --version&lt;/pre&gt;
&lt;/div&gt;
 &lt;h2&gt;How to Roll Back  &lt;a id=&quot;how-to-roll-back&quot; class=&quot;anchor&quot; href=&quot;#how-to-roll-back&quot;&gt;#&lt;/a&gt;&lt;/h2&gt; &lt;div class=&quot;outline-text-2&quot; id=&quot;text-org6ba9616&quot;&gt;
 &lt;p&gt;
A good hacker respects filesystem layout and modularity.  &lt;b&gt;Do not delete this build directory.&lt;/b&gt; Keeping this folder intact ensures you retain the local blueprint of your installation. If you ever want to upgrade to a newer upstream commit or cleanly purge this build from your system, simply navigate back here and run:
&lt;/p&gt;

 &lt;pre&gt;sudo make uninstall&lt;/pre&gt;

 &lt;p&gt;
Your operating environment remains clean, untainted, and completely under your control. Welcome to the bleeding edge. Happy hacking! 🚀
&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;</content><source><title>jointhefreeworld</title></source></entry><entry><title>Scheme Requests for Implementation: SRFI 124: Ephemerons</title><link href="https://srfi.schemers.org/srfi-124/" rel="alternate"/><id>https://srfi.schemers.org/srfi-124/</id><updated>2026-06-30T12:00:00-08:00</updated><author><name>John Cowan</name></author><content type="html">SRFI 124 is now in &lt;em&gt;withdrawn&lt;/em&gt; status.&lt;blockquote&gt;      &lt;p&gt;An ephemeron is an object with two components
      called its &lt;em&gt;key&lt;/em&gt; and its &lt;em&gt;datum&lt;/em&gt;. It differs from an
      ordinary pair as follows: if the garbage collector (GC) can prove that
      there are no references to the key except from the ephemeron itself and
      possibly from the datum, then it is free to &lt;em&gt;break&lt;/em&gt; the ephemeron,
      dropping its reference to both key and datum. In other words, an
      ephemeron can be broken when nobody else cares about its key. Ephemerons
      can be used to construct weak vectors or lists and (possibly in
      combination with finalizers) weak hash tables.
      &lt;/p&gt;&lt;p&gt;Much of this specification is derived with
      thanks from the MIT Scheme Reference Manual.&lt;/p&gt;&lt;/blockquote&gt;</content><source><title>Scheme Requests for Implementation</title></source></entry><entry><title>Scheme Requests for Implementation: SRFI 254: Ephemerons and Guardians</title><link href="https://srfi.schemers.org/srfi-254/" rel="alternate"/><id>https://srfi.schemers.org/srfi-254/</id><updated>2026-06-30T12:00:00-08:00</updated><author><name>Marc Nieper-Wißkirchen</name></author><content type="html">SRFI 254 is now in &lt;em&gt;final&lt;/em&gt; status.&lt;blockquote&gt;&lt;p&gt;This SRFI describes three concepts associated with the storage
  management of a Scheme system, &lt;i&gt;ephemerons&lt;/i&gt;, &lt;i&gt;guardians&lt;/i&gt;, and
&lt;i&gt;transport cell guardians&lt;/i&gt;.&lt;/p&gt;

&lt;p&gt;
  An ephemeron is a record structure with a &lt;i&gt;key&lt;/i&gt; and a &lt;i&gt;value&lt;/i&gt; field.
  An ephemeron can be &lt;i&gt;broken&lt;/i&gt;.  Breaking an ephemeron replaces the
  key and value with &lt;code&gt;#f&lt;/code&gt;.  An implementation of this SRFI
  breaks an ephemeron when it proves that the storage occupied by
  the key could be reclaimed if the ephemeron were broken.
&lt;/p&gt;

&lt;p&gt;
  A guardian is a structure containing objects as &lt;i&gt;guarded&lt;/i&gt; or
  &lt;i&gt;resurrected&lt;/i&gt; elements.  Initially, guardians are empty.
  Objects can be added in guarded elements to the guardian by the
  programmer.  An implementation of this SRFI resurrects an
  element when it proves that the storage occupied by
  the object could be reclaimed if all guardians in the system
  were empty.  Objects from resurrected elements can be queried
  and removed from the guardian by the programmer.  Instead of the
  object itself, a &lt;i&gt;representative&lt;/i&gt; can be returned.
&lt;/p&gt;

&lt;p&gt;
  A transport cell guardian is a structure containing &lt;i&gt;transport
    cells&lt;/i&gt;, similar to a guardian.  Whenever an object in a
  guarded transport cell in the transport cell guardian is
  moved by the garbage collector, the transport cell is resurrected
  so that it can be queried by the programmer.
&lt;/p&gt;&lt;/blockquote&gt;</content><source><title>Scheme Requests for Implementation</title></source></entry><entry><title>Gwen Weinholt: Loko Scheme 0.13.0</title><link href="https://weinholt.se/articles/loko-scheme-0-13-0/" rel="alternate"/><id>https://weinholt.se/articles/loko-scheme-0-13-0/</id><updated>2026-06-27T02:00:00+02:00</updated><author><name>weinholt</name></author><content type="html">&lt;p&gt;Loko Scheme 0.13.0 is now available from:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://scheme.fail/releases/loko-0.13.0.tar.gz&quot;&gt;https://scheme.fail/releases/loko-0.13.0.tar.gz&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://scheme.fail/releases/loko-0.13.0.tar.gz.sig&quot;&gt;https://scheme.fail/releases/loko-0.13.0.tar.gz.sig&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;span class=&quot;more&quot;/&gt;&lt;/p&gt;
&lt;p&gt;A bootable disk image for 64-bit PCs is available from:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://scheme.fail/releases/disk-images/loko-hdd-0.13.0.img.gz&quot;&gt;https://scheme.fail/releases/disk-images/loko-hdd-0.13.0.img.gz&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://scheme.fail/releases/disk-images/loko-hdd-0.13.0.img.gz.sig&quot;&gt;https://scheme.fail/releases/disk-images/loko-hdd-0.13.0.img.gz.sig&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The signatures are made with the GnuPG key 0xDD839B748F10AD4D.&lt;/p&gt;
&lt;p&gt;Loko Scheme 0.13.0 fixes bugs, improves performance and adds features.
See NEWS.md in the distribution for a more detailed summary of
changes.&lt;/p&gt;
&lt;p&gt;Loko Scheme is an optimizing Scheme compiler that builds statically
linked binaries for bare metal, Linux and NetBSD/amd64. It supports
the R6RS Scheme and R7RS Scheme standards.&lt;/p&gt;
&lt;p&gt;Loko Scheme’s web site is &lt;a href=&quot;https://scheme.fail&quot;&gt;https://scheme.fail&lt;/a&gt;, where you can find
the release tarballs and the manual. There is also a mailing list
at &lt;a href=&quot;https://lists.scheme.fail&quot;&gt;https://lists.scheme.fail&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Loko Scheme is licensed under the EUPL v. 1.2 or later.&lt;/p&gt;
</content><source><title>Gwen Weinholt</title></source></entry></feed>
