Building a Self-Evolving AI Agent in Under One Hundred Lines of Lisp
By leveraging Common Lisp's homoiconic nature, developers can build a recursive agent loop that dynamically writes, compiles, and registers its own tools.
Impact: Medium
Why it matters
You can design highly minimal agent systems where the LLM writes its own runtime code to expand its active tool catalog.
TL;DR
- 01Replaces bulky orchestrators with a clean 100-line SBCL agent utilizing basic recursion.
- 02Enables self-evolving toolsets where the LLM writes and compiles its own HTTP requests and parsers.
- 03Demonstrates the conceptual power of homoiconicity for model-driven programming loops.
Key facts
- Agent Core Size
- 8 lines of Common Lisp
- Total Codebase Size
- ~100 lines of SBCL
The Minimalist Lisp Agent Loop
An elegant recursive agent loop can be implemented in Common Lisp in just a few lines of code. The model's state is simply folded as arguments through the recursive stack:
(let* ((message (ref (call-model messages) "choices" 0 "message"))
(tool-calls (gethash "tool_calls" message)))
(if (and tool-calls (plusp (length tool-calls)))
(agent-loop (append messages (execute-tools tool-calls)))
messages))Self-Evolving Tool Catalogs via Eval
Instead of pre-programming tools like file readers, calculators, or web crawlers, the agent is given a single, powerful tool: the language compiler itself via eval and read-from-string. When asked to complete a task requiring external data, the model writes the necessary Lisp code, compiles it into the live image, and runs it immediately. This permits runtime adaptation without altering the core codebase.
*Caveat: Exposing an arbitrary code execution tool (eval) to an LLM poses massive security risks. This pattern must always run inside an isolated, local Docker sandbox.*
Try it in 2 minutes
(defun agent-loop (messages)
(let* ((msg (call-model messages))
(tool-calls (gethash "tool_calls" msg)))
(if tool-calls
(agent-loop (append messages (execute-tools tool-calls)))
messages)))common-lisp
✓ When to use
- When exploring sandboxed agent concepts that require zero overhead and minimal orchestration dependencies.
- To research dynamic tool creation and self-modifying software loops.
✕ When NOT to use
- In production pipelines or public servers where untrusted model outputs could compromise the host machine.
- If your team lacks familiarity with Lisp-based environments like SBCL.
What to do today
- Run a local SBCL instance inside a sandboxed Docker container to safely test the execution loop
- Experiment with passing the 'eval' tool to Claude inside your Lisp environment
Sources