Skip to content
luckycoldPublic

About

No description, website, or topics provided.

Resources

Stars

1 star

Watchers

1 watching

Forks

Repository files navigation

My dotfiles

These are the dotfiles for my system

Canonical repository: github.com/luckycold/dotfiles.

Requirements

Recommended

For Linux

Arch
sudo pacman -S yay stow git github-cli ghostty neovim lsof oath-toolkit solaar opencode
# yay -S ...
Debian/Ubuntu
sudo apt install stow git gh neovim ghostty lsof oathtool solaar opencode
Fedora
sudo dnf install stow git gh neovim ghostty lsof oathtool solaar
Steam on Hyprland (personal profile)

Launch Steam from the application menu using the package-provided /usr/share/applications/steam.desktop. The personal profile provides no Steam launcher wrapper, desktop-entry override, or autostart. Use Steam's Accessibility UI Scale slider to adjust the client size.

SteamOS

SteamOS is immutable. The SteamOS bootstrap uses per-user Flatpaks and user-local CLI tools only; it does not invoke pacman, sudo, or steamos-readonly. From Desktop Mode, clone this repository to ~/dotfiles and run:

./bootstrap/steamos/apply.sh

It installs Brave, Proton Pass, Obsidian, ElectronMail, Zed, Flatseal, and Solaar as per-user Flatpaks. Stow, Neovim, GitHub CLI, Lazygit, Proton Pass CLI, and OpenCode are installed below ~/.local (OpenCode uses ~/.opencode). Stow comes from Arch's prebuilt package and is extracted into ~/.local; no programs are compiled. A user-systemd timer checks for Flatpak and CLI updates daily. Its --update path updates existing user-local tools and Flatpaks without reapplying Stow packages or re-enabling services. Resilio is intentionally not managed here. Beeper and Ghostty are not in Flathub, so they are not installed on SteamOS.

Universal Extras
#Proton Pass CLI
curl -fsSL https://proton.me/download/pass-cli/install.sh | bash
#OpenCode
curl -fsSL https://opencode.ai/install | bash
#MCPorter (preferred when Homebrew is available)
brew install steipete/tap/mcporter

With mise and Node.js 24 or newer, install MCPorter with mise use -g npm:mcporter@latest. Without mise or Homebrew, use npm install -g mcporter.

Voxtype

Voxtype is recommended for local voice-to-text, but it is intentionally not part of any default Stow profile. Opt in manually on Fedora/Nobara KDE systems with the bootstrap script:

./bootstrap/voxtype-fedora-kde/apply.sh

The script installs the upstream RPM, Fedora runtime/build packages, and upstream dotool; configures ydotool as a fallback; writes local-only Voxtype config; sets hold-to-talk to F9; uses the small.en Whisper model; and keeps output in real typing mode rather than clipboard/paste mode. Log out and back in afterward if this is the first time adding the user to the input group.

If voxtype setup --download leaves a too-small or corrupt small.en model, replace it directly:

rm -f ~/.local/share/voxtype/models/ggml-small.en.bin
curl -L --fail -o ~/.local/share/voxtype/models/ggml-small.en.bin https://huggingface.co/ggerganov/whisper.cpp/resolve/main/ggml-small.en.bin
systemctl --user restart voxtype

Verify with:

YDOTOOL_SOCKET=/run/ydotoold/socket voxtype setup check
voxtype config
systemctl --user status voxtype
Universal Flatpaks
flatpak install io.github.pwr_solaar.solaar

For Mac (Mostly for work)

/usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"
brew install stow git neovim iterm2 karabiner-elements aerospace lsof opencode
Caveat for Mac

iTerm2's settings do not support symlinks. Stow the manually selected mac package for its other items, then hard-link the ignored plist separately:

# Create directories that tools also write state into, so Stow links files
# inside them instead of folding the whole directory into this checkout.
mkdir -p ~/.agents ~/.claude ~/.grok
stow -t ~ common
stow -t ~ mac
ln ~/dotfiles/mac/Library/Preferences/com.googlecode.iterm2.plist ~/Library/Preferences/com.googlecode.iterm2.plist

Minimum

Make sure you have the these installed on your system

For Linux

