r/Common_Lisp

Follow-up: the rough paper from a month ago is now a preprint. The Lisp side: an agent orchestrator in CL, and agents that edit code by form, not text.

A month ago I posted the very rough beginnings of a paper here. That version got pulled apart and rebuilt, and it is now a proper preprint: https://doi.org/10.5281/zenodo.21139628. The paper is deliberately language-neutral, though, and the system behind it is Common Lisp top to bottom: an orchestrator that runs execution graphs (the graphs themselves are plain Lisp data), agent worker loops, a process supervisor, a document store, a dashboard, and a set of MCP servers that give coding agents structured access to Lisp systems. So this follow-up is about the Lisp side, since this is the group that would ask.

The learnings that mattered most carry straight over from the paper. The first was composable domains. A domain is a bundle of instructions, skills, and tool access handed to an agent for a class of task: lisp knows the language, cl-naive knows the stack's conventions, a role adds the stance on top, and a resolver merges the layers per session. Built as one-offs they were dead weight. Redesigned to compose (stack cleanly, assume nothing about each other) they started turning up useful in places I had not planned for, and the same domains are now carrying a separate CL application build unchanged.

The second was the ratchet. An agent once delivered a load test asserting a record count was greater than or equal to zero: green forever, catches nothing, looks completely normal in review. So the loop runs backwards from instinct now. Acceptance criteria are written before the code exists, the coding agent writes no tests at all, a fresh session verifies the code against those criteria, another session then derives regression tests from them, and a judge breaks the implementation on purpose to confirm each test can actually fail. Standards move one way only. And the part I am most pleased about: the system develops itself through exactly this cycle, agents editing the orchestrator's own source through its own gates. It is the third generation of the design and only recently became my daily driver, so I will not oversell maturity.

The third was MCP tool naming, which mattered far more than it should. Models route off a tool's name, and the name drags their training priors with it. My file writer took code where every built-in file tool takes content; agents thrashed on it until I renamed the parameter. The code analyzer (definitions, callers, call graphs, effect sets over ASDF systems) sat ignored while agents grepped, until its descriptions spoke the vocabulary models already know from IDE land (Find All References, go to definition) and stated the economics plainly: the query is instant and exact, the text search is the slow, lossy path. One more rule from that fight: test your tool surface with the weakest model that can still do the work, because a strong one absorbs interface defects and hides them from you.

