diff --git a/README.org b/README.org index 45212850..7d4c99aa 100644 --- a/README.org +++ b/README.org @@ -31,9 +31,9 @@ published GitHub Pages site is still generated from that document. - Container and deployment configuration for personal org-agenda-api instances. This is not intended to be a generic starter dotfiles repo. Many modules assume -my users, hostnames, hardware, SSH keys, secrets layout, and local checkout path -=(~/dotfiles=). It is still useful as a reference for how the pieces fit -together. +my users, hostnames, hardware, SSH keys, secrets layout, and shared checkout +path =/srv/dotfiles= on NixOS machines. It is still useful as a reference for +how the pieces fit together. * Layout @@ -65,7 +65,7 @@ The broad feature set is assembled by [[file:nixos/configuration.nix][nixos/conf Common workflow: #+begin_src sh -cd ~/dotfiles/nixos +cd /etc/nixos just switch #+end_src @@ -77,7 +77,7 @@ directly. Useful variants: #+begin_src sh -cd ~/dotfiles/nixos +cd /etc/nixos just switch-remote just switch-local-taffybar just remote-switch @@ -86,8 +86,8 @@ just remote-switch Build/check examples: #+begin_src sh -nix flake check ~/dotfiles/nixos -nix build ~/dotfiles/nixos#nixosConfigurations.strixi-minaj.config.system.build.toplevel +nix flake check /etc/nixos +nix build /etc/nixos#nixosConfigurations.strixi-minaj.config.system.build.toplevel #+end_src The flake also exposes package/check outputs for Hyprland plugins and a @@ -177,7 +177,7 @@ behind nginx with ACME certificates and Podman. To enter the deployment shell: #+begin_src sh -nix develop ~/dotfiles/nixos#org-agenda-api +nix develop /etc/nixos#org-agenda-api #+end_src * Secrets @@ -201,7 +201,9 @@ Some third-party or upstream projects are tracked as submodules: Clone with submodules when bootstrapping a new checkout: #+begin_src sh -git clone --recurse-submodules git@github.com:IvanMalison/dotfiles.git ~/dotfiles +git clone --recurse-submodules git@github.com:IvanMalison/dotfiles.git /tmp/dotfiles +cd /tmp/dotfiles +just setup-shared-dotfiles #+end_src This repo also contains project-local git worktrees under =.worktrees/= during diff --git a/docs/shared-dotfiles.md b/docs/shared-dotfiles.md new file mode 100644 index 00000000..5de9312d --- /dev/null +++ b/docs/shared-dotfiles.md @@ -0,0 +1,33 @@ +# Shared Dotfiles Worktree + +This repo is intended to live at `/srv/dotfiles` on shared NixOS machines. +Home Manager links user dotfiles to that shared checkout instead of to +`$HOME/dotfiles`, so the links work consistently for every managed user. + +Set it up from any existing checkout: + +```sh +just setup-shared-dotfiles +``` + +The setup command: + +- copies the current checkout to `/srv/dotfiles` when needed +- makes the checkout readable by everyone +- makes it writable by the `wheel` group +- sets directory setgid/default ACLs so new files stay group-writable +- configures Git for group sharing +- creates `/etc/nixos -> /srv/dotfiles/nixos` when `/etc/nixos` is absent or already a symlink + +Use a different target or group when needed: + +```sh +just setup-shared-dotfiles --target /srv/dotfiles --group wheel +``` + +If a machine has a real `/etc/nixos` directory and you want to replace it with +the shared checkout symlink: + +```sh +just setup-shared-dotfiles --force-etc-nixos +``` diff --git a/dotfiles/agents/AGENTS.md b/dotfiles/agents/AGENTS.md index 8e6d54c7..21ca30e6 100644 --- a/dotfiles/agents/AGENTS.md +++ b/dotfiles/agents/AGENTS.md @@ -26,7 +26,7 @@ - Only use a non-`.worktrees/` location when the user explicitly asks for a different path. ## NixOS workflow -- This system is managed with a Nix flake at `~/dotfiles/nixos`. +- This system is managed with a Nix flake at `/etc/nixos` (`/srv/dotfiles/nixos`). - Use `just switch` from that directory for rebuilds instead of plain `nixos-rebuild`. - Host configs live under `machines/`; choose the appropriate host when needed. diff --git a/dotfiles/config/autorandr/jay-lenovo-with-benq/config b/dotfiles/config/autorandr/jay-lenovo-with-benq/config new file mode 100644 index 00000000..ddc3c313 --- /dev/null +++ b/dotfiles/config/autorandr/jay-lenovo-with-benq/config @@ -0,0 +1,37 @@ +output HDMI-A-0 +off +output DisplayPort-1-1 +off +output DisplayPort-1-2 +off +output DisplayPort-1-3 +off +output DisplayPort-1-4 +off +output DisplayPort-0 +crtc 1 +mode 2560x1440 +pos 0x0 +rate 144.00 +x-prop-colorspace Default +x-prop-max_bpc 16 +x-prop-non_desktop 0 +x-prop-scaling_mode None +x-prop-tearfree auto +x-prop-underscan off +x-prop-underscan_hborder 0 +x-prop-underscan_vborder 0 +output eDP +crtc 0 +mode 2560x1600 +pos 2560x0 +primary +rate 165.00 +x-prop-colorspace Default +x-prop-max_bpc 16 +x-prop-non_desktop 0 +x-prop-scaling_mode None +x-prop-tearfree auto +x-prop-underscan off +x-prop-underscan_hborder 0 +x-prop-underscan_vborder 0 diff --git a/dotfiles/config/autorandr/jay-lenovo-with-benq/setup b/dotfiles/config/autorandr/jay-lenovo-with-benq/setup new file mode 100644 index 00000000..2ec34fae --- /dev/null +++ b/dotfiles/config/autorandr/jay-lenovo-with-benq/setup @@ -0,0 +1,2 @@ +DisplayPort-0 00ffffffffffff0009d1767f45540000281d0103803c22782a9325ad4f44a9260d5054a56b80d1fcd1e8d1c0b300a9c08180810081c0f8e300a0a0a032500820980455502100001a000000ff0033414b30313335343031390a20000000fd0028901ede3c000a202020202020000000fc0042656e5120455832373830510a0174020350f1515d5e5f60613f40101f22212004131203012309070783010000e200cf6d030c001000383c20006001020367d85dc401788003681a000001012890e6e305c301e40f180000e60605016262216fc200a0a0a055503020350055502100001e565e00a0a0a029502f20350055502100001a0000000000000000000000bf +eDP 00ffffffffffff0009e59b0a000000001c1e0104b5221578037ce5a4554c9f260f5054000000010101010101010101010101010101016b6e00a0a04084603020360058d71000001a000000fd0c3ca51f1f4e010a202020202020000000fe00424f452043510a202020202020000000fe004e4531363051444d2d4e59310a02d502031d00e3058000e60605016a6a246d1a000002033ca500046a246a240000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ff7013790000030114a52f0185ff099f002f001f003f0683000200050000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003e90 diff --git a/dotfiles/config/hypr/hypridle.conf b/dotfiles/config/hypr/hypridle.conf index 5ebf8a7f..c8f1337f 100644 --- a/dotfiles/config/hypr/hypridle.conf +++ b/dotfiles/config/hypr/hypridle.conf @@ -5,6 +5,6 @@ general { listener { timeout = 300 - on-timeout = /home/imalison/dotfiles/dotfiles/lib/bin/hypr-screensaver start - on-resume = /home/imalison/dotfiles/dotfiles/lib/bin/hypr-screensaver stop + on-timeout = hypr-screensaver start + on-resume = hypr-screensaver stop } diff --git a/dotfiles/config/hypr/hyprland/binds.lua b/dotfiles/config/hypr/hyprland/binds.lua index 465c59ee..4cc24cb1 100644 --- a/dotfiles/config/hypr/hyprland/binds.lua +++ b/dotfiles/config/hypr/hyprland/binds.lua @@ -49,8 +49,8 @@ function M.setup(ctx) bind("XF86AudioRaiseVolume", exec("set_volume --unmute --change-volume +5"), desc("Raise volume", { repeating = true })) bind("XF86AudioLowerVolume", exec("set_volume --unmute --change-volume -5"), desc("Lower volume", { repeating = true })) bind("XF86AudioMute", exec("set_volume --toggle-mute"), desc("Toggle mute")) - bind(hyper .. " + O", exec("/home/imalison/dotfiles/dotfiles/lib/functions/rofi_paswitch"), desc("Open PulseAudio output switcher")) - bind(hyper .. " + SHIFT + O", exec("/home/imalison/dotfiles/dotfiles/lib/bin/kef-optical"), desc("Switch KEF speakers to optical input")) + bind(hyper .. " + O", exec("rofi_paswitch"), desc("Open PulseAudio output switcher")) + bind(hyper .. " + SHIFT + O", exec("kef-optical"), desc("Switch KEF speakers to optical input")) end local function setup_display_wallpaper_and_capture_bindings() @@ -58,9 +58,9 @@ function M.setup(ctx) bind("XF86MonBrightnessDown", exec("brightness.sh down"), desc("Lower display brightness", { repeating = true })) bind("Print", exec("flameshot gui"), desc("Take screenshot")) bind(hyper .. " + H", exec("flameshot gui"), desc("Take screenshot")) - bind(hyper .. " + backslash", exec("/home/imalison/dotfiles/dotfiles/lib/functions/mpg341cx_input toggle"), desc("Toggle monitor input")) + bind(hyper .. " + backslash", exec("mpg341cx_input toggle"), desc("Toggle monitor input")) bind(hyper .. " + comma", exec("rofi_wallpaper.sh"), desc("Open wallpaper menu")) - bind(hyper .. " + SHIFT + comma", exec("/home/imalison/dotfiles/dotfiles/lib/bin/neowall-wallpaper toggle"), desc("Toggle neowall wallpaper")) + bind(hyper .. " + SHIFT + comma", exec("neowall-wallpaper toggle"), desc("Toggle neowall wallpaper")) end local function setup_rofi_and_tool_bindings() diff --git a/dotfiles/config/river-xmonad/Main.hs b/dotfiles/config/river-xmonad/Main.hs index f007078c..0a671093 100644 --- a/dotfiles/config/river-xmonad/Main.hs +++ b/dotfiles/config/river-xmonad/Main.hs @@ -165,7 +165,7 @@ spawnBindings = , key (hyper .|. shift) xK_k (spawnAction "rofi_kill_all.sh") , key hyper xK_r (spawnAction "rofi_systemd_mono") , key hyper xK_9 (spawnAction "start_synergy.sh") - , key hyper xK_backslash (spawnAction "$HOME/dotfiles/dotfiles/lib/functions/mpg341cx_input toggle") + , key hyper xK_backslash (spawnAction "mpg341cx_input toggle") , key hyper xK_i (spawnAction "rofi_select_input.hs") , key hyper xK_o (spawnAction "rofi_paswitch") , key hyper xK_comma (spawnAction "rofi_wallpaper.sh") diff --git a/dotfiles/config/taffybar/AGENTS.md b/dotfiles/config/taffybar/AGENTS.md index 2975d37c..eab7f379 100644 --- a/dotfiles/config/taffybar/AGENTS.md +++ b/dotfiles/config/taffybar/AGENTS.md @@ -23,7 +23,7 @@ - Do not create extra panes or windows unless the user asks. ## NixOS workflow -- This system is managed with a Nix flake at `~/dotfiles/nixos`. +- This system is managed with a Nix flake at `/etc/nixos` (`/srv/dotfiles/nixos`). - Use `just switch` from that directory for rebuilds instead of plain `nixos-rebuild`. - Host configs live under `machines/`; choose the appropriate host when needed. diff --git a/dotfiles/config/taffybar/TaffybarConfig/Widgets.hs b/dotfiles/config/taffybar/TaffybarConfig/Widgets.hs index a1c7d7ab..7feafa48 100644 --- a/dotfiles/config/taffybar/TaffybarConfig/Widgets.hs +++ b/dotfiles/config/taffybar/TaffybarConfig/Widgets.hs @@ -355,9 +355,9 @@ omniMenuWidget = OmniMenuSection "System" [ omniMenuItem "Lock" "system-lock-screen" "loginctl lock-session", - omniMenuItem "Toggle screensaver" "video-display" "/home/imalison/dotfiles/dotfiles/lib/bin/hypr-screensaver toggle", + omniMenuItem "Toggle screensaver" "video-display" "hypr-screensaver toggle", omniMenuItem "Reload WM" "view-refresh" "sh -lc 'hyprctl reload || xmonad --restart || river-xmonad-restart'", - omniMenuItem "Restart taffybar" "view-refresh-symbolic" "/home/imalison/dotfiles/dotfiles/config/taffybar/scripts/taffybar-restart", + omniMenuItem "Restart taffybar" "view-refresh-symbolic" "/srv/dotfiles/dotfiles/config/taffybar/scripts/taffybar-restart", omniMenuItem "Logout" "system-log-out" "sh -lc 'hyprctl dispatch exit || riverctl exit'", omniMenuItem "Suspend" "media-playback-pause" "systemctl suspend", omniMenuItem "Reboot" "system-reboot" "systemctl reboot", diff --git a/dotfiles/config/xmonad/xmonad.hs b/dotfiles/config/xmonad/xmonad.hs index 29c0d562..fab09c0a 100644 --- a/dotfiles/config/xmonad/xmonad.hs +++ b/dotfiles/config/xmonad/xmonad.hs @@ -1084,11 +1084,11 @@ addKeys conf@XConfig { modMask = modm } = , ((hyper, xK_r), spawn "rofi_systemd_mono") , ((hyper, xK_9), spawn "start_synergy.sh") , ((hyper, xK_slash), spawn "toggle_taffybar") - , ((hyper, xK_backslash), spawn "$HOME/dotfiles/dotfiles/lib/functions/mpg341cx_input toggle") + , ((hyper, xK_backslash), spawn "mpg341cx_input toggle") , ((hyper, xK_space), spawn "skippy-xd") , ((hyper, xK_i), spawn "rofi_select_input.hs") , ((hyper, xK_o), spawn "rofi_paswitch") - , ((hyper .|. shiftMask, xK_o), spawn "$HOME/dotfiles/dotfiles/lib/bin/kef-optical") + , ((hyper .|. shiftMask, xK_o), spawn "kef-optical") , ((hyper, xK_comma), spawn "rofi_wallpaper.sh") , ((hyper, xK_y), spawn "rofi_agentic_skill") , ((modm, xK_e), spawn "emacsclient --eval '(emacs-everywhere)'") diff --git a/dotfiles/hammerspoon/init.lua b/dotfiles/hammerspoon/init.lua index 61a1b60c..6f172978 100644 --- a/dotfiles/hammerspoon/init.lua +++ b/dotfiles/hammerspoon/init.lua @@ -348,7 +348,7 @@ local function toggleMonitorInput() end end, { "-lc", - "export PATH=\"$HOME/.nix-profile/bin:/run/current-system/sw/bin:/opt/homebrew/bin:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:$PATH\"; \"$HOME/dotfiles/dotfiles/lib/functions/mpg341cx_input\" toggle", + "export PATH=\"$HOME/.nix-profile/bin:/run/current-system/sw/bin:/opt/homebrew/bin:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:$PATH\"; \"${DOTFILES_WORKTREE:-$HOME/dotfiles}/dotfiles/lib/functions/mpg341cx_input\" toggle", }):start() end diff --git a/dotfiles/lib/bin/rofi_tmcodex.sh b/dotfiles/lib/bin/rofi_tmcodex.sh index f84850ae..e9a99a36 100755 --- a/dotfiles/lib/bin/rofi_tmcodex.sh +++ b/dotfiles/lib/bin/rofi_tmcodex.sh @@ -10,6 +10,7 @@ state_dir="${XDG_STATE_HOME:-$HOME/.local/state}/rofi-tmcodex" history_file="$state_dir/dirs" codex_home="${CODEX_HOME:-$HOME/.codex}" terminal="${TMCODEX_TERMINAL:-${TERMINAL:-ghostty}}" +dotfiles_root="${DOTFILES_WORKTREE:-/srv/dotfiles}" debug_log="$state_dir/debug.log" tmcodex_args=("$@") mkdir -p "$state_dir" @@ -29,8 +30,8 @@ emit_candidates() { # 2) A few common roots. Keep these before slow/best-effort discovery so # rofi still has useful entries if a metadata scan breaks. for d in \ - "$HOME/dotfiles" \ - "$HOME/dotfiles/nixos" \ + "$dotfiles_root" \ + "$dotfiles_root/nixos" \ "$HOME/Projects" \ "$HOME/config" \ "$HOME/org" @@ -43,7 +44,7 @@ emit_candidates() { # 4) Shallow git repo discovery under a few likely roots. if command -v fd >/dev/null 2>&1; then - for root in "$HOME/Projects" "$HOME/dotfiles" "$HOME/config" "$HOME/org"; do + for root in "$HOME/Projects" "$dotfiles_root" "$HOME/config" "$HOME/org"; do [[ -d "$root" ]] || continue # Find ".git" directories; print their parent (repo root). # Keep it shallow for speed. diff --git a/dotfiles/lib/bin/setup-shared-dotfiles b/dotfiles/lib/bin/setup-shared-dotfiles new file mode 100755 index 00000000..3df03f44 --- /dev/null +++ b/dotfiles/lib/bin/setup-shared-dotfiles @@ -0,0 +1,123 @@ +#!/usr/bin/env bash +set -euo pipefail + +usage() { + cat <<'EOF' +Usage: setup-shared-dotfiles [--target /srv/dotfiles] [--group wheel] [--no-etc-nixos] [--force-etc-nixos] + +Copies this dotfiles checkout to an absent or empty shared machine-local +worktree, then configures permissions so everyone can read it and sudoers can +edit it without sudo. When the target already contains a git checkout, this +repairs permissions/config only and does not overwrite local changes. + +Defaults: + target: /srv/dotfiles + group: wheel + +The script also creates /etc/nixos -> /nixos when /etc/nixos is absent +or already a symlink. Use --force-etc-nixos to replace an existing /etc/nixos +path with the symlink. +EOF +} + +target=/srv/dotfiles +group=wheel +manage_etc_nixos=1 +force_etc_nixos=0 + +while [[ $# -gt 0 ]]; do + case "$1" in + --target) + target="$2" + shift 2 + ;; + --group) + group="$2" + shift 2 + ;; + --no-etc-nixos) + manage_etc_nixos=0 + shift + ;; + --force-etc-nixos) + force_etc_nixos=1 + shift + ;; + -h|--help) + usage + exit 0 + ;; + *) + echo "Unknown argument: $1" >&2 + usage >&2 + exit 2 + ;; + esac +done + +script_dir="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)" +source_root="$(git -C "$script_dir" rev-parse --show-toplevel)" +target="$(realpath -m "$target")" + +if ! getent group "$group" >/dev/null; then + echo "Group '$group' does not exist" >&2 + exit 1 +fi + +sudo install -d -m 2775 -o root -g "$group" "$(dirname "$target")" + +if [[ "$source_root" != "$target" ]]; then + target_has_content=0 + if [[ -d "$target" ]] && find "$target" -mindepth 1 -maxdepth 1 -print -quit | grep -q .; then + target_has_content=1 + fi + + if [[ "$target_has_content" == 1 && ! -d "$target/.git" ]]; then + echo "Refusing to copy into non-empty non-git target: $target" >&2 + exit 1 + fi + + if [[ "$target_has_content" == 0 ]]; then + sudo install -d -m 2775 -o root -g "$group" "$target" + sudo rsync -a --chown="root:$group" "$source_root/" "$target/" + else + echo "Existing git checkout found at $target; repairing permissions only." + fi +fi + +sudo chown -R "root:$group" "$target" +sudo find "$target" -type d -exec chmod 2775 {} + +sudo find "$target" -type f -exec chmod u+rw,g+rw,o+r {} + + +if command -v setfacl >/dev/null; then + sudo setfacl -R -m "g::rwX,o::rX,m::rwX" "$target" + sudo setfacl -R -d -m "g::rwX,o::rX,m::rwX" "$target" +fi + +sudo git -C "$target" config core.sharedRepository group +if ! sudo git config --system --get-all safe.directory 2>/dev/null | grep -Fx -- "$target" >/dev/null; then + sudo git config --system --add safe.directory "$target" 2>/dev/null || true +fi + +if [[ "$manage_etc_nixos" == 1 ]]; then + nixos_target="$target/nixos" + if [[ ! -d "$nixos_target" ]]; then + echo "Expected NixOS flake directory is missing: $nixos_target" >&2 + exit 1 + fi + + if [[ -L /etc/nixos || ! -e /etc/nixos ]]; then + sudo rm -rf /etc/nixos + sudo ln -s "$nixos_target" /etc/nixos + elif [[ "$force_etc_nixos" == 1 ]]; then + backup="/etc/nixos.backup.$(date +%Y%m%d-%H%M%S)" + sudo mv /etc/nixos "$backup" + sudo ln -s "$nixos_target" /etc/nixos + echo "Moved previous /etc/nixos to $backup" + else + echo "Leaving existing /etc/nixos in place; pass --force-etc-nixos to replace it." >&2 + fi +fi + +echo "Shared dotfiles worktree ready: $target" +echo "Nix/Home Manager should use dotfiles-worktree = \"$target\"." diff --git a/dotfiles/lib/functions/windows_toast b/dotfiles/lib/functions/windows_toast index bfc136f5..7fbd7cb4 100755 --- a/dotfiles/lib/functions/windows_toast +++ b/dotfiles/lib/functions/windows_toast @@ -1,7 +1,7 @@ #!/usr/bin/env sh function windows_toast { - powershell.exe -File ~/dotfiles/dotfiles/lib/bin/windows-toast.ps1 -Title "$@" 2>/dev/null + powershell.exe -File "${DOTFILES_WORKTREE:-/srv/dotfiles}/dotfiles/lib/bin/windows-toast.ps1" -Title "$@" 2>/dev/null } windows_toast "$@" diff --git a/dotfiles/tmux.conf b/dotfiles/tmux.conf index fe914808..abd411f2 100644 --- a/dotfiles/tmux.conf +++ b/dotfiles/tmux.conf @@ -4,7 +4,7 @@ bind-key C new-session -c '#{pane_current_path}' 'codex --dangerously-bypass-app source-file -q /etc/tmux-host-style.conf -set -g status-right '#($HOME/dotfiles/dotfiles/lib/functions/multiplexer_host_label --tmux 2>/dev/null || multiplexer_host_label --tmux 2>/dev/null || hostname -s) #{?window_bigger,[#{window_offset_x}#,#{window_offset_y}] ,}"#{=21:pane_title}" %H:%M %d-%b-%y' +set -g status-right '#(multiplexer_host_label --tmux 2>/dev/null || hostname -s) #{?window_bigger,[#{window_offset_x}#,#{window_offset_y}] ,}"#{=21:pane_title}" %H:%M %d-%b-%y' set -g status-right-length 150 set -g set-titles on set -g set-titles-string '#{?#{==:#{session_name},#{window_name}},#{session_name},#{session_name}:#{window_name}}#{?pane_title, - #{pane_title},}' diff --git a/dotfiles/tmux.powerline b/dotfiles/tmux.powerline index d54827b8..e0d88b27 100644 --- a/dotfiles/tmux.powerline +++ b/dotfiles/tmux.powerline @@ -6,7 +6,7 @@ set -g status-interval 2 set -g status-justify left set -g status-left-length 150 set -g status-right-length 150 -set -g status-right '#($HOME/dotfiles/dotfiles/lib/functions/multiplexer_host_label --tmux 2>/dev/null || multiplexer_host_label --tmux 2>/dev/null || hostname -s) #(eval $POWERLINE_COMMAND tmux right -R pane_id=`tmux display -p "#D"`)' +set -g status-right '#(multiplexer_host_label --tmux 2>/dev/null || hostname -s) #(eval $POWERLINE_COMMAND tmux right -R pane_id=`tmux display -p "#D"`)' set -g window-status-format "#[fg=white] #[fg=white,bg=black]#I #[fg=white] #[default]#W " set -g window-status-current-format "#[fg=black,bg=blue]#[fg=white,bg=blue] #I  #[fg=white,bold]#W #[fg=blue,bg=black,nobold]" set-window-option -g window-status-fg white diff --git a/justfile b/justfile index 9ff55d88..810a8904 100644 --- a/justfile +++ b/justfile @@ -53,3 +53,12 @@ cachix-auth-from-clipboard: if command -v wl-paste >/dev/null; then wl-paste --no-newline | cachix authtoken --stdin; printf '' | wl-copy; \ elif command -v xclip >/dev/null; then xclip -o -selection clipboard | tr -d '\n' | cachix authtoken --stdin; printf '' | xclip -selection clipboard; \ else echo "No clipboard tool found (expected wl-paste or xclip)." >&2; exit 1; fi + +# Install or re-permission the repo as a shared machine-local checkout. +# +# Usage: +# - `just setup-shared-dotfiles` +# - `just setup-shared-dotfiles --target /srv/dotfiles --group wheel` +# - `just setup-shared-dotfiles --force-etc-nixos` +setup-shared-dotfiles *args: + ./dotfiles/lib/bin/setup-shared-dotfiles {{args}} diff --git a/nixos/.claude/skills/bump-overlay-versions/SKILL.md b/nixos/.claude/skills/bump-overlay-versions/SKILL.md index b99cc162..19305844 100644 --- a/nixos/.claude/skills/bump-overlay-versions/SKILL.md +++ b/nixos/.claude/skills/bump-overlay-versions/SKILL.md @@ -7,7 +7,7 @@ description: Use when user asks to bump, update, or upgrade claude-code or codex ## Overview -Updates claude-code and/or codex to latest versions in `~/dotfiles/nixos/overlay.nix`. Nix requires correct hashes which must be discovered through failed builds. +Updates claude-code and/or codex to latest versions in `/etc/nixos/overlay.nix`. Nix requires correct hashes which must be discovered through failed builds. ## Quick Reference @@ -30,7 +30,7 @@ curl -s "https://api.github.com/repos/openai/codex/releases/latest" | jq -r '.ta ### 2. Update Version and Clear Hashes -In `~/dotfiles/nixos/overlay.nix`: +In `/etc/nixos/overlay.nix`: **For claude-code:** ```nix @@ -77,4 +77,4 @@ enableClaudeCodeOverride = true; # Set false to use nixpkgs claude-code ## File Location -`~/dotfiles/nixos/overlay.nix` +`/etc/nixos/overlay.nix` diff --git a/nixos/AGENTS.md b/nixos/AGENTS.md index 7ae60487..7cd78ac6 100644 --- a/nixos/AGENTS.md +++ b/nixos/AGENTS.md @@ -1,6 +1,6 @@ # Agent Notes (dotfiles/nixos) -This repository is a single git repo rooted at `~/dotfiles`. This `nixos/` directory is the NixOS flake, but most "user command" scripts and shell functions live outside of it. +This repository is a single git repo rooted at `/srv/dotfiles` on NixOS machines. This `nixos/` directory is the NixOS flake, but most "user command" scripts and shell functions live outside of it. ## Where To Put Things @@ -13,7 +13,7 @@ Avoid dropping scripts in `~/bin` or `~/.local/bin` unless the user explicitly a ## NixOS Rebuild Workflow -- Run `just switch` from `~/dotfiles/nixos` (not `nixos-rebuild` directly). +- Run `just switch` from `/etc/nixos` or `/srv/dotfiles/nixos` (not `nixos-rebuild` directly). - Host configs live under `machines/`. ## Rofi/Tmux Integration Pointers diff --git a/nixos/dotfiles-links.nix b/nixos/dotfiles-links.nix index 3f771646..26fbebd9 100644 --- a/nixos/dotfiles-links.nix +++ b/nixos/dotfiles-links.nix @@ -1,10 +1,11 @@ { config, lib, + nixos, ... }: let # Replicate the useful part of rcm/rcup: - # - dotfiles live in ~/dotfiles/dotfiles (no leading dots in the repo) + # - dotfiles live in /dotfiles (no leading dots in the repo) # - links in $HOME add a leading '.' to the first path component # - link files individually so unmanaged state can coexist (e.g. ~/.cabal/store) # @@ -13,7 +14,10 @@ oos = config.lib.file.mkOutOfStoreSymlink; # Where the checked-out repo lives at runtime (activation time). - worktreeDotfiles = "${config.home.homeDirectory}/dotfiles/dotfiles"; + # Keep this outside individual home directories so links work for every + # managed user on a shared machine. + worktreeRoot = nixos.config.dotfiles-worktree or "${config.home.homeDirectory}/dotfiles"; + worktreeDotfiles = "${worktreeRoot}/dotfiles"; # Use the flake source for enumeration (pure), but point links at the worktree. srcDotfiles = ../dotfiles; diff --git a/nixos/environment.nix b/nixos/environment.nix index 62a6341e..d89df995 100644 --- a/nixos/environment.nix +++ b/nixos/environment.nix @@ -6,7 +6,7 @@ inputs, ... }: let - libDir = "${config.dotfiles-directory}/dotfiles/lib"; + libDir = "${config.dotfiles-worktree}/dotfiles/lib"; machineFilenames = builtins.attrNames (builtins.readDir ./machines); machineNameFromFilename = filename: builtins.head (builtins.split "\\." filename); machineNames = map machineNameFromFilename machineFilenames; @@ -26,6 +26,15 @@ in type = types.path; default = ../.; }; + dotfiles-worktree = mkOption { + type = types.str; + default = "/srv/dotfiles"; + description = '' + Runtime path to the shared, editable dotfiles checkout. Home Manager + uses this for out-of-store symlink targets so links are stable across + users instead of depending on each user's home directory. + ''; + }; }; config = { @@ -105,6 +114,7 @@ in } // multiplexerAliases; variables = { + DOTFILES_WORKTREE = config.dotfiles-worktree; ROFI_SYSTEMD_TERM = "ghostty -e"; NIXPKGS_GIT_REV = "${inputs.nixpkgs.rev}"; NIXPKGS_SOURCE = "${inputs.nixpkgs.outPath}"; diff --git a/nixos/imalison.nix b/nixos/imalison.nix index b272b12e..5080a0ca 100644 --- a/nixos/imalison.nix +++ b/nixos/imalison.nix @@ -1,10 +1,15 @@ -{pkgs, ...}: let +{ + config, + pkgs, + ... +}: let session = import ./session-variables.nix; + dotfilesRoot = config.dotfiles-worktree; cargoSweepRustTargets = pkgs.writeShellApplication { name = "cargo-sweep-rust-targets"; runtimeInputs = [pkgs.cargo-sweep]; text = '' - for root in /home/imalison/Projects /home/imalison/org /home/imalison/dotfiles; do + for root in /home/imalison/Projects /home/imalison/org ${dotfilesRoot}; do if [[ -d "$root" ]]; then cargo-sweep sweep -r --hidden --maxsize 15GB "$root" fi