Arch
sudo pacman -S git stow
Debian
sudo apt install git stow
Fedora
sudo dnf install git stow

For Mac (Mostly for work)

/usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"
brew install stow git

Installation

First, "check out" (the meaning you use in git not "take a look at") the dotfiles repo in your $HOME directory using git.

cd
git clone git@github.com:luckycold/dotfiles.git
cd dotfiles

then use GNU stow to create symlinks

# Create directories that tools also write state into, so Stow links files
# inside them instead of folding the whole directory into this checkout.
mkdir -p ~/.agents ~/.claude ~/.grok
stow -t ~ common
stow -t ~ personal

# For systems with my exclusive use
# sudo stow -t / root

For a headless agent host, use common plus agent instead:

mkdir -p ~/.agents ~/.claude ~/.grok
stow -n -t ~ common agent
stow -t ~ common agent

See the agent profile for scoped-secret handling and the desktop-service exceptions. Do not enable the desktop Proton auto-login helper for this profile.

Post-stow: Enable systemd user services

On desktop profiles only, after stowing common, enable the Proton Pass service. Skip this section for the headless agent profile:

systemctl --user daemon-reload
systemctl --user enable --now proton-pass-cli-autologin.service

This single service handles:

  • Auto-login to Proton Pass at startup
  • SSH agent bootstrap
  • Periodic health checks (every 5 minutes)
  • Re-authentication after waking from sleep/hibernate

View logs with:

journalctl --user -u proton-pass-cli-autologin.service -f
journalctl --user -u proton-pass-cli-ssh-agent.service -f

The systemd login uses a Proton Pass agent token stored in the local keyring. Create one from an authenticated interactive pass-cli session with access to the vault containing SSH keys, store it, then restart the service.

The desktop notification includes an action to update the relevant keyring secret. Manual fallback:

~/Applications/proton-pass-web-login

The helper prompts for the vault, agent token name, and expiration, then stores the resulting token in the local keyring without printing it.

The above is a bit of a departure from the instructional video for GNU stow. It's basically using the same idea but instead of using stow . you can switch between personal, steamos, and agent "profiles" to cleanly and quickly get up and running on any new computer install.

stow-profile is home-directory only: it stows common plus one home profile and deliberately excludes root and any future *-root packages. Apply root-target packages explicitly with sudo stow -t / ....

The switch checks the complete Stow plan before changing links and applies it in one invocation. It restows (stow -R) common and the chosen profile, so links left dangling by files removed from the repo are cleaned up, like update-dotfiles' restow. If local files conflict, it aborts without removing the active profile. Back up and reconcile those files before retrying; it never adopts or overwrites them automatically. Desktop switches also report Hyprland configuration errors after reloading.

After switching desktop profiles, refresh generated secret-backed configs:

init-env-secrets --all

For the scoped agent profile, skip bulk rendering. Verify the existing scoped Proton session with pass-cli info, set a short PROTON_PASS_AGENT_REASON, and render only an explicitly authorized selector with init-env-secrets <selector>. In non-interactive shells, load common/.bashrc.d/secrets.bash explicitly first. The manual renderer is unchanged; do not use --all on scoped agent hosts.

Repository layout

The repo is organised as Stow packages plus a few things Stow cannot manage cleanly:

  • common/ - everything shared across machines (shell, editors, terminals, Hyprland, AI tooling, systemd user units). Always stowed.
  • personal/, steamos/, and agent/ - mutually exclusive home-directory machine/persona profiles. Stow exactly one alongside common; agent is for scoped, headless hosts. The former work profile's Teams, Oneleet, and Betterbird autostart settings are included in personal.
  • common/.agents/AGENTS.md - Luke's canonical cross-agent working agreement. Portable Agent Skills live only in the external luckycold/agent-skills repository and are installed into ~/.agents/skills; no skills tree is tracked here. Each harness keeps its required global-instruction entry point.
  • mac/ - macOS-only files (e.g. the iTerm2 plist, which must be hard-linked rather than symlinked).
  • root/ - system files that are safe to manage with sudo stow -t / root (target /, not $HOME).
  • bootstrap/ - host-specific setup that must be copied into place (not stowed): Limine post hooks, SDDM keyring PAM, host audio.
  • .github/ - GitHub Actions (see Automation).

