Skip to content

Architecture

LoricaOS is not one program. It is a fleet of independently versioned repositories — a kernel, a compositor, a toolkit, a shell, a package manager, and a set of leaf applications — each built, released, and signed on its own cadence, then assembled into a bootable image.

The organizing principle is the same one that governs the security model: nothing is implicit. Just as a process holds no authority it was not granted, the OS image embeds no component it did not explicitly fetch and pin. The repository that produces the ISO (LoricaOS/LoricaOS) builds almost none of what ends up on it. It fetches the kernel, the GUI components, the toolkit, and the base utilities as versioned, signed artifacts, and assembles them.

This is exactly how a Linux distribution consumes a kernel: the distro does not compile Linus's tree as part of its image build — it pulls a released kernel artifact and packages a userland around it. LoricaOS applies that model to the whole graphical stack.

The layered picture

From the metal up:

Layer Component Repo Role
Kernel Aegis LoricaOS/Aegis The from-scratch x86-64 kernel: capability model, scheduler, memory (PMM/VMM), VFS, sockets, drivers. Ships as a standalone aegis.elf artifact.
Base userland coreutils LoricaOS/coreutils The unprivileged base utilities (/bin). Present in both profiles, graphical or not.
Display server Lumen LoricaOS/lumen The compositor / display server. Owns the framebuffer; every GUI app is one of its clients over the /run/lumen.sock window protocol.
Toolkit glyph LoricaOS/glyph The GUI toolkit components link against — software renderer, theme system, fonts, the Lumen client protocol, terminal core, auth helpers. A build-time dependency, not a runtime package.
Shell bastion LoricaOS/bastion The greeter / display manager — login, unlock, session start.
Shell citadel-dock LoricaOS/citadel-dock The desktop dock.
Apps lumen-* LoricaOS/lumen-* The applications — terminal, files, editor, settings, calculator, and more. Each in its own repo.
Packaging herald + Chancery LoricaOS/herald The package manager (herald) and the signed package repository (Chancery). The .hpkg format with an ECDSA-P256 trust chain.

Aegis is the kernel; LoricaOS is the OS

