@yibie: Recommend this article that gave me chills. A developer recalls a professor 25 years ago saying "Lisp is the language of AI," and then he wrote a complete agent in 100 lines of Common Lisp—8 lines of recursive agent loop, one tool being e…

X AI KOLs Timeline News

Summary

A developer built an AI agent in 100 lines of Common Lisp, with the only tool being eval. The model executes code through a recursive agent loop and restores skills via a persisted transcript, showcasing Lisp's unique advantage as an AI language.

Recommend this article that gave me chills. A developer recalls a professor 25 years ago in an AI class saying "Lisp is the language of AI," and then he wrote a complete agent in 100 lines of Common Lisp—8 lines of recursive agent loop, one tool being eval (the model writes Lisp code, the agent executes it on the spot), and 20 lines of persistent memory. The most mind-blowing part isn't the simplicity—it's that the agent used its own eval to write a Brave Search function for itself, and when the process died, the function disappeared but the transcript remained. Next time it started, the agent read the history and defun'd it back. The author says: "An agent's ability is the story it tells itself." 100 Lines of Lisp Agent—or Why My Professor Was Right, Just 25 Years Early Around 2000 I took an AI course at the University of Guelph. I don't remember what I learned—no neural networks, no transformers, no CUDA. But I remember doing a lot: writing Lisp code in a dark computer lab. The professor called it "the language of AI." 25 years later, I've spent over a month building an AI agent platform. This morning, a thought tugged at the back of my brainstem: "Could Lisp be a useful language for the agent loop?" An agent is a recursive function Don't be fooled by the power of Claude Code, OpenClaw, or any other AI agent tool—strip away the framework, and the agent loop is dead simple. You have a list of messages. You send it to the model. The model either answers with text or requests to use a tool. If it requests, you run the tool, append the result, and do it again. Some agents might be implemented as a while loop with state. But maybe it's better suited for a recursive implementation with a base case. (defun agent-loop (messages) (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 (list message) (map 'list #'execute tool-calls))) (append messages (list message))))) The entire agent, 8 lines of Common Lisp. Base case: the model answers, return history. Recursive case: it wants a tool, execute the tool, recurse with the enriched message list. No joke. No framework. No state machine. The agent's state is just the parameter being folded in the recursion. With Claude's help, I assembled a complete AI agent in about 100 lines of Common Lisp, running on OpenRouter. SBCL, two libraries (dexador for HTTP, shasht for JSON), nothing else. The only tool is eval When building an agent, you typically start mounting tools—web search and crawlers, spreadsheet and file tools, Python executors, etc. In fact, most of an agent's code is a tool catalog. Lisp lets you cheat. Lisp is what language nerds call a homoiconic language—a fancy word for a simple idea: Lisp programs are written in Lisp's own data structure (lists), so code is data and data is code. A program can construct another program the same way it would build a shopping list. This means you don't need to build tools—you give the language itself to the model: (defun lisp-eval (form-string) (handler-case (format nil "~s" (eval (read-from-string form-string))) (error (e) (format nil "ERROR: ~a" e)))) One tool. The model writes Common Lisp expressions as strings. The agent reads them, evaluates them, and sends back whatever is printed. Ask it for the 30th Fibonacci number—it doesn't recall the answer, it writes a loop and runs it: • (agent:run "What is the 30th Fibonacci number? Calculate, don't recall.") ⤷ (defun fibonacci (n) ...) => FIBONACCI ⤷ (fibonacci 30) => 832040 The 30th Fibonacci number is 832040. I didn't tell it to use recursion, but in a blog post about a recursive agent loop, the model itself reached for textbook-style double-recursive Fibonacci. Its first eval defined a function in the live image, and the second eval called it. Memory is 20 lines Once the loop worked, I wanted persistence—conversations that survive across sessions. In Agent Foundry, I implemented memory with pgvector, but in this experiment, messages are already lists of hash tables—in other words, they're already JSON. Memory is just writing it down and reading it back: (defun remember (messages) (with-open-file (out memory-file :direction :output :if-exists :supersede) (shasht:write-json (coerce messages 'vector) out)) messages) (defun recall () (if (probe-file memory-file) (coerce (with-open-file (in memory-file) (shasht:read-json in)) 'list) (list system-message))) The loop itself remained completely unchanged. The entry point became a pipeline: (remember (agent-loop (append (recall) (list new-user-message)))) Recall. Recurse. Record. No schema. No migration. No storage abstraction. The serialization format is the runtime format. Tell it your name today, ask it in a new process tomorrow—it answers. Then it wrote its own web search The Fibonacci trick was neat, but that's when things got crazy. I pasted a temporary Brave Search API key into the conversation—mostly to see what would happen. And what happened surprised me a bit. The agent used its eval to defun a brave-search function in the live image. It inspected what it had, wrote the HTTP call, parsed the JSON response itself—and then started answering questions with live web results. I never built a web search tool. Pause for a second. This reverses the way we usually think about agent capabilities. In Agent Foundry, in Claude Code, in every agent platform I know, the tool catalog is fixed at design time. Someone like me decides what the agent can do, writes the tools, and publishes them. Here, the catalog is open. The model decides what it needs, writes it in its own substrate language, and evaluates it into existence. There's another twist that takes a minute to understand. The defun itself dies when the process exits—the function lives in the running Lisp image, not on disk. But the transcript persists. The source code of the Brave Search function, the process by which the model wrote it, all exist in plain text in memory.json. So in a brand new session, the function doesn't exist—until the agent re-reads its own history and evaluates it back into existence. An agent's skills—are the story it tells itself. Skills are just memory Every serious agent platform today treats the tool catalog as a design-time decision. MCP is essentially a formalization of design-time assumptions—capabilities as contracts, negotiated, versioned, and approved in advance. This experiment sits at the other pole: capabilities are determined at runtime, by the agent, in response to whatever the conversation needs. Maybe the whole industry has been sliding along this continuum without naming it. Code interpreter was the first step. Skill (SKILL.md pattern) is the second step—because a skill is just an ability stored as text, loaded at runtime. This 100-line Lisp agent just collapses the remaining distance. Its skills are stored in its own transcript. In a broader sense, this is essentially how we operate. Almost nothing you do was installed at design time. You learned it, stored it, and now reactivate it on demand—often by writing it into your own memory, like remembering the summer you learned to ride a bike. He wasn't wrong, just early Symbolic AI lost. Nobody's expert systems survived backpropagation and gradient descent. But what Lisp was truly built for—code as data, computation that can inspect, transform, and feed back into itself—turns out to be a very good description of what an agent actually is. Models do inference now. But the loop around the model—the part we actually engineer—is exactly what Lisp has always been good at. 25 years is a long time to be ahead of something. Somewhere, maybe my old AI professor is still out there ahead on something else. Full source code + Dockerfile: https://github.com/jamiebeach/lisp-agent… Original article: https://thebeach.dev/posts/lisp-agent/… #Lisp #AgentLoop #AIPaleontology
Original Article
View Cached Full Text

Cached at: 07/13/26, 07:51 AM

Here is a mind-blowing article I want to recommend. A developer recalls an AI class 25 years ago where the professor said “Lisp is the language of AI.” Then he wrote a complete agent in 100 lines of Common Lisp—an 8-line recursive agent loop, a single tool eval (the model writes Lisp code, the agent executes it on the spot), and 20 lines of persistent memory. The most shocking part isn’t the brevity—it’s that the agent used its own eval to write itself a Brave Search function. When the process died, the function vanished but the transcript remained, and on the next startup the agent read the history and defun’d it back into existence. The author says: “An agent’s capability is the story it tells itself.”

100 Lines of Lisp Agent — or Why My Professor Was Right, Just 25 Years Early

Around 2000 I took an AI course at the University of Guelph. I don’t remember what I learned—no neural networks, no transformers, no CUDA. But I remember what I did: writing a lot of Lisp code in a dark computer lab. The professor called it “the language of AI.”

25 years later, I’ve spent the last month buried in building an AI agent platform. This morning, a thought tugged at the base of my brainstem: “Could Lisp be a useful language for an agent loop?”

An Agent is a Recursive Function

Don’t be fooled by the power of Claude Code, OpenClaw, or any other AI agent tool—strip away the frameworks, and the agent loop is dead simple. You have a list of messages. You send it to the model. The model either responds with text or requests to use a tool. If it requests, you run the tool, append the result, and go again.

Some agents might implement this as a stateful while loop. But maybe it’s better suited to a recursive implementation with a base case.

(defun agent-loop (messages)
  (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
                            (list message)
                            (map 'list #'execute tool-calls)))
        (append messages (list message)))))

