🚧 UNDER CONSTRUCTION 🚧 welcome to pricklypear 🌵 a lisp machine that lives in postgres · sign the guestbook · best viewed in netscape 4.0 at 800x600 · built in public · 🚧 UNDER CONSTRUCTION 🚧 welcome to pricklypear 🌵 a lisp machine that lives in postgres · sign the guestbook · best viewed in netscape 4.0 at 800x600 · built in public ·
UNDER CONSTRUCTION welcome to my homepage!! — last updated 2026 —

Pricklypear

What if WordPress was a Lisp Machine? (Nobody has asked this question)

What is Pricklypear?

Pricklypear is a multi-user Lisp operating system. One unix process is the whole OS surface — HTTP, REPL, eval, auth. Postgres is the filesystem: every function, type, route, and data row lives there as rows. The image is ephemeral and rebuilds from the store.

You don't deploy Nopales code. You save a row. Change a function and every route that calls it picks it up immediately — no compile step, no restart.

What is Nopales?

Nopales is the language. It's a small Scheme-family Lisp-1. It's homoiconic: the AST is the source, and function definitions persist in Postgres as JSONB. Editing the AST is editing the code.

Here's a handler function. The browser hits /hello and this runs.

(define hi-page
  (lambda () (render-html "<h1>Hello</h1>")))

You don't need to restart to see this page. There's no translation layer. Postgres just stores the direct AST of your sexp, serialized as JSONB:

columnvalue
namehi-page
body
{"lambda":[[],
  {"app":[{"var":"render-html"},
            {"lit":{"str":"<h1>Hello</h1>"}}]}]}
docRender the hello page.
authoradmin

It has closures, lambda, let, quasiquote macros, pattern matching, and a frozen core. Dynamic typing, impure functional, effects-inferred. Two kinds of function: data builders you call from the REPL, and HTTP handlers you bind to a URL.

A handler is just (route "/hello" "hi-page") — where hi-page is a function you defined. The browser hits /hello; the REPL calls hi-page.

Interpreted runtime

Agent skills and MCP are 2024 era coding dude. Here in Pricklypear we directly access the REPL. POST one Lisp expression to /api/eval and get a value back. Pure prims (+, car, string-append) run in the interpreter; DB prims (get, create, rows, route, fork, merge) read and write real Postgres rows. No build, no deploy, no second language. You can also mirror the whole language and run the interpreter locally.

HTML & CSS primitives

Sexp wrappers for the whole tree. html/div, html/a, html/p, html/attr. You build pages in Lisp, not string templates. A tiny CSS DSL (css/rule, css/sheet, css/media) emits a real stylesheet. This page is styled that way.

htmx, server-evaluated

Route handlers return htmx fragments. A server-side swap simulator (the hypermedia harness) lets agents can verify a flow without a browser. You don't have to do a goofy Chrome / screenshot workflow.

Local-first evaluation

The same interpreter runs three ways: in the image against Postgres, over HTTP via /api/eval (local compute, remote data), and against a local lens offline that grafts back on reconnect. One language, one seam, three modes.

3 hour tour

After you log in (or from scripts/repl.sh against a local image):

  1. scripts/repl.sh
  2. (define hi-page (lambda () (render-html "<h1>Hello</h1>")))
  3. (route "/hello" "hi-page")
  4. open /hello in the browser
  5. edit at /edit/hi-page
  6. optional: (propose-function "double" "lambda of int x -> (* x 2)")

Agents: no special API

Remote agents (Agora, pi, curl on a phone) do not need a custom REST surface. Fetch the public bootstrap doc, take a username/password from a human once, then POST Lisp to /api/eval.

Machine contract: /.well-known/agent.json · Prose: /agent.txt. No secrets in either document.

Read agent.txt agent.json

Harness, agent, habitat

Has anybody noticed there's a third thing missing? I call it The Third Substrate if I'm trying to be fancy. Your harness writes code. Your agent manages tasks and processes. But there's nowhere to deploy your code. Now your poor OpenClaw is a TypeScript DevOps engineer

Pricklypear is the third thing. It's an living app and a memory. If you want you can write all your agent memory to it.

The agent calls it a habitat. I kind of think that name sucks, but oh well. Maybe its natural habitat is living inside its own Lisp. I think Cloudflare is trying to solve this problem with some insane, poorly designed abstraction. (like everything they touch)

I kind of think a habitat has to be a Lisp. I think you could build it in CL or Clojure. But there are big advantages to having an interpreted Lisp. I'd actually like to see a CL or Clojure habitat. My agents say you could build one in less than 10000 LoC. That's about a quarter of the size of Pricklypear. But then I built an interpreter, too.

Get in, Loser. We're a cactus now.

Browse the source or download the book without an account. To run code in the image, log in — workspace home, Functions, Pages, Data, and the REPL stay private.

Code browser Book PDF Agent instructions Sign in
Pricklypear · hosted release · background · roadmap · signup · guestbook · agent instructions · concepts (after login)
[ prev | list | random | next ] the pricklypear webring
BEST VIEWED IN NETSCAPEHAND-CODED LISPNO JAVASCRIPTPOSTGRES POWEREDAGENT READYSIGN GUESTBOOKY2K READYVALID HTML 4.01
you are visitor0000042since 2026

this site is hand-coded in a lisp machine and rendered by a cactus 🌵 powered by postgres, htmx, and questionable life choices. no javascript was harmed. best viewed at 800x600.