"Aegis" names only the kernel — the aegis.elf artifact, the /etc/aegis/caps.d/* capability paths, "the Aegis kernel." Everything user-facing — installers, banners, window titles, ISO filenames — is LoricaOS. The two version independently and are released from separate repositories.

Aegis — the kernel

Aegis is a standalone, clean-slate x86-64 kernel and nothing else. It embeds no userland: at boot it mounts the root filesystem the bootloader provides and execs /bin/vigil as init, panicking "no init found" if there is none — exactly like Linux. Its surface is a small, deliberate one: a capability-checked syscall boundary, an SMP scheduler, paging and a physical/virtual memory manager, a VFS (ext2, ramfs, procfs, memfd), an IP/TCP/UDP network stack with sockets, and drivers (NVMe, xHCI, PS/2, framebuffer, HDA). The capability subsystem is written in no_std Rust; the rest is C.

Crucially, Aegis is independently adoptable. It publishes a versioned aegis.elf that an OS consumes — LoricaOS is the reference OS, but it is not a privileged one. Another operating system could build its own userland on Aegis the same way LoricaOS does: fetch the artifact, provide a rootfs with an init at /bin/vigil, and boot. The kernel knows nothing about Lumen, herald, or the desktop.

Lumen, glyph, and the desktop shell

Lumen is the compositor and display server. It owns the framebuffer; every graphical program is a client that connects to /run/lumen.sock, is handed a shared-memory pixel buffer over SCM_RIGHTS, draws into a private back buffer, and presents. There are no in-process built-in apps masquerading as part of the compositor — even the calculator is an external client.

glyph is the GUI toolkit every graphical component links against: software-framebuffer drawing primitives, the runtime theme/accent system, TTF and bitmap text, image decoding, the client side of the Lumen window protocol, a reusable terminal-emulator core, and credential helpers. It is a build-time dependency only — four static archives (libglyph, libcitadel, libaudio, libauth), no shared object, nothing installed at runtime. Like the kernel, glyph publishes a versioned artifact (glyph-<version>.tar.gz) that consumers fetch and link, rather than rebuilding from source.

bastion (the greeter) and citadel-dock (the dock) are the shell chrome around the apps — login/unlock and the launcher/dock — each its own repo and its own package.

The lumen-* applications

Each desktop application lives in its own LoricaOS/lumen-* repository and publishes a class=system herald package. They are leaves of the graphical stack: a lumen-* app fetches a pinned glyph toolkit, compiles against it, runs as an external Lumen client, and ships as a signed .hpkg. The default set includes the terminal, file manager, editor, settings, calculator, run dialog, applications menu, system monitor, network manager, and more.

Why class=system

A first-party component installs across multiple trees — its binary under /apps/<id>/, its bundle descriptor (app.ini), and its capability policy under /etc/aegis/caps.d/. That cross-tree, signature-trusted, installed-verbatim shape is exactly what class=system denotes, versus an ordinary single-prefix package.

coreutils

coreutils is the unprivileged base userland — the /bin utilities that exist on every LoricaOS system, graphical or not. It is built by its own repo's CI and consumed as a pinned, signature-trusted coreutils.hpkg artifact. Nothing in it requires elevated capability; it is the plain, everyday command set the shared base rootfs is built from.

herald + Chancery

herald is the package manager and Chancery is the signed repository it pulls from. Packages are .hpkg files — manifest-first, uncompressed POSIX ustar archives — carrying a detached ECDSA-P256/SHA-256 signature. Every component above (except the in-tree installer and the kernel) is delivered as a herald package. The desktop image is assembled from these packages with the herald installed-package database pre-seeded, and additional packages are installable on demand from Chancery once a system is running.

The fetched-artifact model

The LoricaOS/LoricaOS repository does not build the kernel and does not build the GUI apps. It fetches them as versioned artifacts and assembles ISOs. The in-tree source is small and deliberate: the init (user/bin/vigil), the installers, some coreutils/net tooling, and the rootfs skeletons. Everything else arrives pre-built.

Four fetch scripts do the work, each pinning a version and caching the artifact under vendor/ so an offline build is possible by dropping the file in place:

Script Pins Fetches Into
tools/fetch-kernel.sh KERNEL_VERSION aegis.elf from the LoricaOS/Aegis release vendor/aegis-<ver>.elf
tools/fetch-components.sh tools/components.list each component .hpkg from its own LoricaOS/<id> release merged into build/desktop-overlay/
tools/fetch-coreutils.sh COREUTILS_VERSION coreutils.hpkg vendor/coreutils/bin/
tools/fetch-glyph.sh (per component) each app's GLYPH_VERSION the glyph toolkit tarball the component's build tree

The pattern is uniform. fetch-kernel.sh resolves a local cache first, otherwise downloads …/LoricaOS/Aegis/releases/download/v<version>/aegis.elf, and records the version it landed. fetch-components.sh walks components.list (one <herald-id> <version> line per package), downloads each from …/LoricaOS/<id>/releases/download/v<version>/<id>.hpkg, and unpacks every payload into a single overlay tree plus a database the desktop image pre-seeds. fetch-coreutils.sh does the same for the base utilities. Note that glyph is fetched one layer down — not by the OS repo, but by each lumen-* component at its own build time, because the toolkit is a link-time dependency of the app, not a thing installed onto the image.

LoricaOS/Aegis  ──(release: aegis.elf)──────────────┐
LoricaOS/coreutils ──(release: coreutils.hpkg)──────┤
LoricaOS/lumen ─┐                                    │
LoricaOS/bastion │                                   ▼
LoricaOS/citadel-dock ├─(release: <id>.hpkg)─►  LoricaOS/LoricaOS
LoricaOS/lumen-* ─┘                              fetch + assemble
        ▲                                             │
        └── each fetches glyph toolkit at build time  ▼
                                              loricaos-*.iso

Why fetch instead of build

The same three reasons hold at every layer — kernel, toolkit, components:

  • Reproducibility — everything that pins glyph 1.0.0 (or kernel 1.x, or any component version) gets bit-for-bit the same artifact, regardless of when or where the image is built.
  • Decoupling — the OS build needs no kernel cross-toolchain and no musl configuration for every app; it pulls finished, signed binaries.
  • Independent cadence — each piece releases on its own schedule. A glyph change never silently alters a component until that component bumps its pin; a kernel release never forces an OS release. Versions move independently, and the fetch scripts are the single points that couple them.

Adding an app to the default image

Because the component set is just a list, the default desktop image is edited by editing data, not code. Add a <herald-id> <version> line to tools/components.list and the next build fetches and bakes it in. Apps not on the list are still installable on demand via herald once they are on Chancery — the mechanism for optional extras (games, niche tools) that should not bloat the base image.

The two profiles

LoricaOS builds two production ISOs from a shared base:

Profile Target Graphical stack Rootfs
Desktop make desktop-isoloricaos-desktop.iso Full Lumen desktop — compositor, shell, apps rootfs/ + rootfs-desktop/ overlay + fetched components
Server make server-isoloricaos-server.iso None — text console, login at /bin/login rootfs/ only

rootfs/ is the shared base both profiles are built from; rootfs-desktop/ overlays the graphical profile on top, and the fetched component overlay merges in. The server profile is genuinely zero-graphical — it pulls the kernel and coreutils but none of the lumen-* components — so it boots straight to a text console.

The capability model is what makes this layering safe rather than merely tidy: a component arriving as a fetched, signed package brings its own caps.d policy, so it gains exactly the authority it declares and not one token more — whether it was baked into the image or installed later from Chancery.