# Chapter 1: The Virtual Laboratory — Linux Mint & Logice
Chapter 1: The Virtual Laboratory — Linux Mint & Logic
Overview
Every serious engineering project begins with a reliable workspace. Before we write a single Prolog clause or a single Go function, we need an environment that is consistent, isolated, secure, and reproducible. This chapter is devoted entirely to that foundation. We are going to provision a Linux Mint 22.x Cinnamon virtual machine on a Proxmox host, install SWI-Prolog 10.x, configure VS Code with the appropriate extensions, and verify the entire stack is working with a small but real first program.
This is not a "hello world" chapter in the dismissive sense. The decisions we make here — the VM configuration, the network topology, the way we install software — will echo through every chapter that follows. We will explain why we are making each choice, particularly around security, because the homelab environment that most readers of this book are working in is not a toy. It is, or will become, a genuinely powerful orchestration system, and systems that have real power deserve real security from day one.
By the end of this chapter, the environment will be ready to support every tutorial in Parts I through III of this book.
1.1 The Case for This Stack: Proxmox, Mint, and the Security Argument
Before we touch the Proxmox web interface, it is worth spending a few pages on why we have assembled this particular combination of tools. The choice of Proxmox as the hypervisor, Linux Mint 22.x as the development guest, and SWI-Prolog paired with Go as the programming environment is not arbitrary. Each decision carries an architectural rationale, and the most important of those rationales is security.
1.1.1 Why Proxmox
Proxmox Virtual Environment (PVE) is an open-source, enterprise-grade hypervisor built on Debian and KVM. It is the hypervisor of choice for the serious homelab because it provides a level of control, observability, and network segmentation that consumer-grade tools like VirtualBox simply cannot match. On Proxmox, every VM lives inside a clearly defined network bridge. We can place our logic development VM on a VLAN that has no outbound internet access except through a controlled gateway, which is exactly the kind of isolation we want for a machine that will eventually be running automated system orchestration tasks.
Readers who are running VMware Workstation Pro or XCP-ng (the Xen Community Edition) will find that the concepts translate directly. The Proxmox-specific steps — creating a VM through the web UI, attaching a disk image, configuring the network bridge — all have direct equivalents in those environments. Where Proxmox-specific CLI commands appear in this chapter, the equivalent VMware vmrun or XCP-ng xe commands will be noted.
1.1.2 Why Linux Mint 22.x Cinnamon
Linux Mint 22.x, based on Ubuntu 24.04 LTS, provides a stable, long-term-supported foundation with a desktop environment that is genuinely comfortable to use. The Cinnamon desktop is relevant here not because we are building desktop applications, but because we are building a development laboratory. Having a functioning file manager, a taskbar, and a GUI text editor available while we are learning the fundamentals of Prolog means that we can focus our cognitive energy on the logic, not on memorising terminal commands for tasks that a file manager handles in three seconds.
This comfort is a pedagogical asset, not a compromise. Later in this book, when we migrate to a headless Debian 13 server, we will do so from a position of confidence. The terminal will not feel alien because we will have been using it steadily throughout Parts I through III. The desktop will simply fall away because we no longer need it.
Mint 22.x also has a more straightforward path to installing SWI-Prolog 10.x than a bare Debian system at this stage of the 10.x release cycle, which matters practically for a reader who is setting this up for the first time.
1.1.3 Why SWI-Prolog and Go — The Security Architecture Argument
This point deserves a full treatment because it is one of the genuine advantages of this stack that is rarely articulated clearly in introductory materials.
The software supply chain has become one of the primary vectors for malicious code in the 2020s. The Python ecosystem, despite its enormous productivity advantages, has been the target of sustained, sophisticated typosquatting campaigns. An attacker registers requets instead of requests, or colourama instead of colorama, and waits for a developer to make a single keystroke error in a pip install command. The result can be credential theft, backdoor installation, or ransomware deployment. This is not a hypothetical; it has happened hundreds of documented times, and the sheer size of PyPI (over 500,000 packages as of 2026) makes comprehensive auditing practically impossible.
The SWI-Prolog ecosystem works differently. The primary package mechanism is the SWI-Prolog Pack system, which is small, curated, and predominantly composed of packages written by researchers and engineers who publish their identity alongside their work. As of 2026, there are roughly 400 packs in the official registry. Every pack we use in this book will be examined, its source code will be referenced, and we will explain what it does before we install it. There is no equivalent of pip install some-package followed by a silent import of 47 transitive dependencies.
The Go ecosystem has a similar characteristic. Go modules are imported by their full repository path (github.com/author/package), which makes it significantly harder to conduct a typosquatting attack — there is no central registry where a near-identical name can be quietly registered. The Go toolchain also performs cryptographic verification of module downloads against a transparency log (sum.golang.org), meaning that a package cannot be silently replaced on a server after a developer has verified it.
This does not mean that Prolog and Go are immune to supply chain attacks. Nothing is immune. But the combination of a small, curated package ecosystem (Prolog) and cryptographic module verification (Go) makes this stack measurably more resistant to the class of attacks that have plagued Python-based systems. This is one of the reasons we are using it, and it is a reason we will return to when we discuss security policy enforcement in the Prolog knowledge base in later chapters.
1.2 Provisioning the VM on Proxmox
We will now walk through the complete process of creating and configuring the Linux Mint 22.x VM on Proxmox. These instructions assume Proxmox VE 8.x, which is the current stable release. The web interface described here is accessed via https://<proxmox-host-ip>:8006.
1.2.1 Downloading the Linux Mint 22.x ISO
The first step is to get the installation ISO onto the Proxmox host. We always download ISOs directly from the official source and verify the checksum before use. This is not paranoia; it is standard operational practice.
https://www.linuxmint.com/download.php
Select Linux Mint 22.x "Wilma" (or the current 22.x point release), Cinnamon Edition, 64-bit. Download the .iso file.
On the same download page, there is a link to the SHA256 checksums file. Download that as well. On a Linux or macOS terminal, verify the download:
sha256sum linuxmint-22.x-cinnamon-64bit.iso
Compare the output against the checksum in the downloaded .sha256sum file. They must match exactly. If they do not, discard the ISO and download again. We do not proceed with an unverified ISO.
Uploading the ISO to Proxmox
In the Proxmox web interface:
- In the left panel, select your node (e.g.,
pve). - Expand the node and select a storage pool that supports ISO images — typically
local. - Select ISO Images from the content panel.
- Click Upload and select the verified
.isofile.
Alternatively, if the Proxmox host has internet access, we can use the Download from URL option, pasting the direct download URL from the Linux Mint website. However, be aware that this bypasses our local checksum verification step. If using this method, download the ISO to a local path on the Proxmox host afterwards and verify it via the Proxmox shell:
# Access the Proxmox shell via the web UI: Node > Shell
sha256sum /var/lib/vz/template/iso/linuxmint-22.x-cinnamon-64bit.iso
1.2.2 Creating the Virtual Machine
In the Proxmox web interface, click Create VM in the top-right corner. We will go through each tab of the creation wizard.
General Tab
- Node: Select your Proxmox node.
- VM ID: Accept the auto-generated ID, or assign a meaningful one (e.g.,
200for the Mint development VM). - Name:
mint-logic-lab— a descriptive name that will appear in the Proxmox panel.
OS Tab
- ISO image: Select the Linux Mint 22.x ISO we uploaded.
- Guest OS Type:
Linux - Version:
6.x - 2.6 Kernel
System Tab
- Machine:
q35— this is the modern PC chipset emulation and is preferred over the olderi440fxfor any VM created in 2024 or later. It provides better PCIe support and is required for some UEFI features. - BIOS:
OVMF (UEFI)— we use UEFI rather than legacy BIOS. Add an EFI disk when prompted (Proxmox will offer this automatically when OVMF is selected). Store it on the same storage pool as the main disk. - SCSI Controller:
VirtIO SCSI single— this is the high-performance paravirtualised storage controller. Do not use the legacy IDE or SATA options for a new VM. - Qemu Agent: Check this box. We will install the QEMU guest agent inside the VM later, which allows Proxmox to report accurate IP addresses, perform clean shutdowns, and freeze the filesystem for consistent snapshots.
Disks Tab
- Bus/Device:
SCSI 0, using the VirtIO SCSI controller we selected above. - Storage: Select your preferred storage pool.
- Disk size:
80GBminimum. For a development machine that will accumulate Prolog knowledge bases, Go module caches, and log files across Parts I through III, 80GB is comfortable. If storage is plentiful, 120GB is better. - Cache:
Write back— this provides the best performance for a development VM. On a production system we would considerWrite throughfor data safety, but for a development lab where we are taking regular Proxmox snapshots, write-back performance is the priority. - Discard: Enable this if the underlying storage pool is an SSD or NVMe. It allows the guest to communicate TRIM operations to the host, keeping the disk image thin.
CPU Tab
- Sockets:
1 - Cores:
4— four cores is the minimum comfortable allocation for running SWI-Prolog, a Go process, and a VS Code instance simultaneously. If the Proxmox host has the cores to spare,6or8is noticeably smoother. - Type:
host— this passes the host CPU's full feature set to the VM, including AVX2 and other extensions that modern compilers (including the Go toolchain) can use. Do not use the defaultkvm64type for a development machine; it presents a very minimal CPU profile.
Memory Tab
- Memory:
8192 MB(8GB) minimum. SWI-Prolog's strength is in-memory reasoning over large knowledge bases. Giving the VM adequate RAM from the start means we will not need to revisit this setting halfway through Part II when our knowledge bases start growing.16384 MB(16GB) is ideal if the host can support it. - Ballooning: Can be left enabled for flexibility, but for a dedicated logic development VM with a fixed memory allocation, disabling it (by unchecking Ballooning Device) gives more predictable performance.
Network Tab
- Bridge: Select the bridge that corresponds to your development VLAN or network segment. On a homelab Proxmox setup, this is typically
vmbr0for the primary LAN. If a dedicated VLAN for lab VMs has been configured (e.g., VLAN 10), select that bridge and enter the VLAN tag. - Model:
VirtIO (paravirt)— always use VirtIO for network adapters in KVM-based VMs. It provides significantly better throughput than the emulated Intel or Realtek adapters. - Firewall: Check the Proxmox firewall box. We will configure specific rules below.
Confirm Tab
Review the summary. Do not check "Start after created" — we have one more step before the first boot.
Click Finish.
1.2.3 Proxmox Firewall Configuration
Before starting the VM for the first time, we configure the Proxmox firewall for it. Select the newly created VM in the left panel, then navigate to Firewall > Options.
- Set Firewall:
Yes(enabled) - Set Input Policy:
DROP - Set Output Policy:
ACCEPT
| Direction | Action | Protocol | Destination Port | Comment |
|---|---|---|---|---|
| IN | ACCEPT | TCP | 22 | SSH (for remote terminal access) |
| IN | ACCEPT | TCP | 5900-5910 | VNC (Proxmox console) |
Everything else inbound is dropped by default. We add more rules as needed when specific services are configured. This is the principle of least privilege applied to network access: if a port has no defined, justified purpose, it is closed.
Note for VMware/XCP-ng users: The equivalent of the Proxmox VM-level firewall in VMware Workstation is a combination of the host-level Windows Firewall and the VMware virtual network adapter settings. In XCP-ng, network policies are managed at the vSwitch level or using Open vSwitch (OVS) rules. The principle is identical regardless of platform — restrict inbound access to only what is required.
1.2.4 Adding the QEMU Guest Agent Channel
In the Proxmox web interface, with the VM selected, go to Hardware > Add > VirtIO Serial Port. This creates a communication channel that the QEMU guest agent inside the VM will use. Without this, the guest agent cannot communicate with Proxmox even after it is installed inside the VM.
1.2.5 Enabling 3D Acceleration
For the Cinnamon desktop to perform well, we need to enable the virtual GPU's 3D acceleration. In the Proxmox web interface, select the VM and go to Hardware. If a Display device is listed, click on it and edit it. Set the type to VirtIO-GPU and ensure 3D acceleration is checked. If no Display device is listed, add one via Hardware > Add > Display Device.
This requires that the Proxmox host has the virtio-gl packages available, which are included in Proxmox VE 8.x by default. Without 3D acceleration, the Cinnamon desktop compositor will fall back to software rendering, which makes the desktop noticeably sluggish on animations and window transitions.
1.3 Installing Linux Mint 22.x
With the VM configured, we start it. In Proxmox, right-click the VM and select Start, then open the Console (the noVNC console in the web browser is fine for installation; we will switch to SSH once the system is up).
The VM will boot from the ISO into the Linux Mint live environment.
1.3.1 The Live Environment Check
Before running the installer, it is worth spending two minutes in the live environment to confirm that the virtual hardware is being detected correctly:
- Open the Files application and confirm the filesystem is accessible.
- Open a Terminal and run
glxinfo | grep "OpenGL renderer". If 3D acceleration is working, this should report a VirtIO or llvmpipe renderer rather than a software fallback. - Check network connectivity:
ip addr show— the VirtIO network adapter should have received a DHCP address.
If any of these checks fail, the most common cause is a missing or mis-configured virtual hardware device in the Proxmox VM settings. Shut down, correct the settings, and restart.
1.3.2 Running the Installer
Double-click Install Linux Mint on the desktop.
Work through the installer wizard:
Language: Select the appropriate language.
Keyboard Layout: Select and test the keyboard layout.
Multimedia Codecs: Check Install multimedia codecs. This installs the ubuntu-restricted-extras package set, which includes the codec support needed for the Cinnamon desktop to function fully. There is no disadvantage to including this.
Installation Type: Select Erase disk and install Linux Mint. Since this is a fresh VM with no prior data on the 80GB virtual disk, this is the correct option. There is no need to manually partition the disk at this stage.
If manual partitioning is preferred (for example, to create a separate
/homepartition), the installer provides a "Something else" option. For the purposes of this book, the default automatic partitioning is sufficient. A separate/homepartition does make it marginally easier to reinstall the OS without losing home directory data, but with Proxmox snapshots available, this is less important than it would be on physical hardware.
Timezone: Set correctly. This matters for log timestamps, which we will be examining in Part II when we build the /var/log parser.
User Account:
- Your name: Use a real or plausible name.
- Computer name:
mint-logic-lab— consistent with the Proxmox VM name. - Username: Choose a short, lowercase username (e.g.,
logicdev). This will appear in all terminal prompts and file paths throughout the book. - Password: Use a strong password. This is a development machine, not a throwaway container. Since it will eventually be running automated processes with real system permissions, the initial account password matters.
- Require password to log in: Yes.
- Do not enable automatic login.
Click Continue and allow the installation to complete. The installer will copy the system, install bootloader (GRUB for UEFI), and ask to restart.
When prompted, click Restart Now. The console will display a message to remove the installation media. In Proxmox, the ISO is automatically detached on shutdown when the Remove ISO after install option was set, or we can manually detach it: VM > Hardware > CD/DVD Drive > Edit > select "Do not use any media".
1.3.3 First Boot and Initial Configuration
On first boot, the system will load into the Cinnamon desktop and display the Welcome Screen. Close it for now; we will return to it briefly in a moment.
Install the QEMU Guest Agent
Open a terminal (Ctrl+Alt+T or via the application menu) and run:
sudo apt update
sudo apt install qemu-guest-agent -y
sudo systemctl enable qemu-guest-agent
sudo systemctl start qemu-guest-agent
Return to the Proxmox web interface. The VM's IP address should now appear in the Summary tab. This confirms the guest agent is communicating correctly.
Update the System
sudo apt update && sudo apt upgrade -y
This will pull the latest package updates for the Ubuntu 24.04 LTS base that Mint 22.x is built upon. On a fresh install there are typically several security updates available. Apply them all.
After the upgrade completes, reboot:
sudo reboot
Configure SSH Access
For day-to-day work, the Proxmox noVNC console is functional but not pleasant for extended coding sessions. SSH into the VM from the host machine or another terminal gives a much better experience. On the VM:
sudo apt install openssh-server -y
sudo systemctl enable ssh
sudo systemctl start ssh
Check the VM's IP address:
ip addr show
Note the IP on the ens18 or eth0 interface (the name depends on the Proxmox network configuration). From the Proxmox host or another machine on the same network:
ssh logicdev@<vm-ip>
For improved security, disable password authentication and use SSH key authentication instead. If a public key has already been configured on the homelab:
On the VM:
mkdir -p ~/.ssh
chmod 700 ~/.ssh
nano ~/.ssh/authorized_keys
# Paste the public key, save and exit
chmod 600 ~/.ssh/authorized_keys
Then edit the SSH daemon configuration:
sudo nano /etc/ssh/sshd_config
Find and set (or add) these lines:
PasswordAuthentication no
PubkeyAuthentication yes
PermitRootLogin no
Restart SSH:
sudo systemctl restart ssh
From this point forward, all terminal work in this book can be performed over SSH. The Proxmox console remains available as a fallback if SSH access is lost.
Take a Proxmox Snapshot
Before installing any additional software, take a snapshot of the VM in its clean state. This is a habit that will save hours of reinstallation work when an experimental package or configuration change breaks something.
In the Proxmox web interface:
Snapshots in Proxmox are instantaneous for VMs on ZFS or LVM-thin storage. On directory storage, they are slightly slower. Either way, this takes under a minute and provides a clean rollback point.
1.4 Installing SWI-Prolog 10.x
With the base system in a clean, snapshotted state, we now install SWI-Prolog. The version matters significantly here. SWI-Prolog 10.x is the current stable development series as of 2026, and it includes several features — most notably the native Dict type, improved string handling, and the tabling infrastructure — that are central to the work in this book. We do not want to accidentally install the older 9.x or 8.x version that may appear in the Ubuntu/Mint default package repositories.
1.4.1 Checking the Default Repository Version
First, let us see what version the Mint package repository offers:
apt-cache show swi-prolog | grep Version
If this returns a version below 10.0, we need to use an alternative installation source. As of mid-2026, the Ubuntu 24.04 LTS repository may still carry an older stable version. We will use the official SWI-Prolog PPA to ensure we get 10.x.
1.4.2 Installing via the SWI-Prolog PPA
The SWI-Prolog project maintains an official PPA (Personal Package Archive) for Ubuntu-based systems. This is the recommended installation method for Mint 22.x.
sudo apt install software-properties-common -y
sudo add-apt-repository ppa:swi-prolog/stable
sudo apt update
sudo apt install swi-prolog -y
Security note on PPAs: A PPA is a third-party package repository. Before adding any PPA, it is good practice to verify its ownership. The
swi-prolog/stablePPA is maintained by the SWI-Prolog project itself and has been in continuous operation since SWI-Prolog's early Ubuntu packaging work. The GPG key added byadd-apt-repositoryensures that packages from this PPA are signed by the PPA owner. If at any pointaptreports a GPG key error for this PPA, stop and investigate before proceeding.
Verify the installation:
swipl --version
The output should show a version in the 10.x.x series, for example:
SWI-Prolog version 10.x.x for x86_64-linux
1.4.3 The First Terminal Conversation
Let us confirm that the engine is working correctly with a direct interactive session. This is not yet a meaningful logic program; it is a system check.
Start the SWI-Prolog interactive top-level (the REPL):
swipl
The prompt changes to:
Welcome to SWI-Prolog (threaded, 64 bits, version 10.x.x)
...
?-
The ?- is the query prompt. Type the following and press Enter:
?- write('Logic laboratory is operational.'), nl.
The engine should respond:
Logic laboratory is operational.
true.
Then:
?- current_prolog_flag(version, V).
This queries the engine for its own version flag. The response will be:
V = 10XXYY.
where 10XXYY encodes the major, minor, and patch version as a single integer. For SWI-Prolog 10.2.3, this would be 100203. This confirms we are running a 10.x engine.
Exit the REPL:
?- halt.
Take another snapshot: 01-swi-prolog-installed.
1.4.4 Understanding the SWI-Prolog Directory Layout
When SWI-Prolog is installed via the PPA, its files are distributed across standard Linux filesystem locations. Understanding this layout is important for the work ahead.
which swipl
# /usr/bin/swipl — the main executable
swipl --dump-runtime-variables | grep PLBASE
# PLBASE="/usr/lib/swi-prolog"
Key directories:
| Path | Contents |
|---|---|
/usr/bin/swipl |
Main executable |
/usr/lib/swi-prolog/ |
Libraries, boot files, C libraries |
/usr/lib/swi-prolog/library/ |
The standard library of built-in Prolog predicates |
~/.local/share/swi-prolog/pack/ |
Packs installed by the current user (we will use this in later chapters) |
/usr/share/doc/swi-prolog/ |
Installed documentation |
The most important of these during early development is the library/ directory. Every time we use a directive like :- use_module(library(lists)). in a Prolog source file, the engine looks here. Understanding that library(lists) corresponds to a physical file /usr/lib/swi-prolog/library/lists.pl demystifies the module system considerably.
1.5 Installing Go
Go (Golang) will be introduced in depth in Part III of this book. However, we install it now for two reasons. First, we want to take a snapshot of the complete development environment as a single, known-good baseline. Second, several of the system utilities referenced in the VS Code setup below are written in Go, and having the Go toolchain available from the start avoids installation interruptions later.
1.5.1 Choosing the Installation Method
There are three common ways to install Go on an Ubuntu-based system:
- The
golang-gopackage from the Ubuntu repository. - The official Go binary distribution from
go.dev. snap install go.
We use method 2. The Ubuntu repository package is often one or two minor versions behind the current stable release, and Go minor versions frequently include performance improvements and new standard library features that we will use. The snap version works, but adds a layer of indirection that is unnecessary on a VM we control directly.
1.5.2 Installing the Go Toolchain
On the VM terminal:
# Replace the URL and filename with the current stable release if newer
wget https://go.dev/dl/go1.26.1.linux-amd64.tar.gz
# Verify the SHA256 checksum against the value listed on go.dev/dl/
sha256sum go1.26.1.linux-amd64.tar.gz
# Remove any previous Go installation and extract the new one
sudo rm -rf /usr/local/go
sudo tar -C /usr/local -xzf go1.26.1.linux-amd64.tar.gz
# Clean up the archive
rm go1.26.1.linux-amd64.tar.gz
Now configure the shell environment. Open the profile file for the current user:
nano ~/.bashrc
Add these lines at the end:
# Go toolchain
export PATH=$PATH:/usr/local/go/bin
export GOPATH=$HOME/go
export PATH=$PATH:$GOPATH/bin
Apply the changes to the current session:
source ~/.bashrc
Verify:
go version
# go version go1.26.1 linux/amd64
A note on GOPATH: In Go 1.11 and later, the module system (go mod) has largely replaced the older GOPATH-based project layout for new code. However, GOPATH still determines where Go installs binaries built with go install, so it remains relevant. We set it to ~/go which is the conventional default.
1.6 Configuring VS Code
The integrated development environment we use throughout this book is Visual Studio Code. It is free, open-source, and has an exceptional extension ecosystem for both Prolog and Go. The key requirement is the combination of the Prolog Language Server Protocol (LSP) extension and the Go extension, which together provide inline error checking, code completion, and the ability to run Prolog and Go code side by side.
1.6.1 Installing VS Code
sudo apt install wget gpg -y
wget -qO- https://packages.microsoft.com/keys/microsoft.asc | \
gpg --dearmor > /tmp/microsoft.gpg
sudo install -o root -g root -m 644 /tmp/microsoft.gpg \
/etc/apt/trusted.gpg.d/microsoft.gpg
sudo sh -c 'echo "deb [arch=amd64] https://packages.microsoft.com/repos/code stable main" \
> /etc/apt/sources.list.d/vscode.list'
sudo apt update
sudo apt install code -y
VS Code can be opened from the application menu or by typing code in the terminal.
1.6.2 Installing the Prolog LSP Extension
The Prolog Language Server Protocol extension connects VS Code to a running SWI-Prolog LSP server, providing real-time syntax checking, predicate completion, and documentation hover. Open VS Code and:
- Press
Ctrl+Shift+Xto open the Extensions panel. - Search for "VSC-Prolog" — the extension by Arthur Wang.
- Click Install.
Once installed, open VS Code's settings (Ctrl+,) and search for prolog. Configure:
- Prolog: Executable Path:
/usr/bin/swipl - Prolog: Dialect:
swi
The extension will start a background LSP server the first time a .pl file is opened. If it does not start automatically, the most common cause is that swipl is not in the path that VS Code uses. Confirm by opening the VS Code integrated terminal (Ctrl+`` ) and running which swipl.
1.6.3 Installing the Go Extension
- In the Extensions panel, search for "Go" — the extension by the Go Team at Google.
- Click Install.
After installation, VS Code will display a notification: "The 'Go' extension recommends installing additional tools." Click Install All. This installs several Go tools into $GOPATH/bin:
gopls— the Go Language Serverdlv— the Delve debuggerstaticcheck— a static analysis toolgotools— formatting and import management
These tools require the Go toolchain to be in the path, which we configured in section 1.5.2. If the "Install All" operation fails, open the VS Code integrated terminal and confirm that go version returns correctly.
1.6.4 Setting Up the Workspace Layout
We will use a consistent workspace layout throughout all parts of this book. Create the following directory structure in the home directory:
mkdir -p ~/logic-lab/{prolog,go,shared,logs,knowledge-bases}
| Directory | Purpose |
|---|---|
~/logic-lab/prolog/ |
All .pl source files |
~/logic-lab/go/ |
All Go module directories |
~/logic-lab/shared/ |
Data files shared between Prolog and Go (JSON, CSV) |
~/logic-lab/logs/ |
Log files for the DCG parser tutorials in Part II |
~/logic-lab/knowledge-bases/ |
Standalone KB files that grow throughout the book |
Open VS Code and add this directory as a workspace:
File > Add Folder to Workspace > ~/logic-lab
Save the workspace:
File > Save Workspace As > ~/logic-lab/logic-lab.code-workspace
This .code-workspace file will preserve the open editor state, extension settings, and panel layout between VS Code sessions.
Take a final snapshot of the fully configured environment: 02-full-dev-environment.
1.7 The First Real Program: A System Status Knowledge Base
The environment is complete. It is time to write the first real Prolog program — not a trivial single-query test, but a small, functional knowledge base that introduces the four fundamental elements of Prolog we will spend the next two chapters examining in detail: facts, rules, queries, and variables.
We are going to create a small knowledge base that models the state of virtual machines on the Proxmox host. This is not just a pedagogical example; it is the embryonic form of the "System Status" knowledge base that will grow substantially in Chapters 2 and 3.
1.7.1 Creating the Source File
In VS Code, create a new file: ~/logic-lab/prolog/system_status.pl
Type the following exactly:
% system_status.pl
% A knowledge base representing the status of VMs on the Proxmox host.
% Part I, Chapter 1 - Modern SWI-Prolog (2026 Edition)
:- module(system_status, [vm_online/1, vm_has_role/2, can_reach/2]).
% --- Facts ---
% vm(Name, Status, RAM_GB, CPU_Cores)
vm(mint_logic_lab, online, 16, 4).
vm(debian_core, offline, 8, 2).
vm(pfsense_fw, online, 4, 2).
vm(backup_target, online, 32, 4).
% network_link(SourceVM, DestVM)
% Defines which VMs can communicate directly at the network level.
network_link(mint_logic_lab, backup_target).
network_link(mint_logic_lab, debian_core).
network_link(pfsense_fw, mint_logic_lab).
network_link(pfsense_fw, backup_target).
% role(VM, Role)
role(mint_logic_lab, development).
role(debian_core, orchestrator).
role(backup_target, storage).
role(pfsense_fw, firewall).
% --- Rules ---
% vm_online(+Name)
% True if the named VM is currently online.
vm_online(Name) :-
vm(Name, online, _, _).
% vm_has_role(+Name, ?Role)
% True if the named VM has the given role.
vm_has_role(Name, Role) :-
vm(Name, _, _, _),
role(Name, Role).
% can_reach(+Source, +Dest)
% True if Source can reach Dest via the network.
% This handles both direct links and symmetric reachability.
can_reach(Source, Dest) :-
network_link(Source, Dest).
can_reach(Source, Dest) :-
network_link(Dest, Source).
Save the file. If the Prolog LSP extension is working correctly, it will begin syntax-checking the file immediately. Any red underlines indicate a syntax error.
1.7.2 Loading and Querying the Knowledge Base
Open the VS Code integrated terminal and start the SWI-Prolog REPL, loading the file directly:
swipl ~/logic-lab/prolog/system_status.pl
The engine loads the file and reports any warnings. A clean load looks like:
% ~/logic-lab/prolog/system_status.pl compiled 0.00 sec, 12 clauses
?-
Now we query the knowledge base. Let us start with something simple: ask the engine which VMs are online.
?- vm_online(Name).
The engine responds:
Name = mint_logic_lab ;
Name = pfsense_fw ;
Name = backup_target.
The semicolons between results are the engine's way of showing it has found multiple solutions. In the interactive REPL, pressing ; after each result asks the engine to search for the next solution. Pressing Enter (or .) stops the search. The full set of results is shown here as they appear after pressing ; through all solutions.
This is the core of Prolog's mechanism: we did not write a loop to iterate through the vm facts. We declared a rule — vm_online(Name) :- vm(Name, online, _, _). — and asked the engine to find all values of Name that satisfy it. The engine did the iteration itself.
Let us ask a more specific question:
?- vm_has_role(mint_logic_lab, Role).
Role = development.
And a reachability query:
?- can_reach(mint_logic_lab, Dest).
Dest = backup_target ;
Dest = debian_core ;
Dest = pfsense_fw.
Notice that pfsense_fw appears in the results even though the network_link fact in the knowledge base is network_link(pfsense_fw, mint_logic_lab) — with pfsense_fw as the source, not the destination. The can_reach rule handles this because we defined it symmetrically with two clauses: one for the direct link direction and one for the reverse.
This small demonstration illustrates something fundamental about programming in Prolog: the relationship between the code we write and the questions we can ask is not one-directional. We will examine this property — and the engine mechanism behind it — in depth in Chapter 3.
1.7.3 Querying from the Command Line
For scripting and automation (which will become important once we connect Go to Prolog in Part III), we need to be able to query a Prolog knowledge base from the shell without entering an interactive session. SWI-Prolog supports this with the -g (goal) flag:
swipl -g "vm_online(Name), write(Name), nl, fail ; true" \
-t halt \
~/logic-lab/prolog/system_status.pl
Output:
mint_logic_lab
pfsense_fw
backup_target
The goal vm_online(Name), write(Name), nl, fail ; true uses a standard Prolog idiom: fail forces the engine to backtrack and find the next solution, while write(Name), nl prints each one as it is found. The ; true ensures the overall goal succeeds once all solutions are exhausted. The -t halt flag sets the top-level goal — the thing the engine runs after the -g goal completes — to halt, which exits cleanly with status code 0. This is the idiomatic form; chaining a second -g halt also works but -t halt is the correct way to express "exit when finished."
This command-line pattern will become the basis for the Go-Prolog shell-level integration in Chapter 6, before we move to the direct FFI.
1.8 Chapter Summary and What Comes Next
We have covered a significant amount of ground in this chapter. The work completed:
- Provisioned a Linux Mint 22.x Cinnamon VM on Proxmox with correct hardware configuration:
q35machine type, UEFI boot, VirtIO storage and network, adequate CPU and RAM allocation. - Configured the Proxmox firewall for the VM with a least-privilege inbound policy.
- Installed the QEMU guest agent and verified Proxmox-guest communication.
- Secured SSH access with key-based authentication.
- Established a snapshot baseline at three key milestones.
- Installed SWI-Prolog 10.x from the official PPA and verified the version.
- Installed the Go toolchain from the official binary distribution and configured the shell environment.
- Configured VS Code with the Prolog LSP and Go extensions and established a consistent workspace layout.
- Created and queried a first real knowledge base, observing the engine's backtracking search in the interactive REPL and from the command line.
The security argument introduced in section 1.1.3 — that the Prolog Pack ecosystem and Go's module transparency log make this stack measurably more resistant to supply chain attacks than a comparable Python setup — is not a closing thought. It is a design principle that will manifest concretely in later chapters when we examine how the Prolog knowledge base itself becomes a security policy enforcement mechanism, preventing both human error and LLM hallucination from causing unintended system actions.
Chapter 2 will examine the three building blocks of every Prolog knowledge base — facts, rules, and queries — in the depth they deserve. We will build a more substantial system status and dependency checker, and we will encounter the two most important concepts in Prolog for a developer coming from a procedural background: the variable as a search parameter rather than a storage location, and the rule as a description of truth rather than a sequence of instructions.
The laboratory is open.
Appendix 1A: Proxmox VM Configuration Reference
The following table summarises the complete VM configuration from section 1.2 for quick reference.
| Setting | Value | Rationale |
|---|---|---|
| Machine type | q35 | Modern PCIe chipset, required for UEFI |
| BIOS | OVMF (UEFI) | Modern boot standard |
| SCSI controller | VirtIO SCSI single | High-performance paravirtualised I/O |
| Disk size | 80GB+ | Adequate for development across Parts I-III |
| Disk cache | Write back | Development performance priority |
| CPU type | host | Full feature passthrough including AVX2 |
| CPU cores | 4 minimum | Required for Prolog + Go + VS Code |
| RAM | 8GB minimum | Adequate for initial KB sizes |
| Network model | VirtIO | High-performance paravirtualised NIC |
| Display | VirtIO-GPU with 3D | Cinnamon compositor performance |
| Guest agent | Installed | Proxmox integration, clean snapshots |
| Firewall policy | DROP inbound | Least-privilege default |
Appendix 1B: Snapshot Schedule for Part I
| Snapshot Name | When to Take | Contents |
|---|---|---|
00-clean-install |
After first boot, SSH configured | Baseline OS |
01-swi-prolog-installed |
After SWI-Prolog verified | OS + Prolog 10.x |
02-full-dev-environment |
After VS Code configured | Complete dev stack |
03-chapter-1-complete |
End of this chapter | + system_status.pl |
Take 03-chapter-1-complete now before proceeding to Chapter 2.
# In the Proxmox web UI: VM > Snapshots > Take Snapshot
# Name: 03-chapter-1-complete
# Description: system_status.pl verified, all queries passing