CLBSD is built around several layers of abstractions, all controlled by Common Lisp structures and callback functions. The interface is meant to be easy for Emacs users to use.
CLBSD assumes host network reachability is pre-configured by the operator (LAN, WireGuard, Tailscale, etc.).
The core of CLBSD is the container abstraction. CLBSD provides a nice CL API over FreeBSD Jails and also Linux Docker containers.
Every container has an isolated ZFS dataset that lies on a zpool. This allows for clear separation and sharing of data, with redundancy and extremely easy migrations. ZFS datasets are logical partitions that can grow dynamically and package together filesystem, data, and snapshot history.
The CLBSD container abstraction creates a nice Lisp image that manages both jails and docker containers into a single abstraction. Containers are represented as Lisp objects that are all managed with a unified interface. Every running container can be modified like a lisp image through a remote SLIME connection.
Docker containers run inside a minimal Alpine Linux Bhyve VM, since Docker requires a real Linux kernel (FreeBSD jails cannot provide Linux namespaces or cgroups).
CLBSD treats reverse proxies (like Nginx) not as static services, but as dynamically generated artifacts of the Lisp control plane. By adding domain and port properties to a container’s struct, CLBSD automatically manages the routing of subdomains to their relevant jails or Docker microVMs.
Whenever the reconciliation loop detects a change in the active clbsd-state (such as a new service spinning up or an existing one going offline), a pure Lisp function maps over the active containers to generate a fresh nginx.conf string. This configuration is automatically written to the ZFS dataset of a dedicated routing jail, and a graceful service nginx reload is triggered. This creates a fully automated, functional ingress controller that exposes container endpoints on the host network interface(s).
The core of CBSD is its container management interface. Containers can be programatically controlled via a lisp library. They are powerful multithreaded abstractions over the host and guest systems.
Akin to docker-compose and service, you can write declarative container configurations in an init file. These can be updated on a running SBCL image by connecting directly through a REPL. Live Lisp code can be executed using a unified container API.
The host system all plug into the kqueue event notification systems. Using the same quicklisp library from above, you can register callbacks that map onto a set of kqueue events to create a custom event handling loop for each container. Events are processed completely separately in different threads for the different jails and containers present.
CLBSD comes with a minimal GNU Emacs package (can be installed through straight.el) that allows you to manage your live running homelab, its containers, and more.
A Dynamic org mode buffer will allow for interactive control of running images. It is created using org-dblock, allowing for dynamic org mode blocks. It abstracts over the quicklisp library described in Layer 2.
CLBSD also creates a remote connection to your SLIME server that autoloads all the context and APIs with a single keybinding. This way, for fine control, users can login to a direct REPL where they can send custom callbacks, monitor usage, and more. Changes from declarative configuration file will be dynamically reconciled to become persistent.
The running state of a system and its data should be able to be easily migrated between machines and reproduced exactly.