[Sync] replace the flat layout with the unified stow tree
Supersedes the old flat .config/ layout (last published 2026-06-28) with the private repo's structure: one shared base plus per-host overlays. - packages: common/ gui/ lw/ fl/ wm/ plus install.sh and bin/ tooling (dotsync, reconcile-hyde.sh) - new README covering the layout, deploy order and the HyDE dependency - current HyDE waybar rig (layouts/, cava), pi agent extensions, claude/ config, tmux, presenterm, aichat roles - fish: kp (keepassxc-cli + fzf picker, db path from $KP_DB) and bind_M_n_history (alt+1..9 recalls the nth history entry) - drops cruft that should never have been tracked: the duplicate top-level .pi/ copy, btop.log, zellij config.kdl.bak, fish_variables - .pi/agent/auth.json is gitignored; auth.json.example ships instead Host-specific work sessions and the personal backlog stay in the private tree. Endpoint locators in the llamacpp/whisper guides are placeholders ($SERVER, <own-domain>) — the guides themselves stay, since they are the useful part.
This commit is contained in:
@@ -1,13 +1,196 @@
|
||||
# dots
|
||||
|
||||
using `gnu stow`
|
||||
Unified dotfiles for all machines: one shared base + per-host overlays, deployed with
|
||||
[GNU Stow](https://www.gnu.org/software/stow/).
|
||||
|
||||
Customized [Hyde](https://github.com/HyDE-Project/HyDE)
|
||||
## Layout
|
||||
|
||||
`hyde`, `waybar` and `fish` are from hyprdots with customizations
|
||||
Every top-level directory is a Stow *package* (they all share one stow dir, which `--override`
|
||||
requires). `bin/` holds repo tooling and is **not** a package (never stowed):
|
||||
|
||||
`nvim` is [nvchad](https://nvchad.com/) custom conf
|
||||
```
|
||||
common/ # shared everywhere (mirrors $HOME): fish, nvim, bat, btop, tmux, pi, claude, presenterm, ...
|
||||
gui/ # GUI configs shared by graphical hosts: hypr, waybar, kitty, alacritty, mpv, zellij
|
||||
wm/ # desktop: 4K monitors, NVIDIA, cloud LLM (duskadiy), work aliases
|
||||
lw/ # laptop: no NVIDIA, roaming VPNs, network/LLM tools
|
||||
fl/ # KDE Plasma box: a few Hyprland overrides + llamacpp, evremap
|
||||
bin/ # tooling (not a stow package): install.sh companions
|
||||
install.sh
|
||||
```
|
||||
|
||||
A **headless** (terminal-only) machine has no overlay package — it runs `common` only. Mark any box
|
||||
headless with `touch ~/.config/dots-headless` (a machine-local, hostname-independent marker); it then
|
||||
skips `gui` too, so the same terminal-only setup replicates across any number of machines. In other
|
||||
words `common` *is* the headless baseline; `gui` and the host packages layer graphical machines on top.
|
||||
|
||||
### How it deploys
|
||||
|
||||
Deploy order is `common → gui → <host>`; later layers win (the host package is stowed last with
|
||||
`--override`, so a host file replaces the common/gui file at the same path). Stow runs with
|
||||
`--no-folding`, so each *file* is symlinked individually (directories stay real) — this is what lets
|
||||
a host override a single file in a shared dir without shadowing the rest.
|
||||
|
||||
**Editing a config edits the repo copy directly** (it's a symlink) — no deploy step. You only re-run
|
||||
`install.sh` when files are **added or removed** (to create/prune symlinks). See **Syncing** below.
|
||||
|
||||
The repo must be cloned to **`~/.dots`** (the relative `../.dots` symlink convention). A host's
|
||||
package name must match `hostname -s` (or pass the host explicitly, e.g. `./install.sh lw`).
|
||||
|
||||
## Install (new machine)
|
||||
|
||||
```fish
|
||||
sudo pacman -S stow
|
||||
git clone <remote> ~/.dots
|
||||
cd ~/.dots
|
||||
./install.sh # auto-detects host via `hostname -s`
|
||||
```
|
||||
|
||||
`./install.sh -h` lists all options: `-n` dry-run, `-a` adopt (first run), `-D` unstow (revert),
|
||||
`-h` help. GUI hosts also need **HyDE installed** first — see *HyDE dependency* below.
|
||||
|
||||
Once per machine afterwards: `bat cache --build` (registers the repo's custom bat themes —
|
||||
without it every `bat` run warns `Unknown theme 'onedark'`), and `:Lazy restore` inside nvim
|
||||
(`restore` obeys the shared `lazy-lock.json` pins; `sync`/`update` would rewrite them).
|
||||
nvim's treesitter (`main` branch) builds parsers via the `tree-sitter` CLI — `pacman -S
|
||||
tree-sitter-cli` first, or `:TSInstallAll` fails with `ENOENT ... 'tree-sitter'`.
|
||||
|
||||
### First run on a machine that still has real config files
|
||||
|
||||
Stow **aborts the whole package on the first conflict** (one real file blocks *everything* in
|
||||
`common`), and refuses to clobber real files without `--adopt` — you'll see
|
||||
`cannot stow … since neither a link nor a directory`. Adopt them, review, then keep the repo's
|
||||
versions:
|
||||
|
||||
```fish
|
||||
cd ~/.dots
|
||||
git status # make sure the repo is clean first (see the restore caveat)
|
||||
./install.sh -a <host> # --adopt: pull existing files into the repo, symlink them back
|
||||
git diff --stat # what this machine had vs the repo (review the drift!)
|
||||
git restore . # discard adopted content, keep the repo versions
|
||||
```
|
||||
|
||||
`--adopt` overwrites the repo copies with the machine's files, so `git restore .` is what keeps the
|
||||
repo versions. Cautions: adopted changes can land under `common/`/`gui/` even when host-specific, and
|
||||
`git restore .` drops **all** uncommitted edits — so commit/stash anything you want first. To keep a
|
||||
genuine machine change (e.g. custom pyradio `stations.csv`), hand-copy it into the right package
|
||||
instead of restoring that path.
|
||||
|
||||
## Syncing (day-to-day)
|
||||
|
||||
Because configs are symlinks into the repo, **you almost never run `install.sh` to sync**:
|
||||
|
||||
- **Pull/propagate edits:** `cd ~/.dots && git pull` — changes are live in place instantly. No
|
||||
re-stow, so **no symlink churn and no app reloads** (kitty etc. keep runtime state).
|
||||
- **`bin/dotsync`** does this safely: `git pull`, then re-link via `install.sh` **only if** the pull
|
||||
added/removed/renamed files (pure edits skip the re-stow). `dotsync -n` previews incoming changes.
|
||||
- **`install.sh` is a (re)deploy tool, not a sync tool** — its `stow -R` deletes+recreates every
|
||||
symlink, which is what makes apps reload. Only needed for the initial link or when files are
|
||||
added/removed.
|
||||
- **Never `stow` the repo root** (`stow .dots`, `stow */`) — it folds package dirs into `~` as stray
|
||||
`~/common`, `~/gui`, … symlinks. `install.sh` only ever links package *contents*.
|
||||
- **New host:** create a top-level `<name>/` package (at least a `host.fish`), commit, then
|
||||
`./install.sh`. If it's terminal-only, skip the package and just `touch ~/.config/dots-headless`
|
||||
(it runs `common` only).
|
||||
|
||||
## Tooling (`bin/`)
|
||||
|
||||
| Command | What it does |
|
||||
|---|---|
|
||||
| `./install.sh [host]` | Deploy `common → gui → <host>`. Flags: `-n` dry-run, `-a` adopt (first run), `-D`/`--unstow` revert (remove this host's symlinks; repo + real files kept), `-h` help. Self-heals: headless hosts get any stray `gui` unstowed; fails loudly (exit 1) if a package couldn't stow. |
|
||||
| `./bin/dotsync [-n]` | Sync with least churn: `git pull`, re-stow only if files were added/removed. |
|
||||
| `./bin/reconcile-hyde.sh [-i\|--relink] [host]` | After a HyDE update overwrote `~/.config/hypr`, reconcile HyDE's new files against your dots versions (report / `-i` keep·take·merge each / `--relink` re-symlink). |
|
||||
|
||||
## How per-host differences are expressed
|
||||
|
||||
| Difference | Mechanism |
|
||||
|---|---|
|
||||
| Monitors | `<h>/.config/hypr/monitors.conf` (sourced by the shared `hyprland.conf`) |
|
||||
| NVIDIA | `wm/.config/hypr/nvidia.conf`, pulled in by wm's `host.conf` (fl/lw have no NVIDIA) |
|
||||
| Shell aliases | shared `config.fish` sources `~/.config/fish/host.fish` (per host) |
|
||||
| Bash extras | shared `.bashrc` sources `~/.bashrc.host` (optional, per host) |
|
||||
| fl's Hyprland | overrides ~9 hypr files (`hyprland.conf`, keybinds, windowrules, theme colors, monitors); inherits the rest from `gui` |
|
||||
| Unique apps | in the owning host overlay (fl: llamacpp/evremap; lw: xremap) |
|
||||
|
||||
`aichat`, `pi`, and `opencode` are **single shared configs** in `common` (LAN-first, with the cloud
|
||||
provider also listed so any host can switch) — no per-host overrides.
|
||||
|
||||
## HyDE dependency (important for GUI hosts)
|
||||
|
||||
The Hyprland config is [HyDE](https://github.com/HyDE-Project/HyDE)-based. `gui/.config/hypr/*` is
|
||||
your customization layer, but it **sources HyDE's framework**:
|
||||
`source = ~/.local/share/hyde/hyprland.conf` — which defines `$mainMod` and other variables and is
|
||||
**not tracked by dots** (HyDE generates it). So a GUI host must have **HyDE installed**, or Hyprland
|
||||
fails to start (`source globbing error` + `invalid mod $mainMod`).
|
||||
|
||||
- Install/update HyDE with its own installer (`~/HyDE/Scripts/install.sh`); it also pulls the
|
||||
required apps (`xdg-desktop-portal-hyprland`, `xdg-desktop-portal-gtk`, `hyprpolkitagent`).
|
||||
- HyDE's `-r`/restore overwrites `~/.config/hypr` — use **`bin/reconcile-hyde.sh`** afterward to fold
|
||||
its new defaults back against your dots configs.
|
||||
- **Wallpapers and generated themes are HyDE-owned, never in dots** (`**/hyde/themes/` and
|
||||
`**/wallpapers/` are gitignored — they once bloated a source repo to 255 MB). A fresh machine gets
|
||||
them from HyDE, not from this repo.
|
||||
|
||||
## Waybar (two worlds: HyDE-generated vs the standalone rig)
|
||||
|
||||
**HyDE owns `~/.config/waybar/config.jsonc` AND `style.css`** — its `waybar.py` *writes* both on
|
||||
any `--set`/`--update`, **through the stow symlinks, i.e. into this repo's checkout**. So dots
|
||||
track neither. HyDE-managed customization goes via:
|
||||
|
||||
- `gui/.config/waybar/layouts/*.jsonc` — dots-tracked layouts; switch with `hyde-shell waybar --set <name>`.
|
||||
- `gui/.config/waybar/modules/*.jsonc` — module defs, globbed into the generated config.
|
||||
|
||||
**The custom cava rig is NOT HyDE-managed**: `layouts/custom.jsonc` + `layouts/custom.css` form a
|
||||
self-contained two-bar config launched raw (`waybar -c …custom.jsonc -s …custom.css` — exec-once,
|
||||
the Ctrl+Alt+W / Super+Shift+R binds, and the `wbar` abbr). **Never route it through
|
||||
`hyde-shell waybar --set`** — waybar.py would clobber the repo's files as above. HyDE only reads
|
||||
from `layouts/`, which is what makes them safe to track. On a rig host, HyDE's own bar (systemd
|
||||
user unit `hyde-<XDG_SESSION_DESKTOP>-bar.service`, auto-restarting) must be disabled once:
|
||||
`systemctl --user stop <unit>; systemctl --user mask <unit>`.
|
||||
|
||||
Note: the Arch `waybar` build has **no native `cava`** module — the rig uses the script module
|
||||
`custom/cava` running `cava-waybar.sh` (self-contained, no HyDE dependency).
|
||||
|
||||
## Secrets
|
||||
|
||||
Never committed. Put `DUSKADIY_API_KEY` etc. in `~/.config/fish/conf.d/secrets.fish` (gitignored).
|
||||
`pi`'s `auth.json` is **not** tracked — it only ever holds `$VAR` references, but pi's `/login`
|
||||
rewrites it with the literal key, so one stray `/login` would commit a real token. A new host
|
||||
bootstraps it with `cp common/.pi/agent/auth.json.example common/.pi/agent/auth.json`, then
|
||||
`./install.sh`. Also gitignored: `fish_variables`,
|
||||
`greet.txt`, pi agent runtime/state, `tmux/plugins/`, `.claude/` (Claude Code project dir/worktrees),
|
||||
`*.bak`/`*.log`.
|
||||
|
||||
## Merge notes (history — the one-time unification)
|
||||
|
||||
The four former per-machine repos had drifted; the merge made some judgment calls:
|
||||
|
||||
- **`config.fish` / `.bashrc`** were hand-reconciled into a neutral shared base + per-host
|
||||
`host.fish` / `.bashrc.host` (removed a committed `fnm_multishells` runtime PATH, stray
|
||||
absolute home-dir paths, duplicate git aliases).
|
||||
- **`pi` lives at `~/.pi`** (repo `.pi/`); **`tmux` at `~/.config/tmux/`** (delete a legacy
|
||||
`~/.tmux.conf` if present after migrating).
|
||||
- **Appearance drift was unified to one canonical** (mostly wm): bat, btop, cava, fastfetch, lazygit,
|
||||
mpv, pyradio, waybar, zellij, most of nvim.
|
||||
- **nvim** is shared entirely (no host overrides); plugin set / `lazy-lock.json` are shared — run
|
||||
`:Lazy restore` per machine once (obeys the lockfile pins — `:Lazy update` on one machine +
|
||||
commit is how versions move forward; other machines converge with `restore`).
|
||||
- **`zellij`** is one shared config with **vim keybinds** (h/j/k/l) + the `guvbox-dark` theme.
|
||||
- **`misc/{clis,tuis}.txt`** launcher inventories use wm's lists in `common`; a machine needing its
|
||||
own can override in its overlay.
|
||||
|
||||
## Third-party content and licensing
|
||||
|
||||
The repo is GPL-3.0 (`LICENSE`). What that does and doesn't cover:
|
||||
|
||||
- **`hypr/`, `waybar/` and the other desktop configs are derived from
|
||||
[HyDE](https://github.com/HyDE-Project/HyDE)** (and, further back, legacy Hyprdots). HyDE is
|
||||
itself GPL-3.0, so the derivation and this repo's licence agree — no conflict, and the
|
||||
Hyprdots-era ASCII banners in those files are left in place as attribution.
|
||||
- **`common/.config/aichat/dark.tmTheme`** is *One Half Dark* by Son A. Pham, **MIT**. The
|
||||
licence header at the top of that file is the attribution — don't strip it.
|
||||
- **`common/.config/fastfetch/pngs/`** holds project and distro marks (Arch, the Open Source
|
||||
Initiative and Open Source Hardware logos, …). Trademarks aren't relicensable, so GPL-3 does
|
||||
not extend to them; they are bundled as nominative use, the way most dotfiles repos do.
|
||||
- **`gui/.config/hypr/hyprlock/assets/`** — the lock screen background and logo. EXIF is
|
||||
stripped, so the files carry no provenance; confirm these are yours to redistribute before
|
||||
publishing, or swap them for something you know the origin of.
|
||||
|
||||
Reference in New Issue
Block a user