An Agent in 100 Lines of Lisp: Why My Professor Was Right

An Agent in 100 Lines of Lisp: Why My Professor Was Right

I revisited Lisp after 25 years to build an AI agent, discovering that its recursive nature perfectly mirrors agent loops. Instead of pre-defined tools, I gave the model a single eval command, allowing it to write its own functions like web search on the fly. This experiment proves that Lisp's homoiconic design, where code is data, remains the ideal substrate for modern symbolic AI.

In every agent platform I know of, the tool catalog is fixed at design time; here the catalog is open, and the model decides what it can do.
  1. goranmoomin

    I like Lisp, I’ve used Common Lisp with a passion, but this doesn’t seem like a valid argument for Lisp.

    Homoiconicity, as I understand, is that the code is structured data that is easy to programmatically modify, hence allowing Lisp macros. While some might disagree, I see Rust macros as the closest thing that demonstrates homoiconicity in mainstream Algol-based languages, as Rust macros modify the loosely structured token stream to produce new Rust code.

    Eval, on the other hand, that’s more of a capability that comes from Lisp’s runtime, which used to be unique when Lisp was thriving, but not anymore — JS, Python, Ruby, all of the runtime-based languages have an eval function. The fact that they are not used as much is more of a security issue, not a capability issue, and I am not sure how having eval can be argued as Lisp being the language of agents.

  2. hankbond

    Maybe this is a reductive comment, but how does this differ from just letting your agent bash tool a `python -c` command (or anything of that class)? I'm not really getting where this is a "wow" moment?

    It is always nice to appreciate how much power you get out of (Model + the absolute bare minimum of control flow). There is just so much baked into the models now that given an inch they will take a mile.

  3. drob518

    So, writing an agent in Lisp is interesting but not particularly novel. If there’s a big idea here it’s giving Lisp’s eval function to the AI as a tool. Yes, AIs write Python and Bash all day long already, but those scripts are run out of process. In this case, the AI can modify the process running the harness, extending it directly and potentially changing it (evolving it). That’s powerful. And obviously quite dangerous. Definitely only for a sandbox. But I wonder how far that can go…

  4. rcarmo

    This is a thing of beauty, no matter what the general feeling in the comments seems to be against LISP. And yeah, you can do it in JS/TS/Python/etc., but somehow it doesn’t feel as elegant.

  5. tosh

    9 lines of python:

    import json,sys,uuid;from subprocess import getoutput as sh;from urllib.request import Request as R,urlopen

    b={"model":"gpt-5.6","prompt_cache_key":uuid.uuid4().hex,"input":[],"tools":[{"type":"custom","name":"shell"}]}

    while prompt:=input("> "):

    b["input"]+=[{"role":"user","content":prompt}]

    while True:

    o=(r:=json.load(urlopen(R(sys.argv[1],json.dumps(b).encode(),{"Content-Type":"application/json"}))))["output"]

    b["input"]+=o;calls=[i for i in o if i["type"]=="custom_tool_call"];used=r["usage"]["total_tokens"]/10500

    if not calls: print(o[-1]["content"][0]["text"],f'\n[{used:06.3f}%]'); break

    b["input"]+=[{"type":"custom_tool_call_output","call_id":i["call_id"],"output":sh(i["input"])} for i in calls]

More from this day

2026-07-12