Components
Table of Contents
What emanix actually installs, by tier. Most of it is Home Manager; the substrate and the compositor are NixOS.
1. Home Manager tier (home/)
1.1. Emacs
The centre of the system, and the reason for the rest of it. Emacs 31.1 on a per-host base: EWM hosts run EWM's pwayl/Skia (GPU) fork, built through emacs-overlay; other hosts run pgtk. One package list, one base per host, with a curated package set and modal editing.
There is exactly one Emacs build on a host. Which one you get depends on
emanix.ewm.enable:
- true — the system-owned build, carrying the compositor's own package, put on
the system PATH so
emacsclientis available everywhere. Home Manager delivers configuration only, never a second Emacs. - false — the same package set minus the compositor, installed at the home level and run as a systemd user service.
Two builds of Emacs on one machine is the failure mode this design exists to prevent.
The per-host base. The EWM compositor is a client of the pwayl/Skia fork, so
an EWM host cannot run an ordinary pgtk Emacs. That fork is built once, in one
place, and used by both the NixOS tier that runs the compositor and the Home
Manager tier that builds the package set — a second copy anywhere would quietly
give a machine two Emacsen differing by more than their display backend. The
fork borrows its build recipe from emacs-overlay's 31.1 because the stable
channel ships 30.2 and has no Emacs 31 attribute. Whichever module owns a host's
Emacs records the choice in emanix.emacs.base, which consumers read when they
have to build an Emacs package against the same base (see
Options). The reasoning is kept as a decision record in
the repository, docs/decisions/gpu-emacs.md.
1.2. EWM — the compositor
A Wayland compositor written in Rust on Smithay, loaded as a dynamic module inside the Emacs process. Windows, workspaces, status bar: all of it is Emacs, so keybindings and configuration are one language. Upstream is codeberg.org/ezemtsov/ewm; what follows is how Emanix launches it.
It launches from the TTY login shell, inside the logind session scope. This is not the obvious approach — there is a shipped systemd user unit — but that unit runs outside any session and cannot acquire display-master without a display manager. Launching from the login shell was the working path.
Three details in that launch are load-bearing and were each found the hard way:
- One compositor per boot session. A stale daemon holds display-master and starves every new launch, so the launcher kills a prior instance first — and matches on the full command line, because the Nix wrapper truncates the process name.
- A flap guard. If the compositor crashes in a loop, a marker file drops you to a normal shell instead of an unusable login cycle. Remove it to re-arm.
- Keyboard options are set in the environment, not in the compositor's own config, because the keymap is built at compositor start — configuration applied afterwards is simply too late.
1.3. Terminal and shell
A GPU-accelerated terminal, gated on emanix.ghostty.enable, and zsh with
completion and a themed prompt. There is no multiplexer; remote sessions are the
consumer's concern.
1.4. arc, and the line around it
This is the clearest place the distribution's boundary shows, because three adjacent things land on three different sides of it.
arc is shipped. It is the distribution's bundled companion: a local, offline
retrieval engine over this machine's own configuration — Emacs, Elisp, NixOS
and Home Manager options, and the org-roam vault — returning ranked, jumpable
citations rather than model-generated prose. Bound to s-i from any slot, and
to C-c i for its command map. When nothing in the searched scope matches, it
says so and names the scope, which is the whole point: a config index that
invents a NixOS option is worse than none. See
Keybindings.
The model runner is not shipped. arc's hybrid retrieval needs a local Ollama for embeddings, and Emanix does not install one — it is a substantial dependency to impose on a machine that may not want it, and a headless box very reasonably does not. Your flake supplies it. arc constructs its providers without contacting anything, so nothing here fails at load time on a host with no runner; at query time it falls back to keyword-only results rather than answering plausibly.
A coding agent is not shipped either. An AI harness is not a decision a
distribution should make for you. Emanix ships the wiring — the
emanix-agent-shell.el ACP glue (C-c C-' for Claude, C-c p for pi), the
adapter wrappers in agent-acp/, and a secret store your flake can point at a
credential. Supply the claude or pi CLI and the keys work; supply none and
the binding reports the missing adapter rather than failing silently. See
Secrets for why credential use and credential access
are separate questions.
1.5. Everything else
Search and file tooling, git and its helpers, a formatter and linters for Nix itself, Python tooling, media tooling, screenshot and screen-recording utilities for Wayland, a password manager, and fonts.
The list is one place. Feature flags decide which of it materializes: a host
with emanix.gui = false does not receive the GUI applications, because the
modules that provide them are gated on that flag. Nothing consults the role.
Two seams let a consumer extend the tier: emanix.emacs.extraPackages adds
Emacs packages to the distribution's build, and
emanix/modeline-extra-segments registers extra tab-bar segments as no-argument
functions. The distribution ships none of either.
2. NixOS tier (modules/)
Six modules. Three are the substrate.
2.1. Base — every host
Shell, primary user, timezone, locale, console keymap, and the Nix settings that make the rest sane:
- Flakes and the modern CLI enabled
- Store auto-optimisation
- Daily garbage collection, deleting generations older than three days
(
--delete-older-than 3d) - A mid-build emergency valve: when free space drops below a floor, Nix collects garbage during the build until a ceiling is available again
That last pair matters more than it looks. A weekly timer is not enough on a host that builds often — a churning machine can accumulate many gigabytes of dead paths within a day or two of a successful collection. And on a virtualised host whose disk image never shrinks below its high-water mark, garbage that lives a week costs real disk on the host side even after it is finally collected.
2.2. init
The first system generation, and emanix-init on the PATH: the tool that adopts
a generated configuration into a git repository, and fails the build rather than
failing on a stranger's console.
2.3. Firstboot
Packages the one-time post-install command. It is built with a wrapper that shellchecks the script at build time, so a broken helper fails the build rather than the install.
2.4. The rest of the tier
gpu.nix and firmware.nix supply hardware capability, and ewm.nix is the
compositor service, exposed as nixosModules.ewm.
Every host gets the secret store: mkHost imports the agenix module, so a
consumer supplies recipients and secrets rather than wiring the mechanism.
3. Hardware and network
Capability, not facts. The distribution ships emanix.hardware.gpu, the
redistributable-firmware default, and lib.mkDisk for describing a disk's shape
— how to bring up a GPU or lay out a disk, not which GPU a box has or which
disk it is.
Which drivers must be in the initrd, how the disks are partitioned, what mesh or network the host joins — those are facts about a particular machine on a particular network, and only your flake knows them. See Architecture for the argument, which is the same one that removed the roles.