Loading and Managing Extensions
On this page
This page covers how a Lisp extension reaches a running kli and how you turn one on or off without restarting. For writing the extension itself, see Write your first Lisp extension; for the full defextension grammar, see Extension reference.
An extension comes from a file or directory on disk. kli reads that source, indexes what it declares as an available extension, and installs the enabled ones into the session. Four things decide which extensions a session has: where kli looks, what config.json says, the --extension flag, and the in-session commands.
Drop a file in a discovery directory
kli scans two directories on every launch, in this order:
~/.config/kli/extensions/— loaded in every session.<project>/.kli/extensions/— loaded only when kli runs in that project. Project files extend the global set; they do not replace it.
A directory that does not exist is skipped, not an error. To add an extension, write its .lisp file (or its unit directory) into one of these and start kli, or run /reload in a session already open.
Load a one-off file with --extension
To load a file or directory that is not in a discovery directory, name it on the command line:
kli --extension ./scratch/greet.lispThe flag is repeatable, and each value is either a file or a directory:
kli --extension ./scratch/greet.lisp --extension ./team-extensions/A path that is a directory is discovered as a unit (or a group of units); any other path loads as a single file. Extensions named with --extension are added on top of whatever the discovery directories and config.json already contribute, for that one session only. Nothing is written to disk and the next launch forgets them.
Add extra roots in config.json
~/.config/kli/config.json is an optional file. Three keys control loading:
| Key | Type | Effect |
|---|---|---|
enabled | array of names | Force these extensions on, overriding their default. |
disabled | array of names | Force these extensions off. |
extension-dirs | array of paths | Extra directories to scan, in addition to the two discovery directories. |
{
"enabled": ["greet"],
"disabled": ["noisy-extension"],
"extension-dirs": ["/srv/shared/kli-extensions"]
}
Names are matched case-insensitively, so "Greet" and "greet" name the same extension. A directory under extension-dirs that does not exist is skipped. If config.json is missing or malformed, kli warns and proceeds as though it were absent rather than failing to start.
Which extensions are enabled
An indexed extension is installed unless something turns it off. Settle a name by walking these checks in order and taking the first that names it:
- The active profile's disable list (if a profile is active) turns it off.
- The active profile's enable list turns it on.
disabledinconfig.jsonturns it off.enabledinconfig.jsonturns it on.- The extension's own
:autoloadmetadata, if it set one. - Otherwise, on.
To override an extension that ships off by default, add its name to enabled. To override an extension that ships on, add it to disabled. A profile wins over config.json, so a profile's lists can flip either way for that profile only. For profiles, see Profiles.
Reload after an edit
In a running session, /reload re-reads every extension file on disk:
/reloadIt retracts every installed user extension, clears the indexed registry and the diagnostics from the previous pass, re-indexes from the current files, and installs the enabled set again. An edit to a file takes effect in place, with no rebuild and no restart. kli replies with the list of user extensions it now knows about and their state.
Loading is fail-soft: a file that errors warns and is isolated under a [diagnostics] entry while every other extension keeps working. Fix the file and run /reload again.
Toggle one extension live
/enable and /disable switch a single extension without touching disk:
/enable greet/enable NAME installs an indexed extension that is currently off. kli replies Enabled greet., or greet is already enabled. if it was already on, or No such extension: greet. if no extension by that name was indexed.
/disable greet/disable NAME retracts an installed extension from the session. kli replies Disabled greet., or greet is not enabled. if it was not installed. The file stays on disk, so a later /reload or the next session brings the extension back unless config.json disables it.
List what is available
/extensions reports every indexed extension and whether it is currently installed:
/extensionsEach line is marked [enabled] or [disabled]. When no user extensions were found, kli says so. To see which files failed to load, run /reload, which appends a [diagnostics] line for each failed unit; /extensions lists state only.