The entire agent, 8 lines of Common Lisp. Base case: the model responds, return history. Recursive case: it asks for a tool, execute the tools, recur with the enriched message list. No joke.

No frameworks. No state machines. The agent’s state is simply the argument folded through recursion.

With help from Claude, I assembled a complete AI agent in about 100 lines of Common Lisp, running on OpenRouter. SBCL, two libraries (dexador for HTTP, shasht for JSON), nothing else.

The Only Tool is eval

When you build an agent, you typically start mounting tools—web search and scraping, spreadsheet and file tools, Python execution, etc. In fact, most of an agent’s code is a toolkit directory.

Lisp lets you cheat. Lisp is what language nerds call homoiconic—a fancy word for a simple idea: Lisp programs are written in Lisp’s own data structures (lists), so code is data and data is code. A program can construct another program the same way it builds a shopping list.

This means you don’t need to build tools—you hand the language itself to the model:

(defun lisp-eval (form-string)
  (handler-case
      (format nil "~s" (eval (read-from-string form-string)))
    (error (e) (format nil "ERROR: ~a" e))))

One tool. The model writes a Common Lisp expression as a string. The agent reads it, evaluates it, and sends back whatever printed result.

Ask it for the 30th Fibonacci number—it doesn’t recall the answer, it writes a loop and runs it:

