Profiles: machines, roles and shared layers

The repo was one machine's capture. It is now a set of profiles built from
layers under profiles/:

  machines/  hp-laptop, macbook-air-m2, coder-desktop
  roles/     developer, devops, ai-agents
  features/  handoff (lan-mouse)
  shared     base, personal, personal-desktop

A profile resolves to its includes (depth first), any --roles, then itself;
for a path several layers provide, the last wins. install.sh --show prints
the layers and which one owns each file.

Hyprland settings no longer share a file: base's hyprland.lua loads
~/.config/hypr/layers/*.lua with Omarchy's own require_all, and bindings.lua
stays stock so nothing binds twice. Verified with Hyprland 0.56.2
--verify-config for all three profiles, plus a broken probe layer to prove
the directory is loaded.

packages.txt gains per-line arch (Arch Linux ARM lacks opencode, codex, mise,
shellcheck) and cmd= (skip when dotfiles' ~/.local/bin already provides the
command), and an [ignore] section that replaces capture.sh's hard-coded list.
Tab-separated records would have collapsed empty fields under read, so
package records use the unit separator.

hp-laptop: re-captured. monitors.lua catch-all scale is now 1, shell.json
has four new plugins, fix-stuck-displays has its connector-name fix,
navbar-cat is gone, plugin-manager and omarchy-phone are pinned, the
herdr-hud working tree is re-diffed and bin/herdr-web rides along. Its
handoff peer is now the Air (192.168.1.49); the old default list was the
HP's own addresses, written from the Air's side.

macbook-air-m2: captured read-only over SSH as it is (no themes, plugins
or bar changes). Its LAN_MOUSE_POINTER_SCALE=0.7 moves from the shared unit
into a lan-mouse.service.d drop-in in its own layer.

coder-desktop: the Omarchy settings covert-cloud's image used to patch in
by hand (Virtual-1 at 1920x1080, no animations, stay-awake, Retro 82 once),
for the image to apply at a pinned commit. Roles reach it per workspace via
install.sh --roles ... --no-clobber.

capture.sh writes each file back into the layer that owns it, and refuses
to run before the first layered install unless --force, since the old file
shapes would land in shared layers.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0153egowV1Xw2RNjZnSyZicc
This commit is contained in:
2026-10-16 16:01:54 -04:00
co-authored by Claude Opus 5.5
parent b3f3f46b98
commit 87a31858fd
98 changed files with 2010 additions and 532 deletions
@@ -0,0 +1,5 @@
-- coder-desktop: a streamed VM with no GPU. vga=virtio without virgl, so
-- Hyprland draws on the CPU (llvmpipe) and every frame is a full-screen copy
-- into the scanout buffer. Anything that animates keeps the CPU busy, so no
-- window animations.
hl.config({ animations = { enabled = false } })
@@ -0,0 +1,20 @@
-- See https://wiki.hypr.land/Configuring/Basics/Monitors/
-- List current monitors and supported resolutions with: hyprctl monitors all
local omarchy_gdk_scale = 1
local omarchy_monitor_scale = "auto"
hl.env("GDK_SCALE", tostring(omarchy_gdk_scale))
hl.monitor({ output = "", mode = "preferred", position = "auto", scale = omarchy_monitor_scale })
-- Configure a specific monitor.
-- hl.monitor({ output = "DP-2", mode = "2560x1440@144", position = "0x0", scale = 1 })
-- Portrait/rotated secondary monitor (transform: 1 = 90°, 3 = 270°).
-- hl.monitor({ output = "DP-2", mode = "preferred", position = "auto", scale = 1, transform = 1 })
-- Streamed desktop: the VM's virtio display, fixed to the stream size.
-- MUST match --manual-width/--manual-height in the image's selkies.service
-- (covert-cloud: platform/workspaces/omarchy-desktop/image/systemd/user/), and
-- the image build fails if this line is missing.
hl.monitor({ output = "Virtual-1", mode = "1920x1080@60", position = "0x0", scale = 1 })
+15
View File
@@ -0,0 +1,15 @@
# Coder desktops: Omarchy in a Proxmox VM, streamed by Selkies, reached only
# through Coder. Built by covert-cloud's platform/workspaces/omarchy-desktop/
# image, which runs `install.sh --profile coder-desktop` at a pinned commit.
#
# This layer is the desktop's Omarchy look and behaviour. The image keeps the
# plumbing: Selkies, the Coder agent, the Super key stand-in, the start page,
# autologin and the lockdown (no SSH, no file transfer, locked password).
#
# Extra roles come from the Coder template's "Roles" parameter, applied at
# every workspace start with --roles and --no-clobber. Nothing personal
# (personal/, personal-desktop/, handoff) belongs here: other people use these.
description="Coder desktop VM (streamed by Selkies): no GPU, fixed 1920x1080"
include=(base roles/developer)
hostnames=(omarchy-desktop)
arch=x86_64
+42
View File
@@ -0,0 +1,42 @@
#!/bin/bash
# coder-desktop setup, run by install.sh's `setup` step after the files are in
# place. Everything here is state outside ~/.config. Idempotent; honours
# OMARCHY_SETUP_DRY=1.
set -uo pipefail
run() { if [[ ${OMARCHY_SETUP_DRY:-0} == 1 ]]; then echo " ? would: $*"; else "$@"; fi; }
state=$HOME/.local/state/omarchy-setup
export OMARCHY_PATH=${OMARCHY_PATH:-/usr/share/omarchy}
# No idle lock or screensaver: Omarchy's stay-awake mode. The desktop user has
# no password (the image locks it), so a locked screen could never be unlocked,
# and an idle lock would darken the stream. The image build checks for this.
marker=$HOME/.local/state/omarchy/indicators/stay-awake
if [[ -e $marker ]]; then
echo " = stay-awake"
else
run mkdir -p "${marker%/*}" && run touch "$marker" && echo " + stay-awake"
fi
# Reduced motion, so Chromium reports prefers-reduced-motion and pages that
# honour it stop animating (see layers/80-coder-desktop.lua for why). No
# session during the image build, hence dbus-run-session.
if command -v gsettings >/dev/null; then
gs=(gsettings); [[ -n ${DBUS_SESSION_BUS_ADDRESS:-} ]] || gs=(dbus-run-session -- gsettings)
if [[ $("${gs[@]}" get org.gnome.desktop.interface enable-animations 2>/dev/null) == false ]]; then
echo " = gtk animations off"
else
run "${gs[@]}" set org.gnome.desktop.interface enable-animations false && echo " + gtk animations off"
fi
fi
# Default theme: Omarchy's Retro 82. Only on the first apply, because install.sh
# also runs at every workspace start (for the roles parameter) and must not undo
# a theme the developer picked. The image also installs the Covert Cloud themes
# for anyone who chooses them.
if [[ -e $state/coder-desktop-theme ]]; then
echo " = default theme already set once (left alone)"
else
run env OMARCHY_THEME_HEADLESS=1 "$OMARCHY_PATH/bin/omarchy-theme-set" "Retro 82" \
&& run mkdir -p "$state" && run touch "$state/coder-desktop-theme" && echo " + theme: Retro 82"
fi
+53
View File
@@ -0,0 +1,53 @@
#!/bin/bash
# Release display pipes the kernel left enabled on unplugged connectors.
#
# After suspend/resume (or unplugging a USB-C display) i915 can leave a
# connector "disconnected" but still "enabled" on a pipe that Hyprland has
# forgotten. That pipe then blocks every other external output from
# modesetting (black screens, or a ~5 s re-modeset loop).
#
# Fix: force the connector on so Hyprland sees it, disable it from Hyprland
# (which releases the pipe), force it off, then return it to auto-detect.
# Never `hyprctl reload` here: a reload re-enables the connector while it is
# forced on and re-sticks the pipe.
log() { echo "fix-stuck-displays: $*"; logger -t fix-stuck-displays -- "$*"; }
wait_for() { # wait_for <seconds> <command...>
local n=$(( $1 * 4 )); shift
for _ in $(seq "$n"); do "$@" && return 0; sleep 0.25; done
return 1
}
stuck=()
for d in /sys/class/drm/card*-*; do
[[ -f $d/status && -f $d/enabled ]] || continue
[[ $d == *eDP* ]] && continue
[[ $(<"$d/status") == disconnected && $(<"$d/enabled") == enabled ]] && stuck+=("$d")
done
if (( ${#stuck[@]} == 0 )); then
log "no stuck connectors"
exit 0
fi
systemctl --user stop hyprmoncfgd
for d in "${stuck[@]}"; do
out=${d##*/}; out=${out#card*-}
log "releasing $out"
echo on | sudo -n tee "$d/status" >/dev/null
wait_for 5 sh -c "hyprctl monitors all | grep -q '^Monitor $out '" || log "$out never appeared in Hyprland"
hyprctl eval "hl.monitor({ output = \"$out\", disabled = true })" >/dev/null
wait_for 5 grep -qx disabled "$d/enabled" || log "$out still enabled after disable"
echo off | sudo -n tee "$d/status" >/dev/null
sleep 1
echo detect | sudo -n tee "$d/status" >/dev/null
log "$out now $(<"$d/status") $(<"$d/enabled")"
done
# Drop any low-refresh fallback hyprmoncfgd wrote while outputs were failing.
rm -f ~/.config/hyprmoncfg/display-fallbacks.json
# hyprmoncfgd re-applies the matching profile (modes, positions) on startup.
systemctl --user start hyprmoncfgd
@@ -0,0 +1,28 @@
general.import = [ "~/.local/state/omarchy/current/theme/alacritty.toml" ]
[env]
TERM = "xterm-256color"
[terminal]
osc52 = "CopyPaste"
[font]
normal = { family = "JetBrainsMono Nerd Font", style = "Regular" }
bold = { family = "JetBrainsMono Nerd Font", style = "Bold" }
italic = { family = "JetBrainsMono Nerd Font", style = "Italic" }
size = 8
[window]
padding.x = 14
padding.y = 14
decorations = "None"
[keyboard]
bindings = [
{ key = "Insert", mods = "Shift", action = "Paste" },
{ key = "Insert", mods = "Control", action = "Copy" },
# Send Shift+Return as CSI-u so TUIs can distinguish it from Return without treating it as Alt+Return.
{ key = "Return", mods = "Shift", chars = "\u001B[13;2u" },
# Legacy encoding sends Alt+Shift+Return the same as Alt+Return; send CSI-u so tmux can match M-S-Enter.
{ key = "Return", mods = "Alt|Shift", chars = "\u001B[13;4u" }
]
@@ -0,0 +1,26 @@
[main]
include=~/.local/state/omarchy/current/theme/foot.ini
term=xterm-256color
font=JetBrainsMono Nerd Font:size=8
pad=14x14
initial-window-mode=windowed
workers=0
[scrollback]
lines=10000
multiplier=7.0
[cursor]
style=block
blink=no
[key-bindings]
clipboard-copy=Control+Insert Control+Shift+c XF86Copy
primary-paste=none
clipboard-paste=Shift+Insert Control+Shift+v XF86Paste
[text-bindings]
# Send Shift+Return as CSI-u so TUIs can distinguish it from Return.
\x1b[13;2u=Shift+Return
# Send Alt+Shift+Return as CSI-u so tmux can match M-S-Enter.
\x1b[13;4u=Mod1+Shift+Return
@@ -0,0 +1,41 @@
# Dynamic theme colors
config-file = ?"~/.local/state/omarchy/current/theme/ghostty.conf"
# Font
font-family = "JetBrainsMono Nerd Font"
font-style = Regular
font-size = 12
# Window
window-theme = ghostty
window-padding-x = 14
window-padding-y = 14
confirm-close-surface=false
resize-overlay = never
gtk-toolbar-style = flat
# Cursor styling
cursor-style = "block"
cursor-style-blink = false
# Cursor styling + SSH session terminfo
# (all shell integration options must be passed together)
shell-integration-features = no-cursor,ssh-env
# Keyboard bindings
keybind = shift+insert=paste_from_clipboard
keybind = control+insert=copy_to_clipboard
# Send Shift+Enter as CSI-u so TUIs can distinguish it from Enter.
keybind = shift+enter=csi:13;2u
# Legacy encoding sends Alt+Shift+Enter the same as Alt+Enter; send CSI-u so tmux can match M-S-Enter.
keybind = alt+shift+enter=csi:13;4u
keybind = super+control+shift+alt+arrow_down=resize_split:down,100
keybind = super+control+shift+alt+arrow_up=resize_split:up,100
keybind = super+control+shift+alt+arrow_left=resize_split:left,100
keybind = super+control+shift+alt+arrow_right=resize_split:right,100
# Slowdown mouse scrolling
mouse-scroll-multiplier = 0.95
# Fix general slowness on hyprland (https://github.com/ghostty-org/ghostty/discussions/3224)
async-backend = epoll
@@ -0,0 +1,10 @@
-- Extra autostart processes.
-- o.launch_on_start("my-service")
-- Keyboard/mouse sharing with the other Omarchy laptop (lan-mouse).
-- Runs as a daemon; input only crosses the screen edge once the peer is
-- activated, so starting it here is inert until Handoff is toggled on.
-- Superseded by the lan-mouse.service systemd user unit (journald logging,
-- ordering after the portal, Restart=on-failure). launch_on_start sent both
-- output streams to /dev/null, which hid every pairing failure.
-- o.launch_on_start("lan-mouse daemon")
@@ -0,0 +1,72 @@
-- Keep only your personal input overrides here. Uncommented settings below
-- replace Omarchy's defaults.
-- Keyboard layout and options.
-- See https://wiki.hypr.land/Configuring/Basics/Variables/#input
-- hl.config({
-- input = {
-- -- Use multiple keyboard layouts and switch between them with Left Alt + Right Alt.
-- kb_layout = "us,dk,eu",
-- kb_options = "compose:caps,shift:both_capslock_cancel,grp:alts_toggle",
--
-- -- Use a specific keyboard variant if needed (e.g. intl for international keyboards).
-- kb_variant = "intl",
--
-- -- Change speed of keyboard repeat.
-- repeat_rate = 40,
-- repeat_delay = 250,
--
-- -- Start with numlock on by default.
-- numlock_by_default = true,
--
-- -- Increase sensitivity for mouse/trackpad (default: 0).
-- sensitivity = 0.35,
--
-- -- Turn off mouse acceleration (default: adaptive).
-- accel_profile = "flat",
--
-- touchpad = {
-- -- Use natural (inverse) scrolling.
-- natural_scroll = true,
--
-- -- Use two-finger clicks for right-click instead of lower-right corner.
-- clickfinger_behavior = true,
--
-- -- Control the speed of your scrolling.
-- scroll_factor = 0.4,
--
-- -- Enable the touchpad while typing.
-- disable_while_typing = false,
--
-- -- Left-click-and-drag with three fingers.
-- drag_3fg = 1,
-- },
-- },
-- })
-- App-specific touchpad scroll speeds.
-- o.window("(Alacritty|kitty|foot)", { scroll_touchpad = 1.5 })
-- o.window("com.mitchellh.ghostty", { scroll_touchpad = 0.2 })
-- Enable touchpad gestures for changing workspaces.
-- See https://wiki.hypr.land/Configuring/Advanced-and-Cool/Gestures/
hl.gesture({ fingers = 3, direction = "horizontal", action = "workspace" })
-- Enable touchpad gestures for moving focus (helpful on scrolling layout).
-- hl.gesture({ fingers = 3, direction = "left", action = function() hl.dispatch(hl.dsp.focus({ direction = "l" })) end })
-- hl.gesture({ fingers = 3, direction = "right", action = function() hl.dispatch(hl.dsp.focus({ direction = "r" })) end })
-- lan-mouse (omarchy-handoff) virtual pointer: kill the SECOND acceleration pass.
-- lan-mouse forwards RELATIVE deltas that the SENDING compositor has already
-- accelerated. Omarchy leaves accel_profile unset (adaptive), so the receiver
-- amplifies them again and the pointer arrives hypersensitive while the local
-- trackpad feels normal. "flat" applies no curve, so a forwarded delta moves
-- exactly as far as the sender intended.
-- The name is "unknown-device" because wlr-virtual-pointer gives Hyprland no
-- name (virtual KEYBOARDS get named, pointers don't). Verified on this machine
-- with `lan-mouse test-emulation` + `hyprctl devices`: no real device here is
-- named unknown-device* (real pointers are elan0138:*, mouse-passthrough*,
-- dp-3-1), so this rule cannot touch the trackpad. Two entries because the
-- daemon may hold more than one virtual pointer at a time.
hl.device({ name = "unknown-device", sensitivity = 0, accel_profile = "flat" })
hl.device({ name = "unknown-device-1", sensitivity = 0, accel_profile = "flat" })
@@ -0,0 +1,48 @@
-- BEGIN hyprmoncfg wake settings
-- Shared with Omarchy while hyprmoncfg manages displays.
hl.monitor({ output = "eDP-1", mode = "preferred", position = "0x0", scale = 1.25 })
-- END hyprmoncfg wake settings
-- See https://wiki.hypr.land/Configuring/Basics/Monitors/
-- List current monitors and supported resolutions with: hyprctl monitors all
--
-- SINGLE SOURCE OF TRUTH for display config.
-- Do not add monitor rules anywhere else (hyprland.lua, a hyprmoncfg-generated
-- file, etc.) -- overlapping rules from several files were what made external
-- displays unrecoverable before.
local omarchy_gdk_scale = 1
local omarchy_monitor_scale = 1
hl.env("GDK_SCALE", tostring(omarchy_gdk_scale))
-- Catch-all: anything not named below gets its EDID-preferred mode.
hl.monitor({ output = "", mode = "preferred", position = "auto", scale = omarchy_monitor_scale })
-- Built-in laptop panel.
hl.monitor({
output = "desc:Chimei Innolux Corporation 0x1642",
mode = "1920x1200@60",
position = "auto",
scale = 1.25,
})
-- LG IPS236 on the laptop's own HDMI port.
hl.monitor({
output = "desc:LG Electronics IPS236 105NDLS5A720",
mode = "1920x1080@60",
position = "auto",
scale = 1,
})
-- LG TV via the Anker USB-C dock.
-- Deliberately NOT forced to 3840x2160@60: the dock negotiates DP alt-mode
-- with only 2 lanes (pin assignment D), which leaves no bandwidth headroom at
-- 4K60. Forcing it produced a "monitor has no mode" loop. "preferred" is
-- 3840x2160@30 here, which links reliably. Use 1920x1080@120 instead if you
-- want high refresh over this dock.
hl.monitor({
output = "desc:LG Electronics LG TV SSCR2 0x01010101",
mode = "preferred",
position = "auto",
scale = 1.25,
})
@@ -0,0 +1,23 @@
# Remove the include below to disconnect Kitty from Omarchy's theming system.
include ~/.local/state/omarchy/current/theme/kitty.conf
# Settings below override Omarchy's defaults in /etc/xdg/kitty/kitty.conf.
# Learn more: https://sw.kovidgoyal.net/kitty/conf/
# Font
# font_family JetBrainsMono Nerd Font
# font_size 12
# Window padding
# window_padding_width 14
# Unmap a shortcut, passing it through to the terminal application
# map ctrl+insert
# Set or replace a shortcut
# map ctrl+shift+c copy_to_clipboard
# Remove all inherited shortcuts, including Kitty's built-in shortcuts
# clear_all_shortcuts yes
font_size 8.0
+48
View File
@@ -0,0 +1,48 @@
# HP laptop (omarchy-laptop) packages beyond the Omarchy 4.x baseline and the
# packages its other layers already list.
#
# Format (every layer's packages.txt): "name [arch...] [cmd=command] # why".
# arch only install on these architectures (x86_64, aarch64)
# cmd=X skip when command X is already on PATH (e.g. a dotfiles shim)
# Sections:
# [repo] official repos + the omarchy repo -> omarchy pkg add
# [aur] AUR only -> omarchy pkg aur add
# [optional] installed here, not required for the desktop to work
# [ignore] installed here on purpose but not managed (capture.sh stays quiet)
[repo]
# --- hardware: Intel + an Anker USB-C dock ---
linux-omarchy # kernel this install actually boots
linux-omarchy-headers # needed to build out-of-tree modules against it
intel-ucode # CPU microcode
vulkan-intel # Intel Vulkan driver
lib32-vulkan-intel # 32-bit Vulkan, for Steam/Proton
sof-firmware # Sound Open Firmware - required for this laptop's audio
thermald # Intel thermal daemon; without it the CPU throttles hard
zram-generator # compressed swap in RAM
# --- audio: full PipeWire stack with the Pulse/JACK/ALSA shims ---
pipewire-pulse
pipewire-alsa
pipewire-jack
libpulse
gst-plugin-pipewire
# --- desktop / input ---
python-evdev # input tooling used while debugging lan-mouse (not required by it)
wayland-utils # wayland-info, used when debugging outputs
ghostty # terminal (alongside Omarchy's default)
# --- apps ---
1password
1password-cli # `op`, which the dotfiles repo's secrets module uses
bun-bin
[optional]
steam # games; pulls a large 32-bit dependency tree
[ignore]
# toolchain/base, present on any Omarchy install or pulled in as a dependency
base base-devel sudo omarchy mkinitcpio linux-firmware efibootmgr devtools cmake ninja
# the remote-access stack, out of this repo's scope
wayvnc sunshine freerdp remmina omarchy-remote-desktop-backend pipewire-debug
+8
View File
@@ -0,0 +1,8 @@
# HP laptop (omarchy-laptop): Intel, an Anker USB-C dock, the LG IPS236 on HDMI
# and the LG TV through the dock. The machine this repo was first captured from.
description="HP laptop (omarchy-laptop): Intel, Anker dock, LG displays"
include=(base personal personal-desktop features/handoff roles/developer roles/devops roles/ai-agents)
hostnames=(omarchy-laptop)
arch=x86_64
# The peer for omarchy-handoff is the Air (Wi-Fi only).
handoff_peer_ips=(192.168.1.49)
@@ -0,0 +1 @@
options hid_apple fnmode=2
@@ -0,0 +1,9 @@
# Two NICs (Wi-Fi wlo1, dock ethernet enp0s13f0u3u4u3) share 192.168.1.0/24.
# With the defaults (arp_ignore=0/arp_announce=0) the host answers ARP for any
# local address on any interface, so the subnet's mapping collapses onto
# whichever NIC replied last -- traffic aimed at the Wi-Fi IP lands on the dock,
# and the Wi-Fi path silently never gets exercised.
# 1 = only answer ARP for addresses configured on the receiving interface.
# 2 = always use the best local address for the target subnet when announcing.
net.ipv4.conf.all.arp_ignore = 1
net.ipv4.conf.all.arp_announce = 2
@@ -0,0 +1,96 @@
onboarding = false
# Mirrors the Omarchy tmux config in config/tmux/tmux.conf
# tmux session -> herdr workspace, tmux window -> herdr tab, tmux pane -> herdr pane
[theme]
# tmux ran on the terminal's own palette (bg=default, fg=default, ANSI blue accents)
name = "terminal"
[theme.custom]
# The active tab is drawn as panel_bg text on an accent background, so panel_bg
# has to be dark for it to read - same colors as status-left's "#[fg=black,bg=blue]"
panel_bg = "black"
[terminal]
# Matches -c "#{pane_current_path}" on every split, window, and session
new_cwd = "follow"
[keys]
prefix = "ctrl+space"
# Config and help
reload_config = "prefix+q"
help = "prefix+?"
detach = "prefix+d"
# Copy mode
copy_mode = "prefix+["
# Panes
split_horizontal = ["prefix+h", "alt+enter"]
split_vertical = ["prefix+v", "alt+shift+enter"]
close_pane = ["prefix+x", "alt+esc"]
zoom = "prefix+z"
last_pane = "prefix+;"
focus_pane_left = "ctrl+alt+left"
focus_pane_down = "ctrl+alt+down"
focus_pane_up = "ctrl+alt+up"
focus_pane_right = "ctrl+alt+right"
resize_mode = ["prefix+ctrl+left", "prefix+ctrl+down", "prefix+ctrl+up", "prefix+ctrl+right"]
# Like resize-pane on C-M-S-arrows
resize_pane_left = "ctrl+alt+shift+left"
resize_pane_down = "ctrl+alt+shift+down"
resize_pane_up = "ctrl+alt+shift+up"
resize_pane_right = "ctrl+alt+shift+right"
# No tmux equivalent; herdr's default prefix+shift+p is taken by previous session
rename_pane = "prefix+shift+o"
# Windows -> tabs
new_tab = "prefix+c"
rename_tab = "prefix+r"
close_tab = "prefix+k"
switch_tab = ["prefix+1..9", "alt+1..9"]
previous_tab = ["prefix+p", "alt+left"]
next_tab = ["prefix+n", "alt+right"]
# Like swap-window -t -1/+1 on M-S-Left/Right
move_tab_previous = "alt+shift+left"
move_tab_next = "alt+shift+right"
# Sessions -> workspaces
new_workspace = "prefix+shift+c"
rename_workspace = "prefix+shift+r"
close_workspace = "prefix+shift+k"
previous_workspace = ["prefix+shift+p", "alt+up"]
next_workspace = ["prefix+shift+n", "alt+down"]
[ui]
accent = "blue"
# tmux drew single-line dividers between adjacent panes and no outer frame
pane_gaps = false
pane_outer_borders = false
# tmux had no scrollbar column beside its panes
pane_scrollbars = false
# kill-window and kill-session never asked
confirm_close = false
# automatic-rename gave windows a name without prompting
prompt_new_tab_name = false
# set -g mouse on
mouse_capture = true
# status-right had the zoom flag followed by #h
tab_bar_right = [{ type = "zoom" }, { type = "hostname" }]
# set -g set-titles on / set -g set-titles-string '#h:#W', where tmux's #W was
# the basename of the pane cwd. This is what Hyprland shows in the group bar,
# and it resolves on the server so remote sessions name the remote host.
window_title = "{hostname}: {workspace}"
@@ -0,0 +1,83 @@
-- Keep only your personal input overrides here. Uncommented settings below
-- replace Omarchy's defaults.
-- Keyboard layout and options.
-- See https://wiki.hypr.land/Configuring/Basics/Variables/#input
-- hl.config({
-- input = {
-- -- Use multiple keyboard layouts and switch between them with Left Alt + Right Alt.
-- kb_layout = "us,dk,eu",
-- kb_options = "compose:caps,shift:both_capslock_cancel,grp:alts_toggle",
--
-- -- Use a specific keyboard variant if needed (e.g. intl for international keyboards).
-- kb_variant = "intl",
--
-- -- Change speed of keyboard repeat.
-- repeat_rate = 40,
-- repeat_delay = 250,
--
-- -- Start with numlock on by default.
-- numlock_by_default = true,
--
-- -- Increase sensitivity for mouse/trackpad (default: 0).
-- sensitivity = 0.35,
--
-- -- Turn off mouse acceleration (default: adaptive).
-- accel_profile = "flat",
--
-- touchpad = {
-- -- Use traditional (non-inverse) scrolling.
-- natural_scroll = false,
--
-- -- Re-enable tap-to-click (one-finger tap = left, two-finger = right).
-- tap_to_click = true,
--
-- -- Use two-finger clicks for right-click instead of lower-right corner.
-- clickfinger_behavior = true,
--
-- -- Control the speed of your scrolling.
-- scroll_factor = 0.4,
--
-- -- Enable the touchpad while typing.
-- disable_while_typing = false,
--
-- -- Left-click-and-drag with three fingers.
-- drag_3fg = 1,
-- },
-- },
-- })
-- App-specific touchpad scroll speeds.
-- o.window("(Alacritty|kitty|foot)", { scroll_touchpad = 1.5 })
-- o.window("com.mitchellh.ghostty", { scroll_touchpad = 0.2 })
-- Enable touchpad gestures for changing workspaces.
-- See https://wiki.hypr.land/Configuring/Advanced-and-Cool/Gestures/
-- hl.gesture({ fingers = 3, direction = "horizontal", action = "workspace" })
-- Enable touchpad gestures for moving focus (helpful on scrolling layout).
-- hl.gesture({ fingers = 3, direction = "left", action = function() hl.dispatch(hl.dsp.focus({ direction = "l" })) end })
-- hl.gesture({ fingers = 3, direction = "right", action = function() hl.dispatch(hl.dsp.focus({ direction = "r" })) end })
-- lan-mouse (handoff) virtual pointer: DO NOT add sensitivity/accel_profile rules here.
--
-- Tried and measured as INERT on 2026-10-10. `hl.device({name="unknown-device", ...})` does
-- match the device (proven by toggling scroll_factor and watching hyprctl report it), 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
-- travel with `lan-mouse test-emulation` + hyprctl cursorpos was 398x198px at sensitivity 0
-- AND at -0.9 -- identical, and exactly 1:1 with the raw deltas. Both machines measure the
-- same 398x198, so neither end scales.
--
-- Corollary: global `accel_profile = "flat"` would also be a no-op for the virtual pointer
-- while permanently changing how the real trackpad feels. Pure loss -- do not do it.
-- The magnitude of forwarded motion originates on the SENDING machine's trackpad.
--
-- ROOT CAUSE FOUND 2026-10-10: lan-mouse 0.11.0 forwards UNACCELERATED deltas.
-- input-capture/src/layer_shell.rs:887 destructures the relative-pointer event as
-- `dx_unaccel: dx, dy_unaccel: dy, ..` -- the `..` throws away the accelerated dx/dy that the
-- same event carries. So the accel curve is stripped at the SENDER and nothing replaces it at
-- the receiver. Consequence: sensitivity/accel_profile are inert for forwarded motion on BOTH
-- ends, so "sync the sensitivity between the laptops" is impossible by configuration.
-- The only fix is a source patch to use the accelerated dx/dy.
-- See memory: lan-mouse-forwards-unaccelerated-deltas.md
@@ -0,0 +1,22 @@
-- See https://wiki.hypr.land/Configuring/Basics/Monitors/
-- List current monitors and supported resolutions with: hyprctl monitors all
-- Monitor scale is Hyprland's scale for the output. It sizes everything
-- Wayland-native, accepts fractions (1.6, 1.75), and applies immediately.
-- "auto" lets Hyprland pick per display.
local omarchy_monitor_scale = 1.33333
hl.monitor({ output = "", mode = "preferred", position = "auto", scale = omarchy_monitor_scale })
-- Configure a specific monitor.
-- hl.monitor({ output = "DP-2", mode = "2560x1440@144", position = "0x0", scale = 1 })
-- Portrait/rotated secondary monitor (transform: 1 = 90°, 3 = 270°).
-- hl.monitor({ output = "DP-2", mode = "preferred", position = "auto", scale = 1, transform = 1 })
-- GDK scale is GDK_SCALE, the factor GTK draws its own UI at. It's what
-- sizes X11/XWayland windows, which Omarchy leaves unscaled so they stay
-- crisp instead of being stretched by the compositor. GTK only honors whole
-- numbers, so use the nearest integer to the monitor scale, and restart an
-- app for a change to reach it.
local omarchy_gdk_scale = 1
hl.env("GDK_SCALE", tostring(omarchy_gdk_scale))
@@ -0,0 +1,5 @@
{
"$schema": "https://opencode.ai/config.json",
"theme": "system",
"autoupdate": false
}
@@ -0,0 +1,100 @@
# Voxtype Configuration
#
# Location: ~/.config/voxtype/config.toml
# All settings can be overridden via CLI flags
#
# State file for external integrations (Waybar, polybar, etc.)
# Use "auto" for default location ($XDG_RUNTIME_DIR/voxtype/state),
# a custom path, or "disabled" to turn off. The daemon writes state
# ("idle", "recording", "transcribing") to this file whenever it changes.
# Required for `voxtype record toggle` and `voxtype status` commands.
state_file = "auto"
[hotkey]
# Hotkey is configured in Hyprland. Default is Super + Ctrl + X
enabled = false
[audio]
# Audio input device ("default" uses system default)
# List devices with: pactl list sources short
device = "default"
# Sample rate in Hz (whisper expects 16000)
sample_rate = 16000
# Maximum recording duration in seconds (safety limit)
max_duration_secs = 60
# Pause MPRIS media players during recording
pause_media = true
# [audio.feedback]
# Enable audio feedback sounds (beeps when recording starts/stops)
# enabled = true
#
# Sound theme: "default", "subtle", "mechanical", or path to custom theme directory
# theme = "default"
#
# Volume level (0.0 to 1.0)
# volume = 0.7
[whisper]
# Model to use for transcription
# Options: tiny, tiny.en, base, base.en, small, small.en, medium, medium.en, large-v3, large-v3-turbo
# .en models are English-only but faster and more accurate for English
# large-v3-turbo is faster than large-v3 with minimal accuracy loss (recommended for GPU)
# Or provide absolute path to a custom .bin model file
model = "base.en"
# Language for transcription
# Use "en" for English, "auto" for auto-detection
# See: https://github.com/openai/whisper#available-models-and-languages
language = "en"
# Translate non-English speech to English
translate = false
# Number of CPU threads for inference (omit for auto-detection)
# threads = 4
[output]
# Primary output mode: "type" or "clipboard"
# - type: Simulates keyboard input at cursor position (requires ydotool)
# - clipboard: Copies text to clipboard (requires wl-copy)
mode = "type"
# Fall back to clipboard if typing fails
fallback_to_clipboard = true
# Delay between typed characters in milliseconds
# 0 = fastest possible, increase if characters are dropped
type_delay_ms = 1
# Post-processing command (optional)
# Pipe transcribed text through an external command for cleanup before output.
# The command receives text on stdin and outputs processed text on stdout.
# Useful for LLM-based text cleanup, grammar correction, filler word removal.
# On any failure (timeout, error), falls back to original transcription.
#
# [output.post_process]
# command = "ollama run llama3.2:1b 'Clean up this dictation. Fix grammar, remove filler words. Output only the cleaned text:'"
# timeout_ms = 30000 # 30 second timeout (generous for LLM)
[output.notification]
# Show notification when recording starts (hotkey pressed)
on_recording_start = false
# Show notification when recording stops (transcription beginning)
on_recording_stop = false
# Show notification with transcribed text after transcription completes
on_transcription = false
# [text]
# Text processing options (word replacements, spoken punctuation)
#
# Enable spoken punctuation conversion (e.g., say "period" to get ".")
# spoken_punctuation = false
#
# Custom word replacements (case-insensitive)
# replacements = { "hyperwhisper" = "hyprwhspr" }
@@ -0,0 +1,35 @@
# MacBook Air M2 packages beyond the Omarchy baseline and the other layers.
# See machines/hp-laptop/packages.txt for the format.
[repo]
# --- Asahi platform: installed by the Asahi installer, listed so a check catches drift ---
linux-asahi
asahi-meta
asahi-audio
asahi-scripts
asahi-fwextract
m1n1
uboot-asahi
speakersafetyd # speaker protection; without it the amps are capped
vulkan-asahi
libva-v4l2_request-avd # hardware video decode (omarchy-aarch64)
pipewire-pulse
pipewire-alsa
# --- access ---
openssh # sshd is enabled: the HP reaches it as `ssh air`
# --- apps ---
obsidian-appimage # omarchy-aarch64
wf-recorder # screen recording
[optional]
steam # asahi-alarm build, runs x86 games through FEX
omarchy-steam-fex
[ignore]
# Arch Linux ARM base system and keyrings
base base-devel sudo omarchy linux-firmware btrfs-progs grub dhcpcd netctl net-tools nano which
ex-vi-compat terminus-font archlinuxarm-keyring asahi-alarm-keyring hyprtoolkit
neovim # Omarchy ships nvim; this is the ALARM name for it
dotnet-runtime-2.1 # explicit, required by nothing; unclear why it is here
+11
View File
@@ -0,0 +1,11 @@
# MacBook Air M2 (omarchy-air): Asahi Linux on Arch Linux ARM, aarch64.
# Captured as it is on 2026-10-16 (Omarchy 4.0.3rc4): no hand-built themes, no
# shell plugins, stock bar, stock terminal fonts. Add personal-desktop to
# include= to give it the HP's desktop.
description="MacBook Air M2 (omarchy-air): Asahi, aarch64"
include=(base personal features/handoff roles/developer roles/devops roles/ai-agents)
hostnames=(omarchy-air)
arch=aarch64
# The peer for omarchy-handoff is the HP: Wi-Fi .24 and the dock NIC .86, which
# disappears on undock, so both.
handoff_peer_ips=(192.168.1.24 192.168.1.86)
@@ -0,0 +1 @@
options appledrm show_notch=1
@@ -0,0 +1 @@
options hid_apple fnmode=1
@@ -0,0 +1,6 @@
# omarchy-air only. Multiplier for the residual logical-ppi difference between
# the two screens (handoff/patch adds it; default 1.0 = upstream). The Air is
# 140.1 logical ppi against ~95.8 for the 23" LG, so 0.7 makes forwarded motion
# cover the same PHYSICAL distance.
[Service]
Environment=LAN_MOUSE_POINTER_SCALE=0.7