# Plan: Dots — preserve and sync user configs out of the box Revision 3. Rev 2 incorporated adversarial review by codex (xhigh) and grok; rev 3 names the feature **dots** (`omarchy dots ...`) and adds the multi-machine sync design. ## Problem Omarchy declares `~/.config` "your files" but does little to preserve them: - `omarchy-refresh-config` litters `*.bak.` files next to originals. - `omarchy-reinstall-configs` clobbers everything back to `/etc/skel` defaults. - Snapper only snapshots the `root` config; recovering one config file from a root snapshot is not a workflow, and `/home` may not be covered at all. - The manual punts to a YouTube video about Stow. There is no way to answer "what did the last update change about my configs?", "restore my bindings from last week," or "make my new laptop feel like my desktop." ## Rejected approaches - **`git init ~/.config`**: dumping ground — Chromium profile, fcitx5 state, app tokens, machine churn. A `.git` there gets discovered by editors and prompts. Can't cover `~/.bashrc` or `~/.XCompose`. - **`~/.config/omarchy` only**: too narrow; misses hypr, terminals, `.bashrc`. - **Stow**: inverted model requiring file migration; organization, not history. - **chezmoi / yadm**: third-party DSLs we'd be wrapping; overkill. - **Raw git passthrough / lazygit over `$HOME`** (rejected in review): `git clean -fd`, `reset --hard`, or "stage all" against a `$HOME` work tree is a home-directory-eraser; `git add -A` can ingest `~/.ssh` and the object store into itself (`status.showUntrackedFiles no` only affects `status`); `remote add` + `push` silently defeats local-only. Experts can construct the raw invocation themselves; Omarchy will not bless it. - **Distributed git across machines**: two machines auto-committing timer and update snapshots into a shared branch conflict constantly. History and sync are different products (see Sync below). ## Chosen design: bare repo over `$HOME`, driven only by constrained commands ```bash git init --bare ~/.local/share/omarchy/dots.git # mode 0700 ``` No `.git` in any directory tools walk; files stay plain files in place. All access goes through one internal helper that runs git **hermetically**: - Repo-local config only: synthetic identity (`Omarchy `), `commit.gpgsign=false`, `core.hooksPath` disabled, `--no-verify`, `GIT_CONFIG_GLOBAL=/dev/null` so user signing/hooks/templates/excludes and a `$HOME/.gitignore` can never break or intercept an automatic commit. - Never export `GIT_DIR`/`GIT_WORK_TREE` (would leak into `omarchy-plugin-*`, `omarchy-theme-update`, `omarchy-update-dev`, user hooks). - Serialized via a lock; concurrent refresh/update/manual snapshots queue. - **Best-effort everywhere**: a failed snapshot warns and continues. History is optional; updates are not. Never on the failure path of `omarchy-update`/`omarchy-migrate` (`set -e` there must not see git errors). ### Audited manifest, not a derived whitelist Tracking is `git add -f --pathspec-from-file=` only. The manifest is a hand-audited file shipped with Omarchy — explicitly **not** derived from `$OMARCHY_PATH/config` (which ships Chromium Preferences, fcitx5, `opencode/opencode.json` where users put API keys, etc.): - Include: `.config/hypr/*.{lua,conf}`, `.config/omarchy/shell.json`, `.config/omarchy/extensions/**`, `.config/omarchy/hooks/**`, terminal configs (alacritty/foot/ghostty/kitty), `.config/btop/btop.conf`, `.config/starship.toml`, `.bashrc`, `.XCompose`. - Exclude (deliberately): `.config/omarchy/plugins/**` and `.config/omarchy/themes/**` (nested git clones managed by `omarchy-plugin-*` / `omarchy-theme-update`), backgrounds (multi-MB binaries), `.config/btop/themes/` (symlink into `~/.local/state`), anything Chromium/fcitx5/opencode/xournalpp. - **Two tiers**: every manifest path is history-tracked, but some are marked `local` — machine-specific files that sync must never touch. At minimum `monitors.lua`; likely hardware quirks like `dell-haptic.conf`. This is the lightweight answer to chezmoi's hostname templates: exclude, no DSL. - Once committed, a secret lives in the object store forever; "no remote" is not a secrets story. The manifest is the deny line — nothing outside it is ever staged, and there is no command that stages more. ### Dotfile-manager detection: stand down, don't fight `manual/31-dotfiles.md` sends users to Stow today, and migrations deliberately write *through* symlinks. For those users git records an unchanged symlink, so snapshots would be silent no-ops — and `restore` could stomp a symlink with a regular file. Therefore: - At seed time and before each snapshot: if manifest paths are symlinks or a known manager (yadm, chezmoi, existing bare-repo alias, `~/.git`) is detected, mark the repo dormant and say so in `omarchy dots status`. - `restore` refuses type changes (symlink↔file) and paths outside the manifest. - These users keep `.bak` behavior, which genuinely works for them (copies content, not links). ### Snapshot points: batch boundaries, before *and* after The unit is a labeled snapshot pair around each *batch* mutation, via an internal `omarchy-dots-snapshot "