• (agent:run "What is the 30th Fibonacci number? Compute, don't recall.")
  ⤷ (defun fibonacci (n) ...) => FIBONACCI
  ⤷ (fibonacci 30) => 832040
The 30th Fibonacci number is 832040.

I didn’t tell it to use recursion, but in a blog post about a recursive agent loop, the model itself reached for the textbook double-recursive Fibonacci. Its first eval defined a function into the live image, and its second eval called it.

Memory is 20 Lines

Once the loop worked, I wanted persistence—conversations that survive across sessions. In Agent Foundry, I implemented memory with pgvector, but in this experiment, messages were already lists of hash tables—in other words, they were already JSON. Memory is just writing it down and reading it back:

(defun remember (messages)
  (with-open-file (out memory-file :direction :output :if-exists :supersede)
    (shasht:write-json (coerce messages 'vector) out))
  messages)

(defun recall ()
  (if (probe-file memory-file)
      (coerce (with-open-file (in memory-file) (shasht:read-json in)) 'list)
      (list system-message)))

The loop itself didn’t change at all. The entry point became a pipeline:

(remember (agent-loop (append (recall) (list new-user-message))))

Recall. Recur. Record. No schema. No migrations. No storage abstraction. The serialization format is the runtime format. Tell it your name today, ask it in a new process tomorrow—it answers.

Then It Wrote Its Own Web Search

The Fibonacci trick was neat, but then things got wild. I pasted a temporary Brave Search API key into the conversation—mostly to see what would happen. And what happened caught me off guard.

The agent used its eval to defun a brave-search function into the live image. It inspected what it had available, wrote the HTTP call, parsed the JSON response itself—and then started answering questions with live web results. I never built a web search tool.

Pause for a second. This flips the way we usually think about an agent’s capabilities. In Agent Foundry, in Claude Code, in every agent platform I know, the toolkit is fixed at design time. Someone like me decides what the agent can do, writes the tools, and ships them. Here, the toolkit is open. The model decides what it needs, writes it in its own substrate language, and evaluates it into existence.

There’s another twist that takes a minute to sink in. The defun itself dies when the process exits—the function lives in the running Lisp image, not on disk. But the transcript persists. The source code of the Brave Search function, the process of the model writing it—all of it exists as plain text in memory.json. So in a brand new session, the function doesn’t exist—until the agent reads its own history and evaluates it back into existence.

An agent’s skill—is the story it tells itself.

Skills Are Just Memory

Every serious agent platform today treats the toolkit as a design-time decision. MCP is essentially a formalization of design-time assumptions—capabilities as contracts, negotiated, versioned, and approved in advance. This experiment sits at the opposite pole: capabilities are determined at runtime, by the agent, in response to whatever the conversation needs.

Maybe the whole industry has been sliding along this continuum without naming it. Code interpreter was the first step. Skills (the SKILL.md pattern) is the second—because a skill is nothing more than a capability stored as text and loaded at runtime. This 100-line Lisp agent just collapses the remaining distance. Its skills are stored in its own transcript.

Thinking about it further, this is basically how we operate. Almost nothing you do is something that was design-time installed. You learned it, stored it, and now reactivate it on demand—often by writing it into your own memory, like remembering the summer you learned to ride a bike.

He Wasn’t Wrong, Just Early

Symbolic AI lost. Nobody’s expert systems survived against backpropagation and gradient descent. But what Lisp was actually built for—code as data, computation that can be inspected, transformed, and fed back into itself—turns out to be a very good description of what an agent is.

Models do the reasoning now. But the loop around the model—the part we actually engineer—is exactly what Lisp has always been good at.

25 years is a long time to stand too far away. Somewhere, maybe that old AI professor of mine is still ahead on something else.

Full source + Dockerfile: https://github.com/jamiebeach/lisp-agent… Original article: https://thebeach.dev/posts/lisp-agent/…

#Lisp #AgentLoop #AIArchaeology


jamiebeach/lisp-agent

Source: https://github.com/jamiebeach/lisp-agent

lisp-agent

“LISP is the language for AI.” — my professor, circa 2000

He was right. He was just 25 years early.

This is a complete AI agent in about 100 lines of Common Lisp. Recursive agent loop, one tool (the Lisp REPL itself), and persistent memory in 20 lines. It talks to any model on OpenRouter (https://openrouter.ai).

No framework. No state machine. No vector database. Just eval, append, and recursion.

The whole agent

(defun agent-loop (messages)
  (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
                            (list message)
                            (map 'list #'execute tool-calls)))
        (append messages (list message)))))

Base case: the model answers in words. Recursive case: it asks for tools, we run them and recur with the enriched history. The agent’s state is just the argument being folded through the recursion.

The only tool is eval

Code is data, data is code. So instead of building a bunch of tools, the agent gets one tool: a live Common Lisp REPL.

(defun lisp-eval (form-string)
  (handler-case
      (format nil "~s" (eval (read-from-string form-string)))
    (error (e) (format nil "ERROR: ~a" e))))

Ask it for the 30th Fibonacci number and it doesn’t recall the answer. It writes the loop and runs it.

Quick start (Docker)

docker build -t lisp-agent .

docker run -it --rm \
  -e OPENROUTER_API_KEY=sk-or-... \
  -v "$(pwd)/data:/agent/data" \
  lisp-agent

You land in a live SBCL REPL with the agent loaded:

(agent:run "What is the 30th Fibonacci number? Compute it, don't recall it.")
(agent:run "My name is Jamie.")

Exit the container. Come back tomorrow.

(agent:run "What's my name?")   ; it remembers
(agent:forget)                  ; wipe the slate

Quick start (bare metal)

Requires SBCL (https://www.sbcl.org/) and Quicklisp (https://www.quicklisp.org/).

export OPENROUTER_API_KEY=sk-or-...
sbcl --load agent.lisp

Dependencies (fetched automatically via Quicklisp): dexador (https://github.com/fukamachi/dexador) for HTTP, shasht (https://github.com/yitzchak/shasht) for JSON. That’s the whole list.

How memory works

Messages are already a list of hash tables, which is to say, already JSON in spirit. So memory is just writing the list down and reading it back:

(remember (agent-loop (append (recall) (list new-user-message))))

Recall, recur, remember. No schema, no migrations, no store abstraction. The full transcript (tool calls included) lands in memory.json, or wherever AGENT_MEMORY points.

Known limitation: it never forgets on its own, so a long-lived conversation will eventually hit the model’s context window. The natural fix is a compress step between recall and the loop, where the agent summarizes its own past. PRs welcome.

Configuration

WhatWhereDefault
API keyOPENROUTER_API_KEY env varrequired
Model*model* in agent.lispanthropic/claude-sonnet-4.5
Memory fileAGENT_MEMORY env varmemory.json

Any OpenRouter model that supports tool calling works. Swap *model* and nothing else changes.

⚠️ Read this before you get clever

eval as a tool means the model executes arbitrary code wherever the agent runs. That is the entire point, and also the entire risk. Run it in the container, mount nothing you care about, and treat the host as off limits. This is a toy for a sandbox, not a pattern for production.

Why

Symbolic AI lost. But the thing LISP was actually built for, programs as data, computation that inspects and transforms itself, turned out to be a pretty good description of what an agent is. The models do the reasoning now. The loop around them is the part LISP was always best at.

Longer version on the blog: My Prof Was Right About LISP. He Was Just 25 Years Early. (https://thebeach.dev/posts/lisp-agent)

Files

agent.lisp    the agent: loop, tool, memory (~100 lines)
Dockerfile    SBCL + Quicklisp + deps, drops you at a REPL
LICENSE       MIT

License

MIT. Go play.

Similar Articles

An agent in 100 lines of Lisp

Hacker News Top

The author reflects on learning Lisp for symbolic AI 25 years ago and demonstrates how a modern AI agent loop can be implemented in just 100 lines of Common Lisp, emphasizing the elegance of recursion.

@yibie: Every programmer should hand-write an agent. It only takes about 50 lines of code, it's fun, and it will surprise you. But to get the most out of it, do these two things: First, write it from scratch. Open a blank text file and type every line yourself. Don't use any AI, not even autocomplete. Second, rely only on the standard library documentation…

X AI KOLs Timeline

This article encourages programmers to manually write a simple AI agent (around 50 lines of code) to deepen their understanding of how agents work, and suggests writing it from scratch while relying only on standard library and API documentation.

@cellinlab: https://x.com/cellinlab/status/2064144608242679822

X AI KOLs Timeline

This article introduces the concept of Loop Engineering — instead of directly writing prompts for AI agents, it designs a system (loop) that recursively lets the agent iterate on tasks until completion. The article provides a detailed comparison of how Claude Code and Codex implement five building blocks: automations, worktrees, skills, sub-agents, etc. It suggests this could be the future trend of collaborating with coding agents, but also warns about token costs and AI slop issues.

This article systematically reviews AI Agent architecture and engineering practices, covering control flow, context engineering, tool design, memory, multi-agent organization, evaluation, tracing, and security. It is based on the OpenClaw implementation and emphasizes the critical role of Harness (testing and validation infrastructure) for system stability.

X AI KOLs

This article systematically reviews AI Agent architecture and engineering practices, covering control flow, context engineering, tool design, memory, multi-agent organization, evaluation, tracing, and security. It is based on the OpenClaw implementation and emphasizes the critical role of Harness (testing and validation infrastructure) for system stability.

@yibie: Recommended article: Eugene Yan from Anthropic (former Amazon/Alibaba ML team lead) writes a practical guide to his personal AI workflow. Not abstract ideas, but concrete methods you can replicate tomorrow: how to organize directories for easier model retrieval, how to write C…

X AI KOLs Timeline

This is a tweet recommending Eugene Yan's AI workflow guide, detailing how to efficiently collaborate with AI and achieve compound work gains by organizing context, configuring CLAUDE.md, creating skills, and more.