The fourth is the CL-only one: structural editing. Agents editing Lisp as raw text eventually break brackets, and then try to repair by counting parens, and that loop does not converge; even strong models ping-pong on it. So agents here do not edit text. The editor MCP exposes code as forms (replace this function's body, add this form after that one, validate before anything touches disk), bracket-correct by construction, courtesy of the reader treating code as data. A whole class of broken files simply stopped existing.

Everything is open, part of the opinionated cl-naive-* family (I came to Lisp late in my career, I care about usability over purity, and these libraries are geared toward shipping business software, not rocket science): https://gitlab.com/naive-x/experimental/cl-naive-full-stack-agentic-system. The preprint with the full methodology is here: https://doi.org/10.5281/zenodo.21139628. One question for this group: is anyone else giving their agents a persistent REPL to verify against, rather than only files and cold subprocesses?

reddit.com
u/Harag — 1 day ago
▲ 58 r/Common_Lisp+1 crossposts

My implementation of Common Lisp has reached version 1.7

alisp is an implementation of Common Lisp that covers most of the standard.  It ships with ASDF and is capable of loading many real-world systems.  It also has a debugger with full support for stepping.

After the redesign of lexical closures and other fixes, now the whole test.pl suite runs without leaks, according to valgrind!  That's quite an achievement.

https://savannah.nongnu.org/news/?id=10910

If you want to support this project and speed up its development, make a subscription at https://www.patreon.com/andreamonaco or at https://liberapay.com/andreamonaco.  Thank you very much!

u/Western-Movie9890 — 4 days ago
▲ 6 r/Common_Lisp+1 crossposts

Coding agent and lisp s-expressions

I've been using Opencode + a local model (Qwen3.6-35B-A3B-Claude-4.6-Opus-Reasoning-Distilled-MLX-8bit) as a coding assistant for common lisp. I've been disappointed to find that the LLM frequently fails to properly balance parentheses (although ... in some sense it's a finite automaton, and LLMs are not good at counting, so it's not that surprising).

Does anyone have a work-around for this to make a coding agent write s-expressions properly?

reddit.com
u/Not-That-rpg — 5 days ago
▲ 37 r/Common_Lisp+2 crossposts

A StumpWM module for defining dual-monitor window layouts per group

I spent way longer than I'd like to admit getting one defcommand to do "make a group, split both monitors top/bottom, launch emacs + firefox + two terminals into the correct frames every time." The annoying part I eventually realized is that run-shell-command is async, so focus frame, launch app, focus next frame, launch next app just lands everything in whichever frame was focused last.

My fix was to register a *new-window-hook*, match each new window by a substring of its WM_CLASS, and pull-window it into the right frame as it appears. Hook removes itself when all the expected windows have shown up. Once that was working I had a ~50-line blob I didn't want to copy-paste for every project, so I pulled it out into a small module: layout-groups.

It exposes one macro, define-layout-group, which takes a command name, a group title, a layout preset, and a list of (slot class-substring launcher) tuples, and expands into a defcommand that does the group/split/hook/launch sequence for you. So a writing setup becomes one form:

(define-layout-group writing "Writing" :tri-2-head-v-r

(:left "emacs" "emacsclient -c -a emacs ~/notes")

(:right-top "firefox" "firefox --no-remote -P writing")

(:right-bottom "zathura" "zathura ~/refs/handbook.pdf"))

(define-key *root-map* (kbd "W") "writing")

Re-running the command after the group exists just switches to it instead of re-splitting.

Comes with 9 presets covering dual/tri/quad layouts across two monitors in every split direction. README has the WM_CLASS gotchas you only learn the hard way (firefox --no-remote -P is the big one; without it the second firefox invocation just opens a tab and no window event ever fires for the hook to catch).

Repo: https://github.com/licjon/stumpwm-layout-groups

Caveats: presets are hardcoded to exactly 2 heads. Module lives in the :stumpwm package directly because (:use :stumpwm) doesn't import the internals you actually need (find-group, head-frames, vsplit, etc.).

u/licjon — 6 days ago
▲ 58 r/Common_Lisp+2 crossposts

FOL (Functional Object Lisp) 0.1.1 is released

FOL is a Clojure-style LISP that transpiles to Common Lisp (specifically, SBCL). The latest version, 0.1.1, has been augmented with APL/q-style array operations and adverbs. All q operations and adverbs have been implemented, but as in APL, they work on n-dimensional arrays, rather than q's one and two dimensional arrays. There are specialized arrays containing only floats <f32-array>, doubles <f64-array>, and fixnums <fixnum-array>, as well as a generic <array> type that holds anything. See the manual section on arrays for more information on these.

In addition, there have been a few transpiler optimizations made - type metadata is migrated to Common Lisp declarations, as are optimizer variable valuess. Small functions/methods can  be inlined. assoc has been optimized and now does not cost as much in loops. Direct slot access for objects has been added to the transpiler.  Type-aware collections have been added. Sequential assocs that are long enough are wrapped in transient operations. See the optimization section at the end of the manual for more information on these and other optimizations.

The next phase of this work is to check the transpliler on Common Lisp implementations other than SBCL. When I have completed testing, I will run comprehensive benchmarks on these systems and Clojure to compare their runtimes. I have the Common Lisp systems I need for the testing, other than Allegro. If anyone would like to help by testing FOL in that system, I would be grateful. Testing against Clojure to find places where the syntax is different and/or the functions are not present would be appreciated, too.

FOL can be found at GitHub.com/frankadrian314159/fol.

reddit.com
u/fadrian314159 — 13 days ago