r/lisp

▲ 27 r/lisp

I built a coding agent in CL to see how far the live Lisp image idea can go

I’ve been building kli, a terminal coding agent written in Common Lisp, and I’m now putting it out publicly.

Just to address the obvious right of the gate. kli was built with AI assistance, it is sort of the point of all of this. However, I’m not very interested in vibecoding as "accept whatever blob the model emits and pray for the best". What I wanted to explore is whether a coding agent can be a live Lisp system where changes are inspectable, retractable, authority-scoped, testable, and patchable? And where those changes are changes to the coding assistant itself.

The core of kli is not really a coding assistant though. The boot kernel knows about live objects, a registry, an active protocol, and three verbs:

install-protocol
switch-protocol
rollback-protocol

It does not know what a model provider is. It does not know what a tool is. It does not know what a terminal UI is. It does not even know what an extension system is.

The extension protocol is the first thing installed through those verbs. After that, the system is extensions all the way down. This means that contribution kinds, capabilities, tools, model providers, commands, session logs, the agent loop, the TUI, and user extensions are all installed into the live protocol and can be retracted through it.

A small trimmed example from the editor extension:

(defextension tui-editor
  (:provides
   (method render-lines () (editor-view t) (view width)
     (render-editor-lines view width))
   (method handle-input () (editor-view t) (view input)
     (handle-editor-input view input))
   (method recode-tui-behavior () (editor-view) (editor &rest args)
     (apply #'recode-editor editor args))))

The method forms are contribution forms. Installing the extension installs methods into the running image; retracting it removes exactly those methods again. Other contribution kinds install tools, commands, event handlers, providers, settings schemas, grants, and effects with explicit retractors.

The design deliberately mixes CLOS and Let Over Lambda / pandoric closures. CLOS handles image-level, per-class behavior: generic functions, methods, live objects, protocol objects. Pandoric closures handle per-instance behavior cells which are small pieces of mutable policy or runtime behavior that can be inspected and hotpatched while keeping closed-over state.

So the editor can keep its buffer while behavior changes underneath. The transcript can keep scrollback. The agent session can recode prompt expansion, context transforms, retry policy, and compaction policy without replacing the whole session object.

To give an example of the more user-facing kind of extension one can build on top of kli I have also released cairn. It gives the agent a durable task graph to plan in and resume into. It hosts tasks, phases, dependencies, observations, handoffs, status, and a small query language over the graph. When the conversation resets, the agent reloads the plan from the graph instead of reconstructing it from old chat.

cairn started as a workflow system I developed around Claude Code, then stripped down to the pieces that kept proving useful over thousands of tasks. In kli it is not a sidecar. If installed, it is as native as the TUI (which is the main advantage of everything being an extension). It contributes tools like observe, task_bootstrap, task_query, and handoff; adds slash commands like /workon; recodes the session context transform so the current task appears in model turns; and recodes compaction so observations and handoffs survive context cuts.

Some practical notes:

  • kli is MIT licensed and built on SBCL.
  • It supports Anthropic, OpenAI, Codex, and OpenAI-compatible providers.
  • Tools carry capability metadata which is authority control, not a sandbox; shell/eval/file-write authority still runs with the process’s authority.
  • The file editing tool uses hashline anchors, so edits reject if the file drifted under the agent.

Install:

curl -fsSL https://kli.kleisli.io | sh

or:

nix run github:kleisli-io/kli

Links in comment.

reddit.com
u/CosmicMarvel — 14 hours ago
▲ 10 r/lisp

A curious question about some classes in ASDF

I wonder if someone can teach me, or explain a little bit of design in ASDF.

Typically in components list I can type:

:components ((:file file1)
             (:file file2)
                   .... ))

where files are file1.lisp, file2.lisp etc. If I want to use an other extension, in my particular case ".cl", I have two choices as I have used thus far: either type out the extension if I want to use :file, (:file file1.cl) and so on, or I can define my own source code class like this:

(defclass src (cl-source-file)
  ((type :initform "cl")))

now I can type:

:components ((:src file1)
             (:src file2)
                   .... ))

I see in also in asdf sources they have these classes defined:

;;;; Component classes
(with-upgradability ()
  (defclass cl-source-file (source-file)
    ((type :initform "lisp"))
    (:documentation "Component class for a Common Lisp source file (using type \"lisp\")"))
  (defclass cl-source-file.cl (cl-source-file)
    ((type :initform "cl"))
    (:documentation "Component class for a Common Lisp source file using type \"cl\""))
  (defclass cl-source-file.lsp (cl-source-file)
    ((type :initform "lsp"))
    (:documentation "Component class for a Common Lisp source file using type \"lsp\"")))

by the magic of mostly try-and-fail method I have figured out I can also write this atrocity:

  :components ((:cl-source-file.cl file1))

where file1 is file1.cl. I understand they meant that class probably to be extended or used elsewhere not typed out as I did there, that was just a little bit of fun. I see also this in sources:

  ;; What :file gets interpreted as, unless overridden by a :default-component-class
 (defvar *default-component-class* 'cl-source-file)

and I figured out they mean we can type this:

:default-component-class :cl-source-file.cl
:components ((:file file1))

Obviously it is not more convenient than just typing out the extension: :file file1.cl. But that is not my question.

My question is, finally I know :), sorry, what does this design buy us?

We could have obviously just used a simple list with file extensions like *component-classes* = '(cl lsp lisp), and get all this done, and it would be also let-bindable and so on. Of course, I understand also that authors are aware they could have just used a list, and that they have done deliberately that design choice, so I wonder why? I am not questioning the choice, I am trying to learn.

I read in the manual they mean that components are not necessarily just things that typically go into source files, and they give example of C processor. Is that the only reason, or are there some other reasons? Are there some more complicated uses for these source code classes, than what I see in the code, or is the generality "just in the case", to be as flexible as possible so to say?

As said, I am just curios, being looking at some libraries, mostly those on s-expressionasts Github, they use a lot of program structuring with CLOS, and not as much with "classical lisp" which a list of extensions would perhaps represent.

Today it struck me I was always curious about if I can teach :file to read all three extensions. so I was looking through ASDF and trying understand why do things get done the way they do, so to say. Trying to learn, I hope you don't misunderstand me here.

reddit.com
u/arthurno1 — 1 day ago
▲ 56 r/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
▲ 7 r/lisp

What next?

So I received some responses from my other post in r/lisp. And I tried Common Lisp and quite enjoyed it. After learning deeper on Macros and a few more stuff, I will do projects, of course. So what projects to start as a first one, any suggestions. However, I have vision for the long run, I am just not sure for the current position. So any help, tips, suggestions?

reddit.com
u/Big-Fill-5789 — 4 days ago
▲ 39 r/lisp

Lisp-11

I found a copy of Lisp-11. It runs on a PDP-11 simulator on the RT-11 operating system. It is written in PDP-11 assembly language and comes with source code. It looks like it was written at the University of Texas about 1975.

The problem is that there is no documentation. I tried a few things (+ 1 2), + (1 2), (print "hello"), and they were rejected. If anyone has pointers to documentation for this, I'd appreciate it and would enjoy playing around with a bit of Lisp history.

reddit.com
u/BrentSeidel — 5 days ago
▲ 38 r/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
▲ 50 r/lisp

Working on a lisp... glisp

about 10 days ago I started working on a lisp-like language because I don't know

It's not really ready for use yet (though I doubt anybody but me will use it), but I wanted to show off this little value visualization gui I made!! BTW the `[a b c]` brackets are equivalent to just using `(list a b c)` which I think is pretty cool. Common lisp doesn't do that! Also `@` can be used before any value and in any context to unwrap a list, and you can have multiple to go n depths: `(+ @@[1 [2] 3 [4 5]])` -> `15`. Is that a bad idea to allow? (I'm not smart when it comes to lang design)

link: https://gitlab.gnome.org/kolunmi/glisp/

Thanks and have a great day!

u/kolunmi — 7 days ago
▲ 25 r/lisp

Help, which Lisp Dialect

I am a new comer, just learnt some Racket. I adapted to S syntax, and I know functional programming(from Haskell), and Racket is well for me now. But considering the future, if Lisp dialects still stay in my reach, I might learn something else. I currently know Common Lisp, Clojure and Scheme other than Racket. I might have to pass on Scheme as I already know Racket, and Clojure bases off JVM right, does that affect me a lot(I came from Rust, Zig, C…), tried Java last time, it was okay. Common Lisp is what I don’t know much. So which should I learn next?(not EMacs Lisp)

reddit.com
u/Big-Fill-5789 — 8 days ago
▲ 31 r/lisp+1 crossposts

Is there some tour I can take or club I can visit that focuses on LISP?

I'm a software engineer and one of my major obsessions is lisp. So obviously I've been reading about MIT's strong lisp culture all my career. I mean I'm not sure right now, but historically. But is there still a remnant of something?

I'm thinking of visiting boston and I know schools like these have tours. Can I see the old lisp machines? Or is there some club that might appreciate a visit from an enthusiast with a cool lisp project?

reddit.com
u/Gold-Advertising-316 — 9 days ago
▲ 14 r/lisp+1 crossposts

Slip Lisp Development

Slip, the Lisp interpreter written in Go just got several new features related to building deployable software. Slip now has a source code coverage tool, support for shebang in scripts, the ability to execute other applications, and better ASDF like system support. https://github.com/ohler55/slip/blob/master/docs/develop.md outlines what I see as a development process. Maybe it matches your development process too.

reddit.com
u/peterohler0 — 7 days ago
▲ 43 r/lisp+4 crossposts

RacketCon 2026: call for participation

The (sixteenth RacketCon) really will be in Oakland, CA on October 3-4 (Sat-Sun).

> RacketCon is a public gathering dedicated to fostering a vibrant, innovative, and inclusive community around the Racket programming language. We aim to create an exciting and enjoyable conference open to anyone interested in Racket, filled with inspiring content, reaching and engaging both the Racket community and the wider programming world.

We are looking for speakers

Talks will be 20-25 minutes long with 5 minutes for questions at the end. Speakers' registration fees will be waived, but we are unable to cover transportation and lodging expenses.

The deadline for proposals is July 15th. Selected speakers will be notified by August 1st.

Streaming

As in previous years, RacketCon will be streamed for those unable to attend in person. Recordings will also be made available on YouTube some time after the conference. Streaming users will have the option to purchase a remote participation ticket to support the livestream.

Volunteers

Let us know if you interested in joining the team. Someone has to carry and arrange all the parentheses. :banana:

Sponsors

We are accepting sponsorships! If you would like to sponsor the conference, please contact us at con-organizers@racket-lang.org to discuss a sponsorship package that meets your needs. The Racket Programming Language Foundation is registered in Delaware and is recognizes as a 501(3)(c) public charity in the US.


Any questions, comments, or concerns? Please contact us at con-organizers@racket-lang.org.

u/sdegabrielle — 8 days ago
▲ 58 r/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 — 12 days ago
▲ 24 r/lisp+3 crossposts

Bay Area Racket Meetup #2 - Saturday, July 4, 3pm

Get ready for the

Bay Area Racket Meetup #2 - Saturday, July 4, 3pm

> Social event for people interested in the Racket programming language, other Lisps, functional programming, language-oriented programming and related topics.

Monthly (first Saturday at 3pm) until RacketCon at Noisebridge, a hackerspace in SF.^[I believe there is a Lisp meet-up at 4pm in the same space but I've not been able to confirm]

Register https://luma.com/fbd1v9ix https://racket.discourse.group/t/bay-area-racket-meetup-2-saturday-july-4-3pm/4280

reddit.com
u/sdegabrielle — 10 days ago
▲ 19 r/lisp

Quicklisp - loading broken packages

Sometimes quicklisp or ultralisp packages are broken. and (ql:quickload :broken) will not work. If you need to edit the package before quickload,

You can run: (ql::ensure-installed (ql::find-system :broken)),

then find it with (ql:where-is-system :broken),

and then edit it and run (ql:quickload :broken)

reddit.com
u/ruby_object — 11 days ago
▲ 48 r/lisp

Inventing the Future, One Lisp Machine at a Time

Conversation with Larry Masinter and Frank Halasz on Xerox PARC, Interlisp, NoteCards, and why “residential programming” still matters

patrickdomanico.com
u/lispm — 13 days ago