Secret templates (init-env-secrets)

Configs that embed secrets are committed as *.template.* files with {{pass://...}} placeholders and are rendered into their real counterparts locally. The renderer is the init-env-secrets shell function (defined in common/.bashrc.d/secrets.bash).

  • A template named foo.template.json renders to foo.json; bar.template renders to bar.
  • {{pass://...}} placeholders are resolved with Proton Pass's pass-cli (not the unrelated pass command).
  • Rendered outputs are gitignored and never committed.
  • An interactive shell checks stale secrets in a locked background startup job. Skills refresh in that job by default without delaying terminal startup; set AGENT_SKILLS_AUTO_UPDATE=0 to disable it (see AI coding tooling). No-op runs stay silent; actual content updates and refresh failures raise desktop notifications. update-dotfiles and stow-profile also support secret refreshes.
  • Scoped agents skip automatic bulk secret rendering at startup, during update-dotfiles, and when switching profiles. Use only authorized manual selectors; the manual init-env-secrets interface is unchanged.

Common commands:

init-env-secrets --all      # desktop profiles only: render everything non-interactively
init-env-secrets -l         # list templated secrets and their status
init-env-secrets -r         # interactively retry/select and re-render

Currently templated secrets include the Zed AI config, the mem0 environment.d key, the OpenCode mem0 token, the Linear MCP token, the Kagi session token, and the Music Assistant widget config.

Shell tooling

common/.bashrc.d/ is split into focused modules. The main user-facing commands:

  • update-dotfiles - pull the repo, restow the profile, refresh allowed secrets, and reload units; a background check also notifies when the repo is behind. update-dotfiles --yes also runs update-agent-skills. Scoped agents skip bulk secret rendering.
  • stow-profile - select personal, steamos, agent, or the manual mac package; restow and reload Hyprland/systemd. Secret refresh is offered only when bulk rendering is allowed, never for the scoped agent profile.
  • proton-pass-login - convenience auth helper.

These commands default to a clone at ~/dotfiles. Set DOTFILES_DIR to use a different clone location consistently across update, notification, profile, and secret tooling.

Mise on immutable systems

On immutable or appliance-style systems such as SteamOS and TrueNAS, keep developer runtimes out of the base operating system. Install mise and Node in the current user's home directory instead:

curl -fsSL https://mise.run | sh
export PATH="$HOME/.local/bin:$PATH"
mise install node@latest
mise reshim
export PATH="$HOME/.local/share/mise/shims:$PATH"
node --version
npm --version

After common is stowed, .bashrc adds the mise shim directory to PATH for both interactive and non-interactive shells. update-agent-skills runs the skills.sh CLI with the first Node.js 22.20+ it finds: on PATH, then the node mise resolves (it also looks for mise in ~/.local/share/agent-tools/bin), then a node@latest it installs with mise. With neither Node.js nor mise it prints a hint and leaves the installed skills as they are:

source "${DOTFILES_DIR:-$HOME/dotfiles}/common/.bashrc.d/dotfiles_management.bash"
update-agent-skills

This setup writes only beneath ~/.local and does not require Homebrew, a system package manager, or changes to the immutable root filesystem.

AI coding tooling

This repo carries a fair amount of agent/LLM configuration:

  • common/.agents/AGENTS.md - canonical cross-agent instructions and personal-skill routing. Codex, Claude, OpenCode, and Grok CLI (common/.grok/AGENTS.md) global instruction files resolve directly to it; Grok CLI also loads skills from ~/.claude/skills. Cursor uses an always-on rule that loads it, common/.cursor/rules/personal-skill-learning.mdc (stowed to ~/.cursor/rules). Cursor reads .cursor/rules per project, so that file applies only when ~ is the open workspace; for global coverage, paste a User Rule in Cursor's settings that points at ~/.agents/AGENTS.md.

  • Luke-authored portable skills live only in luckycold/agent-skills, not a tracked dotfiles skills tree. update-agent-skills installs them with the official skills.sh CLI: skills add luckycold/agent-skills --skill '*' --global --yes --agent codex --agent claude-code --agent cursor --agent opencode. That writes real copies to ~/.agents/skills/<skill> (read by Codex, Cursor, and OpenCode), links ~/.claude/skills/<skill> to them for Claude Code, and records them in ~/.agents/.skill-lock.json. The CLI version is pinned in dotfiles_management.bash (Renovate proposes bumps; AGENT_SKILLS_CLI_VERSION overrides it on one host), and it runs with telemetry off and no prompts.

  • A run first compares the repository's upstream commit (git ls-remote) with the last sync in ~/.local/state/agent-skills/last-sync. When nothing changed and every installed skill is still in place it prints one line and changes nothing; when GitHub cannot be reached it keeps the installed skills and exits 0. Otherwise it installs that exact commit (luckycold/agent-skills#<sha>); skills deleted upstream are copied aside and removed with skills remove. The stamp is written only after a clean run, so anything left undone is retried. Entries from other sources (cua-driver, Claude's synced/ and .trash/) stay untouched. Without Node.js it prints a hint and exits 69; update-dotfiles --yes and the startup job treat that as a warning, not a failure.

  • Hosts still on the old git-clone layout (~/.local/share/agent-skills with per-skill links) are migrated on the next run: the links and the clone move to ~/.local/state/agent-skills/replaced-<timestamp>/, and nothing is deleted. If the install fails or is interrupted (the startup job's timeout), the links are put back and any partial copies move to replaced-<timestamp>/partial/. A clone whose origin is not luckycold/agent-skills is reported and left alone. A git checkout at ~/.agents, or a ~/.agents or ~/.claude that Stow folded into a link to this checkout, is refused with the commands to fix it.

  • Automatic skills refresh runs in the locked background interactive-shell startup job by default, without delaying terminal startup. Set AGENT_SKILLS_AUTO_UPDATE=0 to disable it. Automatic refresh has a 120-second timeout plus a 5-second kill grace and is skipped if neither timeout nor gtimeout is available. The manual update-agent-skills command does not use that timeout. update-dotfiles --yes runs the restow, secret refresh, and update-agent-skills from the file it just pulled (in a fresh bash), so a changed updater takes effect on the same run. A restow conflict or skills failure is reported with a nonzero exit but neither skips the other steps nor undoes the dotfiles update. There is no timer: refresh happens on interactive shell startup, on update-dotfiles --yes, or when an agent runs it at session start. Concurrent runs wait on a lock (flock, or a mkdir lock where flock is missing, as on macOS).

  • common/.agents/private-context.template.md - Proton Pass reference for private hostnames, domains, topology, and privileged connection values. init-env-secrets renders the ignored, mode-0600 ~/.agents/private-context.md. Never commit the rendered private-context file. Portable skills use placeholders and load exact values only when needed.

  • common/.config/opencode/opencode.json - the main OpenCode config: automatic compaction/pruning settings and the single local MCPorter aggregate bridge. It defines no default model or custom provider.

  • common/.config/opencode/config.json - a separate OpenCode config listing only @mem0/opencode-plugin and opencode-scheduler.

  • common/.config/zed/settings.template.json - Zed AI config (templated; see Secret templates), connected only to MCPorter.

  • common/.codex/AGENTS.md - the only tracked Codex file. There is no Codex config template: ~/.codex/config.toml is host-local and stow, init-env-secrets, and update-dotfiles never create or modify it (see Universal MCP aggregation).

  • common/.config/music-assistant/config.template.json - Omarchy Music Assistant widget and local-player config. init-env-secrets renders ~/.config/music-assistant/config.json.

  • common/.mcporter/mcporter.template.json - the canonical MCPorter MCP registry. It owns all upstream server definitions.

  • common/.local/bin/mcporter-mcp - the aggregate stdio adapter used by OpenCode, Zed, and any client registered by hand.

Universal MCP aggregation

MCPorter is the primary MCP config path. Upstream servers are defined once, in ~/.mcporter/mcporter.json (rendered from common/.mcporter/mcporter.template.json), and agents either call them with the mcporter CLI (mcporter list, mcporter call <server.tool> key=value) or connect to the one stdio bridge, mcporter-mcp, named mcporter. Add, change, or remove servers with mcporter config add|remove|get|list|doctor (OAuth with mcporter config login), keeping credentials as Proton Pass placeholders in the template. The tracked OpenCode and Zed configs do that. Individual agent configs must not carry direct upstream MCP definitions.

Codex has no tracked config. An existing ~/.codex/config.toml stays as it is (earlier renders already point at the bridge). On a host without one, register the bridge with codex mcp add mcporter -- "$HOME/.local/bin/mcporter-mcp" and keep any further settings local.

Rollout from the old Codex template: pulling this change leaves a dangling ~/.codex/config.template.toml link where common was stowed. update-dotfiles and stow-profile both restow (stow -R), which removes it. A shell still running the older stow-profile (stow -S) leaves it; remove it with [ -L ~/.codex/config.template.toml ] && [ ! -e ~/.codex/config.template.toml ] && rm ~/.codex/config.template.toml. A real ~/.codex/config.template.toml file (a local override) is no longer rendered and can be deleted by hand. None of this touches ~/.codex/config.toml; where ~/.codex was folded into the repo, the file stays ignored at common/.codex/config.toml.

After stowing common on a desktop profile, render the registry and verify it. Scoped agents must instead render only an authorized registry selector and use only the upstream services approved for their session:

init-env-secrets --all
mcporter --config ~/.mcporter/mcporter.json config doctor
mcporter --config ~/.mcporter/mcporter.json list

The shared adapter exposes kagi-ken,context7,gh_grep,gitlab,mem0 by default. Set MCPORTER_SERVERS locally to a comma-separated subset or to include work servers (Brokkr, Bridge, NetBox, Gravwell, and the others in the registry). OAuth state stays local under MCPorter's data directory and must not be committed.

On a desktop with Cua Driver installed, include cua-driver in the host's MCPORTER_SERVERS to expose desktop tools through the same bridge. The driver daemon needs the desktop session environment and explicit approval before attaching to an existing browser profile.

Authenticate OAuth-backed servers with mcporter --config ~/.mcporter/mcporter.json config login <server>. This avoids the keep-alive authentication error in MCPorter 0.14.2's direct auth command. NetBox uses the upstream Python server through uvx, installed with mise, so it does not require Docker access.

Personal skill self-learning

This repo supports a foreground learning loop through always-on agent instructions. The writable skills are installed externally at ~/.agents/skills from luckycold/agent-skills, not tracked in dotfiles. After a verified reusable workflow or correction, an agent updates only skills marked author: Luke.

The shared setup deliberately has no background usage counters, automatic stale/archive transitions, or LLM consolidation. Those require runtime-specific hooks and provenance state that standard SKILL.md consumers do not expose consistently. Review and version skill changes in the external luckycold/agent-skills repository, not in dotfiles; changes remain uncommitted until explicitly requested.

Private operational context is kept out of the portable skill packages. Agents resolve approved exact values from the local Proton Pass-backed private context and must not quote or copy that rendered file into tracked documentation.

Other systemd user services

common/.config/autostart/clevis-luks-udisks2.desktop intentionally disables the distro clevis-luks-udisks2 desktop autostart. Root disk auto-unlock is handled by the initramfs Clevis hook; the desktop helper is not needed here and fails on this setup because there is no clevis user.

Automation

  • Renovate (.github/workflows/renovate.yml, .github/renovate-image, renovate.json) keeps the self-hosted Renovate image pin up to date via a custom regex manager, surfacing updates through the dependency dashboard. The workflow authenticates with GITHUB_TOKEN (or optional RENOVATE_TOKEN) so it can run on GitHub Actions without a Forgejo leftover secret.

Omarchy Setup Notes

This repo leaves hibernation setup to stock Omarchy. Use Omarchy's own setup and removal commands for hibernation rather than host-specific wrappers or custom Limine noresume policy.

The one exception is the Thunderbolt eGPU (RX 6600 in the TREBLEET enclosure, behind the OWC Go Dock), which does not survive hibernation. Resuming with it attached reset the machine (Previous system reset reason [0x08000800]: an uncorrected error caused a data fabric sync flood event), and a resume that did get through hit an amdgpu/TTM NULL dereference (ttm_lru_bulk_move_del) seconds later. Hibernation works without the eGPU. Sandman's idle and lid Sleep request suspend-then-hibernate (Sandman writes its timer to /etc/systemd/sleep.conf.d/90-sandman.conf), so three drop-ins keep the eGPU out of hibernation:

  • root/etc/systemd/sleep.conf.d/95-egpu-ac.conf - HibernateOnACPower=no, overriding Sandman's yes: on dock power, suspend-then-hibernate stays suspended. Also covers docking while suspended.
  • root/etc/systemd/system/systemd-suspend-then-hibernate.service.d/10-egpu-plain-suspend.conf - if any DRM card's PCI device reports removable (only the eGPU does), runs plain systemd-sleep suspend instead, so undocking while suspended is safe. The journal logs Removable GPU … attached; suspending without hibernation.
  • root/etc/systemd/system/systemd-hibernate.service.d/10-egpu-plain-suspend.conf - the same check for an explicit systemctl hibernate (the Omarchy menu's Hibernate and Sandman's lid Hibernate): with the eGPU attached it suspends instead. Omarchy files are untouched; this overrides systemd's own unit from /etc.

Docked suspend still resumes with AMD USB4 display-tunnel failures (DPIA AUX failed) even when all monitors use the iGPU. Until that driver path is reliable, 20-thunderbolt-sleep-guard.conf on all four systemd sleep services skips sleep whenever /sys/bus/thunderbolt/devices/*/device_name exists. External Thunderbolt peripherals expose that file; the host controllers and retimers on this machine do not. This deliberately covers manual sleep and hibernation as well as idle/lid requests, and applies to any Thunderbolt peripheral, not just one dock. Undocked sleep remains available. Sandman's lock and display-off timers are unchanged. No polling daemon or resume hook is required.

The older eGPU hibernation drop-ins remain useful if the docked-sleep guard is removed after a driver fix. A matching upstream Sandman change is proposed in lgse/sandman#14.

The eGPU now connects to the laptop through its own Thunderbolt cable and drives the middle AOC directly; the left Dell uses the OWC Go Dock on a separate Thunderbolt connection. Hyprland uses both GPUs through Aquamarine's native discovery, which prioritizes the GPU with the built-in laptop panel. Keep the eGPU connected during the desktop session: losing it (undock, failed resume) can abort the compositor.

  • root/etc/udev/rules.d/60-drm-igpu.rules - stable /dev/dri/igpu symlink for the iGPU (PCI 0000:c1:00.0), because cardN numbers swap when the eGPU is attached and AQ_DRM_DEVICES splits on :, which rules out /dev/dri/by-path names.
  • personal/.config/uwsm/env.d/30-aq-gpus - unsets the former iGPU-only AQ_DRM_DEVICES restriction so monitors connected to the eGPU can work. Uses Aquamarine's native GPU discovery; takes effect at the next login.

Install or refresh them as real root-owned copies:

sudo install -Dm 0644 root/etc/systemd/sleep.conf.d/95-egpu-ac.conf /etc/systemd/sleep.conf.d/95-egpu-ac.conf
sudo install -Dm 0644 root/etc/systemd/system/systemd-suspend-then-hibernate.service.d/10-egpu-plain-suspend.conf /etc/systemd/system/systemd-suspend-then-hibernate.service.d/10-egpu-plain-suspend.conf
sudo install -Dm 0644 root/etc/systemd/system/systemd-hibernate.service.d/10-egpu-plain-suspend.conf /etc/systemd/system/systemd-hibernate.service.d/10-egpu-plain-suspend.conf
for kind in suspend suspend-then-hibernate hibernate hybrid-sleep; do
  sudo install -Dm 0644 "root/etc/systemd/system/systemd-$kind.service.d/20-thunderbolt-sleep-guard.conf" "/etc/systemd/system/systemd-$kind.service.d/20-thunderbolt-sleep-guard.conf"
done
sudo systemctl daemon-reload
sudo install -Dm 0644 root/etc/udev/rules.d/60-drm-igpu.rules /etc/udev/rules.d/60-drm-igpu.rules
sudo udevadm control --reload && sudo udevadm trigger --subsystem-match=drm --action=change

The remaining Omarchy-specific pieces are:

  • common/.config/hypr/*.lua - Omarchy 4 Hyprland overrides (bindings, input, looknfeel, monitors)
  • common/Applications/notion-latest-note - Super+Shift+O queries the Notion journal on each press and opens the newest entry dated today or earlier. Install the mise-managed ntn CLI, run ntn login, and put the journal's data source UUID in the local file ~/.config/notion/daily-journal-id. Authentication stays in the OS keyring; keep the private journal ID out of Git. The journal must have a Date property. Use ~/Applications/notion-latest-note --print to check the selected URL without opening it.
  • bootstrap/windows-notion/ - the Windows counterpart installs Notion CLI through WinGet, guides browser login, saves the selected journal, and creates a desktop shortcut that opens the newest note in the default browser.
  • personal/.config/hyprmoncfg/profiles/ - native hyprmoncfg profiles for the Framework laptop: Docked (Dell 4K/30 Hz through the Thunderbolt Go Dock and AOC 1440p/144 Hz directly on the eGPU, with separate Thunderbolt connections to the laptop) and Stand alone. Layouts match display identities rather than fixed connector numbers. After installing hyprmoncfg and stowing the personal profile, run hyprmoncfg manage to install its generated-config include, then hyprmoncfg apply Docked or hyprmoncfg apply "Stand alone". Back up existing local profiles before stowing; generated active monitor files and plugin code are not tracked. After changing a layout, save it with hyprmoncfg and sync its profile files back here.
  • personal/.config/wluma/config.toml - wluma auto-brightness for the Framework ALS when undocked. Install extra iio-sensor-proxy, install wluma through mise (github:max-baz/wluma), install root/etc/udev/rules.d/90-wluma-backlight.rules, and enable wluma.service. Gamma remains disabled for the laptop so Omarchy nightlight keeps hyprsunset; capturer = "none" avoids this compositor's capture bugs. AC idle dimming is disabled.
  • The Docked hyprmoncfg profile stops wluma, sets the laptop backlight to 100%, and sets both external monitors to 100% using native brightnessctl and ddcutil commands. DDC matches manufacturer/model rather than connector or bus number, with a sleep multiplier of 2 for reliable responses. Stand alone starts wluma again. Profile exec fields replace the former laptop-curve helper; standalone learned data remains local.
  • personal/.config/hypr/hypridle.conf - install extra hypridle and enable its packaged service with systemctl --user enable --now hypridle.service. Disable Omarchy's duplicate idle service with omarchy plugin disable omarchy.idle, and turn off Sandman's Displays off timer (omarchy-shell lgse.sandman setDisplay 0). Sandman retains lid and sleep management. Hypridle starts the screensaver at 5 minutes, turns displays off at 10 minutes, and locks at 15 minutes. Its supported command fields ignore windowed Brave wake locks while preserving fullscreen Brave and other application inhibitors; the Stay Awake indicator is also respected. Input restores display power.
  • personal/.config/hypr/autostart.lua - desktop autostart, including Teams, Oneleet (~/AppImages/oneleet.appimage), Betterbird, Brave, Beeper, and Steam
  • bootstrap/limine/ - Limine post hooks copied into /etc/boot/hooks/post.d/: 87-limine-theme reapplies the black-and-white header palette from /etc/limine-theme.conf after every limine-update (including omarchy-refresh-limine) and before config checksum enrollment, 89-limine-default-linux-entry keeps default_entry on the first Omarchy kernel, and 91-limine-sync-fallback mirrors limine_x64.efi to EFI/BOOT/BOOTX64.EFI
  • root/etc/sddm.conf.d/zz-where-is-my-sddm.conf and root/usr/share/sddm/themes/where_is_my_sddm_theme/theme.conf.user - SDDM theme selection, no autologin, and the matching black-and-white login colors
  • bootstrap/sddm-gnome-keyring/ - root-owned SDDM PAM config that unlocks the GNOME keyring on login
  • bootstrap/philosophia-audio/ - host-specific user-session bootstrap for disabling WirePlumber's headphone-removal media pause behavior on philosophia

Apply the personal Omarchy profile like this:

mkdir -p ~/.agents ~/.claude ~/.grok
stow -t ~ common
stow -t ~ personal
sudo stow -t / root
sudo install -m 0644 bootstrap/limine/limine-theme.conf /etc/limine-theme.conf
sudo install -m 0755 -t /etc/boot/hooks/post.d bootstrap/limine/hooks/*
sudo limine-update
sudo ./bootstrap/sddm-gnome-keyring/apply.sh
./bootstrap/philosophia-audio/apply.sh

limine-update runs the hooks, re-enrolls the config checksum, and re-signs the loaders through sbctl. Never hand-edit the BLAKE2 hashes in /boot/limine.conf.

Secure Boot uses this machine's own sbctl keyset; sbctl verify should be clean after every limine-update. Do not change BootOrder or set BootNext to work around a boot problem: that is how PCR 1 bindings go stale, and the working firmware path is the internal disk's own EFI Hard Drive / fallback loader, not a named Limine NVRAM entry.

The working Clevis policy is PCR 7 (Secure Boot state). PCR 1,7 is stricter and breaks across firmware-variable changes and hibernation resume. With the Thunderbolt dock and eGPU attached, PCR 7 can alternate between boots as option-ROM db authority events come and go, so keep one Clevis PCR 7 slot per observed state (plus the passphrase slot) instead of replacing a slot that only fails in the other state.

agent-tts and Kokoro units are intentionally not part of this repo anymore.

After changing Secure Boot, Limine, UKI, or UEFI boot order, boot once through the final intended path before regenerating Clevis TPM bindings. Once booted, check the slot and regenerate it if the binding was created on this same laptop TPM:

sudo clevis luks list -d <LUKS_DEVICE>
sudo clevis luks regen -q -d <LUKS_DEVICE> -s <CLEVIS_SLOT>

Use /dev/nvme0n1p2 for the root LUKS partition on this Framework install (confirm with lsblk -f).

If a Clevis slot came from another laptop, or was bound to PCR 1,7 on an old named firmware entry, do not expect regen to work after the boot path changed. Boot once with the normal LUKS passphrase, then replace the foreign or stale TPM binding:

sudo clevis luks list -d <LUKS_DEVICE>
sudo clevis luks unbind -d <LUKS_DEVICE> -s <OLD_CLEVIS_SLOT> -f
sudo clevis luks bind -d <LUKS_DEVICE> tpm2 '{"pcr_bank":"sha256","pcr_ids":"7"}'
sudo clevis luks list -d <LUKS_DEVICE>

Keep the normal passphrase slot. The Clevis slot should be an additional unlock path, not the only way back in.

If you are moving an already-tuned machine under Stow management instead of setting up a fresh install, use --adopt once for the profiles that already exist on disk:

stow --adopt -t ~ personal
sudo stow --adopt -t / root

What this covers:

  • keep the black-and-white Limine palette, default entry, and fallback loader in place across limine-update
  • stow the SDDM theme overlay and disable autologin after TPM disk unlock
  • install the SDDM PAM configuration that hooks GNOME keyring into login
  • disable WirePlumber's MPRIS pause-on-output-removal behavior on philosophia

What is still a manual post-install step:

  • if TPM/Clevis auto-unlock stops working after reinstall or after boot-chain changes, regenerate or rebind the TPM slot after the first successful reboot

Useful verification commands after reboot:

cat /proc/cmdline
swapon --show
cat /sys/power/state /sys/power/disk
busctl call org.freedesktop.login1 /org/freedesktop/login1 org.freedesktop.login1.Manager CanHibernate
systemctl hibernate

Important note for root/ files:

  • root/ is now reserved for files that are safe to manage directly with Stow
  • the SDDM theme overlay and autologin override live under root/ and are applied with sudo stow -t / root
  • the SDDM PAM login file lives under bootstrap/sddm-gnome-keyring/ so it is installed as a real root-owned file under /etc/pam.d
  • SDDM PAM files are copied into /etc as real root-owned files because symlinks into /home are not reliable for login-time PAM configuration

Instructional Video

This is a useful video if you get lost:

https://www.youtube.com/watch?v=y6XCebnB9gs

About

No description, website, or topics provided.

Resources

Stars

1 star

Watchers

1 watching

Forks

Releases

Packages

Contributors

Languages