hosts/<hostname>/{config,system}/ now overlays the shared trees. install.sh
installs a host file in place of the shared copy at the same path, and
capture.sh pulls back into whichever copy the host installs from. That keeps
hardware-specific files off the wrong machine: the HP's EDID-named monitors.lua
and its fnmode=2 would otherwise land on the Air.
capture.sh refreshes the shared trees only on omarchy-laptop, where they were
captured, or when CAPTURE_SHARED=1 is set. On the Air, a plain run copied its
stock terminal, hypr and shell files over every one of the HP's customizations.
air's overlay holds monitors.lua (1.33333 scale and GDK_SCALE=1 for the
2560x1664 panel), input.lua (stock settings plus the inert-accel measurements),
herdr onboarding=false, git identity and credential helpers (no secrets),
mimeapps.list, and the Asahi installer's hid_apple fnmode=1 and show_notch=1.
bindings.lua is not overlaid because the shared one is a strict superset.
hosts/omarchy-air/README.md records what was left out on purpose and why, and
warns that the shared packages.txt is x86-specific.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KKPyqMc7MGKyBLKVdeDejp
200 lines
11 KiB
Markdown
200 lines
11 KiB
Markdown
# omarchy-setup
|
|
|
|
Every customization this laptop has on top of a stock Omarchy install, in one
|
|
place, so a second machine can be brought to the same state.
|
|
|
|
Captured from Omarchy **4.0.4-1** on **2026-10-10**.
|
|
|
|
```bash
|
|
git clone <this repo> ~/omarchy-setup
|
|
cd ~/omarchy-setup
|
|
./install.sh --dry-run # see what it would change
|
|
./install.sh # do it
|
|
```
|
|
|
|
`install.sh` is idempotent and backs up anything it overwrites as
|
|
`<file>.bak.<epoch>`. `capture.sh` runs the other way, pulling live changes back
|
|
into the repo so this stays the source of truth.
|
|
|
|
## What is in here
|
|
|
|
| Path | What |
|
|
|---|---|
|
|
| `config/` | Mirrors `~/.config`. Only files that differ from Omarchy's shipped defaults. |
|
|
| `themes/` | The three hand-built themes, wallpapers included. |
|
|
| `plugins.txt` | The 10 Omarchy shell plugins, each pinned to a commit. |
|
|
| `plugin-patches/` | Local plugin work that exists on no remote (see below). |
|
|
| `bin/` | `omarchy-handoff` and `fix-stuck-displays`. |
|
|
| `handoff/` | The lan-mouse source patch that fixes pointer feel, plus example `config.toml`s. Not a `~/.config` mirror. |
|
|
| `systemd/user/` | `lan-mouse.service`, `voxtype.service`. |
|
|
| `system/` | `/etc` drop-ins: the ARP sysctl and `hid_apple` fnmode. |
|
|
| `packages.txt` | Packages beyond the Omarchy baseline, each with a reason. |
|
|
| `hosts/<hostname>/` | Per-host overlay of `config/` and `system/`: a file there replaces the shared copy on that host only. See `hosts/omarchy-air/README.md`. |
|
|
|
|
## The customizations, and why
|
|
|
|
**Displays** (`config/hypr/monitors.lua`) are the fiddliest part. The file is the
|
|
single source of truth for monitor rules on purpose — overlapping rules spread
|
|
across several files is what previously made external displays unrecoverable.
|
|
Three outputs are named by EDID description rather than connector, so they match
|
|
whichever port they land on: the built-in Chimei panel at 1.25x, the LG IPS236 on
|
|
HDMI at 1x, and the LG TV through the Anker dock. The TV is deliberately left on
|
|
`preferred` (3840x2160@30) — the dock negotiates DP alt-mode with only two lanes,
|
|
so forcing 4K60 produced a "monitor has no mode" loop. `GDK_SCALE=1` with a 1.25
|
|
monitor scale; the stock pairing is 2 and `auto`.
|
|
|
|
`hyprland.lua` sources `hyprmoncfg-monitors.lua` last so the `hyprmoncfg` daemon's
|
|
generated layout wins over anything above it.
|
|
|
|
`bin/fix-stuck-displays` recovers the related kernel-side failure: after
|
|
suspend/resume i915 can leave an unplugged connector "disconnected" but still
|
|
"enabled" on a pipe Hyprland has forgotten, which blocks every other output from
|
|
modesetting. It forces the connector on, disables it through Hyprland to release
|
|
the pipe, then returns it to auto-detect. It needs passwordless sudo for
|
|
`tee /sys/class/drm/*/status`.
|
|
|
|
**Keyboard/mouse sharing** (`bin/omarchy-handoff`, `systemd/user/lan-mouse.service`)
|
|
drives `lan-mouse` to share input with the other Omarchy laptop, bound to
|
|
`SUPER+SHIFT+K` (`SUPER+K` is already Keybindings). The script's header comment
|
|
is the real documentation — it records the non-obvious facts that cost hours:
|
|
`capture_backend` must be `layer-shell` (the portal backend is a silent no-op on
|
|
Hyprland 0.56.2), `[authorized_fingerprints]` is keyed by fingerprint and the
|
|
reversed form fails silently, and the log variable is `LAN_MOUSE_LOG_LEVEL`, not
|
|
`RUST_LOG`. It runs as a user unit rather than from `autostart.lua` because
|
|
`o.launch_on_start` sends both streams to `/dev/null`, hiding every pairing
|
|
failure.
|
|
|
|
Three further facts were only established after the above was first written, and
|
|
they are what actually made it work:
|
|
|
|
- **Fingerprints are case-sensitive.** lan-mouse generates them lowercase and
|
|
compares with a plain map lookup — no normalisation — while `openssl` prints
|
|
uppercase and `cli authorize-key` stores whatever it is handed. An uppercase
|
|
digest is the *correct* digest, valid TOML, non-empty, passes every guard, and
|
|
never matches: the DTLS handshake dies `bad_certificate`, indistinguishable
|
|
from a wrong key or a dropped packet. This was the root cause of a full day of
|
|
dead crossings. `omarchy-handoff fixcase` repairs it; `doctor` now fails on it.
|
|
- **Authorization is receiver-side only, not mutual.** `connect.rs` sets
|
|
`insecure_skip_verify`, so the *connecting* side never checks the peer's
|
|
certificate — only the listener consults `authorized_fingerprints`. Each
|
|
direction therefore depends solely on the receiver's list, two-way control
|
|
needs both lists, and a sender cannot tell whether it is talking to the real
|
|
peer. Input goes to whatever answers on that IP:port.
|
|
- **`ufw` is default-deny inbound**, and a dropped inbound 4242 presents
|
|
*identically* to a bad certificate. `install.sh --handoff` opens it for the
|
|
peer's addresses. Check it first: `journalctl -k -g 'UFW BLOCK'`.
|
|
|
|
`handoff/patch/` carries a two-line source patch so the daemon forwards the
|
|
accelerated deltas, which is the only way to make the sender's `sensitivity` and
|
|
`accel_profile` affect remote pointer feel at all; it also adds
|
|
`LAN_MOUSE_POINTER_SCALE` for the residual difference in logical pixel density
|
|
between the two screens. `install.sh` builds it per-machine — the two laptops are
|
|
different architectures — and `systemd/user/lan-mouse.service` runs the result.
|
|
|
|
`system/sysctl.d/99-omarchy-handoff-arp.conf` goes with it: Wi-Fi and the dock's
|
|
ethernet both sit on `192.168.1.0/24`, and with the default ARP settings the
|
|
subnet's mapping collapses onto whichever NIC replied last.
|
|
|
|
**Bar and shell** (`config/omarchy/shell.json`) adds `omarchy.active-window` to
|
|
the left, five plugin widgets, and `indie.herdr-hud` as a non-bar plugin. Idle is
|
|
stretched a long way past stock — screensaver at 20 minutes, lock at 30, against
|
|
2.5 and 5.
|
|
|
|
**Keybindings** (`config/hypr/bindings.lua`) rebinds `SUPER+SHIFT+A` from the
|
|
stock ChatGPT webapp to Claude, and adds four Herdr HUD bindings plus Handoff.
|
|
|
|
**Input** (`config/hypr/input.lua`) enables the three-finger horizontal
|
|
workspace gesture that ships commented out, and flattens pointer acceleration for
|
|
`unknown-device*`.
|
|
|
|
That second rule is **a no-op, and the reasoning originally given for it was
|
|
wrong.** It was added believing lan-mouse forwards deltas the sending compositor
|
|
had already accelerated, which the receiver then amplified a second time. Upstream
|
|
does the opposite: it forwards the *unaccelerated* deltas and discards the
|
|
accelerated pair in the same event (`handoff/patch/REBUILD.md`). And the rule
|
|
cannot act either way — `hl.device({name="unknown-device"})` does match the
|
|
virtual pointer (provable by toggling `scroll_factor`), but `sensitivity` and
|
|
`accel_profile` are libinput pointer-acceleration settings and a
|
|
`wlr-virtual-pointer` is not a libinput device, so they have nothing to act on.
|
|
Measured 2026-10-10 on both machines with `lan-mouse test-emulation` + `hyprctl
|
|
cursorpos`: travel was 398x198px at `sensitivity = 0` and identical at `-0.9`,
|
|
exactly 1:1 with the raw deltas. The lines are kept because they are harmless and
|
|
the `unknown-device` naming note is worth preserving; the real fix is
|
|
`handoff/patch/`. Do not add sensitivity or accel_profile rules here expecting
|
|
them to change remote pointer feel.
|
|
|
|
**Terminals** are all dropped to a smaller font (9 -> 8) except ghostty, which
|
|
went the other way to 12. `shell.toml` sets the bar font base size to 10.
|
|
|
|
**Branding** (`config/omarchy/branding/`) replaces the about and screensaver
|
|
ASCII art.
|
|
|
|
**`hid_apple` fnmode=2** makes the F-keys act as F-keys on an Apple keyboard.
|
|
It only takes effect after `sudo mkinitcpio -P` or a module reload.
|
|
|
|
## Local plugin work
|
|
|
|
`indie.herdr-hud` is the one piece that exists on no remote. Ten commits live on
|
|
its `local` branch — touchpad scroll feel, agent ordering, context-size display —
|
|
and they stay off the upstream PR deliberately. `plugin-patches/` carries them as
|
|
a git bundle plus a patch for the uncommitted working tree, and `install.sh`
|
|
replays both after cloning. `io.github.tallsam.navbar-cat` has a one-file working
|
|
tree change captured the same way.
|
|
|
|
`capture.sh plugins` re-bundles and re-diffs these, so local work keeps flowing
|
|
back into the repo.
|
|
|
|
## Not in here, on purpose
|
|
|
|
- **Secrets.** `~/.config/lan-mouse/` holds a private key and per-machine
|
|
fingerprints; `~/.config/novnc/auth.env`, SSH keys and the git credential
|
|
helpers are likewise machine-local. Start from
|
|
`handoff/config/config.toml.example-{air,laptop}` (which carry the
|
|
`capture_backend`, edge and lowercase-fingerprint rules), then pair with
|
|
`omarchy-handoff pair <peer> <lowercase-sha256>` and `omarchy-handoff doctor`.
|
|
A fresh install regenerates the certificate, so this machine's fingerprint
|
|
changes and the *peer* has to re-pair. Back up `lan-mouse.pem` beforehand if
|
|
you would rather keep it stable — somewhere private, not here.
|
|
- **Shell, git and dev tooling.** That is already its own repo, `dotfiles`
|
|
(`git.nic-oconnor.com/public/dotfiles`), which handles zsh, mise, 1Password and
|
|
the `~/.local/bin` tool shims. The only overlap avoided here is
|
|
`~/.config/git/config`, whose customizations are identity and credential
|
|
helpers — `dotfiles` territory.
|
|
- **The remote-access stack.** `wayvnc`, `novnc`, `sunshine`, `freerdp`, `remmina`
|
|
and `omarchy-remote-desktop` are installed on this laptop but scoped out.
|
|
`kokd.remote-desktop` is still in `plugins.txt` since it is a bar plugin, but
|
|
it is not placed in `shell.json`.
|
|
- **Work tooling.** The keycloak helpers (`kcadm`, `kclogin`, `wren-keycloak`) and
|
|
`paperclipai.service`.
|
|
- **aether-managed themes.** `pink-gt3rs`, `porsche-cayman` and `porsche-rain`
|
|
carry a `.aether-managed` marker and are reinstallable with `aether`, so their
|
|
~18MB of wallpapers and previews stay out.
|
|
- **`btop.conf`.** Its only diff against stock is v1.4.7 default drift, not a
|
|
real customization.
|
|
- **Backup files.** Fifteen `.bak.*` and `.prefix.*` files are sitting in
|
|
`~/.config/hypr` and `~/.config/omarchy` from earlier editing sessions. They are
|
|
not tracked and are safe to delete.
|
|
|
|
## Adding a file
|
|
|
|
`capture.sh` only refreshes what the repo already tracks, so start it by hand:
|
|
|
|
```bash
|
|
cp ~/.config/foo/bar.conf config/foo/bar.conf # path mirrors ~/.config
|
|
git add config/foo/bar.conf
|
|
```
|
|
|
|
`install.sh config` and `capture.sh config` both walk `config/` recursively, so
|
|
nothing else needs changing. Check first that the file actually differs from
|
|
stock — `diff /usr/share/omarchy/config/foo/bar.conf ~/.config/foo/bar.conf` —
|
|
or you will be tracking a file Omarchy already ships.
|
|
|
|
### Per-host files
|
|
|
|
Hardware-specific files (monitor scale, fnmode) go under `hosts/<hostname>/`,
|
|
mirroring `config/` or `system/`, rather than into the shared tree. The shared
|
|
tree comes from `omarchy-laptop`, and `capture.sh` refreshes it only there (or
|
|
with `CAPTURE_SHARED=1`). On any other host it refreshes just that host's overlay,
|
|
so a machine running stock files cannot overwrite the shared customizations.
|
|
`OMARCHY_SETUP_HOST` overrides the detected hostname for both scripts.
|