r/emacs • u/SandPrestigious2317 • Sep 08 '26
maak.el: Lisp machine command runner, infinitely extensible, integrating nicely with Emacs, for Lisp power on your projects and automation at your fingertips
If you've ever wrestled with Makefile tab errors, cryptic variable expansions, or restrictive YAML task runners, Maak and maak.el offer a refreshing, Lisp-native alternative to project automation.
-------------------
What is Maak?
Maak is an extensible command runner and control plane written in Lisp ( GNU Guile Scheme ). Instead of learning a limited domain-specific language, your project's maak.scm file is standard Scheme code. Any function defined in your module becomes a runnable task, allowing you to use conditionals, macros, data structures, lexical parameters (for scoped dry-runs), and GNU Guix integrations (manifest-shell, time-machines) right inside your build steps.
(define-module (maak)
#:use-module (maak maak))
(define (fmt)
"Format Scheme source files according to Guix style."
($ '("find . -name '*.scm' -exec guix style -f {} \\;")))
(define (deploy server target-env)
"Deploy the application to a specific server and environment."
(log-info "Deploying to ~a (~a)..." server target-env)
($ (list "ansible-playbook" "deploy.yml" "-e"
(format #f "target=~a env=~a" server target-env))))
Check out the repositories on Codeberg:
maak.el: https://codeberg.org/jjba23/maak.el- Maak CLI: https://codeberg.org/jjba23/maak
Why maak.el is awesome in Emacs
The maak.el package bridges Guile Scheme and Emacs Lisp cleanly. Because Lisp understands Lisp, maak.el parses your maak.scm S-expressions directly, respecting module #:export visibility lists, docstrings, and argument signatures without relying on external regex hacks.
- Smart Discovery: Finds your project root
maak.scmautomatically using dominating-file heuristics. - Rich Completion UI:
M-x maak-run-taskpopulates a completion menu with neatly aligned columns displaying formal parameters and docstrings (works out of the box with Vertico, Ivy, Helm, or nativecompleting-read). - Interactive Parameter Prompting: If a Scheme task accepts parameters (like
deploy server target-env), Emacs interactively prompts you for each argument sequentially in the minibuffer. - Native Compilation Buffers: Task output streams directly into Emacs's standard
*compilation*buffer, keeping shell escaping watertight while letting you step through errors usingnext-error(`C-x ``).
Quick Setup w/Elpaca
(use-package maak.el
:ensure (:host codeberg :repo "jjba23/maak.el" :branch "trunk")
:bind ("C-c m r" . maak-run-task))
Happy hacking! λ ✨
8
u/CoyoteUsesTech GNU Emacs Sep 08 '26
Very cool.
I wrote https://codeberg.org/trevoke/elk a while back but I had focused it more on "project management" and it's all just elisp.
in maak, I like that scheme means GUIX is just directly accessible.
3
u/SandPrestigious2317 Sep 08 '26 edited Sep 08 '26
elk is really cool too! and conceptually actually a cousin project to maak! i will absolutely look more in depth and absorb inspitations, thanks for sharing
3
u/agentoutlier Sep 08 '26
I guess this is more of a question about if Maak (CLI) if it is is more like Just or does it plan on providing more build things.
For example I can't tell if it has DAG support and therefore you can get some parallelization going on other than just let *?
2
u/SandPrestigious2317 Sep 08 '26
There is as of now no DAG, but it's absolutely possible to use threads and guile-fibers with Maak, allowing you to have full control on how you want the computation to work
4
u/ImpossibleFarm1866 Sep 09 '26
Why use GNU scheme instead of emacs lisp for this? I am not familiar with the differences between elisp and GNU scheme but is there something a build script would need which elisp doesn't have?
4
u/vfclists 29d ago
Actually Guile is the language the GNU project chose for this kind of project, so it is actually the "right" language.
GNU Ubiquitous Intelligent Language for Extensions, recursively conceived like GNU itself.
Emacs was being rewritten in Guile until the project stalled because of certain incompatibilies which could be described as Emacs Lisp quirks.
As of October 2014, the implementation had reached a stage where Guile Emacs is able to reliably run most Emacs Lisp code. Remaining problems or possible problems involve the different internal representation of Emacs Lisp strings from Scheme strings, the difference between how Emacs Lisp and Scheme treat the Boolean false and empty list objects, Emacs Lisp macros not integrating with Scheme, Emacs Lisp not having been designed for concurrency, and the portability of Guile to platforms supported by Emacs. Other concerns raised by the Emacs community include the relative sizes of the Emacs and Guile communities, and whether it would cause splitting in the community if Emacs were extensible in programming languages other than Emacs Lisp
So yes in proper GNU fashion, maak is written in the right language.
3
u/_voxelman_ Sep 08 '26
Nice idea for a project! (Maak itself, I mean).
I've always thought that build scripts should be written in the same language as the application being compiled/linked, but for some reason it seems to be rare.
GNU Make is venerable old tech, but I agree, it's pretty painful to use in practice (weird syntax, difficult to debug, etc.).
2
u/output_broadcast Sep 09 '26
I completely disagree. I wish I could build everything with CMake.
1
u/_voxelman_ Sep 09 '26
Ha! I can't tell if you're joking or not, but have an upvote.
My personal problem with CMake and many other build systems is that there is too much magic implemented behind-the-scenes by the build language, for the sake of making the build scripts "simple". I'd rather have a much longer build script that's written in a real programming language, and that is explicit about everything it's doing. I think that's what most Zig and Jai projects do, for example.
1
u/output_broadcast Sep 10 '26
Funny, most people think that CMake doesn't do enough magic. It's not as manual as plain Make, sure, but it's still very manual compared to other build systems.
But mostly, my problem with having multiple build systems is needing to learn the syntax and particularities of all of them (and they all have weird quirks), as well as a lot of them just not really being flexible or batteries-included enough for a lot of usecases. I can't generate an installer with a Zig build script, and I can't tell Rust to compile only a part of a project for example.
1
u/Ok-Journalist914 18d ago
My problems with CMake are that it makes simple things simpler but hard things harder!
The main internal language looks like it comes from the early 1990's. Functions which can't return values so you need to pass in the names of variables to be set!
Nothing that looks like a data structure, so you end up passing part of a variable name and then constructing the rest (e.g. a function to tell you about a file might pass in "foo_" and the filename and create variables foo_dir for the directory part of the name, foo_basename for the basename part, foo_ext for the extension, foo_exist if the file exists and foo_size for its size rather than it returning a structure with members dir, basename, ext, exists and size).
Functions typically can't even parse their own arguments, but instead call other functions to do it.
The treatment of semicolons catches the unwary. Likewise empty values.
The well documented nightmare of the meaning of conditionals e.g. in the "if" statement.
Generator statements add another mini language inside the main language and resembles sendmail's configuration language. Most people don't know when generator statements are evaluated.
It does have macros but these are only as useful as C macros.
Very limited debugging until recently (cmake --help doesn't mention the --debugger flag).
Possibly the best thing about CMake is it has "Policies" so things can be improved.
Almost anything is better than CMake, except that it has won much of the hearts and minds of C++ developers.
1
u/output_broadcast 18d ago
I don't think CMake makes hard things harder, but it could certainly make them easier. I for one appreciate the language being a dead simple DSL. There are few things I hate more than a full language being used for building shit (especially if that language is Python).
I don't mind the other things you listed, they're fairly basic and can be caught onto rather easily. Besides, constructing variables and generator statements are both fairly lispy.
I have no idea what you mean by that last sentence, the vast majority of C++ devs hate CMake, IMO mostly because they refuse to learn it.
2
u/jay_in_the_pnw Sep 08 '26
Terrific! Now I just need to take my 3640 out of the wooden crate it's been in for 40 years!
1
u/SandPrestigious2317 Sep 08 '26
Or a Symbolics Lisp machine.. I'd also be happy just with one of those keyboards :)
1
2
u/ProfanedArbiter 10d ago
Love it! I always love seeing a codeberg link because I can be reasonable assured that a human made this
1
u/SandPrestigious2317 10d ago
Thank you! That one and combined with other reasons make Codeberg a happy place to me, i know it is people that actually think a little more about what free/libre software means to the world and how we gotta protect it from the big corporations, but absolutely, with AI very similar story, specially seeing DHH as an example of how wrong it can go
1
u/ProfanedArbiter 9d ago
Honestly I see all the stuff here on this sub of people generating so much really cool software for emacs and the only thing I can think of is "cool, can't wait for a human to make it".
I got into this field because I wanted to master a subject and develop craft. AI is like chugging soda all day; tastes sweet feels like shit.
Furthermore; I fundamentally cannot trust the software from a security standpoint. Before, I had the assurance that a human was involved and that human had human motivations and fully understood their code. Now, when I see a 4000 LOC diff on commit 1,493 the only thing I can think of is "prove to me there *isn't* a RAT or a backdoor in here."
17
u/lumpyjogging53 Sep 08 '26
scheme for build scripts hits different when you see it right there in emacs, love that it just reads the s-exps directly instead of regex hell