Write Your First Lisp Extension
On this page
By the end of this page you will have a working slash command, /greet, that you wrote, loaded into a running kli, edited, reloaded without restarting, and switched off. You will do all of it against one live session.
You write an extension as a Common Lisp file on disk. kli reads the file and installs the command it declares. There is no build step and no restart.
Create the file
Extensions in ~/.config/kli/extensions/ load in every session. Create that directory if it does not exist, then write a file named greet.lisp inside it.
(defextension greet
(:provides
(command "greet"
:description "Greet someone by name."
:arguments '(:tail :name)
:handler (lambda (command arguments context &key call-id on-update)
(declare (ignore command context call-id on-update))
(reply (format nil "Hello ~A!"
(or (rest-arg arguments) "world")))))))
That is the whole extension. Reading it line by line:
defextension greetnames the extensiongreet.(command "greet" ...)declares the slash command. The string is the name you type after the slash.:arguments '(:tail :name)captures everything typed after/greetas one free-text tail.- The handler signature
(command arguments context &key call-id on-update)is fixed; declare-ignore the parameters you do not use. (rest-arg arguments)returns that captured tail, ornilwhen you typed nothing after the command name.(reply text)builds the result kli shows.
A single .lisp file loads in the kli/author package, so defextension, command, reply, and rest-arg are available unqualified. You import nothing.
Load it into the running session
Switch to your kli session and run:
/reload/reload re-reads every extension file on disk and installs what it finds. kli prints the list of user extensions it now knows about; greet is among them, marked enabled.
Now run the command:
/greet Adakli answers Hello Ada!. Run it with no argument:
/greetkli answers Hello world!, because (rest-arg arguments) returned nil and the or fell through to the default.
Edit it and reload live
You can change the command against the same running session. Open greet.lisp and change the greeting.
(reply (format nil "Welcome, ~A."
(or (rest-arg arguments) "stranger")))
Save the file, return to kli, and run /reload again. /reload retracts every installed user extension, re-reads the files, and reinstalls them, so your edit replaces the old command in place. Run /greet Ada and kli now answers Welcome, Ada..
If a file has an error, loading is fail-soft: kli warns about that one file and isolates it while every other extension keeps working. Fix the file and /reload again.
Switch it off
To take the command out of the session without deleting the file, disable it by name:
/disable greetkli answers Disabled greet., and /greet no longer runs. The file stays on disk, so a later /reload (or the next session) brings it back. To list what is available and which extensions are currently enabled, run:
/extensionsWhat you did
You wrote a slash command in a Lisp file, loaded it with /reload, edited it and reloaded it against the same live session, and disabled it with /disable. Edit, /reload, repeat: that is how you build a kli extension.
From here:
- Add a command that reacts to session events, or one the model can call as a tool: see Lisp extensions.
- Understand why a running kli can change itself this way: see The live image.
- See the full
defextensiongrammar, every contribution kind, and the author DSL: see Extension reference.