Skip to main content

max / alloy

Write the user-facing manual docs/ has been design rationale written for the author: why each pick was made, what was rejected, what is still open. A stranger who installs Alloy had nothing to read. Fifteen chapters under docs/manual/, written against the code and the Containerfile rather than against the design docs, which disagree with the shipped system in places. Covers building an image (there is nothing to download), the installer and the recovery phrase, the first fifteen minutes, the full keybinding reference, the console, the isolation dial, updating by rebuild-and-switch, appearance, continuity, hardware, troubleshooting by symptom, and an FAQ. Anything unbuilt is named as unbuilt rather than described in the future tense: the bluetooth view, `alloy theme <name>`, mode picking in `alloy display`, USB automounting, the staleness report in `alloy update`, a headless install, the wallpaper collection. No contact address, since that decision is still open.
Co-Authored-By
Claude Opus 5 (1M context) <noreply@anthropic.com>
Author: Max Johnson <me@maxj.phd> · 2026-07-31 04:24 UTC
Signed with PGP, not checked
Commit: 0659d87d4dfcb159c7e2c85d27ef67c82c581218
Parent: 49731c1
17 files changed, +1576 insertions, -0 deletions
M README.md +5
@@ -27,6 +27,11 @@
27 27
28 28 ## Docs
29 29
30 + The [manual](docs/manual/README.md) is for people who run Alloy: building an
31 + image, installing, the keybindings, how software gets installed, how to roll
32 + back, troubleshooting. Everything below it is design rationale, written for
33 + whoever works on Alloy.
34 +
30 35 - [`docs/MANIFESTO.md`](docs/MANIFESTO.md) — what Alloy is, who it's for, the thesis.
31 36 - [`docs/STACK.md`](docs/STACK.md) — every pick (base, compositor, bar, lock, launcher, notifications, screenshot, file manager) with reasoning and what was rejected.
32 37 - [`docs/MARQUEE-APPS.md`](docs/MARQUEE-APPS.md) — the egui design-system app pipeline.
@@ -1,0 +1,56 @@
1 + # 1. What Alloy is
2 +
3 + Alloy is a curated desktop built on Fedora's atomic base. The pieces:
4 +
5 + - **Fedora bootc as the base.** The operating system is a container image. It
6 + is not modified in place; a new version is staged and swapped at boot, and
7 + the previous one stays on disk to roll back to.
8 + - **sway as the compositor.** i3-style manual tiling on Wayland. Workspaces,
9 + splits, tabs, and stacks. No scrolling columns, no animation.
10 + - **A terminal-first stack.** rio for the terminal, nushell for the shell,
11 + helix for the editor, yazi for files, bottom for processes, zathura for PDFs,
12 + imv for images, mpv for video.
13 + - **One authored program, the `alloy` console.** Network, audio, displays,
14 + packages, settings, sync, and the installer, all as terminal views sharing
15 + one keymap and one palette.
16 +
17 + Alloy adopts everything graphical it needs (swaylock, mako, swaybar, swayosd)
18 + and authors nothing that a terminal can serve.
19 +
20 + ## Who it is for
21 +
22 + Developers and keyboard-driven users who prefer configuring once to configuring
23 + often, and who are comfortable in a terminal. Alloy assumes you would rather
24 + read one page about how the system is put together than click through settings
25 + looking for a checkbox.
26 +
27 + It is not a gaming distro, not a GNOME spin, and not a fork of Universal Blue's
28 + images.
29 +
30 + ## What is different from a normal Linux desktop
31 +
32 + Three things surprise people, in roughly this order.
33 +
34 + **You cannot `dnf install` into the running system.** The root filesystem is
35 + read only. Software goes to one of three places instead, and chapter 7 is about
36 + choosing between them.
37 +
38 + **There is no graphical settings app.** Settings live in `alloy settings` and
39 + the other console verbs. Anything the console does not cover is a config file
40 + under `~/.config`, and `alloy settings` can edit most of those too.
41 +
42 + **Your machine is meant to be disposable.** The interesting state is your files
43 + and your identity, both of which can follow you to the next install. Chapter 12
44 + covers the two enrollments that make that true.
45 +
46 + ## What Alloy deliberately does not have
47 +
48 + - No emoji font, and no fallback that draws them. Emoji in a web page render as
49 + missing glyphs.
50 + - No screen recorder. The picked tool is not packaged for Fedora yet.
51 + - No scanner support. Printing is driverless only (chapter 13).
52 + - No automatic updates of any kind.
53 + - No graphical file manager, launcher, or editor. Each has a terminal answer.
54 +
55 + These are positions, not omissions waiting to be fixed. Where one turns out to
56 + be wrong, it changes in a release rather than in a preference toggle.
@@ -1,0 +1,87 @@
1 + # 2. Building your image
2 +
3 + Alloy publishes source and never publishes a binary image. You build the
4 + installer ISO yourself, on a machine you already own.
5 +
6 + That is not an interim state waiting on infrastructure. It is the distribution
7 + model: what you boot is the thing you configured, and Make Creative hosts no
8 + registry, signs no images, and redistributes nobody's binaries.
9 +
10 + ## What you need
11 +
12 + - **A Linux machine with podman.** The build runs rootful.
13 + - **Disk.** The image, the container cache, and the ISO working directory
14 + together want tens of gigabytes free.
15 + - **Time.** A cold build compiles nothing of Fedora but does pull around 600
16 + packages and compress a squashfs. Budget an hour on a laptop, more on slow
17 + storage.
18 +
19 + There is no path to an Alloy ISO from macOS or Windows. The build needs Linux
20 + with podman, and nothing emulates that cheaply enough to recommend.
21 +
22 + ## Get the source
23 +
24 + git clone https://makenot.work/git/max/alloy
25 + cd alloy
26 +
27 + ## Build the ISO
28 +
29 + build/build-iso.sh
30 +
31 + That builds the bootc image (`localhost/alloy:local`), then wraps it into an
32 + installer ISO under `output/`. The ISO carries the image twice: once as the
33 + live system you boot, and once as the source that gets installed to the disk.
34 +
35 + Useful flags:
36 +
37 + | Flag | What it does |
38 + |---|---|
39 + | `--skip-build` | Reuse the image already in container storage |
40 + | `--fast` | Reuse the image and compress cheaply. For iterating on the boot chain |
41 + | `--skip-source` | Omit the install source. The ISO boots but cannot install |
42 + | `--update-target host:5000/alloy:43` | Bake an update registry into the medium (development builds only) |
43 +
44 + Without `--update-target`, machines installed from the medium never fetch
45 + updates. That is the intended state for anything but a development build.
46 +
47 + ## Write it to a USB stick
48 +
49 + Any of the usual tools work on the ISO in `output/`. If you would rather have
50 + the write checked for you, the disk-image path has guards:
51 +
52 + build/build-image.sh --skip-bib --write /dev/sdX
53 +
54 + It refuses partitions, refuses anything with a mounted filesystem, demands an
55 + explicit device path plus a typed confirmation, and verifies the result with
56 + `cmp` before claiming success.
57 +
58 + ## Building a disk image instead
59 +
60 + `build/build-image.sh` produces raw or qcow2 disk images through
61 + bootc-image-builder, which is what you want for a VM:
62 +
63 + build/build-image.sh --type qcow2
64 +
65 + It refuses to build ISOs on purpose. Every ISO type that tool offers composes
66 + an Anaconda installer, and an Anaconda install of Alloy leaves a machine with
67 + no account and a locked root. The Alloy installer ISO comes from
68 + `build/build-iso.sh` and nowhere else.
69 +
70 + ## Changing what goes in
71 +
72 + The Containerfile at the repo root is the whole package list, and it is meant
73 + to be read and edited. Adding a package is a line in the right group; removing
74 + one is deleting a line. Two cautions:
75 +
76 + - The build asserts a number of things it depends on (that `satty`, `grim`,
77 + `slurp`, `jq` and `notify-send` exist for the screenshot script, that the
78 + fontconfig picks resolve, that the polkit rules name actions that exist).
79 + Removing a package can trip an assertion, which is the build telling you the
80 + removal has consequences somewhere else.
81 + - Anything you add that Alloy ships should get a line in
82 + `crates/alloy/credits.toml`, which is what the installer's credits page
83 + reads. It is hand-curated on purpose, so nothing adds itself.
84 +
85 + Two builds a week apart can differ: the RPM set is not pinned to a snapshot
86 + yet. Fonts and the Rust dependency tree are pinned; the Fedora packages are
87 + not.
@@ -1,0 +1,72 @@
1 + # 3. Installing
2 +
3 + Boot the USB stick you wrote in chapter 2. The live system starts the Alloy
4 + installer by itself; there is nothing to type at a prompt and no desktop to
5 + find it in. On an already-installed machine the same unit is inert, so the
6 + installer cannot fire by accident.
7 +
8 + The installer is `alloy install`, a wizard over `bootc install to-disk`. bootc
9 + does the real work: partitioning, the ostree deploy, and the bootloader. The
10 + wizard asks four questions, shows you what it is about to run, and runs it.
11 +
12 + ## The six screens
13 +
14 + **1. Disk.** Every disk the machine can see, with its size and model. This is
15 + the one answer nothing later recovers from, so it comes first: if the disk you
16 + expect is not listed, stop here rather than after typing a password.
17 +
18 + **2. Hostname.** What the machine is called on your network and in your
19 + prompt.
20 +
21 + **3. Account.** Your username and password. Alloy creates one account and does
22 + not enable a root login.
23 +
24 + **4. Encryption.** Optional, and if you say yes you type a passphrase and then
25 + see a recovery phrase. Read the next section before deciding.
26 +
27 + **5. Summary.** Every command the installer is about to run, in order, before
28 + any of them runs. Nothing is hidden behind a progress bar.
29 +
30 + **6. Credits.** What Alloy ships, each project's license, and its URL. It is
31 + the only screen that asks nothing, and the install starts from here rather than
32 + from the summary: the last screen before a disk is erased should be the one
33 + naming whose work is about to be written to it.
34 +
35 + Then the install runs, streaming its output, for the several minutes bootc
36 + takes.
37 +
38 + ## Encryption and the recovery phrase
39 +
40 + Choosing encryption sets up LUKS on the root filesystem and binds it to the
41 + machine's TPM, so the disk unlocks at boot without a password prompt.
42 +
43 + That binding has one failure mode that ends in permanent data loss: the TPM
44 + stops answering. Clearing it, replacing the board, or moving the disk to
45 + another machine all do that. So Alloy enrolls two ways in rather than one:
46 +
47 + - **Your passphrase**, the one you typed.
48 + - **A recovery phrase**, eight words the installer generates and shows you
49 + once.
50 +
51 + Write the recovery phrase down on paper. It is not stored anywhere you can read
52 + it back from later, it is never rotated, and it is what stands between a dead
53 + TPM and a lost disk. Words rather than a random key string because this is a
54 + phrase a person reads off one screen and types into another, months later.
55 +
56 + If you skip encryption, none of this applies and the disk is readable by anyone
57 + holding it.
58 +
59 + ## After the install
60 +
61 + Reboot and remove the medium. You land on the greeter (tuigreet on VT1), sign
62 + in with the account you made, and sway starts.
63 +
64 + A machine installed from a locally built medium has its update timer disabled.
65 + It will never poll anything. Chapter 8 covers what updating means instead.
66 +
67 + ## Installing without a screen
68 +
69 + `alloy install` needs a terminal, which means a headless install is not a
70 + one-command flow today. Collecting an SSH key at install time, and minting
71 + media with a key and hostname already baked in, are both filed work rather than
72 + shipped features. For now, install on a machine with a display attached.
@@ -1,0 +1,108 @@
1 + # 4. The first fifteen minutes
2 +
3 + You have signed in and the screen is mostly empty: a bar across the top, a
4 + wallpaper colour behind it, and nothing else. That is correct. Alloy opens no
5 + windows for you.
6 +
7 + Throughout this manual **Mod** means the Super key (the one between Ctrl and
8 + Alt on most keyboards).
9 +
10 + ## The screen that greets you once
11 +
12 + The first time you log in, a terminal opens on `alloy setup`. It offers two
13 + enrollments, both optional:
14 +
15 + - **Network identity** (Tailscale), so this machine can reach your others.
16 + - **File sync** (Syncthing), so your files follow you onto this machine.
17 +
18 + Skipping is fine and reversible. `alloy mesh` and `alloy sync` do the same
19 + enrollments later. Press `q` when you are done. The screen appears once; typing
20 + `alloy setup` by hand always opens it again.
21 +
22 + ## Open a terminal
23 +
24 + Mod+Return
25 +
26 + That is rio, running nushell. It is where you will spend most of your time.
27 +
28 + If you would rather find a graphical app by name than type a binary:
29 +
30 + Mod+D
31 +
32 + That is the launcher: a fuzzy picker over installed desktop entries, running in
33 + a floating terminal. Two keys, two jobs. `Mod+Return` is for typing commands,
34 + `Mod+D` is for the apps whose binary name nobody remembers.
35 +
36 + ## Move a window around
37 +
38 + Open two or three terminals with `Mod+Return`. They tile automatically.
39 +
40 + - `Mod+H/J/K/L` moves focus left, down, up, right.
41 + - `Mod+Shift+H/J/K/L` moves the window itself.
42 + - `Mod+Q` closes the focused window.
43 + - `Mod+F` makes it fullscreen.
44 + - `Mod+1` through `Mod+4` switch workspaces; `Mod+Shift+1` and friends send the
45 + window with you.
46 +
47 + Chapter 5 has the whole list. Those six get you through the day.
48 +
49 + ## Meet the console
50 +
51 + alloy
52 +
53 + is not a command by itself. Every surface is a verb:
54 +
55 + alloy net # wifi and connections
56 + alloy audio # outputs, inputs, and which stream goes where
57 + alloy display # scale, rotation, which outputs are on
58 + alloy settings # time, hostname, locale, theme, and app configs
59 + alloy pkg # what is installed and where it lives
60 + alloy update # what image is booted, what is staged, how to go back
61 +
62 + Every one of them has the same shape: Tab moves between panes, arrow keys or
63 + `j`/`k` move within a list, Enter acts, Esc cancels, `q` quits, `?` shows help.
64 +
65 + Every action prints the command it ran in a pane at the bottom. That is
66 + deliberate. The console is not hiding the CLI from you, it is showing you which
67 + one to learn.
68 +
69 + ## Get online
70 +
71 + alloy net
72 +
73 + Pick your network, press Enter. Joining a network you have never joined before
74 + needs authorization the console does not yet ask for, so for a brand new wifi
75 + network use:
76 +
77 + run0 nmcli device wifi connect "Network Name" --ask
78 +
79 + `run0` is how you become root on Alloy. There is no `sudo` habit to keep here.
80 +
81 + ## Set the volume
82 +
83 + The Fn keys work: volume up, down, mute, and the media keys, all with an
84 + on-screen indicator. For anything more precise, `alloy audio` shows every
85 + stream and every device and lets you move one onto the other.
86 +
87 + ## Take a screenshot
88 +
89 + - `Print` captures the whole output.
90 + - `Shift+Print` selects a region.
91 + - `Ctrl+Print` captures the active window.
92 + - `Mod+Print` opens the most recent capture in satty to annotate it.
93 +
94 + Captures land in `~/Pictures/Screenshots` and raise a notification saying so.
95 +
96 + ## Lock the screen
97 +
98 + Mod+Ctrl+L
99 +
100 + The session also dims after four and a half minutes, locks at five, and turns
101 + the displays off at ten. A closed lid always locks before suspending.
102 +
103 + ## Then what
104 +
105 + - Chapter 7 if you want to install software. Read it before reaching for a
106 + package manager; the answer is not `dnf`.
107 + - Chapter 11 if the light theme is not what you want at night.
108 + - Chapter 12 if this machine should share files with your other ones.
@@ -1,0 +1,94 @@
1 + # 5. Keybindings
2 +
3 + **Mod** is the Super key. These are the shipped defaults, from
4 + `~/.config/sway/config`. Edit that file and press `Mod+Shift+C` to reload.
5 +
6 + ## Session
7 +
8 + | Keys | Action |
9 + |---|---|
10 + | `Mod+Return` | Open a terminal |
11 + | `Mod+D` | Launcher: fuzzy picker over installed apps |
12 + | `Mod+Shift+V` | Clipboard history picker |
13 + | `Mod+Ctrl+L` | Lock the screen |
14 + | `Mod+Shift+C` | Reload the sway config |
15 + | `Mod+Shift+E` | Exit the session |
16 +
17 + ## Windows
18 +
19 + | Keys | Action |
20 + |---|---|
21 + | `Mod+Q` | Close the focused window |
22 + | `Mod+F` | Fullscreen |
23 + | `Mod+Shift+F` | Fullscreen across all outputs |
24 + | `Mod+H` `Mod+J` `Mod+K` `Mod+L` | Focus left, down, up, right |
25 + | `Mod+Shift+H/J/K/L` | Move the window left, down, up, right |
26 + | `Mod+Shift+Space` | Toggle floating |
27 + | `Mod+Space` | Move focus between tiled and floating |
28 +
29 + ## Layout
30 +
31 + | Keys | Action |
32 + |---|---|
33 + | `Mod+B` | Split horizontally |
34 + | `Mod+V` | Split vertically |
35 + | `Mod+W` | Tabbed layout |
36 + | `Mod+S` | Stacking layout |
37 + | `Mod+E` | Toggle split direction |
38 + | `Mod+R` | Resize mode: `h/j/k/l` resize, Enter or Esc leaves |
39 + | `Mod+-` | Shrink width by 10% |
40 + | `Mod+=` | Grow width by 10% |
41 +
42 + ## Workspaces
43 +
44 + | Keys | Action |
45 + |---|---|
46 + | `Mod+1` .. `Mod+4` | Switch to workspace 1 through 4 |
47 + | `Mod+Shift+1` .. `Mod+Shift+4` | Move the window to that workspace |
48 + | `Mod+N` | Switch to the `notes` workspace |
49 + | `Mod+M` | Switch to the `main` workspace |
50 +
51 + ## Screenshots
52 +
53 + | Keys | Action |
54 + |---|---|
55 + | `Print` | Capture the whole output |
56 + | `Shift+Print` | Select a region (Esc cancels) |
57 + | `Ctrl+Print` | Capture the active window |
58 + | `Mod+Print` | Annotate the most recent capture in satty |
59 +
60 + Every capture goes to `~/Pictures/Screenshots` and raises a notification.
61 +
62 + ## Media and hardware keys
63 +
64 + | Keys | Action |
65 + |---|---|
66 + | Volume up / down / mute | Output volume, with an on-screen indicator |
67 + | Mic mute | Input mute |
68 + | Brightness up / down | Backlight |
69 + | Play / pause / next / previous | Whatever is playing, over MPRIS |
70 + | Caps Lock | Shows a caps indicator |
71 +
72 + ## Inside the console
73 +
74 + Every `alloy` view shares one keymap.
75 +
76 + | Keys | Action |
77 + |---|---|
78 + | `Tab` / `Shift+Tab` | Move between panes |
79 + | `j` / `k` or arrows | Move within a list |
80 + | `Enter` | Activate the selection |
81 + | `Space` | Toggle a switch, or fold a section in a form |
82 + | `Esc` | Cancel. In a view with nothing to cancel, leave |
83 + | `Ctrl+S` | Save, in a file-backed form |
84 + | `?` | Help |
85 + | `q` | Quit |
86 +
87 + Views with tabs switch between them with `h` and `l`. A field being edited owns
88 + every key while it is open, so `q` types a `q` there rather than quitting.
89 +
90 + ## Inside the other tools
91 +
92 + Alloy does not rebind the applications it adopts. helix, yazi, zathura, imv,
93 + mpv and bottom keep their own upstream keys, all of them vim-shaped. Their own
94 + help (`?` in yazi and bottom, `:tutor` in helix) is the reference.
@@ -1,0 +1,79 @@
1 + # 6. The console
2 +
3 + `alloy` is the one program Alloy authors. It is a set of terminal views over
4 + the CLIs that already run the system, sharing one palette, one keymap, and one
5 + habit: every action shows the command it ran.
6 +
7 + That last part is the point. The console is not a layer over the system you
8 + have to learn instead of the system. It shows you `nmcli connection up 'Coffee
9 + Shop Wifi'` in a pane at the bottom of the screen, and the day you want to
10 + script that, you already know what to type.
11 +
12 + ## The verbs
13 +
14 + | Command | What it shows |
15 + |---|---|
16 + | `alloy net` | Interfaces, connections, the wifi radio |
17 + | `alloy audio` | Streams, outputs and inputs, and which is routed where |
18 + | `alloy display` | Outputs sway is driving: scale, rotation, on or off |
19 + | `alloy mesh` | Mesh VPN peers and exit node (alias: `alloy tail`) |
20 + | `alloy sync` | Synchronized folders, devices, and pending invitations |
21 + | `alloy pkg` | What is installed and where it lives |
22 + | `alloy update` | The booted image, the staged one, and rollback |
23 + | `alloy settings` | System settings and application configs |
24 + | `alloy config <path>` | One config file, opened directly |
25 + | `alloy setup` | The first-boot enrollment offer |
26 + | `alloy install` | The installer |
27 + | `alloy theme apply` | Put the day or night skeleton in place |
28 + | `alloy status --bar` | The status line, as JSON. Run by the bar, not by you |
29 +
30 + `alloy --help` lists them, and `alloy <verb> --help` covers the flags.
31 +
32 + ## Settings
33 +
34 + `alloy settings` is two tabs over one form.
35 +
36 + **System** holds live state: timezone, network time, hostname, locale, keymap,
37 + and the theme. Rows here commit as you edit them, because setting a timezone is
38 + atomic on its own. Each writing row runs exactly one command, and each of those
39 + is narrowly granted so it does not prompt for a password.
40 +
41 + The clock is shown and never settable. Moving a system clock invalidates
42 + certificates and reorders logs; the row is there so you can see what changing
43 + the timezone did.
44 +
45 + **Applications** holds config files, listed by the app they configure rather
46 + than by path. You pick `rio`, not `~/.config/rio/config.toml`. Editing here is
47 + schema-driven: fields carry types, ranges, allowed values, and their own help
48 + text, and the file keeps its comments and key order when it is written back.
49 +
50 + File-backed forms save with `Ctrl+S`. Live-state rows have nothing to save.
51 +
52 + An app with no schema still appears in the list and opens a plain text editor
53 + with syntax highlighting, so looking for "where do I configure sway" finds an
54 + answer rather than a blank.
55 +
56 + ## A row that says it cannot do something
57 +
58 + If a row is shown but not settable, and says why, that is deliberate. A tool
59 + that did not answer, or a vocabulary that came back empty, gets reported rather
60 + than hidden: hiding it would answer "where do I set this" with silence, and
61 + offering it would promise a command that is not there.
62 +
63 + ## What the console will not do
64 +
65 + - **It does not browse or search a catalog.** `alloy pkg` shows what is
66 + installed, where it lives, and what each surface costs. It will not help you
67 + find software you have not named.
68 + - **It is not a systemd control panel.** `systemctl` is fine.
69 + - **It is not a launcher or a shell.** You invoke it for a task and close it.
70 +
71 + ## Not built yet
72 +
73 + - `alloy theme <name>` for swapping the runtime theme without logging out.
74 + Today the theme is chosen in `alloy settings` and applied at the next login.
75 + - A Bluetooth view. Pairing is `bluetoothctl` for now (chapter 13).
76 + - MagicDNS lookup and share/unshare in `alloy mesh`.
77 + - Editing an existing folder's share list in `alloy sync`.
78 + - Multi-output mode picking in `alloy display`. Scale and enable work; the mode
79 + picker waits on a machine with two displays to test against.
@@ -1,0 +1,110 @@
1 + # 7. Installing software
2 +
3 + This is the chapter that makes an atomic system make sense. It is also the
4 + thing Alloy is most opinionated about.
5 +
6 + On a normal distro there is one question: install it or not. Here there are
7 + three places software can live, and picking the right one is most of the skill.
8 + Alloy replaces "which tool" with one question: **how much of your machine
9 + should this software be able to reach?**
10 +
11 + ## The isolation dial
12 +
13 + | Level | Sees | Use it for |
14 + |---|---|---|
15 + | `host` | Your whole home directory, your devices, the session bus | Development toolchains, anything that must feel installed |
16 + | `workspace` | Its own private home, plus the directories you name | Running someone else's build, a package manager over untrusted code |
17 + | `sandboxed` | What a portal hands it: a file picker, permission-gated devices | Graphical apps you did not write |
18 +
19 + You pick the level. Alloy picks the implementation behind it: distrobox for
20 + `host`, podman directly for `workspace`, flatpak for `sandboxed`. The level is
21 + the stable interface, which is why the backend can change later without your
22 + boxes changing.
23 +
24 + **Be clear about what `workspace` is.** A rootless container with a bind mount
25 + limits blast radius. It is not a security boundary and Alloy will not call it
26 + one. `sandboxed` is the only level with a real isolation model behind it.
27 +
28 + ## Boxes
29 +
30 + alloy pkg box
31 +
32 + lists every box on the machine, including ones created outside Alloy with a
33 + bare `podman run` or a direct `flatpak install`. An inventory that hid those
34 + would be lying. Rows mark which boxes are declared (reproducible) and which are
35 + ad hoc (gone on a rebuild).
36 +
37 + From that tab you can start, stop, enter, remove, and export a box.
38 +
39 + **Entering** a box hands the terminal over to it, so the console tears itself
40 + down and comes back when you exit.
41 +
42 + **Exporting** puts a command from inside a box onto your host `PATH`, at
43 + `~/.local/bin`, which Fedora already searches. Running `rg` then runs it inside
44 + its box, in the right directory, starting the box first if it was stopped.
45 +
46 + One caution: an exported wrapper takes the plain name of the binary, so
47 + exporting something the host already has puts the box's copy ahead of the
48 + system one.
49 +
50 + ## Declaring boxes
51 +
52 + Boxes can be described in TOML, which makes them reproducible and syncable:
53 +
54 + ```toml
55 + [box.dev]
56 + level = "host"
57 + image = "registry.fedoraproject.org/fedora-toolbox:43"
58 + export = { bin = ["rg", "fd", "hx"] }
59 +
60 + [box.scratch]
61 + level = "workspace"
62 + image = "registry.fedoraproject.org/fedora-toolbox:43"
63 + mounts = ["~/code/thing"]
64 +
65 + [box.somegui]
66 + level = "sandboxed"
67 + app = "org.example.SomeApp"
68 + ```
69 +
70 + `host` and `workspace` boxes take an `image`; a `sandboxed` box is one app, so
71 + it takes an `app`.
72 +
73 + ## Layering onto the base image
74 +
75 + The fourth option is putting a package into the operating system itself:
76 +
77 + rpm-ostree install <package>
78 +
79 + This does not change the running system. It stages a new deployment that takes
80 + effect at the next boot. `alloy pkg install` shows what is layered and which
81 + rows are staged rather than active, which is the single most confusing thing
82 + about an atomic base and the reason that tab exists.
83 +
84 + Layer sparingly. Every layered package slows down every future image update,
85 + and a package you layer is one that has to keep resolving against a base that
86 + moves. If it can be a box, make it a box.
87 +
88 + Removing one is `rpm-ostree uninstall <package>`, and it stages the removal the
89 + same way.
90 +
91 + ## Flathub
92 +
93 + The `flatpak` client is in the image and no Flatpaks are provisioned. Adding
94 + Flathub and pulling an app is the ordinary thing:
95 +
96 + flatpak install flathub org.example.SomeApp
97 +
98 + Alloy ships no graphical file manager, so this is where one comes from if you
99 + want one.
100 +
101 + ## Which one, in practice
102 +
103 + - **A CLI tool you use daily and Fedora has it.** Layer it, or put it in a
104 + `host` box and export it. Layering is simpler; the box keeps the base clean.
105 + - **A language toolchain for one project.** `workspace`, with the project
106 + directory mounted.
107 + - **A graphical app from the internet.** `sandboxed`.
108 + - **Something the desktop itself needs to work** (a compositor piece, a font, a
109 + daemon). Edit the Containerfile and rebuild. That is what the builder model
110 + is for.
@@ -1,0 +1,82 @@
1 + # 8. Updating and rolling back
2 +
3 + Alloy publishes no images, so there is nothing for your machine to download.
4 + Updating means rebuilding the image on a machine you own and switching to it.
5 + Rolling back means picking last boot's deployment from the boot menu.
6 +
7 + ## What your machine is running
8 +
9 + alloy update
10 +
11 + shows the deployments: which image is booted, which is staged for the next
12 + boot, and what can be rolled back to. It fronts `rpm-ostree status`, so the
13 + same information is available as:
14 +
15 + rpm-ostree status
16 +
17 + Deployments are the whole model. Nothing is ever edited in place. An update,
18 + a layered package, and a rollback all produce or select a deployment, and the
19 + switch happens at boot.
20 +
21 + ## Updating
22 +
23 + On the machine where you keep the source:
24 +
25 + cd alloy
26 + git pull
27 + build/build-iso.sh --skip-source # or build/build-image.sh --skip-bib
28 +
29 + Either one rebuilds `localhost/alloy:local`. Then, on the machine to update:
30 +
31 + bootc switch --transport containers-storage localhost/alloy:local
32 + systemctl reboot
33 +
34 + That adopts the locally built image in place. It is staged with A/B rollback,
35 + exactly like a registry-fed update would be, with the image coming from local
36 + container storage instead of the network.
37 +
38 + You do not reinstall. Your home directory, your accounts, and your layered
39 + packages survive. What you give up against a published image is the build time,
40 + not the machine.
41 +
42 + If the build happened somewhere else, move the image the way you would move any
43 + container image (`podman save` / `podman load`, or a local registry) and switch
44 + against that.
45 +
46 + ## Rolling back
47 +
48 + If a new image is worse:
49 +
50 + rpm-ostree rollback
51 + systemctl reboot
52 +
53 + The previous deployment is still on disk, so this is fast and does not need a
54 + network. It swaps which deployment boots by default.
55 +
56 + You can also do it without booting the broken image at all: hold `Esc` or
57 + `Shift` at boot to get the GRUB menu, and pick the older entry. That boots it
58 + once. If the older one is the one you want to keep, run `rpm-ostree rollback`
59 + from it.
60 +
61 + ## Why nothing updates itself
62 +
63 + An installed machine does not poll for updates. The timer that would do it is
64 + enabled only when the installer medium named an update target, which only a
65 + development build does.
66 +
67 + The consequence worth stating: **an image built in January and run until June
68 + carries January's packages**, including the browser, which is the program on
69 + your machine that faces the whole internet all day. If you run Alloy as a daily
70 + driver, rebuild on a rhythm you decide rather than when something breaks.
71 +
72 + `alloy update` reporting how far behind the image has fallen, with the browser
73 + called out rather than buried in a package count, is filed work and not yet
74 + shipped. Until it is, the honest answer is that the date of your last rebuild
75 + is the number that matters, and only you know it.
76 +
77 + ## What about `bootc upgrade`
78 +
79 + It works, and does nothing useful here: there is no registry for it to fetch
80 + from unless you set one up yourself. If you run your own registry, point the
81 + build at it with `build/build-iso.sh --update-target <registry>/alloy:43` and
82 + the installed machines will use the standard bootc update path.
@@ -1,0 +1,110 @@
1 + # 9. Files, editing, and media
2 +
3 + Alloy ships one default per job. All of them are keyboard-driven, and most of
4 + them are vim-shaped.
5 +
6 + ## Files: yazi
7 +
8 + yazi
9 +
10 + A two-pane file manager in the terminal, with previews. Under rio it renders
11 + images inline using the kitty graphics protocol rather than falling back to
12 + coloured blocks, which is most of the reason rio is the terminal.
13 +
14 + `?` lists its keys. `q` leaves.
15 +
16 + There is no graphical file manager in the image. Apps that need to open or save
17 + a file get a portal dialog, which is what a browser uses, so the daily case is
18 + covered. If you want one anyway, it comes from Flathub (chapter 7).
19 +
20 + ## Editing: helix
21 +
22 + hx <file>
23 +
24 + Modal, selection-first: you select and then act, so it is `3wd` where vim is
25 + `d3w`. Language servers, tree-sitter highlighting, and formatters are built in
26 + rather than assembled from plugins. It is useful with no configuration.
27 +
28 + `EDITOR` is set to `hx`, so git commit messages and everything else that
29 + respects `$EDITOR` open here.
30 +
31 + Alloy ships the Akari theme and a small config at `~/.config/helix/`. If you
32 + have vim muscle memory, expect a week or two of friction; the grammar is a real
33 + improvement but it is not the one your fingers know. `:tutor` is the fastest
34 + way through.
35 +
36 + ## PDFs: zathura
37 +
38 + zathura <file.pdf>
39 +
40 + vim keys, statusbar-only chrome. `i` toggles recolouring, which is off in the
41 + day theme (the page already agrees with the chrome) and on at night (an
42 + unrecoloured PDF in a dark session is a floodlight).
43 +
44 + zathura reads. It does not annotate, and Alloy does not ship an annotator.
45 +
46 + ## Images: imv
47 +
48 + imv <file>
49 +
50 + Wayland-native, tiny, vi-like keys. The overlay is hidden until you ask for it.
51 +
52 + ## Video and audio: mpv
53 +
54 + mpv <file-or-url>
55 +
56 + No chrome by default, hardware decoding on, screenshots to
57 + `~/Pictures/Screenshots`. It plays streams through yt-dlp, capped at 1080p in
58 + the shipped config.
59 +
60 + A fullscreen mpv window holds the screen lock off. A windowed one does not,
61 + because a windowed video is usually something being glanced at.
62 +
63 + ## System monitoring: bottom
64 +
65 + btm
66 +
67 + or `top`, which is aliased to it. ratatui-based, same visual family as the
68 + console. Clicking is disabled on purpose; it is keyboard-only.
69 +
70 + ## Disk usage: dua
71 +
72 + du
73 +
74 + is aliased to `dua interactive`. Navigate with vim keys, mark things for
75 + deletion, delete them.
76 +
77 + ## Clipboard history
78 +
79 + Everything you copy is recorded, text and images both. `Mod+Shift+V` opens a
80 + picker over the history; choose an entry and it goes back on the clipboard.
81 +
82 + The store is at `~/.local/share/cliphist/db` and needs no configuration. If you
83 + want a copy to never be recorded, there is no per-copy exclusion today; clear
84 + the history with `cliphist wipe`.
85 +
86 + ## Screenshots and annotation
87 +
88 + Covered in chapter 5. The one thing worth repeating here: `Mod+Print` opens the
89 + most recent capture in satty, which is where you crop, arrow, and blur before
90 + sending it somewhere.
91 +
92 + ## The browser
93 +
94 + Helium ships in the image as the default browser, unconfigured. It is
95 + ungoogled-chromium with ad blocking, tracker blocking, cookie-banner handling
96 + and anti-fingerprinting already on upstream, and it makes no network request on
97 + first launch.
98 +
99 + Alloy ships no policy file, no preference seed, no chrome CSS and no pinned
100 + extension for it. That is why it is the default: an app earns a recommendation
101 + here by not needing to be configured. Anything past what a well-behaved app
102 + reads from the system (light or dark, the GTK theme for dialogs, the cursor,
103 + the fonts) is yours to set in the browser's own settings.
104 +
105 + Firefox is one line in the Containerfile if you want Gecko, and would ship with
106 + no Alloy configuration on it either.
107 +
108 + Two honest notes. The browser is packaged from an upstream binary rather than
109 + built from source, and it is pre-1.0. And because it lives in the image, it
110 + updates when you rebuild the image and not before (chapter 8).
@@ -1,0 +1,79 @@
1 + # 10. The shell
2 +
3 + Your login shell is **nushell**. Its pipelines carry structured data rather
4 + than lines of text, so `ls | where size > 10mb | sort-by modified` is a whole
5 + pipeline and not an awk exercise.
6 +
7 + bash is untouched at `/bin/sh` and `/bin/bash`. Nothing that runs a shell
8 + script cares which login shell you use, so the `curl | sh` pattern and every
9 + system script behave exactly as they would anywhere else. If you want bash
10 + back:
11 +
12 + chsh -s /bin/bash
13 +
14 + ## What is already wired up
15 +
16 + - **starship** draws the prompt.
17 + - **zoxide** tracks directories you visit, so `z alloy` lands in that project
18 + from anywhere.
19 + - **direnv** loads a directory's `.envrc` when you enter it and unloads it when
20 + you leave. After editing an `.envrc`, run `direnv-reload`.
21 +
22 + All three are live at first login with nothing to set up.
23 +
24 + ## Aliases
25 +
26 + A short list, in `~/.config/nushell/aliases.nu`:
27 +
28 + | Alias | Runs |
29 + |---|---|
30 + | `ll`, `la` | `ls -la`, `ls -a` |
31 + | `..`, `...`, `....` | Up one, two, three directories |
32 + | `gs` `gd` `ga` `gc` `gp` `gl` | git status, diff, add, commit, push, log |
33 + | `vim`, `vi` | `hx` |
34 + | `du` | `dua interactive` |
35 + | `top` | `btm` |
36 +
37 + It is meant to stay short. If the file grows past about thirty lines, the next
38 + alias probably has not earned its place.
39 +
40 + ## Config
41 +
42 + | File | Holds |
43 + |---|---|
44 + | `~/.config/nushell/env.nu` | Environment: `EDITOR`, cursor theme, paths |
45 + | `~/.config/nushell/config.nu` | Shell behaviour |
46 + | `~/.config/nushell/aliases.nu` | The list above |
47 + | `~/.config/starship.toml` | Prompt |
48 +
49 + Note that nushell is not bash: `export FOO=bar` is `$env.FOO = "bar"`, and
50 + command substitution is `(...)` rather than backticks. Its own book covers the
51 + differences, and the migration is smaller than it looks because scripts keep
52 + running under bash.
53 +
54 + ## Becoming root
55 +
56 + run0 <command>
57 +
58 + `run0` is systemd's, and it is what Alloy documents instead of `sudo`. It
59 + authenticates through polkit rather than by setuid, and it runs the command in
60 + a fresh session rather than in your shell's.
61 +
62 + `sudo` still exists; nothing removes it. Alloy just does not build habits
63 + around it.
64 +
65 + ## Secrets
66 +
67 + Two different jobs, and they get confused for each other constantly:
68 +
69 + - **gnome-keyring** is the Secret Service provider. It is what programs call
70 + when they need to store a credential. You do not use it directly; it is there
71 + so applications that expect it work.
72 + - **gopass** is where you keep your own logins. It uses an age identity for
73 + encryption and git for syncing, so a store is a git repository of ciphertext
74 + and a concurrent edit is a merge conflict rather than a silently duplicated
75 + file.
76 +
77 + Alloy provisions neither with any content. `gopass init` sets up a store when
78 + you want one, and the age identity that decrypts it should never live in the
79 + repository it decrypts or travel with it.
@@ -1,0 +1,116 @@
1 + # 11. Appearance
2 +
3 + Alloy ships one design language, Akari, in two renders: **Akari Dawn** for day
4 + and **Akari Night** for dark. Everything the system draws is themed from it,
5 + including the terminal, the editor, the bar, the lock screen, notifications,
6 + the console, GTK dialogs, and even the virtual consoles.
7 +
8 + ## Switching between day and night
9 +
10 + alloy settings
11 +
12 + then the theme row on the System tab. Two things happen when you set it: the
13 + console re-themes immediately, and a mode file at `~/.config/alloy/mode` records
14 + your choice.
15 +
16 + The rest of the desktop follows **at your next login**. The reason is sway: it
17 + reads its config once at start, and the config is one of the themed files, so
18 + applying mid-session would need a reload and would still leave everything
19 + already running on the old palette.
20 +
21 + Under the hood, the login wrapper runs:
22 +
23 + alloy theme apply
24 +
25 + which copies the matching render of every themed config into your home
26 + directory. You can run it by hand:
27 +
28 + | Command | Effect |
29 + |---|---|
30 + | `alloy theme apply --dry-run` | Report what would change, write nothing |
31 + | `alloy theme apply --mode night` | Apply the night render for this run without changing your saved choice |
32 + | `alloy theme apply --verbose` | Name every file, including unchanged ones |
33 + | `alloy theme apply --force` | Overwrite files you have edited, keeping a `.alloy-bak` |
34 +
35 + **Files you have edited are never replaced.** If a config matches neither the
36 + day nor the night render, `alloy theme apply` treats it as yours, keeps it, and
37 + names it in its output. `--force` is the only way past that, and it leaves a
38 + backup.
39 +
40 + Swapping the theme in place, without logging out, is filed as `alloy theme
41 + <name>` and is not built yet.
42 +
43 + ## What the greeter does
44 +
45 + The login screen and every virtual console carry the Akari palette, applied as
46 + the kernel's console colour table plus a small unit at boot. There is one
47 + limitation worth knowing: boot and login are always Dawn, whatever your session
48 + is set to. Choosing between the two tables needs a system-wide setting that
49 + does not exist yet, since the greeter runs before any user is known.
50 +
51 + ## Wallpaper
52 +
53 + The default background is a flat colour from the palette. Alloy ships **swww**
54 + for image wallpapers but starts no daemon and provisions no images:
55 +
56 + swww-daemon &
57 + swww img ~/Pictures/wallpaper.jpg
58 +
59 + Add those to `~/.config/sway/config` if you want them at login. The curated
60 + wallpaper collection the design docs describe (public-domain impressionist
61 + paintings, chosen because they are tonally restrained and treat light as
62 + information) is not in the image yet.
63 +
64 + ## Night colour temperature
65 +
66 + **gammastep** is installed and not enabled. Its config at
67 + `~/.config/gammastep/config.ini` is set to 3700K at night and 6500K by day with
68 + a fade, and carries a placeholder location you have to fill in:
69 +
70 + systemctl --user enable --now gammastep
71 +
72 + This is separate from the light and dark theme. One changes what colours the
73 + system draws; the other changes the colour temperature of the whole display.
74 +
75 + ## Fonts
76 +
77 + | Role | Font |
78 + |---|---|
79 + | Monospace | IosevkaTerm Nerd Font Mono |
80 + | Sans | Atkinson Hyperlegible |
81 + | Serif | Not shipped; falls through to Fedora's default |
82 + | Emoji | Not shipped |
83 +
84 + Atkinson Hyperlegible is designed by the Braille Institute to make letters as
85 + distinguishable from each other as possible, which is the most literal answer
86 + to "make UI text readable". If you want something more conventional, Inter is a
87 + one-line swap in `~/.config/fontconfig/fonts.conf` and the GTK settings.
88 +
89 + CJK, Arabic, Hebrew, Indic and Thai coverage comes from Fedora's font
90 + metapackages, so web pages in those scripts render. **Emoji do not.** No emoji
91 + font is installed and the fontconfig alias for them was removed rather than
92 + left pointing at something absent. Emoji show as missing glyphs. Installing any
93 + emoji font makes them work with no further configuration.
94 +
95 + ## Cursor
96 +
97 + Bibata Modern Classic at size 24, set three ways because different apps read
98 + the cursor from different places: `~/.icons/default/index.theme`, the GTK
99 + settings files, and `XCURSOR_THEME` in the nushell environment. Change all
100 + three if you change it at all.
101 +
102 + ## GTK apps
103 +
104 + GTK 3 and 4 apps get the Akari palette layered over adw-gtk3, through
105 + `~/.config/gtk-3.0/gtk.css` and `~/.config/gtk-4.0/gtk.css`. That covers the
106 + portal file dialogs, swayosd's overlays, and most modern GTK apps.
107 +
108 + Two gaps, stated rather than discovered: there is no dark-mode variant of the
109 + GTK patch yet (it is light-first), and Qt apps are not themed at all.
110 +
111 + ## Terminal, editor, and everything else
112 +
113 + Each adopted tool has its own themed config under `~/.config/`, rendered from
114 + the same palette: rio, helix, yazi, mako, swaylock, satty, bottom, zathura,
115 + imv, mpv, swayosd, and the sway config itself. Editing one is fine; the theme
116 + system will notice and stop overwriting it.
@@ -1,0 +1,101 @@
1 + # 12. Network, mesh, sync, and backup
2 +
3 + Alloy assumes the machine is disposable and your state is not. An install
4 + should be rejoinable: build the medium, install, sign in to two things, and
5 + your files and your other machines are there.
6 +
7 + Both enrollments are opt-in. Nothing connects to anything until you say so.
8 +
9 + ## Wifi and wired networking
10 +
11 + alloy net
12 +
13 + lists interfaces and connections. Connecting, disconnecting, and toggling the
14 + wifi radio all work without any privilege, because NetworkManager grants those
15 + to an active session.
16 +
17 + Joining a network you have never joined before is a different permission, and
18 + the console does not yet ask for it. For a new network:
19 +
20 + run0 nmcli device wifi connect "Network Name" --ask
21 +
22 + Once it is saved, `alloy net` connects to it like any other.
23 +
24 + ## Mesh: Tailscale
25 +
26 + alloy mesh
27 +
28 + A machine that has not joined anything shows an offer rather than an empty
29 + list. Press `e` to set the control server before signing in: leave it empty for
30 + tailscale.com, or enter a URL for a self-hosted Headscale.
31 +
32 + Signing in escalates to root and then waits on a browser login, so the console
33 + gets out of the way while that happens and comes back into the peer list
34 + afterwards.
35 +
36 + Once enrolled, the view lists your peers, whether each is online, when it was
37 + last seen, and lets you pick or clear an exit node. This machine is listed
38 + first. If you are on a self-hosted control plane, the title says so.
39 +
40 + The plain command is `run0 tailscale up`, and `alloy tail` is kept as an alias
41 + for the verb.
42 +
43 + Alloy does not ship a Headscale server. That is fleet-admin work, not
44 + client-OS work.
45 +
46 + ## File sync: Syncthing
47 +
48 + alloy sync
49 +
50 + Three tabs: **folders**, **devices**, and **pending**.
51 +
52 + - Folders shows each synchronized folder's path, share mode, and whether it is
53 + paused. `a` adds one, `d` removes one, and both confirms tell you what is
54 + *not* deleted, because "remove folder" must never read as "delete my
55 + documents".
56 + - Devices shows connection state, this machine first.
57 + - Pending lists devices that have added you and are knocking. Accepting one
58 + finishes the pairing.
59 +
60 + Enrollment is a user service and needs no root:
61 +
62 + systemctl --user enable --now syncthing.service
63 +
64 + One asymmetry to know about: you can accept a pending device but not decline
65 + it. The command-line client Syncthing ships has no verb for dropping a pending
66 + entry, so an unaccepted device stays listed. The view says so when you press
67 + `d` there.
68 +
69 + Syncthing's own web UI is still at `127.0.0.1:8384` for anything the console
70 + does not cover.
71 +
72 + ## Backup: restic
73 +
74 + restic is in the image and Alloy prescribes no policy. Where you back up to is
75 + answerable only by you, so there is no default repository, schedule, or
76 + retention.
77 +
78 + This matters more than it looks. Sync is mesh plus latest-wins; it gets your
79 + files onto the new machine. It does not get back the file you deleted three
80 + weeks ago and only just noticed. That case needs versioned backup, which means
81 + configuring restic:
82 +
83 + restic init --repo <destination>
84 + restic backup ~/Documents ~/Pictures
85 + restic snapshots
86 +
87 + Any of restic's backends work: local disk, SFTP, S3, B2, rclone. A systemd
88 + user timer is the usual way to make it recurring.
89 +
90 + There is no `alloy backup` view. It is a candidate, not a plan.
91 +
92 + ## What is deliberately not synced
93 +
94 + - **Secrets.** Too personal, and the security models vary too much for a
95 + defensible default. gopass (chapter 10) is the shipped tool, and you decide
96 + what it holds and where it goes.
97 + - **Dotfiles.** Syncthing can carry `~/.config` and Alloy does not set that up
98 + for you.
99 + - **The first-boot marker.** Deliberately never replicated: a synced copy would
100 + suppress the enrollment screen on the next machine you set up, which is
101 + exactly the machine that needs it.
@@ -1,0 +1,135 @@
1 + # 13. Hardware and peripherals
2 +
3 + ## Displays
4 +
5 + alloy display
6 +
7 + lists the outputs sway is driving, with their scale and whether they are on.
8 + `s` walks the scale ladder. The console writes what it changes to
9 + `~/.config/sway/config.d/50-display.conf`, which the shipped sway config
10 + includes after the system drop-ins, so your setting beats the image's.
11 +
12 + A fresh install seeds that file at install time by reading the panel's size out
13 + of EDID and snapping to the nearest scale, so a high-density laptop boots at a
14 + sensible scale rather than at 1.0. A panel that cannot be read seeds nothing,
15 + which means 1.0 and one keypress from correct.
16 +
17 + Mode picking (refresh rate and resolution) is not built. Multi-output setups
18 + are the untested case: nothing has attached a second display to an Alloy
19 + machine yet, so if you do, expect the display view to be the rough part.
20 +
21 + Anything the view does not cover is a sway `output` line in that same file.
22 + `swaymsg -t get_outputs` names your outputs.
23 +
24 + ## Audio
25 +
26 + alloy audio
27 +
28 + Two panes: the streams that are playing and the devices they could play
29 + through. Move a stream from one to the other, change volumes, pick defaults.
30 + The Fn keys handle the everyday case with an on-screen indicator.
31 +
32 + Underneath is PipeWire, and `pactl` is the command the view shows you.
33 +
34 + ## Brightness
35 +
36 + The brightness keys work, through the same on-screen indicator. If they do not,
37 + see the note in chapter 14: it takes two separate grants (a udev rule and your
38 + account being in the `video` group) and either one alone leaves the keys dead
39 + silently.
40 +
41 + Screen dimming before the lock is separate, and handled by `alloy-dim` from the
42 + idle configuration.
43 +
44 + ## Power and idle
45 +
46 + The shipped idle behaviour, in `~/.config/sway/config`:
47 +
48 + | After | What happens |
49 + |---|---|
50 + | 4.5 minutes | The screen dims. Move the mouse or type and it comes back |
51 + | 5 minutes | swaylock takes over |
52 + | 10 minutes | Displays power off |
53 + | Lid close or suspend | Always locks first |
54 +
55 + The dim stage is the closest thing to a grace period on offer: upstream
56 + swaylock has no `--grace` flag, and thirty seconds of dimmed screen is enough
57 + to notice before the lock arrives.
58 +
59 + Fullscreen mpv, imv, and the browser hold the lock off. A fullscreen terminal
60 + deliberately does not: walking away from a shell should not leave the machine
61 + unlocked indefinitely.
62 +
63 + ## Fingerprint reader
64 +
65 + fprintd is installed, and nothing is enrolled, so nothing asks for a finger
66 + until you do:
67 +
68 + fprintd-enroll
69 +
70 + Once enrolled, the lock screen, the greeter and `run0` all accept it from that
71 + one step, because they share a PAM stack. A finger that does not match, a
72 + reader that is busy, and a user with nothing enrolled all fall through to the
73 + password prompt.
74 +
75 + ## Printing
76 +
77 + Alloy prints to **IPP Everywhere (driverless) printers and nothing else**.
78 + There are no vendor driver packages in the image, and there will not be. Nearly
79 + every printer sold since about 2015 speaks the protocol.
80 +
81 + A driverless printer on the same network appears by itself; discovery over mDNS
82 + is already set up. The surface for anything else is CUPS' own web interface:
83 +
84 + http://localhost:631
85 +
86 + The daemon is socket-activated, so nothing runs until something connects to it.
87 +
88 + A printer that needs a vendor driver is not supported. Saying so here is better
89 + than you discovering it at the moment you need to print.
90 +
91 + ## Scanning
92 +
93 + Not shipped. Scanning means per-device backends and USB permission work with
94 + opaque failures, and no one has needed one yet. If you do:
95 +
96 + rpm-ostree install sane-backends
97 +
98 + Worth trying first: most network scanners scan to a folder or to email with no
99 + host driver at all.
100 +
101 + ## Bluetooth
102 +
103 + bluez is installed and running. PipeWire's Bluetooth plugins are in the image,
104 + LC3 and AAC included, so a paired headset plays.
105 +
106 + What is missing is a view, not a daemon. Pairing today is the interactive
107 + prompt:
108 +
109 + bluetoothctl
110 + # scan on, pair <MAC>, trust <MAC>, connect <MAC>
111 +
112 + An `alloy bluetooth` view is intended and not built.
113 +
114 + ## USB storage
115 +
116 + There is no automounter. Plugging in a stick makes the kernel see it and
117 + nothing else happens on screen.
118 +
119 + lsblk
120 + run0 mkdir -p /mnt/stick
121 + run0 mount /dev/sdX1 /mnt/stick
122 + # and when you are done
123 + run0 umount /mnt/stick
124 +
125 + This is a known gap rather than a position.
126 +
127 + ## Locale and keymap
128 +
129 + Both are rows on the System tab of `alloy settings`, fronting `localectl`.
130 +
131 + One caveat: the image carries a minimal set of glibc language packs. Setting a
132 + locale the image cannot deliver records your choice and gives you no
133 + translations, because the data is not there. If you need a locale beyond
134 + English, layer its `glibc-langpack-*` package (chapter 7) or add it to the
135 + Containerfile and rebuild.
@@ -1,0 +1,199 @@
1 + # 14. Troubleshooting
2 +
3 + ## The general moves
4 +
5 + **Get a console that is not sway.** `Ctrl+Alt+F2` through `F6` are virtual
6 + terminals. They are themed the same way and they work when the session does
7 + not. `Ctrl+Alt+F1` goes back to the greeter.
8 +
9 + **Read the logs.**
10 +
11 + journalctl -b -p err # this boot, errors and worse
12 + journalctl --user -b # your session's services
13 + journalctl -b -u greetd # the login screen
14 +
15 + **Reload sway** after editing its config: `Mod+Shift+C`.
16 +
17 + **Boot the previous image.** Hold `Esc` or `Shift` at boot for the GRUB menu
18 + and pick the older deployment. Nothing you do to the running system can take
19 + that away, which is the point of an atomic base.
20 +
21 + ---
22 +
23 + ## The session
24 +
25 + ### Nothing opens when I press Mod+Return
26 +
27 + Check the config's terminal name. Fedora packages the terminal as `rio` but
28 + installs its binary as `rioterm`, and a config naming `rio` leaves you with no
29 + way to open a terminal at all.
30 +
31 + Two ways out that do not need a terminal: `Mod+D` opens the launcher, and
32 + `Ctrl+Alt+F2` gets you a virtual console where you can edit
33 + `~/.config/sway/config` and log back in.
34 +
35 + ### I edited the sway config and the session will not start
36 +
37 + Log in on a virtual console and check it:
38 +
39 + sway --validate
40 +
41 + Then fix the file, or move it aside to fall back to the shipped one:
42 +
43 + mv ~/.config/sway/config ~/.config/sway/config.broken
44 + alloy theme apply
45 +
46 + ### The screen locked and I cannot unlock it
47 +
48 + Type your password even if nothing is drawn; swaylock accepts input before it
49 + has anything to show. If the lock has genuinely crashed, switch to a virtual
50 + console and kill it:
51 +
52 + pkill swaylock
53 +
54 + That leaves an unlocked session, so do it only at a machine you trust.
55 +
56 + ### My session locks while I am watching a video
57 +
58 + Only a handful of applications hold the lock off, and only when fullscreen:
59 + mpv, imv, and the browser. Add yours in `~/.config/sway/config` next to the
60 + existing `inhibit_idle fullscreen` lines. A blanket rule is deliberately not
61 + shipped, because it would make walking away from a fullscreen terminal leave
62 + the machine unlocked.
63 +
64 + ---
65 +
66 + ## Hardware
67 +
68 + ### The brightness keys do nothing
69 +
70 + This one is silent by design of the underlying pieces, so check both halves:
71 +
72 + groups | grep video # your account is in the video group
73 + ls -l /sys/class/backlight/*/brightness # group-writable, group video
74 +
75 + Brightness is a direct write to a sysfs file. It takes a udev rule to make that
76 + file writable and your account being in the `video` group for the rule to grant
77 + anything. Either one alone leaves the keys dead with no error anywhere: the
78 + process that would have complained has nowhere to log.
79 +
80 + Volume keys use a different path entirely (PipeWire, no privilege), which is
81 + why one can work while the other does not.
82 +
83 + ### The volume overlay never appears
84 +
85 + `swayosd-server` is started by the sway config, not by a systemd unit. If it
86 + died, restart it:
87 +
88 + swayosd-server &
89 +
90 + ### Print Screen seems to do nothing
91 +
92 + It probably worked. Check `~/Pictures/Screenshots`. Every capture also raises a
93 + notification, so if you get neither the file nor the notification, run the
94 + script by hand to see the error:
95 +
96 + alloy-shot output
97 +
98 + ### A second monitor is not behaving
99 +
100 + This is the least tested part of the system. `swaymsg -t get_outputs` shows
101 + what sway sees, and `~/.config/sway/config.d/50-display.conf` is where to write
102 + `output` lines by hand. `alloy display` will not pick modes yet.
103 +
104 + ---
105 +
106 + ## The console
107 +
108 + ### alloy net cannot join a new network
109 +
110 + Connecting to a saved network needs no privilege; creating one does, and the
111 + console does not escalate yet. Use:
112 +
113 + run0 nmcli device wifi connect "Network Name" --ask
114 +
115 + ### alloy pkg or alloy update says it cannot read the system
116 +
117 + Those two tabs front `rpm-ostree`, which exists only on an ostree system. If
118 + you are running the console somewhere else, that message is correct rather than
119 + broken.
120 +
121 + ### The console will not start at all
122 +
123 + It needs a theme on its search path and fails loudly if there is none. Two
124 + verbs deliberately survive that, because they are on the login path:
125 + `alloy theme apply` and `alloy status --bar`. If the console is broken but the
126 + bar still draws, the theme directory is what to look at
127 + (`/usr/share/alloy/themes`).
128 +
129 + ---
130 +
131 + ## Appearance
132 +
133 + ### I switched to night and nothing changed
134 +
135 + The switch applies at the next login. Log out and back in, or run
136 + `alloy theme apply` and restart the affected programs. sway itself needs the
137 + re-login regardless, because it reads its config exactly once.
138 +
139 + ### alloy theme apply says it skipped my files
140 +
141 + It found a config that matches neither the day nor the night render, decided it
142 + was yours, and left it alone. That is the intended behaviour. If you want the
143 + shipped render back:
144 +
145 + alloy theme apply --force
146 +
147 + which keeps your version as a `.alloy-bak` beside it.
148 +
149 + ### Some characters render as boxes
150 +
151 + If they are emoji, that is expected: no emoji font is installed. Install any
152 + one and fontconfig picks it up with no further configuration.
153 +
154 + If they are not emoji, `fc-list :lang=<code>` will say whether anything in the
155 + image covers that script.
156 +
157 + ### The browser is light when my desktop is dark
158 +
159 + System appearance reaches the browser through the desktop portal rather than
160 + through any file Alloy ships, and that path has not been verified on real
161 + hardware yet. If it does not work, set the theme in the browser's own settings;
162 + Alloy does not ship browser configuration to fix it with.
163 +
164 + ---
165 +
166 + ## Disks and boot
167 +
168 + ### The machine asks for a passphrase it never asked for before
169 +
170 + The TPM stopped answering: it was cleared, the board changed, or the disk moved
171 + to another machine. Type the passphrase you set at install. If you do not have
172 + it, this is what the eight-word recovery phrase from the installer is for.
173 +
174 + Without either one, the data is gone. That is what encryption means.
175 +
176 + ### The new image is worse than the old one
177 +
178 + rpm-ostree rollback
179 + systemctl reboot
180 +
181 + Or pick the previous entry in the GRUB menu at boot. See chapter 8.
182 +
183 + ### I layered a package and now the system will not boot
184 +
185 + Boot the previous deployment from the GRUB menu, then remove it:
186 +
187 + rpm-ostree uninstall <package>
188 +
189 + Layered packages are the most common way to break an otherwise reliable base,
190 + which is the argument in chapter 7 for putting things in boxes instead.
191 +
192 + ---
193 +
194 + ## Reporting something
195 +
196 + Alloy is pre-v0 and this manual describes a moving system. If something here is
197 + wrong, the repository is at `makenot.work/git/max/alloy` and the design
198 + documents in `docs/` say what each piece is supposed to do, which is usually
199 + enough to tell a bug from a decision.
@@ -1,0 +1,100 @@
1 + # 15. Questions
2 +
3 + **Where do I download Alloy?**
4 +
5 + You do not. You build it. Alloy publishes source and never publishes a binary
6 + image, so what you boot is the thing you configured on your own machine. See
7 + chapter 2.
8 +
9 + **Can I build it on a Mac or on Windows?**
10 +
11 + No. The build needs Linux with podman, real disk, and a long wall clock. There
12 + is no path to an Alloy ISO from either.
13 +
14 + **How do I install software?**
15 +
16 + Not with `dnf`. Chapter 7 is the whole answer: pick how much of your machine
17 + the software should reach, and Alloy picks the mechanism from that.
18 +
19 + **How do I update?**
20 +
21 + Rebuild the image and `bootc switch` to it. Your home directory and your
22 + layered packages survive; you never reinstall. Chapter 8.
23 +
24 + **Does Alloy phone home?**
25 +
26 + No. Nothing enrolls, checks, or reports without you asking. The update timer is
27 + disabled on any machine installed from a locally built medium, Tailscale and
28 + Syncthing are both off until you enroll them, and the browser makes no network
29 + request on first launch.
30 +
31 + **Is it Rust?**
32 +
33 + The parts Alloy writes are. The parts it adopts are whatever they are: sway is
34 + C, Tailscale and Syncthing are Go, CUPS is C. Where a competitive Rust option
35 + exists it gets picked, and where one does not the gap is named rather than
36 + papered over.
37 +
38 + **Why sway and not Hyprland or niri?**
39 +
40 + Alloy wants the i3 model: predictable, workspace-based, no scrolling columns
41 + and no animation. sway is that model, mature, and well packaged, and the whole
42 + sway ecosystem (lock, idle, bar, OSD) fits behind it with no glue.
43 +
44 + **Why is there no settings app?**
45 +
46 + There is: it is `alloy settings`, and it runs in a terminal. Every action it
47 + takes prints the command it ran, so the console teaches the system instead of
48 + hiding it.
49 +
50 + **Can I use bash instead of nushell?**
51 +
52 + Yes: `chsh -s /bin/bash`. bash is untouched at `/bin/sh` and `/bin/bash`, so
53 + nothing else on the system changes either way.
54 +
55 + **Can I use vim instead of helix?**
56 +
57 + Yes, install it. helix is the default because it is useful with no
58 + configuration, which is the same test that picked every other default here. If
59 + you would rather assemble your editor from plugins, nothing stops you.
60 +
61 + **Why does my emoji not render?**
62 +
63 + No emoji font is shipped. Alloy uses none in its own interface, so it carries
64 + none. Install any emoji font and it works immediately.
65 +
66 + **Can I put GNOME or KDE on it?**
67 +
68 + You can layer whatever you want, but at that point you are running Fedora with
69 + extra steps. Alloy is the curation; removing it leaves the base.
70 +
71 + **Is my data safe if I lose the machine?**
72 +
73 + Only if you encrypted the disk at install (chapter 3). Alloy does not encrypt
74 + by default and does not pretend to.
75 +
76 + **What happens if the TPM fails on an encrypted machine?**
77 +
78 + You type the passphrase you set, or the eight-word recovery phrase the
79 + installer showed you. Both are enrolled precisely because a TPM-only setup has
80 + one failure mode that ends in a lost disk.
81 +
82 + **Is there a graphical file manager, launcher, or editor?**
83 +
84 + No. yazi, `Mod+D`, and helix are the answers. If you want a graphical file
85 + manager, Flathub has several and chapter 7 explains how to install one.
86 +
87 + **How stable is this?**
88 +
89 + Pre-v0. The base underneath it is Fedora and is as stable as Fedora, but the
90 + console, the installer and the image composition are young, and parts of the
91 + system named in this manual are not built yet. Every one of those is called out
92 + where it comes up rather than described in the future tense.
93 +
94 + **Where is the rest of the documentation?**
95 +
96 + `docs/` in the repository. `MANIFESTO.md` is what Alloy is and who it is for,
97 + `STACK.md` is every pick with its reasoning and what was rejected, `CONSOLE.md`
98 + is the console's design, `IMAGE.md` is how the image is composed, and
99 + `CONTINUITY.md` is the sync and mesh story. They are written for people working
100 + on Alloy, and they are the honest record of why each default is what it is.
@@ -1,0 +1,43 @@
1 + # The Alloy Manual
2 +
3 + Alloy is an opinionated tiling user layer for Fedora Silverblue: an immutable
4 + base, the sway compositor, a curated terminal-first stack, and one authored
5 + control surface, the `alloy` console.
6 +
7 + This manual is for people who run Alloy. It says what the system does, which
8 + keys do it, and what to do when something does not work. The design documents
9 + one directory up (`docs/MANIFESTO.md`, `docs/STACK.md`, `docs/CONSOLE.md` and
10 + the rest) explain why each pick was made; they are written for whoever works on
11 + Alloy, not for whoever uses it. Nothing here replaces them.
12 +
13 + Alloy is pre-v0. Where a thing is not built yet, this manual says so instead of
14 + describing it in the future tense.
15 +
16 + ## Chapters
17 +
18 + 1. [What Alloy is](01-what-alloy-is.md)
19 + 2. [Building your image](02-building-your-image.md)
20 + 3. [Installing](03-installing.md)
21 + 4. [The first fifteen minutes](04-first-fifteen-minutes.md)
22 + 5. [Keybindings](05-keybindings.md)
23 + 6. [The console](06-the-console.md)
24 + 7. [Installing software](07-installing-software.md)
25 + 8. [Updating and rolling back](08-updating-and-rolling-back.md)
26 + 9. [Files, editing, and media](09-files-and-apps.md)
27 + 10. [The shell](10-the-shell.md)
28 + 11. [Appearance](11-appearance.md)
29 + 12. [Network, mesh, sync, and backup](12-continuity.md)
30 + 13. [Hardware and peripherals](13-hardware.md)
31 + 14. [Troubleshooting](14-troubleshooting.md)
32 + 15. [Questions](15-faq.md)
33 +
34 + ## Two things to know before anything else
35 +
36 + **Nobody downloads Alloy.** There is no image to fetch and no registry to pull
37 + from. You take the source, build an installer ISO on your own Linux machine,
38 + and write it to a USB stick. Chapter 2 covers it.
39 +
40 + **An installed machine never reaches out on its own.** It does not check for
41 + updates, does not phone home, and does not enroll in anything until you ask.
42 + Updating means rebuilding the image and switching to it, which chapter 8
43 + covers.