An agent in 100 lines of Lisp

214 points66 comments5 days ago
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.

show comments
kazinator

> Symbolic AI lost.

Symbolic AI lost? At what, surely not chess?

A symbolic AI solution to a problem requires vastly less energy. And is deterministic; you can cover it with expected input/output pair regression test cases.

show comments
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…

show comments
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]
show comments
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.

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.

show comments
whartung

I never realized that when chatting with the bot, the entirety of the session was sent each time. I guess I just figured there was some state maintained Out There, rather than simply resubmitted each time.

skapadia

This is beautiful, I can't deny that. But the claim that Claude Code is a fixed set of tools is quite wrong. Claude Code regularly generates new code to carry out tasks, and you can choose to promote those tasks to skills, workflows, etc.

scarredwaits

Nice, but this is the equivalent of always running with `--dangerously-skip-permissions` with all the security implications of that.

show comments
sroerick

I made an interpreted lisp and stored the AST in postgres and exposed the functions with htmx, and honestly it works pretty great.

sim04ful

Prolog would have been a better choice

show comments
elij

it is also possible to sandbox elisp at least. I allow pure functions through by default: https://github.com/elij/macher-agent/blob/main/macher-agent-... -- more an interpreter then straight eval but works as author states

emp17344

Littered with AI writing tells.

show comments